diff --git a/.github/workflows/CI-unixish-docker.yml b/.github/workflows/CI-unixish-docker.yml index a38feb452f0..16c1615ed04 100644 --- a/.github/workflows/CI-unixish-docker.yml +++ b/.github/workflows/CI-unixish-docker.yml @@ -72,7 +72,7 @@ jobs: - name: Run CMake run: | - 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 + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -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 if: matrix.full_build diff --git a/.github/workflows/CI-unixish.yml b/.github/workflows/CI-unixish.yml index 3251a6b5adb..8fb5c8d76d6 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 -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 -S . -B cmake.output.tinyxml2 -Werror=dev --warn-uninitialized -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 -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 -S . -B cmake.output.tinyxml2 -Werror=dev --warn-uninitialized -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 -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 + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -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 -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 + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -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: | @@ -150,17 +150,18 @@ jobs: - name: Run CMake install run: | cmake --build cmake.output --target install + # TODO: validate the installed files - name: Run CMake on ubuntu (no CLI) if: matrix.os == 'ubuntu-22.04' run: | - cmake -S . -B cmake.output_nocli -Werror=dev -DBUILD_TESTING=Off -DBUILD_CLI=Off + cmake -S . -B cmake.output_nocli -Werror=dev --warn-uninitialized -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 -Werror=dev -DBUILD_TESTING=On -DBUILD_CLI=Off; then + if cmake -S . -B cmake.output_nocli_tests -Werror=dev --warn-uninitialized -DBUILD_TESTING=On -DBUILD_CLI=Off; then exit 1 else exit 0 @@ -169,18 +170,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 -Werror=dev -DBUILD_TESTING=Off -DBUILD_CLI=Off -DBUILD_GUI=On + cmake -S . -B cmake.output_nocli_gui -Werror=dev --warn-uninitialized -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 -Werror=dev -DBUILD_TESTING=Off -DBUILD_GUI=Off + cmake -S . -B cmake.output_nogui -Werror=dev --warn-uninitialized -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 -Werror=dev -DBUILD_TESTING=Off -DBUILD_GUI=Off -DBUILD_TRIAGE=On; then + if cmake -S . -B cmake.output_nogui_triage -Werror=dev --warn-uninitialized -DBUILD_TESTING=Off -DBUILD_GUI=Off -DBUILD_TRIAGE=On; then exit 1 else exit 0 @@ -189,7 +190,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 -Werror=dev -DBUILD_TESTING=Off -DBUILD_GUI=Off + cmake -S . -B cmake.output_nocli_nogui -Werror=dev --warn-uninitialized -DBUILD_TESTING=Off -DBUILD_GUI=Off build_cmake_cxxstd: @@ -243,12 +244,12 @@ jobs: - name: Run CMake on ubuntu (with GUI) if: contains(matrix.os, 'ubuntu') run: | - 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 + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -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 -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 + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -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 +374,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 -Werror=dev -DBUILD_TESTING=Off -DUSE_BOOST=On; then + if cmake -S . -B cmake.output.boost-force-noavail -Werror=dev --warn-uninitialized -DBUILD_TESTING=Off -DUSE_BOOST=On; then exit 1 else exit 0 @@ -386,12 +387,12 @@ jobs: - name: Run CMake on macOS (force Boost) run: | - cmake -S . -B cmake.output.boost-force -Werror=dev -DBUILD_TESTING=Off -DUSE_BOOST=On + cmake -S . -B cmake.output.boost-force -Werror=dev --warn-uninitialized -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 -Werror=dev -DBUILD_TESTING=Off -DUSE_BOOST=Off + cmake -S . -B cmake.output.boost-no -Werror=dev --warn-uninitialized -DBUILD_TESTING=Off -DUSE_BOOST=Off if grep -q '\-DHAVE_BOOST' ./cmake.output.boost-no/compile_commands.json; then exit 1 else @@ -400,7 +401,7 @@ jobs: - name: Run CMake on macOS (with Boost) run: | - 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 + cmake -S . -B cmake.output.boost -Werror=dev --warn-uninitialized -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) @@ -436,11 +437,13 @@ jobs: - name: Run CMake (without GUI) run: | export PATH=cmake-${{ env.CMAKE_VERSION_FULL }}-linux-x86_64/bin:$PATH + # FIXME: cannot use --warn-uninitialized here as it completely breaks the build 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 + # FIXME: cannot use --warn-uninitialized here as it completely breaks the build cmake -S . -B cmake.output.gui -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On build: @@ -596,7 +599,7 @@ jobs: - name: Test Signalhandler run: | - cmake -S . -B build.cmake.signal -Werror=dev -DBUILD_TESTING=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On + cmake -S . -B build.cmake.signal -Werror=dev --warn-uninitialized -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* . @@ -607,7 +610,7 @@ jobs: - name: Test Stacktrace if: contains(matrix.os, 'ubuntu') run: | - cmake -S . -B build.cmake.stack -Werror=dev -DBUILD_TESTING=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On + cmake -S . -B build.cmake.stack -Werror=dev --warn-uninitialized -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* . @@ -734,7 +737,7 @@ jobs: - name: CMake run: | - 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 + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -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: | diff --git a/.github/workflows/CI-windows.yml b/.github/workflows/CI-windows.yml index 71d72025cf9..a63be4e0ad9 100644 --- a/.github/workflows/CI-windows.yml +++ b/.github/workflows/CI-windows.yml @@ -47,29 +47,30 @@ jobs: modules: 'qtcharts' setup-python: 'false' cache: true - aqtversion: '==3.1.*' # TODO: remove when aqtinstall 3.2.2 is available - name: Run CMake run: | rem TODO: enable rules? - rem specify Release build so matchcompiler is used - 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! + cmake -S . -B build -Werror=dev --warn-uninitialized -DCMAKE_BUILD_TYPE=Debug -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DBUILD_TESTING=Off -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DBUILD_ONLINE_HELP=On -DISABLE_DMAKE=On -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! - - name: Build GUI release + - name: Build GUI run: | - cmake --build build --target cppcheck-gui --config Release || exit /b !errorlevel! + cmake --build build --config Debug --target cppcheck-gui || exit /b !errorlevel! + # TODO: can this be done in CMake? - name: Deploy GUI run: | - windeployqt build\bin\Release || exit /b !errorlevel! - del build\bin\Release\cppcheck-gui.ilk || exit /b !errorlevel! - del build\bin\Release\cppcheck-gui.pdb || exit /b !errorlevel! + windeployqt --no-translations build\bin\Debug || exit /b !errorlevel! + del build\bin\Debug\cppcheck-gui.pdb || exit /b !errorlevel! # TODO: run GUI tests - name: Run CMake install run: | - cmake --build build --target install + rem TODO: the Qt DLLs are not being installed + cmake --build build --config Debug --target install + rem TODO: validate the installed files + rem TODO: the structure does not match an actual Windows installation build_cmake_cxxstd: strategy: @@ -92,7 +93,7 @@ jobs: - name: Run CMake run: | - 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! + cmake -S . -B build.cxxstd -Werror=dev --warn-uninitialized -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: | @@ -128,7 +129,6 @@ jobs: 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: | @@ -272,7 +272,7 @@ jobs: - name: Test SEH wrapper if: matrix.config == 'release' run: | - cmake -S . -B build.cmake.seh -Werror=dev -DBUILD_TESTING=On -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! + cmake -S . -B build.cmake.seh -Werror=dev --warn-uninitialized -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/clang-tidy.yml b/.github/workflows/clang-tidy.yml index c4f8cc0cf6b..7a5b317693a 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 -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 + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -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/iwyu.yml b/.github/workflows/iwyu.yml index 05d5643bdf7..de047b8d10a 100644 --- a/.github/workflows/iwyu.yml +++ b/.github/workflows/iwyu.yml @@ -71,7 +71,7 @@ jobs: - name: Install missing software on Fedora if: contains(matrix.image, 'fedora') run: | - dnf install -y cmake clang pcre-devel + dnf install -y cmake clang dnf install -y libglvnd-devel # fixes missing dependency for Qt in CMake dnf install -y p7zip-plugins # required as fallback for py7zr in Qt installation dnf install -y python3-pip # fixes missing pip module in jurplel/install-qt-action @@ -125,7 +125,8 @@ jobs: - name: Prepare CMake run: | - 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++' }} + # TODO: re-enable HAVE_RULES + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=Off -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++ @@ -232,7 +233,8 @@ jobs: - name: Prepare CMake run: | - 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 }} + # TODO: re-enable HAVE_RULES + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=Off -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 bacf32c8eaf..8d09a55302e 100644 --- a/.github/workflows/release-windows.yml +++ b/.github/workflows/release-windows.yml @@ -56,7 +56,7 @@ jobs: cd pcre-%PCRE_VERSION% || exit /b !errorlevel! git apply --ignore-space-change ..\externals\pcre.patch || 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! + msbuild -m PCRE.slnx -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! @@ -85,7 +85,7 @@ jobs: run: | :: TODO: enable rules? :: specify Release build so matchcompiler is used - 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 -S . -B build -Werror=dev --warn-uninitialized -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/sanitizers.yml b/.github/workflows/sanitizers.yml index d7ff31939d0..ea0a0276c99 100644 --- a/.github/workflows/sanitizers.yml +++ b/.github/workflows/sanitizers.yml @@ -96,7 +96,7 @@ jobs: - name: CMake run: | - 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 + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -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 diff --git a/.github/workflows/selfcheck.yml b/.github/workflows/selfcheck.yml index cfd1107e92d..3517486df31 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 -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 + cmake -S . -B cmake.output -Werror=dev --warn-uninitialized -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 -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 + cmake -S . -B cmake.output.notest -Werror=dev --warn-uninitialized -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 -Werror=dev -DHAVE_RULES=On -DBUILD_TESTING=Off -DENABLE_CHECK_INTERNAL=On -DCPPCHK_GLIBCXX_DEBUG=Off + cmake -S . -B cmake.output.notest_nogui -Werror=dev --warn-uninitialized -DHAVE_RULES=On -DBUILD_TESTING=Off -DENABLE_CHECK_INTERNAL=On -DCPPCHK_GLIBCXX_DEBUG=Off - name: Generate dependencies (no test / no gui) run: | @@ -121,8 +121,25 @@ jobs: - name: Self check (unusedFunction / no test / no gui) run: | - 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 + echo ' + + + unusedFunction + lib/errorlogger.h + verboseMessage + + + unusedFunction + lib/importproject.cpp + selectVsConfigurations + + + unusedFunction + lib/importproject.cpp + getVSConfigs + + ' > supprs.xml + ./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 --suppress-xml=supprs.xml env: DISABLE_VALUEFLOW: 1 UNUSEDFUNCTION_ONLY: 1 @@ -131,7 +148,7 @@ jobs: # unusedFunction notest nocli - start - name: CMake (no test / no cli) run: | - 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 + cmake -S . -B cmake.output.notest_nocli -Werror=dev --warn-uninitialized -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 +171,7 @@ jobs: # unusedFunction notest nocli nogui - start - name: CMake (no test / no cli / no gui) run: | - 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 + cmake -S . -B cmake.output.notest_nocli_nogui -Werror=dev --warn-uninitialized -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: | diff --git a/.gitignore b/.gitignore index 434203fe2a9..a821204bf2d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.gcno *.gch *.o +*.a *.pyc /cppcheck /cppcheck.exe diff --git a/.selfcheck_suppressions b/.selfcheck_suppressions index 1687753c268..63d33fd2704 100644 --- a/.selfcheck_suppressions +++ b/.selfcheck_suppressions @@ -62,6 +62,8 @@ templateInstantiation:test/testutils.cpp naming-varname:externals/simplecpp/simplecpp.h naming-privateMemberVariable:externals/simplecpp/simplecpp.h +# false positive; lambda captures its owner +danglingLifetime:externals/simplecpp/simplecpp.h:505 # TODO: these warnings need to be addressed upstream uninitMemberVar:externals/tinyxml2/tinyxml2.h @@ -78,5 +80,4 @@ 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 40391c83d7d..b4917d7d157 100644 --- a/AUTHORS +++ b/AUTHORS @@ -22,6 +22,7 @@ Alexey Eryomenko Alexey Zhikhartsev Alfi Maulana Ali Can Demiralp +Alvin Che-Chia Chang Allen Winter Alon Alexander Alon Liberman @@ -33,6 +34,7 @@ Andreas Lutsch Andreas Pokorny Andreas Rönnquist Andreas Vollenweider +Andreas Wilhelm Andrei Karas Andrew C Aitchison Andrew C. Martin @@ -131,6 +133,7 @@ Felipe Pena Felix Faber Felix Geyer Felix Passenberg +Felix Patschkowski Felix Wolff Florian Mueller Florin Iucha @@ -141,6 +144,7 @@ Frank Winklmeier Frank Zingsheim Frederik Schwarzer fu7mu4 +Gaël Bonithon Galimov Albert Garrett Bodily Gary Leutheuser @@ -153,6 +157,7 @@ Gerhard Zlabinger Gerik Rhoden Gianfranco Costamagna Gianluca Scacco +Gilmar Santos Jr Gleydson Soares Goncalo Mao-Cheia Goran Džaferi @@ -203,6 +208,7 @@ Jonathan Clohessy Jonathan Haehne Jonathan Neuschäfer Jonathan Thackray +Jonny Paton José Martins Jose Roquette Joshua Beck @@ -327,6 +333,7 @@ Philip Chimento Philipp Kloke Pierre Schweitzer Pieter Duchi +Piotr Idzik Pino Toscano Pranav Khanna Radek Jarecki @@ -363,6 +370,7 @@ Samuel Degrande Samuel Poláček Sandeep Dutta Savvas Etairidis +Sayed Kaif Scott Ehlert Scott Furry Seafarix Ltd. @@ -434,6 +442,7 @@ Vladimir Petrigo Wang Haoyu Wang Yang WenChung Chiu +William Jakobsson Wolfgang Stöggl x29a XhmikosR diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c037a10b36..b5857a8413a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.22) -project(Cppcheck VERSION 2.20.99 LANGUAGES CXX) +project(Cppcheck VERSION 2.21.99 LANGUAGES CXX) include(cmake/options.cmake) diff --git a/Makefile b/Makefile index bb006c36fea..42b754733ec 100644 --- a/Makefile +++ b/Makefile @@ -208,7 +208,6 @@ LIBOBJ = $(libcppdir)/valueflow.o \ $(libcppdir)/addoninfo.o \ $(libcppdir)/analyzerinfo.o \ $(libcppdir)/astutils.o \ - $(libcppdir)/check.o \ $(libcppdir)/check64bit.o \ $(libcppdir)/checkassert.o \ $(libcppdir)/checkautovariables.o \ @@ -221,6 +220,7 @@ LIBOBJ = $(libcppdir)/valueflow.o \ $(libcppdir)/checkersreport.o \ $(libcppdir)/checkexceptionsafety.o \ $(libcppdir)/checkfunctions.o \ + $(libcppdir)/checkimpl.o \ $(libcppdir)/checkinternal.o \ $(libcppdir)/checkio.o \ $(libcppdir)/checkleakautovar.o \ @@ -228,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 \ @@ -482,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/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 +$(libcppdir)/valueflow.o: lib/valueflow.cpp lib/analyzer.h lib/astutils.h lib/calculate.h lib/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(libcppdir)/tokenize.o: lib/tokenize.cpp externals/simplecpp/simplecpp.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 $(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/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 +$(libcppdir)/symboldatabase.o: lib/symboldatabase.cpp 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 $(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 @@ -497,31 +498,28 @@ $(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/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 +$(libcppdir)/astutils.o: lib/astutils.cpp lib/astutils.h lib/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.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 $(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/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/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 +$(libcppdir)/check64bit.o: lib/check64bit.cpp lib/check.h lib/check64bit.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checkassert.o: lib/checkassert.cpp lib/astutils.h lib/check.h lib/checkassert.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checkautovariables.o: lib/checkautovariables.cpp lib/astutils.h lib/check.h lib/checkautovariables.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checkbool.o: lib/checkbool.cpp lib/astutils.h lib/check.h lib/checkbool.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checkbufferoverrun.o: lib/checkbufferoverrun.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/checkbufferoverrun.h lib/checkers.h lib/checkimpl.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/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/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 +$(libcppdir)/checkclass.o: lib/checkclass.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checkcondition.o: lib/checkcondition.cpp lib/astutils.h lib/check.h lib/checkcondition.h lib/checkers.h lib/checkimpl.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 $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkcondition.cpp $(libcppdir)/checkers.o: lib/checkers.cpp lib/checkers.h lib/config.h @@ -530,58 +528,64 @@ $(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/regex.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/library.h lib/mathlib.h lib/platform.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/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 +$(libcppdir)/checkexceptionsafety.o: lib/checkexceptionsafety.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkexceptionsafety.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checkfunctions.o: lib/checkfunctions.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkfunctions.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checkimpl.o: lib/checkimpl.cpp lib/checkers.h lib/checkimpl.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 + $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkimpl.cpp + +$(libcppdir)/checkinternal.o: lib/checkinternal.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checkio.o: lib/checkio.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checkleakautovar.o: lib/checkleakautovar.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checkmemoryleak.o: lib/checkmemoryleak.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checknullpointer.o: lib/checknullpointer.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checkother.o: lib/checkother.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checkpostfixoperator.o: lib/checkpostfixoperator.cpp lib/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(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/checkimpl.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/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checkstl.o: lib/checkstl.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checkstring.o: lib/checkstring.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checktype.o: lib/checktype.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checkuninitvar.o: lib/checkuninitvar.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checkunusedfunctions.o: lib/checkunusedfunctions.cpp externals/tinyxml2/tinyxml2.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 $(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/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 +$(libcppdir)/checkunusedvar.o: lib/checkunusedvar.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +$(libcppdir)/checkvaarg.o: lib/checkvaarg.cpp lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.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 $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkvaarg.cpp $(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 @@ -590,13 +594,13 @@ $(libcppdir)/clangimport.o: lib/clangimport.cpp lib/clangimport.h lib/config.h l $(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/rule.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/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 +$(libcppdir)/errorlogger.o: lib/errorlogger.cpp externals/tinyxml2/tinyxml2.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 $(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 @@ -605,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/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 +$(libcppdir)/forwardanalyzer.o: lib/forwardanalyzer.cpp 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 $(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/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 +$(libcppdir)/fwdanalysis.o: lib/fwdanalysis.cpp 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 $(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/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 +$(libcppdir)/importproject.o: lib/importproject.cpp externals/picojson/picojson.h externals/tinyxml2/tinyxml2.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 $(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 @@ -638,70 +642,70 @@ $(libcppdir)/pathmatch.o: lib/pathmatch.cpp lib/config.h lib/path.h lib/pathmatc $(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/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h +$(libcppdir)/preprocessor.o: lib/preprocessor.cpp externals/simplecpp/simplecpp.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 $(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/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 +$(libcppdir)/programmemory.o: lib/programmemory.cpp 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 $(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/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 +$(libcppdir)/reverseanalyzer.o: lib/reverseanalyzer.cpp 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 $(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/regex.h lib/sarifreport.h lib/settings.h lib/standards.h lib/utils.h +$(libcppdir)/sarifreport.o: lib/sarifreport.cpp externals/picojson/picojson.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 $(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/regex.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/rule.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/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 +$(libcppdir)/summaries.o: lib/summaries.cpp 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/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/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 +$(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/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/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 +$(libcppdir)/templatesimplifier.o: lib/templatesimplifier.cpp 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 $(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/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 +$(libcppdir)/token.o: lib/token.cpp externals/simplecpp/simplecpp.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 $(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/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 +$(libcppdir)/tokenlist.o: lib/tokenlist.cpp externals/simplecpp/simplecpp.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 $(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/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 +$(libcppdir)/vf_analyzers.o: lib/vf_analyzers.cpp 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 $(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/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 +$(libcppdir)/vf_common.o: lib/vf_common.cpp 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 $(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/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 +$(libcppdir)/vf_settokenvalue.o: lib/vf_settokenvalue.cpp 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 $(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/regex.h lib/settings.h lib/standards.h lib/utils.h +frontend/frontend.o: frontend/frontend.cpp frontend/frontend.h lib/checkers.h lib/config.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 $(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/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/rule.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/regex.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/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 $(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/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h +cli/executor.o: cli/executor.cpp cli/executor.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 $(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 @@ -710,7 +714,7 @@ cli/filelister.o: cli/filelister.cpp cli/filelister.h lib/config.h lib/filesetti 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/regex.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/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 $(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 @@ -719,247 +723,247 @@ cli/sehwrapper.o: cli/sehwrapper.cpp cli/sehwrapper.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/regex.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/check.h lib/checkers.h lib/config.h lib/cppcheck.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 $(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/regex.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/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/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/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 +test/fixture.o: test/fixture.cpp externals/tinyxml2/tinyxml2.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/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/regex.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/checkers.h lib/config.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 $(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/regex.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/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 $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/main.cpp 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/regex.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/check.h lib/check64bit.h lib/checkers.h lib/checkimpl.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 $(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/regex.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/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 $(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/regex.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/check.h lib/checkassert.h lib/checkers.h lib/checkimpl.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 $(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/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 +test/testastutils.o: test/testastutils.cpp 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 $(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/regex.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/check.h lib/checkautovariables.h lib/checkers.h lib/checkimpl.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 $(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/regex.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/check.h lib/checkbool.h lib/checkers.h lib/checkimpl.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 $(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/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 +test/testbufferoverrun.o: test/testbufferoverrun.cpp lib/check.h lib/checkbufferoverrun.h lib/checkers.h lib/checkimpl.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 $(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/regex.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/check.h lib/checkers.h lib/checkimpl.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 $(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/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testcheck.o: test/testcheck.cpp 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/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/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 +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/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 +test/testclangimport.o: test/testclangimport.cpp 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 $(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/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 +test/testclass.o: test/testclass.cpp lib/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.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 $(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/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 +test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.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/rule.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/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testcolor.o: test/testcolor.cpp 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 $(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/regex.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/check.h lib/checkcondition.h lib/checkers.h lib/checkimpl.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 $(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/regex.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/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.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 $(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/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 +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 $(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/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 +test/testerrorlogger.o: test/testerrorlogger.cpp externals/tinyxml2/tinyxml2.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 $(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/regex.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/check.h lib/checkers.h lib/checkexceptionsafety.h lib/checkimpl.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 $(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/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/testexecutor.o: test/testexecutor.cpp cli/executor.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 $(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/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testfilelister.o: test/testfilelister.cpp cli/filelister.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 $(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/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testfilesettings.o: test/testfilesettings.cpp 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 $(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/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testfrontend.o: test/testfrontend.cpp 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 $(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/regex.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/check.h lib/checkers.h lib/checkfunctions.h lib/checkimpl.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 $(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/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 +test/testgarbage.o: test/testgarbage.cpp 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/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/regex.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/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 $(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/regex.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/check.h lib/checkers.h lib/checkimpl.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 $(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/regex.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/check.h lib/checkers.h lib/checkimpl.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 $(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/regex.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/check.h lib/checkers.h lib/checkimpl.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 $(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/regex.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/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +test/testlibrary.o: test/testlibrary.cpp 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 $(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/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 +test/testmathlib.o: test/testmathlib.cpp 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 $(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/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 +test/testmemleak.o: test/testmemleak.cpp lib/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +test/testnullpointer.o: test/testnullpointer.cpp lib/check.h lib/checkers.h lib/checkimpl.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 $(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/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h test/options.h +test/testoptions.o: test/testoptions.cpp 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 $(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/regex.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/check.h lib/checkers.h lib/checkimpl.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 $(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/regex.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/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 $(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/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testpathmatch.o: test/testpathmatch.cpp 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 $(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/regex.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/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 $(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/regex.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/check.h lib/checkers.h lib/checkimpl.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 $(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/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/testpreprocessor.o: test/testpreprocessor.cpp externals/simplecpp/simplecpp.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 $(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/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 +test/testprocessexecutor.o: test/testprocessexecutor.cpp cli/executor.h cli/processexecutor.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 $(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/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 +test/testprogrammemory.o: test/testprogrammemory.cpp 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 $(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 +test/testregex.o: test/testregex.cpp 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/regex.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/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 $(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/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/testsettings.o: test/testsettings.cpp 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 $(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/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 +test/testsimplifytemplate.o: test/testsimplifytemplate.cpp 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 $(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/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 +test/testsimplifytokens.o: test/testsimplifytokens.cpp 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 $(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/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 +test/testsimplifytypedef.o: test/testsimplifytypedef.cpp 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 $(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/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 +test/testsimplifyusing.o: test/testsimplifyusing.cpp 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 $(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/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 +test/testsingleexecutor.o: test/testsingleexecutor.cpp cli/executor.h cli/singleexecutor.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 $(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/regex.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/check.h lib/checkers.h lib/checkimpl.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 $(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/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/teststandards.o: test/teststandards.cpp 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 $(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/regex.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/check.h lib/checkers.h lib/checkimpl.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 $(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/regex.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/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +test/testsummaries.o: test/testsummaries.cpp 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 $(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/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/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 $(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/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 +test/testsymboldatabase.o: test/testsymboldatabase.cpp 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 $(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/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 +test/testthreadexecutor.o: test/testthreadexecutor.cpp cli/executor.h cli/threadexecutor.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 $(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/regex.h lib/settings.h lib/standards.h lib/timer.h lib/utils.h test/fixture.h test/redirect.h +test/testtimer.o: test/testtimer.cpp 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/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/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 +test/testtoken.o: test/testtoken.cpp 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 $(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/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 +test/testtokenize.o: test/testtokenize.cpp externals/simplecpp/simplecpp.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 $(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/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 +test/testtokenlist.o: test/testtokenlist.cpp externals/simplecpp/simplecpp.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 $(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/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 +test/testtokenrange.o: test/testtokenrange.cpp 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 $(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/regex.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/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +test/testuninitvar.o: test/testuninitvar.cpp lib/check.h lib/checkers.h lib/checkimpl.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 $(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/regex.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/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 $(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/regex.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/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.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 $(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/regex.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/check.h lib/checkers.h lib/checkimpl.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 $(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/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h +test/testutils.o: test/testutils.cpp 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 $(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/regex.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/check.h lib/checkers.h lib/checkimpl.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 $(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/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 +test/testvalueflow.o: test/testvalueflow.cpp 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 $(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/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 +test/testvarid.o: test/testvarid.cpp 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 $(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/regex.h lib/settings.h lib/standards.h lib/utils.h lib/vfvalue.h test/fixture.h +test/testvfvalue.o: test/testvfvalue.cpp 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 $(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/addons/threadsafety.py b/addons/threadsafety.py index 9475e1a5b0d..390a245d4e1 100755 --- a/addons/threadsafety.py +++ b/addons/threadsafety.py @@ -111,6 +111,8 @@ 'cuserid', 'drand48', 'ecvt', + 'elf_fill', + 'elf_flagelf', 'encrypt', 'endfsent', 'endgrent', diff --git a/cfg/boost.cfg b/cfg/boost.cfg index 722c4c83cd7..b09d9ccd9e5 100644 --- a/cfg/boost.cfg +++ b/cfg/boost.cfg @@ -83,12 +83,12 @@ - + - + - - + + diff --git a/cfg/gtk.cfg b/cfg/gtk.cfg index c4ab8972155..5e94a0bbb5c 100644 --- a/cfg/gtk.cfg +++ b/cfg/gtk.cfg @@ -4,16 +4,30 @@ - - - - + + + + + + + + + + + + + + + + + + @@ -78,6 +92,7 @@ + @@ -112,6 +127,7 @@ + @@ -234,6 +250,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g_thread_new g_thread_try_new @@ -909,7 +1005,6 @@ g_zlib_decompressor_new g_object_ref g_object_unref - gtk_widget_destroy g_tree_new @@ -925,6 +1020,11 @@ g_file_attribute_matcher_ref g_file_attribute_matcher_unref + + gtk_window_new + gtk_widget_destroy + gtk_window_destroy + false @@ -2153,6 +2253,7 @@ + false @@ -5120,6 +5221,7 @@ + false @@ -6488,6 +6590,7 @@ + false @@ -9693,6 +9796,14 @@ false + + + false + + + + false @@ -21135,10 +21246,6 @@ false - - - false - false @@ -21795,6 +21902,13 @@ false + + false + + + + + false @@ -22972,6 +23086,13 @@ + + + + + + + diff --git a/cfg/microsoft_gsl.cfg b/cfg/microsoft_gsl.cfg new file mode 100644 index 00000000000..07fbfcb74a6 --- /dev/null +++ b/cfg/microsoft_gsl.cfg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/cfg/qt.cfg b/cfg/qt.cfg index 66f6e78b3b6..c7bf3d8779b 100644 --- a/cfg/qt.cfg +++ b/cfg/qt.cfg @@ -410,7 +410,6 @@ - diff --git a/cfg/std.cfg b/cfg/std.cfg index e282dd99995..4662d0a4632 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -3989,7 +3989,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + arg1 false @@ -4010,7 +4010,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + arg1 false @@ -4056,7 +4056,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + arg1 @@ -4077,7 +4077,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + arg1 @@ -4118,7 +4118,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + arg1 false @@ -4136,7 +4136,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + arg1 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 - + @@ -4812,7 +4812,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + arg1 false @@ -4828,9 +4828,9 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + - + arg1 false @@ -4861,7 +4861,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + @@ -4942,7 +4942,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + arg1 false @@ -5044,7 +5044,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + @@ -5057,7 +5057,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + arg1 false @@ -5123,10 +5123,10 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + false - + arg1 @@ -5373,7 +5373,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun - + arg1 false @@ -5433,7 +5433,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + @@ -8814,6 +8814,12 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init + + + + true + + malloc,std::malloc calloc,std::calloc diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index f63f3291849..52103bdb8ec 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -40,27 +40,32 @@ if (BUILD_CLI) endif() install(TARGETS cppcheck - RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT applications) install(PROGRAMS ${CMAKE_SOURCE_DIR}/htmlreport/cppcheck-htmlreport - DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} + DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT applications) + # TODO: leverage CMAKE_INSTALL_DATAROOTDIR (share)? + install(FILES ${addons_py} - DESTINATION ${FILESDIR_DEF}/addons + DESTINATION ${FILESDIR_INSTALL}/addons COMPONENT headers) install(FILES ${addons_json} - DESTINATION ${FILESDIR_DEF}/addons + DESTINATION ${FILESDIR_INSTALL}/addons COMPONENT headers) install(FILES ${cfgs} - DESTINATION ${FILESDIR_DEF}/cfg + DESTINATION ${FILESDIR_INSTALL}/cfg COMPONENT headers) install(FILES ${platforms} - DESTINATION ${FILESDIR_DEF}/platforms + DESTINATION ${FILESDIR_INSTALL}/platforms COMPONENT headers) + # TODO: install manpage into CMAKE_INSTALL_MANDIR + # TODO: install documentation into CMAKE_INSTALL_DOCDIR? + endif() diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 43361c6e5bc..f2d2254f833 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -20,6 +20,7 @@ #include "addoninfo.h" #include "check.h" +#include "checks.h" #include "checkers.h" #include "color.h" #include "config.h" @@ -49,7 +50,6 @@ #include #include #include -#include #include #include #include @@ -57,9 +57,12 @@ #ifdef HAVE_RULES #include "regex.h" +#include "rule.h" // xml is used for rules #include "xml.h" + +#include #endif static bool addFilesToList(const std::string& fileList, std::vector& pathNames) @@ -359,9 +362,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"; @@ -1156,7 +1159,10 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a if (!parseNumberArg(argv[i], 31, tmp, true)) return Result::Fail; } - mSettings.premiumArgs += "--" + p; + if (p.find(' ') != std::string::npos) + mSettings.premiumArgs += "\"--" + p + "\""; + else + mSettings.premiumArgs += "--" + p; if (isCodingStandard) { // All checkers related to the coding standard should be enabled. The coding standards // do not all undefined behavior or portability issues. @@ -1302,7 +1308,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a // Rule given at command line else if (std::strncmp(argv[i], "--rule=", 7) == 0) { #ifdef HAVE_RULES - Settings::Rule rule; + Rule rule; rule.pattern = 7 + argv[i]; if (rule.pattern.empty()) { @@ -1338,7 +1344,8 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a if (node && strcmp(node->Value(), "rules") == 0) node = node->FirstChildElement("rule"); for (; node && strcmp(node->Value(), "rule") == 0; node = node->NextSiblingElement()) { - Settings::Rule rule; + Rule rule; + Regex::Engine regexEngine = Regex::Engine::Pcre; for (const tinyxml2::XMLElement *subnode = node->FirstChildElement(); subnode; subnode = subnode->NextSiblingElement()) { const char * const subname = subnode->Name(); @@ -1371,7 +1378,7 @@ 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; + regexEngine = Regex::Engine::Pcre; } else { mLogger.printError(std::string("unknown regex engine '") + engine + "'."); @@ -1405,7 +1412,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a } std::string regex_err; - auto regex = Regex::create(rule.pattern, rule.engine, regex_err); + auto regex = Regex::create(rule.pattern, regexEngine, regex_err); if (!regex) { mLogger.printError("unable to load rule-file '" + ruleFile + "' - pattern '" + rule.pattern + "' failed to compile (" + regex_err + ")."); return Result::Fail; diff --git a/cli/filelister.cpp b/cli/filelister.cpp index 65a77ea6306..9b95689679c 100644 --- a/cli/filelister.cpp +++ b/cli/filelister.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/main.cpp b/cli/main.cpp index 9bea4336c84..d1a635e1f6f 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -20,7 +20,7 @@ /** * * @mainpage Cppcheck - * @version 2.20.99 + * @version 2.21.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 a410f58d5ea..959d16d37ec 100644 --- a/cli/processexecutor.cpp +++ b/cli/processexecutor.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -44,9 +45,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -515,7 +516,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/singleexecutor.cpp b/cli/singleexecutor.cpp index d710a4d4c57..e25fc804490 100644 --- a/cli/singleexecutor.cpp +++ b/cli/singleexecutor.cpp @@ -21,7 +21,6 @@ #include "cppcheck.h" #include "filesettings.h" #include "settings.h" -#include "timer.h" #include #include diff --git a/cli/threadexecutor.cpp b/cli/threadexecutor.cpp index b8581d7e772..5d723366574 100644 --- a/cli/threadexecutor.cpp +++ b/cli/threadexecutor.cpp @@ -26,7 +26,6 @@ #include "filesettings.h" #include "settings.h" #include "suppressions.h" -#include "timer.h" #include #include diff --git a/cmake/compilerDefinitions.cmake b/cmake/compilerDefinitions.cmake index 5f03b83dcee..3daf0e7ba87 100644 --- a/cmake/compilerDefinitions.cmake +++ b/cmake/compilerDefinitions.cmake @@ -20,7 +20,7 @@ endif() 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 + if((CMAKE_CXX_COMPILER_ID STREQUAL "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() diff --git a/cmake/compileroptions.cmake b/cmake/compileroptions.cmake index aa7deb8552c..6343a8a5102 100644 --- a/cmake/compileroptions.cmake +++ b/cmake/compileroptions.cmake @@ -134,7 +134,6 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") # TODO: fix and enable these warnings - or move to suppression list below add_compile_options_safe(-Wno-sign-conversion) add_compile_options_safe(-Wno-shadow-field-in-constructor) - add_compile_options_safe(-Wno-shorten-64-to-32) add_compile_options_safe(-Wno-implicit-int-conversion) add_compile_options_safe(-Wno-double-promotion) add_compile_options_safe(-Wno-shadow-field) diff --git a/cmake/options.cmake b/cmake/options.cmake index d640710e428..bda080fe77b 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -134,18 +134,22 @@ set(CMAKE_DISABLE_PRECOMPILE_HEADERS Off CACHE BOOL "Disable precompiled headers # see https://gitlab.kitware.com/cmake/cmake/-/issues/21219 set(CMAKE_PCH_PROLOGUE "") +# TODO: do we need to set these? 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") +# TODO: do we need to set these? set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) string(LENGTH "${FILESDIR}" _filesdir_len) # override FILESDIR if it is set or empty +# needs to be an absolute path in Cppcheck but a relative one for CMake install if(FILESDIR OR ${_filesdir_len} EQUAL 0) -# TODO: verify that it is an absolute path? - set(FILESDIR_DEF ${FILESDIR}) + set(FILESDIR_INSTALL "${FILESDIR}") # TODO: make relative - leverage CMAKE_INSTALL_DATAROOTDIR? + set(FILESDIR_DEF "${FILESDIR}") else() - set(FILESDIR_DEF ${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME} CACHE STRING "Cppcheck files directory") + set(FILESDIR_INSTALL "share/${PROJECT_NAME}") + set(FILESDIR_DEF "${CMAKE_INSTALL_PREFIX}/${FILESDIR_INSTALL}") endif() diff --git a/cmake/printInfo.cmake b/cmake/printInfo.cmake index 87c7e41f284..7869169708d 100644 --- a/cmake/printInfo.cmake +++ b/cmake/printInfo.cmake @@ -8,6 +8,7 @@ message(STATUS "Compiler Version = ${CMAKE_CXX_COMPILER_VERSION}") message(STATUS "Build type = ${CMAKE_BUILD_TYPE}") message(STATUS "CMake C++ Standard = ${CMAKE_CXX_STANDARD}") message(STATUS "CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}") +message(STATUS "CMAKE_INSTALL_BINDIR = ${CMAKE_INSTALL_BINDIR}") message(STATUS "CMAKE_DISABLE_PRECOMPILE_HEADERS = ${CMAKE_DISABLE_PRECOMPILE_HEADERS}") message(STATUS "C++ flags (General) = ${CMAKE_CXX_FLAGS}") message(STATUS "C++ flags (Release) = ${CMAKE_CXX_FLAGS_RELEASE}") @@ -109,6 +110,7 @@ message(STATUS) message(STATUS "USE_LIBCXX = ${USE_LIBCXX}") message(STATUS) message(STATUS "FILESDIR = ${FILESDIR}") +message(STATUS "FILESDIR_INSTALL = ${FILESDIR_INSTALL}") message(STATUS "FILESDIR_DEF = ${FILESDIR_DEF}") message(STATUS) diff --git a/createrelease b/createrelease index de85d64395b..6a611a5a469 100755 --- a/createrelease +++ b/createrelease @@ -1,6 +1,6 @@ #!/bin/bash # -# A script for creating release packages. The release packages are create in the home directory. +# A script for creating release packages. The release packages are created in the home directory. # # Create release candidate # ======================== @@ -8,15 +8,22 @@ # Review trac roadmap, are tickets closed properly? # Only tickets that should be retargeted should be open. # -# update cppcheck used in premium addon CI -# create jira issue "CI: update cppcheck binary" -# cd ~/cppchecksolutions/addon/tools && python3 ci-update-cppcheck.py +# Versioning scheme +# ======================== +# VERSION=2.22.0 # the new release tag created +# PREV=2.21.0 # the previous release +# BRANCH=2.22.x # release branch +# +# 2.22.x BRANCH - release branch +# 2.22.0 TAG - the release +# 2.22.1, ... TAG - patch releases +# 2.22.0-rc1 TAG - release candidate # -# update mappings.. +# Update mappings: # cd ~/cppchecksolutions/addon/coverage # CPPCHECK_REPO=~/cppchecksolutions/cppcheck python3 coverage.py --code # -# check every isPremiumEnabled call: TODO write helper script +# 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 # ./cppcheck --errorlist | grep ' id="' | sed 's/.* id="//' | sed 's/".*//' | sort | uniq > ids2.txt @@ -29,93 +36,97 @@ # - ensure latest build was successful # - ensure cfg files etc are included (win_installer/cppcheck.wxs) # -# self check, fix critical issues: +# Self check, fix critical issues: # make clean && make CXXOPTS=-O2 MATCHCOMPILER=yes -j4 # ./cppcheck -D__CPPCHECK__ -D__GNUC__ -DCHECK_INTERNAL -DHAVE_RULES --std=c++11 --library=cppcheck-lib --library=qt --enable=style --inconclusive --inline-suppr --suppress=bitwiseOnBoolean --suppress=shadowFunction --suppress=useStlAlgorithm --suppress=*:externals/picojson.h --suppress=functionConst --suppress=functionStatic --suppress=normalCheckLevelMaxBranches --xml cli gui/*.cpp lib 2> selfcheck.xml # -# Generate lib/checkers.cpp (TODO the premium checkers should not be statically coded) +# Generate lib/checkers.cpp: (TODO the premium checkers should not be statically coded) # cd ~/cppchecksolutions/cppcheck && python3 tools/get_checkers.py > lib/checkers.cpp # -# Update copyright year TODO release script -# git diff 2.8 -- */*.cpp */*.h | grep '^diff --git a/' | sed 's|.* b/||' | xargs sed -i 's/Copyright (C) 2007-20[12]./Copyright (C) 2007-2022/' +# Update copyright year: TODO release script +# git diff $PREV -- */*.cpp */*.h | grep '^diff --git a/' | sed 's|.* b/||' | xargs sed -i "s/Copyright (C) 2007-20[12]./Copyright (C) 2007-$(date +%Y)/" # git diff | grep '^diff --git a/' # # Make sure "cppcheck --errorlist" works: # make clean && make -j4 && ./cppcheck --errorlist > errlist.xml && xmllint --noout errlist.xml # # Update AUTHORS using output from: -# git log --format='%aN' 2.7..HEAD | sort -u > AUTHORS2 && diff -y AUTHORS AUTHORS2 | less +# git log --format='%aN' $PREV..HEAD | sort -u > AUTHORS2 && diff -y AUTHORS AUTHORS2 | less +# Include github usernames in PR title and commit message # -# Update GUI translations -# lupdate gui.pro +# Update GUI translations: +# cd ~/cppchecksolutions/cppcheck/gui && lupdate gui.pro # -# Create 2.18.x branch -# git checkout -b 2.18.x ; git push -u origin 2.18.x +# Create new release branch: +# git checkout -b $BRANCH && git push -u origin $BRANCH # in fork: -# * add upstream: git remote add upstream git@github.com:/cppcheck-opensource//cppcheck.git -# * add branch: git fetch upstream 2.19.x +# * add upstream: git remote add upstream git@github.com:cppcheck-opensource/cppcheck.git +# * add branch: git fetch upstream $BRANCH # # Release notes: # - ensure safety critical issues are listed properly # - empty the releasenotes.txt in main branch # # Update version numbers in: -# python3 tools/release-set-version.py 2.19.0 +# python3 tools/release-set-version.py $VERSION # Verify: # grep '\.99' */*.[ch]* && grep '[0-9][0-9] dev' */*.[ch]* # egrep "2\.[0-9]+" */*.h */*.cpp man/*.md | grep -v "test/test" | less -# git commit -a -m "2.8: Set versions" +# git commit -a -m "$VERSION: Set versions" # # Build and test the windows installer # # Update the Makefile: # make dmake && ./dmake --release -# git commit -a -m "2.8: Updated Makefile" +# git commit -a -m "$VERSION: Updated Makefile" +# +# Push changes: +# git push # # Ensure that CI is happy # # Tag: -# git tag 2.8-rc1 +# git tag $VERSION-rc1 # git push --tags # # Release -# ======= +# ======================== # # Remove "-rc1" from versions. Test: git grep "\-rc[0-9]" # # Create a release folder on sourceforge: # https://sourceforge.net/projects/cppcheck/files/cppcheck/ # -# git tag 2.8 ; git push --tags -# ./createrelease 2.8 +# git tag $VERSION && git push --tags +# ./createrelease $VERSION # -# copy msi from release-windows, install and test cppcheck -# copy manual from build-manual +# Copy msi from release-windows, install and test cppcheck +# Copy manual from build-manual # # Update download link on index.php main page # # Trac: -# 1. Create ticket "2.18 safety cosmetic changes" -# git log --format=oneline 2.17.0..HEAD | egrep -v "^[0-9a-f]*[ ][ ]*([Ff]ix|fixed|Fixup|Fixes|refs)?[ ]*#*[0-9]+" +# 1. Create ticket "$VERSION safety cosmetic changes" +# git log --format=oneline $PREV..HEAD | egrep -v "^[0-9a-f]*[ ][ ]*([Ff]ix|fixed|Fixup|Fixes|refs)?[ ]*#*[0-9]+" # 2. Check priorities for all tickets in milestone. Should be: safety-* # 3. Create new milestone # 4. Close old milestone # -# write a news +# Write a news # -# save "cppcheck --doc" output on wiki +# Save "cppcheck --doc" output on wiki # -# compile new democlient: +# Compile new democlient: # 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 +# 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 +# - summary: [meta] performance regressions in $VERSION # -# run daca with new release +# 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/ # @@ -123,14 +134,14 @@ # * trac: cd /var && nice tar -cJf ~/trac.tar.xz trac-cppcheck/db/trac.db # * 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 /cppcheck-opensource//cppcheck -t 2.15.0 -p out +# * git log $PREV..$VERSION > Changelog +# * mkdir out && python3 ~/cppchecksolutions/release/getWorkflowAndIssueLogs.py -r /cppcheck-opensource//cppcheck -t $VERSION -p out -# Folder/tag to use -folder=$1 -tag=$folder.0 +# Folder/tag to use: +tag=$1 +folder=${tag%.*} -# Name of release +# Name of release: releasename=cppcheck-$tag set -e @@ -162,7 +173,7 @@ scp htdocs/* danielmarjamaki,cppcheck@web.sourceforge.net:htdocs/ cd .. rm -rf upload -# Local cppcheck binary +# Local cppcheck binary: mkdir -p ~/.cppcheck/$tag cd ~/.cppcheck/$tag cp -R ~/cppcheck/cfg . diff --git a/externals/simplecpp/simplecpp.cpp b/externals/simplecpp/simplecpp.cpp index 7afc17ab735..d2c398c49e1 100644 --- a/externals/simplecpp/simplecpp.cpp +++ b/externals/simplecpp/simplecpp.cpp @@ -3,18 +3,12 @@ * Copyright (C) 2016-2023 simplecpp team */ +// needs to be specified here otherwise _mingw.h will define it as 0x0601 +// causing FileIdInfo not to be available #if defined(_WIN32) # ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0602 # endif -# ifndef NOMINMAX -# define NOMINMAX -# endif -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include -# undef ERROR #endif #include "simplecpp.h" @@ -51,10 +45,19 @@ #include #include -#ifdef _WIN32 +#if defined(_WIN32) +# ifndef NOMINMAX +# define NOMINMAX +# endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# undef ERROR # include #else # include +# include #endif static bool isHex(const std::string &s) @@ -275,8 +278,10 @@ class simplecpp::TokenList::Stream { return ch; } - unsigned char peekChar() { - auto ch = static_cast(peek()); + int peekChar() { + int ch = peek(); + if (ch == EOF) + return ch; // For UTF-16 encoded files the BOM is 0xfeff/0xfffe. If the // character is non-ASCII character then replace it with 0xff @@ -285,7 +290,7 @@ class simplecpp::TokenList::Stream { const auto ch2 = static_cast(peek()); unget(); const int ch16 = makeUtf16Char(ch, ch2); - ch = static_cast(((ch16 >= 0x80) ? 0xff : ch16)); + ch = (ch16 >= 0x80) ? 0xff : ch16; } // Handling of newlines.. @@ -598,7 +603,7 @@ std::string simplecpp::TokenList::stringify(bool linenrs) const return ret.str(); } -static bool isNameChar(unsigned char ch) +static bool isNameChar(int ch) { return std::isalnum(ch) || ch == '_' || ch == '$'; } @@ -635,10 +640,10 @@ static bool isStringLiteralPrefix(const std::string &str) str == "R" || str == "uR" || str == "UR" || str == "LR" || str == "u8R"; } -void simplecpp::TokenList::lineDirective(unsigned int fileIndex, unsigned int line, Location &location) +void simplecpp::TokenList::lineDirective(unsigned int fileIndex_, unsigned int line, Location &location) { - if (fileIndex != location.fileIndex || line >= location.line) { - location.fileIndex = fileIndex; + if (fileIndex_ != location.fileIndex || line >= location.line) { + location.fileIndex = fileIndex_; location.line = line; return; } @@ -656,8 +661,6 @@ static const std::string COMMENT_END("*/"); void simplecpp::TokenList::readfile(Stream &stream, const std::string &filename, OutputList *outputList) { - std::stack loc; - unsigned int multiline = 0U; const Token *oldLastToken = nullptr; @@ -696,59 +699,44 @@ void simplecpp::TokenList::readfile(Stream &stream, const std::string &filename, if (oldLastToken != cback()) { oldLastToken = cback(); - const Token * const llTok = isLastLinePreprocessor(); - if (!llTok) + + // #line 3 + // #line 3 "file.c" + // #3 + // #3 "file.c" + const Token * ppTok = isLastLinePreprocessor(); + if (!ppTok) + continue; + + const auto advanceAndSkipComments = [](const Token* tok) { + do { + tok = tok->next; + } while (tok && tok->comment); + return tok; + }; + + // skip # + ppTok = advanceAndSkipComments(ppTok); + if (!ppTok) continue; - const Token * const llNextToken = llTok->next; - if (!llTok->next) + + if (ppTok->str() == "line") + ppTok = advanceAndSkipComments(ppTok); + + if (!ppTok || !ppTok->number) continue; - if (llNextToken->next) { - // #file "file.c" - if (llNextToken->str() == "file" && - llNextToken->next->str()[0] == '\"') - { - const Token *strtok = cback(); - while (strtok->comment) - strtok = strtok->previous; - loc.push(location); - location.fileIndex = fileIndex(strtok->str().substr(1U, strtok->str().size() - 2U)); - location.line = 1U; - } - // TODO: add support for "# 3" - // #3 "file.c" - // #line 3 "file.c" - else if ((llNextToken->number && - llNextToken->next->str()[0] == '\"') || - (llNextToken->str() == "line" && - llNextToken->next->number && - llNextToken->next->next && - llNextToken->next->next->str()[0] == '\"')) - { - const Token *strtok = cback(); - while (strtok->comment) - strtok = strtok->previous; - const Token *numtok = strtok->previous; - while (numtok->comment) - numtok = numtok->previous; - lineDirective(fileIndex(replaceAll(strtok->str().substr(1U, strtok->str().size() - 2U),"\\\\","\\")), - std::atol(numtok->str().c_str()), location); - } - // #line 3 - else if (llNextToken->str() == "line" && - llNextToken->next->number) - { - const Token *numtok = cback(); - while (numtok->comment) - numtok = numtok->previous; - lineDirective(location.fileIndex, std::atol(numtok->str().c_str()), location); - } - } - // #endfile - else if (llNextToken->str() == "endfile" && !loc.empty()) - { - location = loc.top(); - loc.pop(); - } + + const unsigned int line = std::atol(ppTok->str().c_str()); + ppTok = advanceAndSkipComments(ppTok); + + unsigned int fileindex; + + if (ppTok && ppTok->str()[0] == '\"') + fileindex = fileIndex(replaceAll(ppTok->str().substr(1U, ppTok->str().size() - 2U),"\\\\","\\")); + else + fileindex = location.fileIndex; + + lineDirective(fileindex, line, location); } continue; @@ -771,8 +759,21 @@ void simplecpp::TokenList::readfile(Stream &stream, const std::string &filename, ch = stream.readChar(); } stream.ungetChar(); - push_back(new Token(currentToken, location)); - location.adjust(currentToken); + std::string::size_type pos = 0; + unsigned int spliced = 0; + while ((pos = currentToken.find('\\', pos)) != std::string::npos) { + if (pos + 1 < currentToken.size() && currentToken[pos + 1] == '\n') { + currentToken.erase(pos, 2); + ++spliced; + } else { + ++pos; + } + } + if (!currentToken.empty()) { + push_back(new Token(currentToken, location)); + location.adjust(currentToken); + } + location.line += spliced; continue; } } @@ -1016,8 +1017,7 @@ static bool isAlternativeAndBitandBitor(const simplecpp::Token* tok) void simplecpp::TokenList::combineOperators() { - std::stack executableScope; - executableScope.push(false); + std::stack> executableScope{{false}}; for (Token *tok = front(); tok; tok = tok->next) { if (tok->op == '{') { if (executableScope.top()) { @@ -1025,7 +1025,7 @@ void simplecpp::TokenList::combineOperators() continue; } const Token *prev = tok->previous; - while (prev && prev->isOneOf(";{}()")) + while (prev && prev->isOneOf(";{}(")) prev = prev->previous; executableScope.push(prev && prev->op == ')'); continue; @@ -1739,6 +1739,9 @@ namespace simplecpp { return tok; } + /** + * @throws Error thrown in case of __VA_OPT__ issues + */ bool parseDefine(const Token *nametoken) { nameTokDef = nametoken; variadic = false; @@ -2201,6 +2204,8 @@ namespace simplecpp { } output.push_back(newMacroToken(tok->str(), loc, true, tok)); + if (it != macros.end()) + output.back()->markExpandedFrom(&it->second); return tok->next; } @@ -2312,9 +2317,6 @@ namespace simplecpp { const Token *nextTok = B->next; if (canBeConcatenatedStringOrChar) { - if (unexpectedA) - throw invalidHashHash::unexpectedToken(tok->location, name(), A); - // It seems clearer to handle this case separately even though the code is similar-ish, but we don't want to merge here. // TODO The question is whether the ## or varargs may still apply, and how to provoke? if (expandArg(tokensB, B, parametertokens)) { @@ -3070,6 +3072,65 @@ static std::string openHeader(std::ifstream &f, const simplecpp::DUI &dui, const return ""; } +namespace { + struct FileID { +#ifdef _WIN32 + struct { + std::uint64_t VolumeSerialNumber; + struct { + std::uint64_t IdentifierHi; + std::uint64_t IdentifierLo; + } FileId; + } fileIdInfo; + + bool operator==(const FileID &that) const noexcept { + return fileIdInfo.VolumeSerialNumber == that.fileIdInfo.VolumeSerialNumber && + fileIdInfo.FileId.IdentifierHi == that.fileIdInfo.FileId.IdentifierHi && + fileIdInfo.FileId.IdentifierLo == that.fileIdInfo.FileId.IdentifierLo; + } +#else + dev_t dev; + ino_t ino; + + bool operator==(const FileID& that) const noexcept { + return dev == that.dev && ino == that.ino; + } +#endif + struct Hasher { + std::size_t operator()(const FileID &id) const { +#ifdef _WIN32 + return static_cast(id.fileIdInfo.FileId.IdentifierHi ^ id.fileIdInfo.FileId.IdentifierLo ^ + id.fileIdInfo.VolumeSerialNumber); +#else + return static_cast(id.dev) ^ static_cast(id.ino); +#endif + } + }; + }; +} + +struct simplecpp::FileDataCache::Impl +{ + void clear() + { + mIdMap.clear(); + } + + using id_map_type = std::unordered_map; + + id_map_type mIdMap; +}; + +simplecpp::FileDataCache::FileDataCache() + : mImpl(new Impl) +{} + +simplecpp::FileDataCache::~FileDataCache() = default; +simplecpp::FileDataCache::FileDataCache(FileDataCache &&) noexcept = default; +simplecpp::FileDataCache &simplecpp::FileDataCache::operator=(simplecpp::FileDataCache &&) noexcept = default; + +static bool getFileId(const std::string &path, FileID &id); + std::pair simplecpp::FileDataCache::tryload(FileDataCache::name_map_type::iterator &name_it, const simplecpp::DUI &dui, std::vector &filenames, simplecpp::OutputList *outputList) { const std::string &path = name_it->first; @@ -3078,8 +3139,8 @@ std::pair simplecpp::FileDataCache::tryload(FileDat if (!getFileId(path, fileId)) return {nullptr, false}; - const auto id_it = mIdMap.find(fileId); - if (id_it != mIdMap.end()) { + const auto id_it = mImpl->mIdMap.find(fileId); + if (id_it != mImpl->mIdMap.end()) { name_it->second = id_it->second; return {id_it->second, false}; } @@ -3090,9 +3151,12 @@ std::pair simplecpp::FileDataCache::tryload(FileDat data->tokens.removeComments(); name_it->second = data; - mIdMap.emplace(fileId, data); + mImpl->mIdMap.emplace(fileId, data); mData.emplace_back(data); + if (mLoadCallback) + mLoadCallback(*data); + return {data, true}; } @@ -3142,7 +3206,14 @@ std::pair simplecpp::FileDataCache::get(const std:: return {nullptr, false}; } -bool simplecpp::FileDataCache::getFileId(const std::string &path, FileID &id) +void simplecpp::FileDataCache::clear() +{ + mImpl->clear(); + mNameMap.clear(); + mData.clear(); +} + +static bool getFileId(const std::string &path, FileID &id) { #ifdef _WIN32 HANDLE hFile = CreateFileA(path.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); @@ -3329,20 +3400,20 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL std::map sizeOfType(rawtokens.sizeOfType); sizeOfType.insert(std::make_pair("char", sizeof(char))); sizeOfType.insert(std::make_pair("short", sizeof(short))); - sizeOfType.insert(std::make_pair("short int", sizeOfType["short"])); + sizeOfType.insert(std::make_pair("short int", sizeof(short))); sizeOfType.insert(std::make_pair("int", sizeof(int))); sizeOfType.insert(std::make_pair("long", sizeof(long))); - sizeOfType.insert(std::make_pair("long int", sizeOfType["long"])); + sizeOfType.insert(std::make_pair("long int", sizeof(long))); sizeOfType.insert(std::make_pair("long long", sizeof(long long))); sizeOfType.insert(std::make_pair("float", sizeof(float))); sizeOfType.insert(std::make_pair("double", sizeof(double))); sizeOfType.insert(std::make_pair("long double", sizeof(long double))); sizeOfType.insert(std::make_pair("char *", sizeof(char *))); sizeOfType.insert(std::make_pair("short *", sizeof(short *))); - sizeOfType.insert(std::make_pair("short int *", sizeOfType["short *"])); + sizeOfType.insert(std::make_pair("short int *", sizeof(short *))); sizeOfType.insert(std::make_pair("int *", sizeof(int *))); sizeOfType.insert(std::make_pair("long *", sizeof(long *))); - sizeOfType.insert(std::make_pair("long int *", sizeOfType["long *"])); + sizeOfType.insert(std::make_pair("long int *", sizeof(long *))); sizeOfType.insert(std::make_pair("long long *", sizeof(long long *))); sizeOfType.insert(std::make_pair("float *", sizeof(float *))); sizeOfType.insert(std::make_pair("double *", sizeof(double *))); @@ -3379,6 +3450,17 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL } output.clear(); return; + } catch (const simplecpp::Macro::Error& e) { + if (outputList) { + simplecpp::Output err{ + Output::DUI_ERROR, + {}, + e.what + }; + outputList->emplace_back(std::move(err)); + } + output.clear(); + return; } } @@ -3435,8 +3517,19 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL includetokenstack.push(rawtokens.cfront()); for (auto it = dui.includes.cbegin(); it != dui.includes.cend(); ++it) { const FileData *const filedata = cache.get("", *it, dui, false, files, outputList).first; - if (filedata != nullptr && filedata->tokens.cfront() != nullptr) + if (filedata == nullptr) { + if (outputList) { + simplecpp::Output err{ + simplecpp::Output::EXPLICIT_INCLUDE_NOT_FOUND, + {}, + "Can not open include file '" + *it + "' that is explicitly included." + }; + outputList->emplace_back(std::move(err)); + } + } + else if (filedata->tokens.cfront() != nullptr) { includetokenstack.push(filedata->tokens.cfront()); + } } std::map> maybeUsedMacros; @@ -3507,14 +3600,14 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL else it->second = macro; } - } catch (const std::runtime_error &) { + } catch (const std::runtime_error &err) { if (outputList) { - simplecpp::Output err{ + simplecpp::Output out{ Output::SYNTAX_ERROR, rawtok->location, - "Failed to parse #define" + std::string("Failed to parse #define, ") + err.what() }; - outputList->emplace_back(std::move(err)); + outputList->emplace_back(std::move(out)); } output.clear(); return; @@ -3671,7 +3764,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL bool closingAngularBracket = false; if (tok) { const std::string &sourcefile = rawtokens.file(rawtok->location); - const bool systemheader = (tok && tok->op == '<'); + const bool systemheader = tok->op == '<'; std::string header; if (systemheader) { diff --git a/externals/simplecpp/simplecpp.h b/externals/simplecpp/simplecpp.h index d499b132b69..3d6fc5262b9 100644 --- a/externals/simplecpp/simplecpp.h +++ b/externals/simplecpp/simplecpp.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -41,10 +42,6 @@ # define SIMPLECPP_LIB #endif -#ifndef _WIN32 -# include -#endif - #if defined(_MSC_VER) # pragma warning(push) // suppress warnings about "conversion from 'type1' to 'type2', possible loss of data" @@ -174,9 +171,9 @@ namespace simplecpp { bool isOneOf(const char ops[]) const; bool startsWithOneOf(const char c[]) const; bool endsWithOneOf(const char c[]) const; - static bool isNumberLike(const std::string& str) { - return std::isdigit(static_cast(str[0])) || - (str.size() > 1U && (str[0] == '-' || str[0] == '+') && std::isdigit(static_cast(str[1]))); + static bool isNumberLike(const std::string& s) { + return std::isdigit(static_cast(s[0])) || + (s.size() > 1U && (s[0] == '-' || s[0] == '+') && std::isdigit(static_cast(s[1]))); } TokenString macro; @@ -213,6 +210,9 @@ namespace simplecpp { bool isExpandedFrom(const Macro* m) const { return mExpandedFrom.find(m) != mExpandedFrom.end(); } + void markExpandedFrom(const Macro* m) { + mExpandedFrom.insert(m); + } void printAll() const; void printOut() const; @@ -376,7 +376,7 @@ namespace simplecpp { const std::string& file(const Location& loc) const; private: - TokenList(const unsigned char* data, std::size_t size, std::vector &filenames, const std::string &filename, OutputList *outputList, int unused); + TokenList(const unsigned char* data, std::size_t size, std::vector &filenames, const std::string &filename, OutputList *outputList, int /*unused*/); void combineOperators(); @@ -396,7 +396,7 @@ namespace simplecpp { void constFoldQuestionOp(Token *&tok1); std::string readUntil(Stream &stream, const Location &location, char start, char end, OutputList *outputList); - void lineDirective(unsigned int fileIndex, unsigned int line, Location &location); + void lineDirective(unsigned int fileIndex_, unsigned int line, Location &location); const Token* lastLineTok(int maxsize=1000) const; const Token* isLastLinePreprocessor(int maxsize=1000) const; @@ -449,13 +449,14 @@ namespace simplecpp { class SIMPLECPP_LIB FileDataCache { public: - FileDataCache() = default; + FileDataCache(); + ~FileDataCache(); FileDataCache(const FileDataCache &) = delete; - FileDataCache(FileDataCache &&) = default; + FileDataCache(FileDataCache &&) noexcept; FileDataCache &operator=(const FileDataCache &) = delete; - FileDataCache &operator=(FileDataCache &&) = default; + FileDataCache &operator=(FileDataCache &&) noexcept; /** Get the cached data for a file, or load and then return it if it isn't cached. * returns the file data and true if the file was loaded, false if it was cached. */ @@ -469,11 +470,7 @@ namespace simplecpp { mNameMap.emplace(newdata->filename, newdata); } - void clear() { - mNameMap.clear(); - mIdMap.clear(); - mData.clear(); - } + void clear(); using container_type = std::vector>; using iterator = container_type::iterator; @@ -502,52 +499,23 @@ namespace simplecpp { return mData.cend(); } - private: - struct FileID { -#ifdef _WIN32 - struct { - std::uint64_t VolumeSerialNumber; - struct { - std::uint64_t IdentifierHi; - std::uint64_t IdentifierLo; - } FileId; - } fileIdInfo; - - bool operator==(const FileID &that) const noexcept { - return fileIdInfo.VolumeSerialNumber == that.fileIdInfo.VolumeSerialNumber && - fileIdInfo.FileId.IdentifierHi == that.fileIdInfo.FileId.IdentifierHi && - fileIdInfo.FileId.IdentifierLo == that.fileIdInfo.FileId.IdentifierLo; - } -#else - dev_t dev; - ino_t ino; + using load_callback_type = std::function; - bool operator==(const FileID& that) const noexcept { - return dev == that.dev && ino == that.ino; - } -#endif - struct Hasher { - std::size_t operator()(const FileID &id) const { -#ifdef _WIN32 - return static_cast(id.fileIdInfo.FileId.IdentifierHi ^ id.fileIdInfo.FileId.IdentifierLo ^ - id.fileIdInfo.VolumeSerialNumber); -#else - return static_cast(id.dev) ^ static_cast(id.ino); -#endif - } - }; - }; + void set_load_callback(load_callback_type cb) { + mLoadCallback = std::move(cb); + } - using name_map_type = std::unordered_map; - using id_map_type = std::unordered_map; + private: + struct Impl; + std::unique_ptr mImpl; - static bool getFileId(const std::string &path, FileID &id); + using name_map_type = std::unordered_map; std::pair tryload(name_map_type::iterator &name_it, const DUI &dui, std::vector &filenames, OutputList *outputList); container_type mData; name_map_type mNameMap; - id_map_type mIdMap; + load_callback_type mLoadCallback; }; /** Converts character literal (including prefix, but not ud-suffix) to long long value. diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index d640c341458..50980bfb262 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -71,8 +71,8 @@ CheckOptions: add_dependencies(cppcheck-gui online-help.qhc) endif() - install(TARGETS cppcheck-gui RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} COMPONENT applications) - install(FILES ${qms} DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} COMPONENT applications) + install(TARGETS cppcheck-gui RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT applications) + install(FILES ${qms} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT applications) install(FILES cppcheck-gui.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications) diff --git a/gui/applicationdialog.cpp b/gui/applicationdialog.cpp index bc8804d6f97..bdf9a4f827e 100644 --- a/gui/applicationdialog.cpp +++ b/gui/applicationdialog.cpp @@ -80,7 +80,7 @@ void ApplicationDialog::ok() { if (mUI->mName->text().isEmpty() || mUI->mPath->text().isEmpty()) { QMessageBox msg(QMessageBox::Warning, - tr("Cppcheck"), + "Cppcheck", tr("You must specify a name, a path and optionally parameters for the application!"), QMessageBox::Ok, this); diff --git a/gui/checkstatistics.cpp b/gui/checkstatistics.cpp index 612e79da63b..830f5eb6b4e 100644 --- a/gui/checkstatistics.cpp +++ b/gui/checkstatistics.cpp @@ -109,10 +109,10 @@ unsigned CheckStatistics::getCount(const QString &tool, ShowTypes::ShowType type QStringList CheckStatistics::getTools() const { QSet ret; - for (const QString& tool: mStyle.keys()) ret.insert(tool); - for (const QString& tool: mWarning.keys()) ret.insert(tool); - for (const QString& tool: mPerformance.keys()) ret.insert(tool); - for (const QString& tool: mPortability.keys()) ret.insert(tool); - for (const QString& tool: mError.keys()) ret.insert(tool); + std::copy(mStyle.keyBegin(), mStyle.keyEnd(), std::inserter(ret, ret.end())); + std::copy(mWarning.keyBegin(), mWarning.keyEnd(), std::inserter(ret, ret.end())); + std::copy(mPerformance.keyBegin(), mPerformance.keyEnd(), std::inserter(ret, ret.end())); + std::copy(mPortability.keyBegin(), mPortability.keyEnd(), std::inserter(ret, ret.end())); + std::copy(mError.keyBegin(), mError.keyEnd(), std::inserter(ret, ret.end())); return ret.values(); } diff --git a/gui/cppcheck_de.ts b/gui/cppcheck_de.ts index c0d68ed6d8a..a9429aa1c94 100644 --- a/gui/cppcheck_de.ts +++ b/gui/cppcheck_de.ts @@ -107,9 +107,8 @@ Parameter: -l(line) (file) Anzeigeanwendung auswählen - Cppcheck - Cppcheck + Cppcheck @@ -120,65 +119,52 @@ Parameter: -l(line) (file) ComplianceReportDialog - Compliance Report - Compliance-Report + Compliance-Report - Project name - Projektname + Projektname - Project version - Projekt-Version + Projekt-Version - Coding Standard - Programmierstandards + Programmierstandards - Misra C - Misra C + Misra C - Cert C - Cert C + Cert C - Cert C++ - Cert C++ + Cert C++ - List of files with md5 checksums - Datei-Listen mit MD5-Prüfsummen + Datei-Listen mit MD5-Prüfsummen - Compliance report - Compliance-Report + Compliance-Report - HTML files (*.html) - HTML-Dateien (*.html) + HTML-Dateien (*.html) - - Save compliance report - Compliance-Report speichern + Compliance-Report speichern - Failed to import '%1' (%2), can not show files in compliance report - Import von '%1' (%2) fehlgeschlagen, Compliance-Report kann nicht angezeigt werden + Import von '%1' (%2) fehlgeschlagen, Compliance-Report kann nicht angezeigt werden @@ -189,10 +175,8 @@ Parameter: -l(line) (file) Konnte die Datei nicht finden: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -218,14 +202,13 @@ Parameter: -l(line) (file) Index - + Helpfile '%1' was not found Hilfedatei '%1' nicht gefunden - Cppcheck - Cppcheck + Cppcheck @@ -345,11 +328,8 @@ Parameter: -l(line) (file) Bibliothek öffnen - - - Cppcheck - Cppcheck + Cppcheck @@ -495,26 +475,11 @@ Parameter: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck - + Standard Standard @@ -524,150 +489,150 @@ Parameter: -l(line) (file) &Datei - + &View &Ansicht - + &Toolbars &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 @@ -678,92 +643,92 @@ Parameter: -l(line) (file) 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 @@ -778,325 +743,312 @@ Parameter: -l(line) (file) Verstecken - - + + 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 - + Misra C - Cert C - Cert C + 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: @@ -1182,35 +1134,35 @@ 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. @@ -1219,7 +1171,7 @@ 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! @@ -1240,17 +1192,11 @@ Dies wurde vermutlich durch einen Wechsel der Cppcheck-Version hervorgerufen. Bi Unknown element Unbekanntes Element - - - Unknown element - Unknown issue - Unbekannter Fehler - - + Error Fehler @@ -1259,70 +1205,68 @@ 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 + Visual Studio - Borland C++ Builder 6 - 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 @@ -1341,7 +1285,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. @@ -1352,7 +1296,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? @@ -1361,109 +1305,104 @@ 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 @@ -1472,22 +1411,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 @@ -1504,12 +1443,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 @@ -1591,29 +1530,24 @@ Options: Nativ - Unix 32-bit - Unix 32-bit + Unix 32-bit - Unix 64-bit - Unix 64-bit + Unix 64-bit - Windows 32-bit ANSI - Windows 32-bit, ANSI + Windows 32-bit, ANSI - Windows 32-bit Unicode - Windows 32-bit, Unicode + Windows 32-bit, Unicode - Windows 64-bit - Windows 64-bit + Windows 64-bit @@ -1639,7 +1573,7 @@ Options: Definitionen müssen mit einem Semikolon getrennt werden. Beispiel: DEF1;DEF2=5;DEF3=int - + Note: Put your own custom .cfg files in the same folder as the project file. You should see them above. Hinweis: Legen Sie eigene .cfg-Dateien in den Ordner der Projektdatei. Dann sollten sie oben sichtbar werden. @@ -1648,17 +1582,17 @@ Options: MISRA C 2012 - + MISRA rule texts MISRA-Regeltexte - + <html><head/><body><p>Copy/paste the text from Appendix A &quot;Summary of guidelines&quot; from the MISRA C 2012 pdf to a text file.</p></body></html> <html><head/><body><p>Text aus Anhang A &quot;Summary of guidelines&quot; aus der MISRA-C-2012-PDF in eine Textdatei einfügen.</p></body></html> - + ... ... @@ -1669,8 +1603,7 @@ Options: - - + Browse... Durchsuchen... @@ -1698,15 +1631,15 @@ Options: - + Edit Bearbeiten - - + + Remove Entfernen @@ -1736,273 +1669,281 @@ Options: Ab - + + Include file + + + + + <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.. + + + + Platform Plattform - - + + Analysis Analyse - + This is a workfolder that Cppcheck will use for various purposes. - + Clang (experimental) - + Check level - + Reduced -- meant for usage where developer wants results directly. Limited and faster analysis with fewer results. - + Normal -- meant for normal analysis in CI. Analysis should finish in reasonable time. - + Exhaustive -- meant for nightly builds etc. Analysis time can be longer (10x slower than compilation is OK). - + If you want to design your classes to be as flexible and robust as possible then the public interface must be very robust. Cppcheck will asumme that arguments can take *any* value. - + Check code in unused templates (should be ON normally, however in theory you can safely ignore warnings in unused templates) Check code in unused templates (slower and less accurate analysis) Prüfe Code in ungenutzten Templates (normalerweise AN, theoretisch können Warnungen in ungenutzten Templates gefahrlos ignoriert werden) - + Max CTU depth Maximale CTU-Tiefe - + Max recursion in template instantiation - - Premium License - - - - + Warning options Warnoptionen - + Root path: Wurzelverzeichnis: - + Filepaths in warnings will be relative to this path - + Warning tags (separated by semicolon) Warnungs-Tags (Semikolon-getrennt) - + Enable inline suppressions Inline-Fehlerunterdrückung aktivieren - + 2025 - + Misra C++ - + 2008 - + Cert C Cert C - + CERT-INT35-C: int precision (if size equals precision, you can leave empty) - + Autosar - + Safety profiles (defined in C++ core guidelines) - + Bug hunting - + External tools Externe Werkzeuge - + Cppcheck build dir (whole program analysis, incremental analysis, statistics, etc) Cppcheck-Arbeitsverzeichnis (Vollständige Programmanalyse, inkrementelle Analyse, Statistiken, etc.) - + Types and Functions - + Libraries Bibliotheken - + Parser - + Cppcheck (built in) - + Check that each class has a safe public interface - + Limit analysis - + Check code in headers (should be ON normally. if you want a limited quick analysis then turn this OFF) - + If tags are added, you will be able to right click on warnings and set one of these tags. You can manually categorize warnings. - + Exclude source files - + Exclude folder... - + Exclude file... - + Suppressions Fehlerunterdrückungen - + Add Hinzufügen - - + + Addons Add-Ons - + Note: Addons require <a href="https://www.python.org/">Python</a> being installed. - + Y2038 Y2038 - + Thread safety Threadsicherheit - + Coding standards Programmierstandards - + Misra C Misra C - + 2012 - - + + 2023 - + Cert C++ Cert C++ - + Bug hunting (Premium) - Clang analyzer - Clang-Analyzer + Clang-Analyzer - Clang-tidy - Clang-Tidy + Clang-Tidy @@ -2013,82 +1954,91 @@ 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 + Visual Studio - + Compile database Compilerdatenbank - Borland C++ Builder 6 - Borland C++-Builder 6 + Borland C++-Builder 6 - + Import Project Projekt importieren - + + C/C++ header + + + + + Include file + + + + 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) @@ -2121,7 +2071,7 @@ Options: - + (Not found) (nicht gefunden) @@ -2320,11 +2270,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2447,10 +2392,8 @@ Options: Kein Tag - - Cppcheck - Cppcheck + Cppcheck @@ -2523,102 +2466,100 @@ Bitte überprüfen Sie ob der Pfad und die Parameter der Anwendung richtig einge ResultsView - + Print Report Bericht drucken - + No errors found, nothing to print. Keine Funde, nichts zu drucken. - + %p% (%1 of %2 files checked) %p% (%1 von %2 Dateien geprüft) - - Cppcheck - Cppcheck + Cppcheck - + No errors found. Keine Fehler gefunden. - + Errors were found, but they are configured to be hidden. To toggle what kind of errors are shown, open view menu. Es wurden Fehler gefunden, aber sie sind so konfiguriert, ausgeblendet zu werden. Legen Sie unter dem Menü Ansicht fest, welche Arten von Fehlern angezeigt werden sollen. - - + + Failed to read the report. Lesen des Berichts fehlgeschlagen. - + XML format version 1 is no longer supported. XML-Format-Version 1 wird nicht länger unterstützt. - + First included by Zuerst inkludiert von - + Id Id - + Clear Log Protokoll leeren - + Copy this Log entry Diesen Protokolleintrag kopieren - + Copy complete Log Gesamtes Protokoll kopieren - + Analysis was stopped Analyse wurde gestoppt - + There was a critical error with id '%1' Kritischer Fehler mit ID '%1' aufgetreten - + when checking %1 beim Prüfen von %1 - + when checking a file beim Prüfen einer Datei - + Analysis was aborted. Analyse abgebrochen. - - + + Failed to save the report. Der Bericht konnte nicht speichern werden. @@ -2923,14 +2864,14 @@ Legen Sie unter dem Menü Ansicht fest, welche Arten von Fehlern angezeigt werde - - + + Statistics Statistik - + Project Projekt @@ -2961,7 +2902,7 @@ Legen Sie unter dem Menü Ansicht fest, welche Arten von Fehlern angezeigt werde - + Previous Scan Vorherige Prüfung @@ -3041,103 +2982,103 @@ Legen Sie unter dem Menü Ansicht fest, welche Arten von Fehlern angezeigt werde PDF-Export - + 1 day 1 Tag - + %1 days %1 Tage - + 1 hour 1 Stunde - + %1 hours %1 Stunden - + 1 minute 1 Minute - + %1 minutes %1 Minuten - + 1 second 1 Sekunde - + %1 seconds %1 Sekunden - + 0.%1 seconds 0,%1 Sekunden - + and und - + Export PDF Exportiere PDF - + Project Settings Projekteinstellungen - + Paths Pfade - + Include paths Include-Pfade - + Defines Definitionen - + Undefines Un-Definitionen - + Path selected Gewählte Pfade - + Number of files scanned Anzahl geprüfter Dateien - + Scan duration Prüfungsdauer - - + + Errors Fehler @@ -3152,32 +3093,32 @@ Legen Sie unter dem Menü Ansicht fest, welche Arten von Fehlern angezeigt werde Kein Cppcheck-Analyseverzeichnis - - + + Warnings Warnungen - - + + Style warnings Stilwarnungen - - + + Portability warnings Portabilitätswarnungen - - + + Performance warnings Performance-Warnungen - - + + Information messages Informationsmeldungen @@ -3214,9 +3155,8 @@ The user interface language has been reset to English. Open the Preferences-dial Die Sprache wurde auf Englisch zurückgesetzt. Öffnen Sie den Einstellungen-Dialog um eine verfügbare Sprache auszuwählen. - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_es.ts b/gui/cppcheck_es.ts index 927a56e05e5..fa03b4457cc 100644 --- a/gui/cppcheck_es.ts +++ b/gui/cppcheck_es.ts @@ -95,9 +95,8 @@ Parameters: -l(line) (file) Selecciona la aplicación para visualizar - Cppcheck - Cppcheck + Cppcheck @@ -105,70 +104,6 @@ Parameters: -l(line) (file) ¡Debes especificar el nombre, la ruta y opcionalmente los parámetros para la aplicación! - - ComplianceReportDialog - - - Compliance Report - - - - - Project name - - - - - Project version - - - - - Coding Standard - - - - - Misra C - - - - - Cert C - - - - - Cert C++ - - - - - List of files with md5 checksums - - - - - Compliance report - - - - - HTML files (*.html) - - - - - - Save compliance report - - - - - Failed to import '%1' (%2), can not show files in compliance report - - - FileViewDialog @@ -177,10 +112,8 @@ Parameters: -l(line) (file) No se ha encontrado el fichero: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -206,14 +139,13 @@ Parameters: -l(line) (file) - + Helpfile '%1' was not found - Cppcheck - Cppcheck + Cppcheck @@ -333,11 +265,8 @@ Parameters: -l(line) (file) Abrir archivo de biblioteca - - - Cppcheck - Cppcheck + Cppcheck @@ -475,23 +404,8 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck @@ -499,152 +413,152 @@ Parameters: -l(line) (file) &Archivo - + &View &Ver - + &Toolbars &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 @@ -655,92 +569,92 @@ Parameters: -l(line) (file) 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 @@ -755,339 +669,314 @@ Parameters: -l(line) (file) Ocultar - - + + 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! @@ -1158,41 +1047,41 @@ 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: @@ -1227,80 +1116,64 @@ Do you want to load this project file instead? Unknown element - - - 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 @@ -1317,7 +1190,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. @@ -1325,81 +1198,76 @@ 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 @@ -1416,67 +1284,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 @@ -1557,29 +1425,24 @@ Options: - Unix 32-bit - Unix 32-bit + Unix 32-bit - Unix 64-bit - Unix 64-bit + Unix 64-bit - Windows 32-bit ANSI - Windows 32-bit ANSI + Windows 32-bit ANSI - Windows 32-bit Unicode - Windows 32-bit Unicode + Windows 32-bit Unicode - Windows 64-bit - Windows 64-bit + Windows 64-bit @@ -1607,58 +1470,58 @@ Options: - + Note: Put your own custom .cfg files in the same folder as the project file. You should see them above. Nota: Ponga sus propios archivos .cfg en la misma carpeta que el proyecto. Debería verlos arriba. - + If tags are added, you will be able to right click on warnings and set one of these tags. You can manually categorize warnings. - + Exclude source files - + Exclude folder... - + Exclude file... - + Misra C - + 2012 - - + + 2023 - + MISRA rule texts - + <html><head/><body><p>Copy/paste the text from Appendix A &quot;Summary of guidelines&quot; from the MISRA C 2012 pdf to a text file.</p></body></html> - + ... @@ -1669,8 +1532,7 @@ Options: - - + Browse... @@ -1698,15 +1560,15 @@ Options: - + Edit Editar - - + + Remove Eliminar @@ -1726,124 +1588,134 @@ Options: - + + Include file + + + + + <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.. + + + + Types and Functions - - + + Analysis - + This is a workfolder that Cppcheck will use for various purposes. - + Parser - + Cppcheck (built in) - + Check level - + Reduced -- meant for usage where developer wants results directly. Limited and faster analysis with fewer results. - + Normal -- meant for normal analysis in CI. Analysis should finish in reasonable time. - + Exhaustive -- meant for nightly builds etc. Analysis time can be longer (10x slower than compilation is OK). - + Check that each class has a safe public interface - + Limit analysis - + Check code in unused templates (should be ON normally, however in theory you can safely ignore warnings in unused templates) Check code in unused templates (slower and less accurate analysis) - + Max CTU depth - - Premium License - - - - + Enable inline suppressions Habilitar supresiones inline - + 2025 - + Misra C++ - + 2008 - + Cert C - + CERT-INT35-C: int precision (if size equals precision, you can leave empty) - + Autosar - + Safety profiles (defined in C++ core guidelines) - + Bug hunting - + External tools @@ -1858,116 +1730,106 @@ Options: Bajar - + Platform - + Clang (experimental) - + If you want to design your classes to be as flexible and robust as possible then the public interface must be very robust. Cppcheck will asumme that arguments can take *any* value. - + Check code in headers (should be ON normally. if you want a limited quick analysis then turn this OFF) - + Max recursion in template instantiation - + Warning options - + Root path: - + Filepaths in warnings will be relative to this path - + Warning tags (separated by semicolon) - + Cppcheck build dir (whole program analysis, incremental analysis, statistics, etc) - + Libraries - + Suppressions Supresiones - + Add Añadir - - + + Addons - + Note: Addons require <a href="https://www.python.org/">Python</a> being installed. - + Y2038 - + Thread safety - + Coding standards - + Cert C++ - + Bug hunting (Premium) - - - Clang analyzer - - - - - Clang-tidy - - Defines: @@ -1977,82 +1839,83 @@ 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 - Compile database + Import Project - - Borland C++ Builder 6 + + C/C++ header - - Import Project + + Include file - + 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) @@ -2085,7 +1948,7 @@ Options: - + (Not found) @@ -2285,11 +2148,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2426,10 +2284,8 @@ Options: - - Cppcheck - Cppcheck + Cppcheck @@ -2517,102 +2373,100 @@ Por favor comprueba que la ruta a la aplicación y los parámetros son correctos - - + + Failed to save the report. Error al guardar el informe. - + Print Report Imprimir informe - + No errors found, nothing to print. No se encontraron errores, nada que imprimir. - + %p% (%1 of %2 files checked) %p% (%1 of %2 archivos comprobados) - - Cppcheck - Cppcheck + Cppcheck - + No errors found. No se han encontrado errores. - + Errors were found, but they are configured to be hidden. To toggle what kind of errors are shown, open view menu. Se han encontrado errores, pero están configurados para que no se muestren. Para cambiar el tipo de comportamiento, abra el menú Ver. - - + + Failed to read the report. Error al leer el informe. - + XML format version 1 is no longer supported. - + First included by - + Id Id - + Clear Log - + Copy this Log entry - + Copy complete Log - + Analysis was stopped - + There was a critical error with id '%1' - + when checking %1 - + when checking a file - + Analysis was aborted. @@ -2897,14 +2751,14 @@ Para cambiar el tipo de comportamiento, abra el menú Ver. - - + + Statistics Estadísticas - + Project Proyecto @@ -2935,7 +2789,7 @@ Para cambiar el tipo de comportamiento, abra el menú Ver. - + Previous Scan Análisis anterior @@ -3015,103 +2869,103 @@ Para cambiar el tipo de comportamiento, abra el menú Ver. - + 1 day 1 día - + %1 days %1 días - + 1 hour 1 hora - + %1 hours %1 horas - + 1 minute 1 minuto - + %1 minutes %1 minutos - + 1 second 1 segundo - + %1 seconds %1 segundos - + 0.%1 seconds 0.%1 segundos - + and y - + Export PDF - + Project Settings Preferencias del proyecto - + Paths Rutas - + Include paths Incluye las rutas - + Defines Definiciones - + Undefines - + Path selected Ruta seleccionada - + Number of files scanned Número de archivos analizados - + Scan duration Duración del análisis - - + + Errors Errores @@ -3126,32 +2980,32 @@ Para cambiar el tipo de comportamiento, abra el menú Ver. - - + + Warnings Advertencias - - + + Style warnings Advertencias de estilo - - + + Portability warnings Advertencias de portabilidad - - + + Performance warnings Advertencias de rendimiento - - + + Information messages Mensajes de información @@ -3188,9 +3042,8 @@ The user interface language has been reset to English. Open the Preferences-dial El idioma de la interfaz gráfica ha sido cambiado a Inglés. Abra la ventana de Preferencias para seleccionar alguno de los idiomas disponibles. - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_fi.ts b/gui/cppcheck_fi.ts index f6c959aa099..bf379534998 100644 --- a/gui/cppcheck_fi.ts +++ b/gui/cppcheck_fi.ts @@ -96,9 +96,8 @@ Parameters: -l(line) (file) Valitse ohjelma jolla avata virhetiedosto - Cppcheck - Cppcheck + Cppcheck @@ -106,70 +105,6 @@ Parameters: -l(line) (file) - - ComplianceReportDialog - - - Compliance Report - - - - - Project name - - - - - Project version - - - - - Coding Standard - - - - - Misra C - - - - - Cert C - - - - - Cert C++ - - - - - List of files with md5 checksums - - - - - Compliance report - - - - - HTML files (*.html) - - - - - - Save compliance report - - - - - Failed to import '%1' (%2), can not show files in compliance report - - - FileViewDialog @@ -180,10 +115,8 @@ Parameters: -l(line) (file) Tiedostoa %1 ei löytynyt - - Cppcheck - Cppcheck + Cppcheck @@ -209,14 +142,13 @@ Parameters: -l(line) (file) - + Helpfile '%1' was not found - Cppcheck - Cppcheck + Cppcheck @@ -336,11 +268,8 @@ Parameters: -l(line) (file) - - - Cppcheck - Cppcheck + Cppcheck @@ -478,31 +407,16 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck - + A&nalyze - + Standard Vakio @@ -512,149 +426,149 @@ Parameters: -l(line) (file) &Tiedosto - + &View &Näytä - + &Toolbars - + 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 @@ -665,92 +579,92 @@ Parameters: -l(line) (file) - + 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 @@ -765,326 +679,301 @@ 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: @@ -1157,42 +1046,42 @@ 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! @@ -1222,85 +1111,69 @@ This is probably because the settings were changed between the Cppcheck versions Unknown element - - - 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 @@ -1317,7 +1190,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. @@ -1325,81 +1198,76 @@ 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 @@ -1410,67 +1278,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 @@ -1550,31 +1418,6 @@ Options: Native - - - Unix 32-bit - - - - - Unix 64-bit - - - - - Windows 32-bit ANSI - - - - - Windows 32-bit Unicode - - - - - Windows 64-bit - - ProjectFile @@ -1601,22 +1444,22 @@ Options: - + Note: Put your own custom .cfg files in the same folder as the project file. You should see them above. - + MISRA rule texts - + <html><head/><body><p>Copy/paste the text from Appendix A &quot;Summary of guidelines&quot; from the MISRA C 2012 pdf to a text file.</p></body></html> - + ... @@ -1627,8 +1470,7 @@ Options: - - + Browse... @@ -1656,15 +1498,15 @@ Options: - + Edit - - + + Remove @@ -1694,274 +1536,274 @@ Options: - + + Include file + + + + + <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.. + + + + Platform - - + + Analysis - + This is a workfolder that Cppcheck will use for various purposes. - + Clang (experimental) - + Check level - + Reduced -- meant for usage where developer wants results directly. Limited and faster analysis with fewer results. - + Normal -- meant for normal analysis in CI. Analysis should finish in reasonable time. - + Exhaustive -- meant for nightly builds etc. Analysis time can be longer (10x slower than compilation is OK). - + If you want to design your classes to be as flexible and robust as possible then the public interface must be very robust. Cppcheck will asumme that arguments can take *any* value. - + Check code in unused templates (should be ON normally, however in theory you can safely ignore warnings in unused templates) Check code in unused templates (slower and less accurate analysis) - + Max CTU depth - + Max recursion in template instantiation - - Premium License - - - - + Warning options - + Root path: - + Filepaths in warnings will be relative to this path - + Warning tags (separated by semicolon) - + Enable inline suppressions - + 2025 - + Misra C++ - + 2008 - + Cert C - + CERT-INT35-C: int precision (if size equals precision, you can leave empty) - + Autosar - + Safety profiles (defined in C++ core guidelines) - + Bug hunting - + External tools - + Cppcheck build dir (whole program analysis, incremental analysis, statistics, etc) - + Types and Functions - + Libraries - + Parser - + Cppcheck (built in) - + Check that each class has a safe public interface - + Limit analysis - + Check code in headers (should be ON normally. if you want a limited quick analysis then turn this OFF) - + If tags are added, you will be able to right click on warnings and set one of these tags. You can manually categorize warnings. - + Exclude source files - + Exclude folder... - + Exclude file... - + Suppressions - + Add - - + + Addons - + Note: Addons require <a href="https://www.python.org/">Python</a> being installed. - + Y2038 - + Thread safety - + Coding standards - + Misra C - + 2012 - - + + 2023 - + Cert C++ - + Bug hunting (Premium) - - - Clang analyzer - - - - - Clang-tidy - - Defines: @@ -1971,82 +1813,83 @@ 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 - Compile database + Import Project - - Borland C++ Builder 6 + + C/C++ header - - Import Project + + Include file - + Select directory to ignore - + Source files - + + All files - + Exclude file - + Select MISRA rule texts file - + MISRA rule texts file (%1) @@ -2081,7 +1924,7 @@ Options: - + (Not found) @@ -2281,11 +2124,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2404,10 +2242,8 @@ Options: - - Cppcheck - Cppcheck + Cppcheck @@ -2477,102 +2313,100 @@ Tarkista että ohjelman polku ja parametrit ovat oikeat. ResultsView - + Print Report - + No errors found, nothing to print. - + %p% (%1 of %2 files checked) - - Cppcheck - Cppcheck + Cppcheck - + No errors found. Virheitä ei löytynyt. - + Errors were found, but they are configured to be hidden. To toggle what kind of errors are shown, open view menu. Virheitä löytyi, mutta asetuksissa kyseiset virheet on määritelty piilotettavaksi. Määrittääksesi minkä tyyppisiä virheitä näytetään, avaa näkymä valikko. - - + + Failed to read the report. - + XML format version 1 is no longer supported. - + First included by - + Id - + Clear Log - + Copy this Log entry - + Copy complete Log - + Analysis was stopped - + There was a critical error with id '%1' - + when checking %1 - + when checking a file - + Analysis was aborted. - - + + Failed to save the report. Raportin tallentaminen epäonnistui. @@ -2870,14 +2704,14 @@ Määrittääksesi minkä tyyppisiä virheitä näytetään, avaa näkymä valik - - + + Statistics - + Project @@ -2908,7 +2742,7 @@ Määrittääksesi minkä tyyppisiä virheitä näytetään, avaa näkymä valik - + Previous Scan @@ -2988,103 +2822,103 @@ Määrittääksesi minkä tyyppisiä virheitä näytetään, avaa näkymä valik - + 1 day - + %1 days - + 1 hour - + %1 hours - + 1 minute - + %1 minutes - + 1 second - + %1 seconds - + 0.%1 seconds - + and - + Export PDF - + Project Settings - + Paths - + Include paths - + Defines - + Undefines - + Path selected - + Number of files scanned - + Scan duration - - + + Errors @@ -3099,32 +2933,32 @@ Määrittääksesi minkä tyyppisiä virheitä näytetään, avaa näkymä valik - - + + Warnings - - + + Style warnings - - + + Portability warnings - - + + Performance warnings - - + + Information messages @@ -3157,9 +2991,8 @@ The user interface language has been reset to English. Open the Preferences-dial - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_fr.ts b/gui/cppcheck_fr.ts index 82e0ea2bf74..6d464bc46af 100644 --- a/gui/cppcheck_fr.ts +++ b/gui/cppcheck_fr.ts @@ -65,11 +65,6 @@ General Public License version 3 Select viewer application Sélection de l'application - - - Cppcheck - - &Executable: @@ -116,70 +111,6 @@ Paramètres : -l(ligne) (fichier) Vous devez spécifier un nom, un chemin, et eventuellement des paramètres en option à l'application ! - - ComplianceReportDialog - - - Compliance Report - - - - - Project name - - - - - Project version - - - - - Coding Standard - - - - - Misra C - - - - - Cert C - - - - - Cert C++ - - - - - List of files with md5 checksums - - - - - Compliance report - - - - - HTML files (*.html) - - - - - - Save compliance report - - - - - Failed to import '%1' (%2), can not show files in compliance report - - - FileViewDialog @@ -187,12 +118,6 @@ Paramètres : -l(ligne) (fichier) Could not find the file: %1 Ne trouve pas le fichier : %1 - - - - Cppcheck - - Could not read the file: %1 @@ -217,15 +142,10 @@ Paramètres : -l(ligne) (fichier) - + Helpfile '%1' was not found - - - Cppcheck - - LibraryAddFunctionDialog @@ -343,13 +263,6 @@ Paramètres : -l(ligne) (fichier) Save as - - - - - Cppcheck - - Save the library as @@ -483,25 +396,6 @@ Paramètres : -l(ligne) (fichier) MainWindow - - - - - - - - - - - - - - - - - Cppcheck - - Checking for updates @@ -518,335 +412,310 @@ Paramètres : -l(ligne) (fichier) &Fichier - + &View &Affichage - - + + 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) - + &Toolbars &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 @@ -857,167 +726,162 @@ Paramètres : -l(ligne) (fichier) 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 : @@ -1029,15 +893,15 @@ Do you want to load this project file instead? - - - - + + + + Project: Projet : - + The project file %1 @@ -1048,32 +912,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 @@ -1083,7 +947,7 @@ Do you want to remove the file from the recently used projects -list? - + C++ standard @@ -1091,7 +955,7 @@ Do you want to remove the file from the recently used projects -list? - + Error Erreur @@ -1145,27 +1009,27 @@ Do you want to remove the file from the recently used projects -list? - + &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 @@ -1174,12 +1038,6 @@ Do you want to remove the file from the recently used projects -list? Unknown element - - - Unknown element - Unknown issue - - Select configuration @@ -1204,50 +1062,50 @@ 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 @@ -1294,206 +1152,196 @@ 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. @@ -1536,31 +1384,6 @@ Do you want to proceed? Platforms - - - Unix 32-bit - - - - - Unix 64-bit - - - - - Windows 32-bit ANSI - - - - - Windows 32-bit Unicode - - - - - Windows 64-bit - - Native @@ -1593,15 +1416,15 @@ Do you want to proceed? - + Edit Editer - - + + Remove Supprimer @@ -1616,22 +1439,22 @@ Do you want to proceed? Descendre - + Suppressions Suppressions - + Add Ajouter - + Note: Put your own custom .cfg files in the same folder as the project file. You should see them above. - + ... @@ -1656,17 +1479,17 @@ Do you want to proceed? - + Root path: - + Warning tags (separated by semicolon) - + Cppcheck build dir (whole program analysis, incremental analysis, statistics, etc) @@ -1676,95 +1499,99 @@ Do you want to proceed? - + + Include file + + + + + <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.. + + + + Types and Functions - + Libraries - + Parser - + Cppcheck (built in) - + Check that each class has a safe public interface - + Limit analysis - - + + Addons - + Note: Addons require <a href="https://www.python.org/">Python</a> being installed. - + Y2038 - + Thread safety - + Coding standards - + Cert C - + CERT-INT35-C: int precision (if size equals precision, you can leave empty) - + Autosar - + Bug hunting - - - Clang analyzer - - - - - Clang-tidy - - - - + Browse... @@ -1774,153 +1601,148 @@ Do you want to proceed? - + Platform - + This is a workfolder that Cppcheck will use for various purposes. - + Clang (experimental) - + Check level - + Reduced -- meant for usage where developer wants results directly. Limited and faster analysis with fewer results. - + Normal -- meant for normal analysis in CI. Analysis should finish in reasonable time. - + Exhaustive -- meant for nightly builds etc. Analysis time can be longer (10x slower than compilation is OK). - + If you want to design your classes to be as flexible and robust as possible then the public interface must be very robust. Cppcheck will asumme that arguments can take *any* value. - + Check code in headers (should be ON normally. if you want a limited quick analysis then turn this OFF) - + Max recursion in template instantiation - - Premium License - - - - + Warning options - + Filepaths in warnings will be relative to this path - + If tags are added, you will be able to right click on warnings and set one of these tags. You can manually categorize warnings. - + Exclude source files - + Exclude folder... - + Exclude file... - + Enable inline suppressions - + Misra C - + 2012 - - + + 2023 - + 2025 - + MISRA rule texts - + <html><head/><body><p>Copy/paste the text from Appendix A &quot;Summary of guidelines&quot; from the MISRA C 2012 pdf to a text file.</p></body></html> - + Misra C++ - + 2008 - + Cert C++ - + Safety profiles (defined in C++ core guidelines) - + Bug hunting (Premium) - + External tools @@ -1940,19 +1762,19 @@ Do you want to proceed? - - + + Analysis - + Check code in unused templates (should be ON normally, however in theory you can safely ignore warnings in unused templates) Check code in unused templates (slower and less accurate analysis) - + Max CTU depth @@ -1960,83 +1782,84 @@ 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 + + C/C++ header - - Select MISRA rule texts file + + Include file - - MISRA rule texts file (%1) + + Exclude file - - Visual Studio + + Select MISRA rule texts file - - Compile database + + MISRA rule texts file (%1) - - Borland C++ Builder 6 + + Compile database @@ -2068,7 +1891,7 @@ Do you want to proceed? - + (Not found) @@ -2267,11 +2090,6 @@ Do you want to proceed? Tags - - - CWE - - QPlatformTheme @@ -2314,12 +2132,6 @@ Do you want to proceed? Undefined file Fichier indéterminé - - - - Cppcheck - - Could not start %1 @@ -2483,87 +2295,81 @@ Please select the default editor application in preferences/Applications.Résultats - - - Cppcheck - - - - + No errors found. Pas d'erreurs trouvées. - + Errors were found, but they are configured to be hidden. To toggle what kind of errors are shown, open view menu. Des erreurs ont été trouvées mais sont configurées pour rester cachées. Pour configurer les erreurs affichées, ouvrez le menu d'affichage. - + Analysis was stopped - + There was a critical error with id '%1' - + when checking %1 - + when checking a file - + Analysis was aborted. - - + + Failed to save the report. Erreur lors de la sauvegarde du rapport. - - + + Failed to read the report. Erreur lors de la lecture du rapport - + %p% (%1 of %2 files checked) %p% (%1 fichiers sur %2 vérifiés) - + Id Id - + Print Report Imprimer le rapport - + No errors found, nothing to print. Aucune erreur trouvée. Il n'y a rien à imprimer - + First included by - + XML format version 1 is no longer supported. @@ -2583,17 +2389,17 @@ Pour configurer les erreurs affichées, ouvrez le menu d'affichage. - + Clear Log - + Copy this Log entry - + Copy complete Log @@ -2870,14 +2676,14 @@ Pour configurer les erreurs affichées, ouvrez le menu d'affichage. - - + + Statistics Statistiques - + Project Projet @@ -2903,7 +2709,7 @@ Pour configurer les erreurs affichées, ouvrez le menu d'affichage. - + Previous Scan Analyse précédente @@ -2968,123 +2774,123 @@ Pour configurer les erreurs affichées, ouvrez le menu d'affichage.Copier vers le presse-papier - + 1 day - + %1 days - + 1 hour - + %1 hours - + 1 minute - + %1 minutes - + 1 second - + %1 seconds - + 0.%1 seconds - + and - + Project Settings - + Paths Chemins - + Include paths - + Defines - + Path selected - + Number of files scanned - + Scan duration - - + + Errors Erreurs - - + + Warnings Avertissements - - + + Style warnings Avertissement de style - - + + Portability warnings - - + + Performance warnings Avertissements de performance - - + + Information messages @@ -3094,7 +2900,7 @@ Pour configurer les erreurs affichées, ouvrez le menu d'affichage. - + Export PDF @@ -3124,7 +2930,7 @@ Pour configurer les erreurs affichées, ouvrez le menu d'affichage. - + Undefines @@ -3156,11 +2962,6 @@ Pour configurer les erreurs affichées, ouvrez le menu d'affichage. - - - Cppcheck - - TxtReport diff --git a/gui/cppcheck_it.ts b/gui/cppcheck_it.ts index 1c8829bb198..65b31b59b1e 100644 --- a/gui/cppcheck_it.ts +++ b/gui/cppcheck_it.ts @@ -107,9 +107,8 @@ Parametri: -l(line) (file) Seleziona l'applicazione di lettura - Cppcheck - Cppcheck + Cppcheck @@ -117,70 +116,6 @@ Parametri: -l(line) (file) Devi specificare un nome, un percorso ed, opzionalmente, i parametri per l'applicazione! - - ComplianceReportDialog - - - Compliance Report - - - - - Project name - - - - - Project version - - - - - Coding Standard - - - - - Misra C - - - - - Cert C - - - - - Cert C++ - - - - - List of files with md5 checksums - - - - - Compliance report - - - - - HTML files (*.html) - - - - - - Save compliance report - - - - - Failed to import '%1' (%2), can not show files in compliance report - - - FileViewDialog @@ -189,10 +124,8 @@ Parametri: -l(line) (file) File non trovato: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -218,14 +151,13 @@ Parametri: -l(line) (file) - + Helpfile '%1' was not found - Cppcheck - Cppcheck + Cppcheck @@ -345,11 +277,8 @@ Parametri: -l(line) (file) - - - Cppcheck - Cppcheck + Cppcheck @@ -487,31 +416,16 @@ Parametri: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck - + A&nalyze - + Standard Standard @@ -521,149 +435,149 @@ Parametri: -l(line) (file) &File - + &View &Visualizza - + &Toolbars &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 @@ -674,92 +588,92 @@ Parametri: -l(line) (file) 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 @@ -774,326 +688,301 @@ Parametri: -l(line) (file) Nascondi - - + + 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: @@ -1173,35 +1062,35 @@ 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. @@ -1210,7 +1099,7 @@ 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! @@ -1235,85 +1124,69 @@ Probabilmente ciò è avvenuto perché le impostazioni sono state modificate tra Unknown element - - - 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 @@ -1330,7 +1203,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. @@ -1338,81 +1211,76 @@ 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 @@ -1429,67 +1297,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 @@ -1570,29 +1438,24 @@ Options: - Unix 32-bit - Unix 32-bit + Unix 32-bit - Unix 64-bit - Unix 64-bit + Unix 64-bit - Windows 32-bit ANSI - Windows 32-bit, ANSI + Windows 32-bit, ANSI - Windows 32-bit Unicode - Windows 32-bit, Unicode + Windows 32-bit, Unicode - Windows 64-bit - Windows 64-bit + Windows 64-bit @@ -1620,58 +1483,58 @@ Options: - + Note: Put your own custom .cfg files in the same folder as the project file. You should see them above. - + If tags are added, you will be able to right click on warnings and set one of these tags. You can manually categorize warnings. - + Exclude source files - + Exclude folder... - + Exclude file... - + Misra C - + 2012 - - + + 2023 - + MISRA rule texts - + <html><head/><body><p>Copy/paste the text from Appendix A &quot;Summary of guidelines&quot; from the MISRA C 2012 pdf to a text file.</p></body></html> - + ... @@ -1682,8 +1545,7 @@ Options: - - + Browse... @@ -1711,15 +1573,15 @@ Options: - + Edit Modifica - - + + Remove Rimuovi @@ -1739,124 +1601,134 @@ Options: - + + Include file + + + + + <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.. + + + + Types and Functions - - + + Analysis - + This is a workfolder that Cppcheck will use for various purposes. - + Parser - + Cppcheck (built in) - + Check level - + Reduced -- meant for usage where developer wants results directly. Limited and faster analysis with fewer results. - + Normal -- meant for normal analysis in CI. Analysis should finish in reasonable time. - + Exhaustive -- meant for nightly builds etc. Analysis time can be longer (10x slower than compilation is OK). - + Check that each class has a safe public interface - + Limit analysis - + Check code in unused templates (should be ON normally, however in theory you can safely ignore warnings in unused templates) Check code in unused templates (slower and less accurate analysis) - + Max CTU depth - - Premium License - - - - + Enable inline suppressions Abilita le soppressioni - + 2025 - + Misra C++ - + 2008 - + Cert C - + CERT-INT35-C: int precision (if size equals precision, you can leave empty) - + Autosar - + Safety profiles (defined in C++ core guidelines) - + Bug hunting - + External tools @@ -1871,116 +1743,106 @@ Options: Giù - + Platform - + Clang (experimental) - + If you want to design your classes to be as flexible and robust as possible then the public interface must be very robust. Cppcheck will asumme that arguments can take *any* value. - + Check code in headers (should be ON normally. if you want a limited quick analysis then turn this OFF) - + Max recursion in template instantiation - + Warning options - + Root path: - + Filepaths in warnings will be relative to this path - + Warning tags (separated by semicolon) - + Cppcheck build dir (whole program analysis, incremental analysis, statistics, etc) - + Libraries - + Suppressions - + Add - - + + Addons - + Note: Addons require <a href="https://www.python.org/">Python</a> being installed. - + Y2038 - + Thread safety - + Coding standards - + Cert C++ - + Bug hunting (Premium) - - - Clang analyzer - - - - - Clang-tidy - - Defines: @@ -1990,82 +1852,83 @@ 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 - Compile database + Import Project - - Borland C++ Builder 6 + + C/C++ header - - Import Project + + Include file - + 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) @@ -2098,7 +1961,7 @@ Options: - + (Not found) @@ -2298,11 +2161,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2429,10 +2287,8 @@ Options: - - Cppcheck - Cppcheck + Cppcheck @@ -2509,102 +2365,100 @@ Per favore verifica che il percorso dell'applicazione e i parametri siano c ResultsView - + Print Report - + No errors found, nothing to print. - + %p% (%1 of %2 files checked) %p% (%1 su %2 file scansionati) - - Cppcheck - Cppcheck + Cppcheck - + No errors found. Nessun errore trovato. - + Errors were found, but they are configured to be hidden. To toggle what kind of errors are shown, open view menu. Sono stati trovati errori, ma sono stati configurati per essere nascosti. Per vedere il tipo di errori che sono mostrati, apri il menu Visualizza. - - + + Failed to read the report. Apertura del report fallito. - + XML format version 1 is no longer supported. - + First included by - + Id Id - + Clear Log - + Copy this Log entry - + Copy complete Log - + Analysis was stopped - + There was a critical error with id '%1' - + when checking %1 - + when checking a file - + Analysis was aborted. - - + + Failed to save the report. Salvataggio del report fallito. @@ -2909,14 +2763,14 @@ Per vedere il tipo di errori che sono mostrati, apri il menu Visualizza. - - + + Statistics Statistiche - + Project Progetto @@ -2947,7 +2801,7 @@ Per vedere il tipo di errori che sono mostrati, apri il menu Visualizza. - + Previous Scan Precedente Scansione @@ -3027,103 +2881,103 @@ Per vedere il tipo di errori che sono mostrati, apri il menu Visualizza. - + 1 day 1 giorno - + %1 days %1 giorni - + 1 hour 1 ora - + %1 hours %1 ore - + 1 minute 1 minuto - + %1 minutes %1 minuti - + 1 second 1 secondo - + %1 seconds %1 secondi - + 0.%1 seconds 0,%1 secondi - + and e - + Export PDF - + Project Settings Impostazioni progetto - + Paths Percorsi - + Include paths Percorsi di inclusione - + Defines Definizioni - + Undefines - + Path selected Selezionato percorso - + Number of files scanned Numero di file scansionati - + Scan duration Durata della scansione - - + + Errors Errori @@ -3138,32 +2992,32 @@ Per vedere il tipo di errori che sono mostrati, apri il menu Visualizza. - - + + Warnings Avvisi - - + + Style warnings Stilwarnungen - - + + Portability warnings Avvisi sulla portabilità - - + + Performance warnings Avvisi sulle performance - - + + Information messages Messaggi di informazione @@ -3200,9 +3054,8 @@ The user interface language has been reset to English. Open the Preferences-dial L'interfaccia utente è stata risettata in Inglese. Apri la finestra di dialogo Preferenze per selezionare una qualunque lingua a disposizione. - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_ja.ts b/gui/cppcheck_ja.ts index 3e486f416dd..eedad8e9515 100644 --- a/gui/cppcheck_ja.ts +++ b/gui/cppcheck_ja.ts @@ -106,9 +106,8 @@ Parameters: -l(line) (file) 表示アプリケーションの選択 - Cppcheck - Cppcheck + Cppcheck @@ -119,65 +118,52 @@ Parameters: -l(line) (file) ComplianceReportDialog - Compliance Report - コンプライアンスレポート + コンプライアンスレポート - Project name - プロジェクト名 + プロジェクト名 - Project version - プロジェクトバージョン + プロジェクトバージョン - Coding Standard - コーディング標準 + コーディング標準 - Misra C - MISRA C + MISRA C - Cert C - CERT C + CERT C - Cert C++ - Cert C++ + Cert C++ - List of files with md5 checksums - md5チェックサムつきファイルリスト + md5チェックサムつきファイルリスト - Compliance report - コンプライアンスレポート + コンプライアンスレポート - HTML files (*.html) - HTMLファイル(*.html) + HTMLファイル(*.html) - - Save compliance report - コンプライアンスレポートの保存 + コンプライアンスレポートの保存 - Failed to import '%1' (%2), can not show files in compliance report - '%1' (%2)のインポートに失敗しました。コンプライアンスレポートに表示できません + '%1' (%2)のインポートに失敗しました。コンプライアンスレポートに表示できません Failed to import '%1', can not show files in compliance report @@ -192,10 +178,8 @@ Parameters: -l(line) (file) ファイル:%1 が見つかりません - - Cppcheck - Cppcheck + Cppcheck @@ -221,14 +205,13 @@ Parameters: -l(line) (file) インデックス - + Helpfile '%1' was not found ヘルプファイル '%1' が見つかりません - Cppcheck - Cppcheck + Cppcheck @@ -348,11 +331,8 @@ Parameters: -l(line) (file) ライブラリファイルを開く - - - Cppcheck - Cppcheck + Cppcheck @@ -501,23 +481,8 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck @@ -525,152 +490,152 @@ Parameters: -l(line) (file) ファイル(&F) - + &View 表示(&V) - + &Toolbars ツールバー(&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 エラーを表示 @@ -681,125 +646,125 @@ Parameters: -l(line) (file) 情報 - + 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) @@ -814,299 +779,294 @@ 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 - Misra C++ 2008 - MISRA C++ 2008 + MISRA C++ 2008 - Cert C - CERT C + CERT C - Cert C++ - Cert C++ + Cert C++ - Misra C++ 2023 - 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. @@ -1115,13 +1075,13 @@ 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: クイックフィルタ: @@ -1197,7 +1157,7 @@ Do you want to load this project file instead? - + Error エラー @@ -1210,73 +1170,72 @@ 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. @@ -1285,60 +1244,58 @@ 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 + Visual Studio - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 - + Select files to analyze チェック対象のファイルを選択 - + Select directory to analyze チェックするディレクトリを選択してください @@ -1387,7 +1344,7 @@ Analysis is aborted. - + %1 Analysis is aborted. @@ -1396,7 +1353,7 @@ Analysis is aborted. 解析は中止した。 - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1406,7 +1363,7 @@ Do you want to proceed? 新しくXMLファイルを開くと現在の結果が削除されます。実行しますか? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1415,77 +1372,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 情報を表示 @@ -1494,22 +1451,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 @@ -1608,29 +1565,24 @@ Options: ネイティブ - Unix 32-bit - Unix 32-bit + Unix 32-bit - Unix 64-bit - Unix 64-bit + Unix 64-bit - Windows 32-bit ANSI - Windows 32-bit ANSIエンコード + Windows 32-bit ANSIエンコード - Windows 32-bit Unicode - Windows 32-bit Unicode + Windows 32-bit Unicode - Windows 64-bit - Windows 64-bit + Windows 64-bit @@ -1658,7 +1610,7 @@ Options: 定義(Define)はセミコロン';'で区切る必要があります。 例: DEF1;DEF2=5;DEF3=int - + Note: Put your own custom .cfg files in the same folder as the project file. You should see them above. カスタマイズした cfgファイルを同じフォルダにプロジェクトファイルとして保存してください。ここに表示できるようになります。 @@ -1667,17 +1619,17 @@ Options: MISRA C 2012 - + MISRA rule texts MISRA ルールテキスト - + <html><head/><body><p>Copy/paste the text from Appendix A &quot;Summary of guidelines&quot; from the MISRA C 2012 pdf to a text file.</p></body></html> <html><head/><body><p>MISRA C 2012 pdfのAppendix A &quot;Summary of guidelines&quot; からテキストをコピーペーストしてください。</p></body></html> - + ... ... @@ -1688,8 +1640,7 @@ Options: - - + Browse... 参照... @@ -1717,15 +1668,15 @@ Options: - + Edit 編集 - - + + Remove 取り除く @@ -1745,155 +1696,169 @@ Options: インクルードパス: - + + Include file + インクルードファイル + + + + <html><head/><body><p><span style=" font-family:'monospace'; color:#000000; background-color:#ffffff;">Force inclusion of a header file</span></p></body></html> + <html><head/><body><p><span style=" font-family:'monospace'; color:#000000; background-color:#ffffff;">ヘッダファイルを強制的にインクルードします</span></p></body></html> + + + + Browse.. + ブラウズ.. + + + Types and Functions 型と関数 - - + + Analysis チェック - + This is a workfolder that Cppcheck will use for various purposes. Cppcheckがさまざまな目的で使用するワークディレクトリ。 - + Parser パーサー - + Cppcheck (built in) Cppcheckビルトイン - + Check level チェックレベル - + Reduced -- meant for usage where developer wants results directly. Limited and faster analysis with fewer results. #R 限定的 -- 開発者が直接的に結果を得るための解析を意味します。解析は限定的で高速ですがより少ない結果になります。 - + Normal -- meant for normal analysis in CI. Analysis should finish in reasonable time. #N 通常 -- CIでの通常の解析を意味します。解析が合理的な時間内に完了すべきです。 - + Exhaustive -- meant for nightly builds etc. Analysis time can be longer (10x slower than compilation is OK). #E 徹底的 -- ナイトリービルド等を意味します。解析時間はより長くなることがあります (コンパイルの10倍以上時間がかかってもよい)。 - + Check code in headers (should be ON normally. if you want a limited quick analysis then turn this OFF) ヘッダファイルのコードもチェック (通常はONにしてください、制限するときのみOFF) - Premium License - プレミアムライセンス + プレミアムライセンス - + If tags are added, you will be able to right click on warnings and set one of these tags. You can manually categorize warnings. タグが追加された場合、警告上で右クリックしてそれらのタグの中の一つを設定できます。警告を分類できます。 - + Exclude source files 除外するソースファイル - + Exclude folder... フォルダで除外... - + Exclude file... ファイルで除外... - + Check that each class has a safe public interface クラスが安全で公開されたインターフェースをもっているか確認 - + Limit analysis 解析の制限 - + Check code in unused templates (should be ON normally, however in theory you can safely ignore warnings in unused templates) Check code in unused templates (slower and less accurate analysis) 未使用テンプレートのコードもチェック (解析に時間がかかり、また正確性は低い) - + Max CTU depth CTUの最大深さ - + Enable inline suppressions inline抑制を有効にする - + Misra C MISRA C - + 2012 2012 - - + + 2023 2023 - + 2025 2025 - + Misra C++ MISRA C++ - + 2008 2008 - + Cert C++ Cert C++ - + Safety profiles (defined in C++ core guidelines) 安全性プロファイル(C++コアガイドラインで定義) - + Bug hunting (Premium) バグハンティング(プレミアム) - + External tools 外部ツール @@ -1908,88 +1873,88 @@ Options: - + Platform プラットフォーム - + Clang (experimental) Clang (実験的) - + If you want to design your classes to be as flexible and robust as possible then the public interface must be very robust. Cppcheck will asumme that arguments can take *any* value. 可能な限りクラスが柔軟であり堅牢であることを望む場合、公開されたインターフェースが非常に堅牢です。Cppcheckは引数があらゆる値をとりうると仮定します。 - + Max recursion in template instantiation テンプレートインスタンス化の最大再帰回数 - + Warning options 警告オプション - + Root path: ルートパス: - + Filepaths in warnings will be relative to this path 警告中のファイルパスはこのパスからの相対パスになります - + Warning tags (separated by semicolon) 警告タグ(セミコロン区切り) - + Cppcheck build dir (whole program analysis, incremental analysis, statistics, etc) Cppcheck ビルドディレクトリ (全プログラムチェック, 差分チェック, 統計等) - + Libraries ライブラリ - + Suppressions 指摘の抑制 - + Add 追加 - - + + Addons アドオン - + Note: Addons require <a href="https://www.python.org/">Python</a> being installed. 注意: アドオンには<a href="https://www.python.org/">Python</a>が必要です。 - + Y2038 Y2038 - + Thread safety スレッドセーフ - + Coding standards コーディング標準 @@ -1998,12 +1963,12 @@ Options: MISRA C 2012 - + Cert C CERT C - + CERT-INT35-C: int precision (if size equals precision, you can leave empty) CERT-INT35-C: int型の精度 (もしサイズが精度と一致する場合空のままにしてください) @@ -2012,24 +1977,22 @@ Options: MISRA C++ 2008 - + Autosar AUTOSAR - + Bug hunting バグハント - Clang analyzer - Clang Analyzer + Clang Analyzer - Clang-tidy - Clang-tidy + Clang-tidy @@ -2040,82 +2003,91 @@ 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 + Visual Studio - + Compile database コンパイルデータベース - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 - + Import Project プロジェクトのインポート - + + C/C++ header + C/C++のヘッダー + + + + Include file + ファイルのインクルード + + + Select directory to ignore 除外するディレクトリを選択してください - + Source files ソースファイル - + + All files 全ファイル - + Exclude file 除外ファイル - + Select MISRA rule texts file MISRAルールテキストファイルを選択 - + MISRA rule texts file (%1) MISRAルールテキストファイル (%1) @@ -2156,7 +2128,7 @@ Options: 行 %1: 必須の属性 '%2' が '%3'にない - + (Not found) (見つかりません) @@ -2357,9 +2329,8 @@ Options: タグ - CWE - CWE + CWE @@ -2491,10 +2462,8 @@ Options: タグなし - - Cppcheck - Cppcheck + Cppcheck @@ -2600,61 +2569,59 @@ Please check the application path and parameters are correct. 警告の詳細 - - + + Failed to save the report. レポートの保存に失敗しました。 - + Print Report レポートの印刷 - + No errors found, nothing to print. 指摘がないため、印刷するものがありません。 - + %p% (%1 of %2 files checked) %p% (%1 / %2 :ファイル数) - - Cppcheck - Cppcheck + Cppcheck - + No errors found. 警告/エラーは見つかりませんでした。 - + Errors were found, but they are configured to be hidden. To toggle what kind of errors are shown, open view menu. 警告/エラーが見つかりましたが、非表示設定になっています。 - - + + Failed to read the report. レポートの読み込みに失敗. - + XML format version 1 is no longer supported. XML フォーマットバージョン 1 はもうサポートされていません。 - + First included by は次のものが最初にインクルードしました - + Id ID @@ -2663,42 +2630,42 @@ To toggle what kind of errors are shown, open view menu. バグハントの解析は不完全です - + Clear Log ログの消去 - + Copy this Log entry このログ項目をコピー - + Copy complete Log ログ全体をコピー - + Analysis was stopped 解析は停止しした - + There was a critical error with id '%1' id '%1'の致命的なエラーがあります - + when checking %1 %1 をチェックするとき - + when checking a file ファイルをチェックするとき - + Analysis was aborted. 解析は中止した。 @@ -2984,14 +2951,14 @@ To toggle what kind of errors are shown, open view menu. - - + + Statistics 統計情報 - + Project プロジェクト @@ -3022,7 +2989,7 @@ To toggle what kind of errors are shown, open view menu. - + Previous Scan 前回の解析 @@ -3102,103 +3069,103 @@ To toggle what kind of errors are shown, open view menu. PDF エクスポート - + 1 day 一日 - + %1 days %1日 - + 1 hour 一時間 - + %1 hours %1時間 - + 1 minute 一分 - + %1 minutes %1分 - + 1 second 一秒 - + %1 seconds %1秒 - + 0.%1 seconds 0.%1秒 - + and - + Export PDF PDF エクスポート - + Project Settings プロジェクトの設定 - + Paths パス - + Include paths インクルードパス - + Defines 定義(define) - + Undefines 定義取り消し(Undef) - + Path selected 選択されたパス - + Number of files scanned スキャンしたファイルの数 - + Scan duration スキャン期間 - - + + Errors エラー @@ -3213,32 +3180,32 @@ To toggle what kind of errors are shown, open view menu. cppcheckビルドディレクトリがありません - - + + Warnings 警告 - - + + Style warnings スタイル警告 - - + + Portability warnings 移植可能性警告 - - + + Performance warnings パフォーマンス警告 - - + + Information messages 情報メッセージ @@ -3273,9 +3240,8 @@ The user interface language has been reset to English. Open the Preferences-dial そのため言語を 英語にリセットします。設定ダイアログから利用可能な言語を選択してください。 - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_ka.ts b/gui/cppcheck_ka.ts index ecc47d7d090..00239743df0 100644 --- a/gui/cppcheck_ka.ts +++ b/gui/cppcheck_ka.ts @@ -96,9 +96,8 @@ Parameters: -l(line) (file) აირჩიეთ აპლიკაცია - Cppcheck - Cppcheck + Cppcheck @@ -109,65 +108,52 @@ Parameters: -l(line) (file) ComplianceReportDialog - Compliance Report - შესაბამისობის ანგარიში + შესაბამისობის ანგარიში - Project name - პროექტის სახელი + პროექტის სახელი - Project version - პროექტის ვერსია + პროექტის ვერსია - Coding Standard - კოდირების სტანდარტი + კოდირების სტანდარტი - Misra C - Misra C + Misra C - Cert C - Cert C + Cert C - Cert C++ - Cert C++ + Cert C++ - List of files with md5 checksums - MD5 საკონტროლო ჯამების მქონე ფაილების სია + MD5 საკონტროლო ჯამების მქონე ფაილების სია - Compliance report - შესაბამისობის ანგარიში + შესაბამისობის ანგარიში - HTML files (*.html) - HTML ფაილები (*.html) + HTML ფაილები (*.html) - - Save compliance report - შესაბამისობის ანგარიშის შენახვა + შესაბამისობის ანგარიშის შენახვა - Failed to import '%1' (%2), can not show files in compliance report - '%1'-ის (%2) შემოტანა ჩავარდა. შესაბამისობის ანგარიშში ფაილებს ვერ ვაჩვენებ + '%1'-ის (%2) შემოტანა ჩავარდა. შესაბამისობის ანგარიშში ფაილებს ვერ ვაჩვენებ @@ -180,10 +166,8 @@ Parameters: -l(line) (file) ვერ ვიპოვე ფაილი: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -209,14 +193,13 @@ Parameters: -l(line) (file) ინდექსი - + Helpfile '%1' was not found დახმარების ფაილი '%1' ვერ ვიპოვე - Cppcheck - Cppcheck + Cppcheck @@ -336,11 +319,8 @@ Parameters: -l(line) (file) ბიბლიოთეკის ფაილის გახსნა - - - Cppcheck - Cppcheck + Cppcheck @@ -477,31 +457,16 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck - + A&nalyze ა&ნალიზი - + Standard სტანდარტული @@ -511,149 +476,149 @@ Parameters: -l(line) (file) &ფაილი - + &View &ხედი - + &Toolbars &ხელსაწყოთა ზოლები - + 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 დამალულის &ჩვენება @@ -664,92 +629,92 @@ Parameters: -l(line) (file) ინფორმაცია - + 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 &ყველას ჩართვა @@ -764,326 +729,313 @@ 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 - - Misra C++ 2008 - - - - Cert C - Cert C + Cert C - Cert C++ - Cert C++ - - - - Misra C++ 2023 - + Cert C++ - + Autosar - + EULA... - + Thread Details - + Show thread details - + &Contents &შემცველობა - + Categories კატეგორიები - - + + Show style warnings სტილის გაფრთხილების ჩვენება - + Open the help contents დახმარების შემცველობის გახსნა - + F1 F1 - + &Help &დახმარება - - + + Quick Filter: სწრაფი ფილტრი: @@ -1166,7 +1118,7 @@ Analysis is aborted. - + %1 Analysis is aborted. @@ -1175,35 +1127,35 @@ 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! ახალი ფაილების ან საქაღალდეების არჩევამდე პრორექტის ფაილი უნდა დახუროთ! @@ -1229,85 +1181,77 @@ This is probably because the settings were changed between the Cppcheck versions Unknown element უცნობი ელემენტი - - - 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 + Visual Studio - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 - + Select files to analyze აირჩეთ ფაილები ანალიზისთვის - + Select directory to analyze აირჩიეთ საქაღალდე ანალიზისთვის @@ -1326,7 +1270,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. @@ -1337,7 +1281,7 @@ Do you want to proceed? გნებავთ, გააგრძელოთ? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1346,47 +1290,46 @@ 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. @@ -1395,27 +1338,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 @@ -1432,67 +1375,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 @@ -1586,29 +1529,24 @@ Options: საკუთარი - Unix 32-bit - Unix 32-bit + Unix 32-bit - Unix 64-bit - Unix 64-bit + Unix 64-bit - Windows 32-bit ANSI - Windows 32-bit ANSI + Windows 32-bit ANSI - Windows 32-bit Unicode - Windows 32-bit Unicode + Windows 32-bit Unicode - Windows 64-bit - Windows 64-bit + Windows 64-bit @@ -1636,67 +1574,67 @@ Options: აღწერები წერტილმძიმით უნდა იყოს გამოყოფილი. მაგ: DEF1;DEF2=5;DEF3=int - + Note: Put your own custom .cfg files in the same folder as the project file. You should see them above. შენიშვნა: ჩადეთ თქვენი .cfg ფაილები იგივე საქაღალდეში, სადაც პროექტის ფაილია. მათ ზემოთ დაინახავთ. - + Clang (experimental) Clang (ექსპერიმენტული) - + If you want to design your classes to be as flexible and robust as possible then the public interface must be very robust. Cppcheck will asumme that arguments can take *any* value. - + Check code in headers (should be ON normally. if you want a limited quick analysis then turn this OFF) თავსართის ფაილებში არსებული კოდის შეწმება (ნაგულისხმევად, ეს ჩართულია. თუ გნებავთ შეზღუდული სწრაფი ანალიზი, მაშინ გამორთეთ ეს) - + Max recursion in template instantiation - + Filepaths in warnings will be relative to this path ფაილის ბილიკები ამ ბილიკის ფარდობითი იქნება - + If tags are added, you will be able to right click on warnings and set one of these tags. You can manually categorize warnings. თუ ჭდეები დამატებულია, შეგიძლიათ, გაფრთხილებებზე მარჯვენა ღილაკით დააწკაპუნოთ და დააყენოთ ერთ-ერთი ჭდე. გაფრთხილებების კატეგორიებად დალაგება ხელით შეგიძლიათ. - + Exclude source files კოდის ფაილების ამოღება - + Exclude folder... საქაღალდის ამოღება... - + Exclude file... ფაილის ამოღება... - + MISRA rule texts MISRA-ის წესის ტექსტები - + <html><head/><body><p>Copy/paste the text from Appendix A &quot;Summary of guidelines&quot; from the MISRA C 2012 pdf to a text file.</p></body></html> - + ... ... @@ -1707,8 +1645,7 @@ Options: - - + Browse... ნუსხა... @@ -1736,15 +1673,15 @@ Options: - + Edit ჩასწორება - - + + Remove წაშლა @@ -1764,124 +1701,134 @@ Options: ჩასმის ბილიკები: - + + Include file + + + + + <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.. + + + + Types and Functions ტიპები და ფუნქციები - - + + Analysis ანალიზი - + This is a workfolder that Cppcheck will use for various purposes. ეს სამუშაო საქაღალდეა, რომელსაც Cppcheck სხვადასხვა მიზნებისთვის გამოიყენებს. - + Parser ანალიზატორი - + Cppcheck (built in) Cppcheck (ჩაშენებული) - + Check level შემოწმების დონე - + Reduced -- meant for usage where developer wants results directly. Limited and faster analysis with fewer results. - + Normal -- meant for normal analysis in CI. Analysis should finish in reasonable time. ნორმალური -- ნიშნავს ნორმალურ ანალიზს CI-ში. ანალიზი მისაღებ დროში დასრულდება. - + Exhaustive -- meant for nightly builds etc. Analysis time can be longer (10x slower than compilation is OK). ამომწურავი -- განკუთვნილია ღამის აგებებისთვის და ა.შ. ანალიზის დრო, შეიძლება, უფრო მეტიც იყოს (კომპილაციაზე 10x მეტი დრო ჩვეულებრივი ამბავია). - + Check that each class has a safe public interface შემოწმება, აქვს თუ არა ყველა კლასს უსაფრთხო საჯარო ინტერფეისი - + Limit analysis ანალიზის შეზღუდვა - + Check code in unused templates (should be ON normally, however in theory you can safely ignore warnings in unused templates) Check code in unused templates (slower and less accurate analysis) - + Max CTU depth CTU-ის მაქსიმალური სიღრმე - - Premium License - - - - + Enable inline suppressions შეცდომების ხაზშივე ჩახშობის ჩართვა - + 2025 2025 - + Misra C++ Misra C++ - + 2008 2008 - + Cert C Cert C - + CERT-INT35-C: int precision (if size equals precision, you can leave empty) CERT-INT35-C: მთელი რიცხვის სიზუსტე (თუ ზომა სიზუსტეს ემთხვევა, შეგიძლიათ, ცარიელი დატოვოთ) - + Autosar - + Safety profiles (defined in C++ core guidelines) - + Bug hunting შეცდომებზე ნადირობა - + External tools გარე ხელსაწყოები @@ -1896,106 +1843,104 @@ Options: ქვემოთ - + Platform პლატფორმა - + Warning options გაფრთხილების მორგება - + Root path: Root ბილიკი: - + Warning tags (separated by semicolon) გაფრთხილების ჭდეები (წერტილმძიმით გამოყოფილი) - + Cppcheck build dir (whole program analysis, incremental analysis, statistics, etc) Cppcheck-ის აგების საქაღალდე (მთელი პროგრამის ანალიზი, ინკრემენტული ანალიზი, სტატისტიკა და ა.შ.) - + Libraries ბიბლიოთეკები - + Suppressions ჩახშობები - + Add დამატება - - + + Addons დამატებები - + Note: Addons require <a href="https://www.python.org/">Python</a> being installed. შენიშვნა: დამატებას დაყენებული <a href="https://www.python.org/">Python</a> სჭირდება. - + Y2038 Y2038 - + Thread safety ნაკადების უსაფრთხოება - + Coding standards კოდირების სტანდარტები - + Misra C Misra C - + 2012 2012 - - + + 2023 2023 - + Cert C++ Cert C++ - + Bug hunting (Premium) შეცდომებზე ნადირობა (ფასიანი) - Clang analyzer - Clang-ის ანალიზატორი + Clang-ის ანალიზატორი - Clang-tidy - Clang-tidy + Clang-tidy @@ -2006,82 +1951,91 @@ 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 + Visual Studio - + Compile database მონაცემთა ბაზის კომპილაცია - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 - + Import Project პროექტის შემოტანა - + + C/C++ header + + + + + Include file + + + + Select directory to ignore აირჩიეთ გამოსატოვებელი საქაღალდე - + Source files კოდის ფაილები - + + All files ყველა ფაილი - + Exclude file ფაილის ამოღება - + Select MISRA rule texts file აირჩიეთ MISRA-ის წესების ტექსტის ფაილი - + MISRA rule texts file (%1) MISRA-ის წესის ტექსტების ფაილი (%1) @@ -2116,7 +2070,7 @@ Options: ხაზი %1: აუცილებელი ატრიბუტი '%2' '%3'-ში აღმოჩენილი არაა - + (Not found) (ვერ ვიპოვე) @@ -2316,11 +2270,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2451,10 +2400,8 @@ Options: ჭდის გარეშე - - Cppcheck - Cppcheck + Cppcheck @@ -2540,56 +2487,54 @@ Please check the application path and parameters are correct. ResultsView - + Print Report ანგარიშის დაბეჭდვა - + No errors found, nothing to print. შეცდომები ვერ ვიპოვე. დასაბეჭდი არაფერია. - + %p% (%1 of %2 files checked) %p% (შემოწმებულია %1 ფაილი %2-დან) - - Cppcheck - Cppcheck + Cppcheck - + No errors found. შეცდომების გარეშე. - + Errors were found, but they are configured to be hidden. To toggle what kind of errors are shown, open view menu. აღმოჩენილია შეცდომები, მაგრამ მითითებულია, რომ ისინი დაიმალოს. იმისათვის, რომ გადართოთ, რა სახის შეცდომებია ნაჩვენები, გახსენით მენიუ 'ხედი'. - - + + Failed to read the report. ანგარიშის წაკითხვა ჩავარდა. - + XML format version 1 is no longer supported. XML-ის ფორმატის პირველი ვერსია მხარდაჭერილი აღარაა. - + First included by პირველად ჩასმულია ფაილში - + Id Id @@ -2598,48 +2543,48 @@ To toggle what kind of errors are shown, open view menu. შეცდომებზე ნადირობის ანალიზი დაუსრულებელია - + Clear Log ჟურნალის გასუფთავება - + Copy this Log entry ამ ჟურნალის ჩანაწერის კოპირება - + Copy complete Log სრული ჟურნალის კოპირება - + Analysis was stopped ანალიზი გაუქმებულია - + There was a critical error with id '%1' აღმოჩენილია კრიტიკული შეცდომა id-ით '%1' - + when checking %1 %1-ის შემოწმებისას - + when checking a file ფაილის შემოწმებისას - + Analysis was aborted. ანალიზი შეწყვეტილია. - - + + Failed to save the report. ანგარიშის შენახვა ჩავარდა. @@ -2945,14 +2890,14 @@ To toggle what kind of errors are shown, open view menu. - - + + Statistics სტატისტიკა - + Project პროექტი @@ -2983,7 +2928,7 @@ To toggle what kind of errors are shown, open view menu. - + Previous Scan წინა სკანირება @@ -3063,103 +3008,103 @@ To toggle what kind of errors are shown, open view menu. PDF-ად გატანა - + 1 day 1 დღე - + %1 days %1 დღე - + 1 hour %1 საათი - + %1 hours %1 საათი - + 1 minute %1 წუთი - + %1 minutes %1 წთ - + 1 second 1 წამი - + %1 seconds %1 წამი - + 0.%1 seconds 0.%1 წამი - + and და - + Export PDF PDF-ში გატანა - + Project Settings პროექტის პარამეტრები - + Paths ბილიკები - + Include paths ჩასმის ბილიკები - + Defines აღწერები - + Undefines წაშლილი მაკროაღწერები - + Path selected არჩეული ბილიკი - + Number of files scanned დასკანერებულია ფაილების რაოდენობა - + Scan duration სკანირების ხანგრძლივობა - - + + Errors შედომები @@ -3174,32 +3119,32 @@ To toggle what kind of errors are shown, open view menu. Cppcheck-ის აგების საქაღალდის გარეშე - - + + Warnings გაფრთხილებები - - + + Style warnings სტილის გაფრთხილებები - - + + Portability warnings გადატანადობის გაფრთხილებები - - + + Performance warnings წარმადობის გაფრთხილებები - - + + Information messages საინფორმაციო შეტყობინებები @@ -3236,9 +3181,8 @@ The user interface language has been reset to English. Open the Preferences-dial მომხმარებლის ინტერფეისი ინგლისურზე გადაირთო. გახსენით მორგების დიალოგი, რომ ხელმისაწვდომი ენებიდან სასურველი აირჩიოთ. - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_ko.ts b/gui/cppcheck_ko.ts index da6bac85bb7..eef9ffac818 100644 --- a/gui/cppcheck_ko.ts +++ b/gui/cppcheck_ko.ts @@ -106,9 +106,8 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: 뷰어 프로그램 선택 - Cppcheck - Cppcheck + Cppcheck @@ -116,70 +115,6 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: - - ComplianceReportDialog - - - Compliance Report - - - - - Project name - - - - - Project version - - - - - Coding Standard - - - - - Misra C - - - - - Cert C - - - - - Cert C++ - - - - - List of files with md5 checksums - - - - - Compliance report - - - - - HTML files (*.html) - - - - - - Save compliance report - - - - - Failed to import '%1' (%2), can not show files in compliance report - - - FileViewDialog @@ -188,10 +123,8 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: 파일 찾기 실패: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -217,14 +150,13 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: - + Helpfile '%1' was not found - Cppcheck - Cppcheck + Cppcheck @@ -344,11 +276,8 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: - - - Cppcheck - Cppcheck + Cppcheck @@ -484,23 +413,8 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck @@ -518,304 +432,279 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: 파일(&F) - + &View 보기(&V) - + &Toolbars 도구바(&T) - - + + 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 @@ -826,58 +715,58 @@ Kate로 파일을 열고, 해당 행으로 이동하는 예제: 정보 - + 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. @@ -886,7 +775,7 @@ 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! 새로운 파일이나 디렉토리를 선택하기 전에 프로젝트 파일을 닫으세요! @@ -900,153 +789,148 @@ 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: 프로젝트: @@ -1081,34 +965,34 @@ 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 @@ -1130,7 +1014,7 @@ Do you want to remove the file from the recently used projects -list? - + C++ standard @@ -1138,7 +1022,7 @@ Do you want to remove the file from the recently used projects -list? - + Error @@ -1190,27 +1074,27 @@ Do you want to remove the file from the recently used projects -list? - + &Print... - + Print the Current Report - + Print Pre&view... - + Open a Print Preview Dialog for the Current Results - + Open library editor @@ -1219,12 +1103,6 @@ Do you want to remove the file from the recently used projects -list? Unknown element - - - Unknown element - Unknown issue - - Select configuration @@ -1249,50 +1127,50 @@ 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 @@ -1309,199 +1187,189 @@ 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. @@ -1545,29 +1413,24 @@ Do you want to proceed? Platforms - Unix 32-bit - Unix 32-bit + Unix 32-bit - Unix 64-bit - Unix 64-bit + Unix 64-bit - Windows 32-bit ANSI - Windows 32-bit ANSI + Windows 32-bit ANSI - Windows 32-bit Unicode - Windows 32-bit Unicode + Windows 32-bit Unicode - Windows 64-bit - Windows 64-bit + Windows 64-bit @@ -1601,15 +1464,15 @@ Do you want to proceed? - + Edit 편집 - - + + Remove 제거 @@ -1624,22 +1487,22 @@ Do you want to proceed? 아래로 - + Suppressions - + Add - + Note: Put your own custom .cfg files in the same folder as the project file. You should see them above. - + ... @@ -1664,17 +1527,17 @@ Do you want to proceed? - + Root path: - + Warning tags (separated by semicolon) - + Cppcheck build dir (whole program analysis, incremental analysis, statistics, etc) @@ -1684,95 +1547,99 @@ Do you want to proceed? - + + Include file + + + + + <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.. + + + + Types and Functions - + Libraries - + Parser - + Cppcheck (built in) - + Check that each class has a safe public interface - + Limit analysis - - + + Addons - + Note: Addons require <a href="https://www.python.org/">Python</a> being installed. - + Y2038 - + Thread safety - + Coding standards - + Cert C - + CERT-INT35-C: int precision (if size equals precision, you can leave empty) - + Autosar - + Bug hunting - - - Clang analyzer - - - - - Clang-tidy - - - - + Browse... @@ -1782,153 +1649,148 @@ Do you want to proceed? - + Platform - + This is a workfolder that Cppcheck will use for various purposes. - + Clang (experimental) - + Check level - + Reduced -- meant for usage where developer wants results directly. Limited and faster analysis with fewer results. - + Normal -- meant for normal analysis in CI. Analysis should finish in reasonable time. - + Exhaustive -- meant for nightly builds etc. Analysis time can be longer (10x slower than compilation is OK). - + If you want to design your classes to be as flexible and robust as possible then the public interface must be very robust. Cppcheck will asumme that arguments can take *any* value. - + Check code in headers (should be ON normally. if you want a limited quick analysis then turn this OFF) - + Max recursion in template instantiation - - Premium License - - - - + Warning options - + Filepaths in warnings will be relative to this path - + If tags are added, you will be able to right click on warnings and set one of these tags. You can manually categorize warnings. - + Exclude source files - + Exclude folder... - + Exclude file... - + Enable inline suppressions Inline suppression 사용 - + Misra C - + 2012 - - + + 2023 - + 2025 - + MISRA rule texts - + <html><head/><body><p>Copy/paste the text from Appendix A &quot;Summary of guidelines&quot; from the MISRA C 2012 pdf to a text file.</p></body></html> - + Misra C++ - + 2008 - + Cert C++ - + Safety profiles (defined in C++ core guidelines) - + Bug hunting (Premium) - + External tools @@ -1948,19 +1810,19 @@ Do you want to proceed? - - + + Analysis - + Check code in unused templates (should be ON normally, however in theory you can safely ignore warnings in unused templates) Check code in unused templates (slower and less accurate analysis) - + Max CTU depth @@ -1968,83 +1830,84 @@ 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 + + C/C++ header - - Select MISRA rule texts file + + Include file - - MISRA rule texts file (%1) + + Exclude file - - Visual Studio + + Select MISRA rule texts file - - Compile database + + MISRA rule texts file (%1) - - Borland C++ Builder 6 + + Compile database @@ -2076,7 +1939,7 @@ Do you want to proceed? - + (Not found) @@ -2275,11 +2138,6 @@ Do you want to proceed? Tags - - - CWE - - QPlatformTheme @@ -2371,10 +2229,8 @@ Do you want to proceed? 숨기기 - - Cppcheck - Cppcheck + Cppcheck @@ -2487,87 +2343,85 @@ Please check the application path and parameters are correct. 결과 - - + + Failed to save the report. 결과 저장 실패. - + %p% (%1 of %2 files checked) %p% (%2 중 %1 파일 검사됨) - - Cppcheck - Cppcheck + Cppcheck - + No errors found. 에러가 발견되지 않았습니다. - + Errors were found, but they are configured to be hidden. To toggle what kind of errors are shown, open view menu. 에러가 발견되었지만, 감추도록 설정되어 있습니다. 에러 종류를 표시하도록 설정하려면, 보기 메뉴를 선택하세요. - - + + Failed to read the report. 결과 불러오기 실패. - + Analysis was stopped - + There was a critical error with id '%1' - + when checking %1 - + when checking a file - + Analysis was aborted. - + Id - + Print Report - + No errors found, nothing to print. - + First included by - + XML format version 1 is no longer supported. @@ -2587,17 +2441,17 @@ To toggle what kind of errors are shown, open view menu. - + Clear Log - + Copy this Log entry - + Copy complete Log @@ -2882,14 +2736,14 @@ To toggle what kind of errors are shown, open view menu. - - + + Statistics 통계 - + Project 프로젝트 @@ -2915,7 +2769,7 @@ To toggle what kind of errors are shown, open view menu. - + Previous Scan 직전 검사 @@ -2980,123 +2834,123 @@ To toggle what kind of errors are shown, open view menu. 클립보드에 복사 - + 1 day 1일 - + %1 days %1일 - + 1 hour 1시간 - + %1 hours %1시간 - + 1 minute 1분 - + %1 minutes %1분 - + 1 second 1초 - + %1 seconds %1초 - + 0.%1 seconds 0.%1초 - + and - + Project Settings 프로젝트 설정 - + Paths 경로 - + Include paths Include 경로 - + Defines Defines - + Path selected 선택된 경로 - + Number of files scanned 검사된 파일 수 - + Scan duration 검사 시간 - - + + Errors 에러 - - + + Warnings 경고 - - + + Style warnings 스타일 경고 - - + + Portability warnings 이식성 경고 - - + + Performance warnings 성능 경고 - - + + Information messages 정보 메시지 @@ -3106,7 +2960,7 @@ To toggle what kind of errors are shown, open view menu. - + Export PDF @@ -3136,7 +2990,7 @@ To toggle what kind of errors are shown, open view menu. - + Undefines @@ -3173,9 +3027,8 @@ The user interface language has been reset to English. Open the Preferences-dial 언어가 영어로 초기화 됐습니다. 설정창을 열어서 설정 가능한 언어를 선택하세요. - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_nl.ts b/gui/cppcheck_nl.ts index 2d3149d2f0a..6a877a34909 100644 --- a/gui/cppcheck_nl.ts +++ b/gui/cppcheck_nl.ts @@ -106,9 +106,8 @@ Parameters: -l(lijn) (bestand) Selecteer applicatie - Cppcheck - Cppcheck + Cppcheck @@ -116,70 +115,6 @@ Parameters: -l(lijn) (bestand) Geef een naam op, een pad en eventueel parameters voor de toepassing! - - ComplianceReportDialog - - - Compliance Report - - - - - Project name - - - - - Project version - - - - - Coding Standard - - - - - Misra C - - - - - Cert C - - - - - Cert C++ - - - - - List of files with md5 checksums - - - - - Compliance report - - - - - HTML files (*.html) - - - - - - Save compliance report - - - - - Failed to import '%1' (%2), can not show files in compliance report - - - FileViewDialog @@ -190,10 +125,8 @@ Parameters: -l(lijn) (bestand) Kon het bestand niet vinden: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -219,14 +152,13 @@ Parameters: -l(lijn) (bestand) - + Helpfile '%1' was not found - Cppcheck - Cppcheck + Cppcheck @@ -346,11 +278,8 @@ Parameters: -l(lijn) (bestand) - - - Cppcheck - Cppcheck + Cppcheck @@ -488,31 +417,16 @@ Parameters: -l(lijn) (bestand) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck - + A&nalyze - + Standard Standaard @@ -522,149 +436,149 @@ Parameters: -l(lijn) (bestand) &Bestand - + &View &Weergave - + &Toolbars &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 @@ -675,92 +589,92 @@ Parameters: -l(lijn) (bestand) 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 @@ -775,326 +689,301 @@ Parameters: -l(lijn) (bestand) Verberg - - + + 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: @@ -1168,35 +1057,35 @@ 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. @@ -1205,7 +1094,7 @@ 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! @@ -1235,85 +1124,69 @@ Dit is waarschijnlijk omdat de instellingen zijn gewijzigd tussen de versies van Unknown element - - - 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 @@ -1330,7 +1203,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. @@ -1338,81 +1211,76 @@ 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 @@ -1428,67 +1296,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 @@ -1568,31 +1436,6 @@ Options: Native - - - Unix 32-bit - - - - - Unix 64-bit - - - - - Windows 32-bit ANSI - - - - - Windows 32-bit Unicode - - - - - Windows 64-bit - - ProjectFile @@ -1619,58 +1462,58 @@ Options: - + Note: Put your own custom .cfg files in the same folder as the project file. You should see them above. - + If tags are added, you will be able to right click on warnings and set one of these tags. You can manually categorize warnings. - + Exclude source files - + Exclude folder... - + Exclude file... - + Misra C - + 2012 - - + + 2023 - + MISRA rule texts - + <html><head/><body><p>Copy/paste the text from Appendix A &quot;Summary of guidelines&quot; from the MISRA C 2012 pdf to a text file.</p></body></html> - + ... @@ -1681,8 +1524,7 @@ Options: - - + Browse... @@ -1710,15 +1552,15 @@ Options: - + Edit Bewerk - - + + Remove Verwijder @@ -1738,124 +1580,134 @@ Options: - + + Include file + + + + + <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.. + + + + Types and Functions - - + + Analysis - + This is a workfolder that Cppcheck will use for various purposes. - + Parser - + Cppcheck (built in) - + Check level - + Reduced -- meant for usage where developer wants results directly. Limited and faster analysis with fewer results. - + Normal -- meant for normal analysis in CI. Analysis should finish in reasonable time. - + Exhaustive -- meant for nightly builds etc. Analysis time can be longer (10x slower than compilation is OK). - + Check that each class has a safe public interface - + Limit analysis - + Check code in unused templates (should be ON normally, however in theory you can safely ignore warnings in unused templates) Check code in unused templates (slower and less accurate analysis) - + Max CTU depth - - Premium License - - - - + Enable inline suppressions Schakel inline suppressies in - + 2025 - + Misra C++ - + 2008 - + Cert C - + CERT-INT35-C: int precision (if size equals precision, you can leave empty) - + Autosar - + Safety profiles (defined in C++ core guidelines) - + Bug hunting - + External tools @@ -1870,116 +1722,106 @@ Options: Omlaag - + Platform - + Clang (experimental) - + If you want to design your classes to be as flexible and robust as possible then the public interface must be very robust. Cppcheck will asumme that arguments can take *any* value. - + Check code in headers (should be ON normally. if you want a limited quick analysis then turn this OFF) - + Max recursion in template instantiation - + Warning options - + Root path: - + Filepaths in warnings will be relative to this path - + Warning tags (separated by semicolon) - + Cppcheck build dir (whole program analysis, incremental analysis, statistics, etc) - + Libraries - + Suppressions - + Add - - + + Addons - + Note: Addons require <a href="https://www.python.org/">Python</a> being installed. - + Y2038 - + Thread safety - + Coding standards - + Cert C++ - + Bug hunting (Premium) - - - Clang analyzer - - - - - Clang-tidy - - Defines: @@ -1989,82 +1831,83 @@ 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 - Compile database + Import Project - - Borland C++ Builder 6 + + C/C++ header - - Import Project + + Include file - + 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) @@ -2099,7 +1942,7 @@ Options: - + (Not found) @@ -2299,11 +2142,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2430,10 +2268,8 @@ Options: - - Cppcheck - Cppcheck + Cppcheck @@ -2510,102 +2346,100 @@ Gelieve te controleren of de het pad en de parameters correct zijn. ResultsView - + Print Report - + No errors found, nothing to print. - + %p% (%1 of %2 files checked) %p% (%1 van %2 bestanden gecontroleerd) - - Cppcheck - Cppcheck + Cppcheck - + No errors found. Geen fouten gevonden. - + Errors were found, but they are configured to be hidden. To toggle what kind of errors are shown, open view menu. Fouten werden gevonden, maar volgens de configuratie zijn deze verborgen. Gebruik het uitzicht menu om te selecteren welke fouten getoond worden. - - + + Failed to read the report. Kon rapport niet lezen. - + XML format version 1 is no longer supported. - + First included by - + Id Id - + Clear Log - + Copy this Log entry - + Copy complete Log - + Analysis was stopped - + There was a critical error with id '%1' - + when checking %1 - + when checking a file - + Analysis was aborted. - - + + Failed to save the report. Kon het rapport niet opslaan. @@ -2907,14 +2741,14 @@ Gebruik het uitzicht menu om te selecteren welke fouten getoond worden. - - + + Statistics Statistieken - + Project Project @@ -2945,7 +2779,7 @@ Gebruik het uitzicht menu om te selecteren welke fouten getoond worden. - + Previous Scan Vorige scan @@ -3025,103 +2859,103 @@ Gebruik het uitzicht menu om te selecteren welke fouten getoond worden. - + 1 day 1 dag - + %1 days %1 dagen - + 1 hour 1 uur - + %1 hours %1 uren - + 1 minute 1 minuut - + %1 minutes %1 minuten - + 1 second 1 seconde - + %1 seconds %1 secondes - + 0.%1 seconds 0.%1 secondes - + and en - + Export PDF - + Project Settings Project instellingen - + Paths Paden - + Include paths Bevat paden - + Defines Omschrijft - + Undefines - + Path selected Pad Geselekteerd - + Number of files scanned Aantal bestanden gescanned - + Scan duration Scan tijd - - + + Errors Fouten @@ -3136,32 +2970,32 @@ Gebruik het uitzicht menu om te selecteren welke fouten getoond worden. - - + + Warnings Waarschuwingen - - + + Style warnings Stijl waarschuwingen - - + + Portability warnings Portabiliteit waarschuwingen - - + + Performance warnings Presentatie waarschuwingen - - + + Information messages Informatie bericht @@ -3198,9 +3032,8 @@ The user interface language has been reset to English. Open the Preferences-dial De gebruikerstaal is gereset naar Engels. Open het dialoogvenster om een van de beschikbare talen te selecteren. - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_ru.ts b/gui/cppcheck_ru.ts index 124e4d783aa..cd1a4c4d0ce 100644 --- a/gui/cppcheck_ru.ts +++ b/gui/cppcheck_ru.ts @@ -106,9 +106,8 @@ Parameters: -l(line) (file) Выберите приложение - Cppcheck - Cppcheck + Cppcheck @@ -116,70 +115,6 @@ Parameters: -l(line) (file) Вы должны задать название и путь к приложению! - - ComplianceReportDialog - - - Compliance Report - - - - - Project name - - - - - Project version - - - - - Coding Standard - - - - - Misra C - - - - - Cert C - - - - - Cert C++ - - - - - List of files with md5 checksums - - - - - Compliance report - - - - - HTML files (*.html) - - - - - - Save compliance report - - - - - Failed to import '%1' (%2), can not show files in compliance report - - - FileViewDialog @@ -190,10 +125,8 @@ Parameters: -l(line) (file) Невозможно найти файл: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -219,14 +152,13 @@ Parameters: -l(line) (file) - + Helpfile '%1' was not found - Cppcheck - Cppcheck + Cppcheck @@ -346,11 +278,8 @@ Parameters: -l(line) (file) Открыть файл библиотеки - - - Cppcheck - Cppcheck + Cppcheck @@ -488,31 +417,16 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck - + A&nalyze Анализ - + Standard Стандартные @@ -522,149 +436,149 @@ Parameters: -l(line) (file) &Файл - + &View &Вид - + &Toolbars &Панель инструментов - + 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 Показать скрытые @@ -675,92 +589,92 @@ Parameters: -l(line) (file) Информационные сообщения - + 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 Отметить все @@ -775,326 +689,301 @@ 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: Быстрый фильтр: @@ -1175,35 +1064,35 @@ 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. @@ -1212,7 +1101,7 @@ This is probably because the settings were changed between the Cppcheck versions Возможно, это связано с изменениями в версии программы. Пожалуйста, проверьте (и исправьте) настройки приложения. - + You must close the project file before selecting new files or directories! Вы должны закрыть проект перед выбором новых файлов или каталогов! @@ -1238,17 +1127,11 @@ This is probably because the settings were changed between the Cppcheck versions Unknown element Неизвестный элемент - - - Unknown element - Unknown issue - Неизвестная проблема - - + Error Ошибка @@ -1257,70 +1140,68 @@ 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 + Visual Studio - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 - + Select files to analyze Выбор файлов для анализа - + Select directory to analyze Выбор каталога для анализа @@ -1339,7 +1220,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. @@ -1350,7 +1231,7 @@ Do you want to proceed? Вы хотите продолжить? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1359,109 +1240,104 @@ 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 @@ -1470,22 +1346,22 @@ Analysis is stopped. Невозможно импортировать '%1', анализ остановлен - + Project files (*.cppcheck) Файлы проекта (*.cppcheck) - + Select Project Filename Выберите имя файла для проекта - + No project file loaded Файл с проектом не загружен - + The project file %1 @@ -1501,12 +1377,12 @@ Do you want to remove the file from the recently used projects -list? Хотите удалить его из списка проектов? - + Install - + New version available: %1. %2 @@ -1600,29 +1476,24 @@ Options: - Unix 32-bit - Unix 32-bit + Unix 32-bit - Unix 64-bit - Unix 64-bit + Unix 64-bit - Windows 32-bit ANSI - Windows 32-bit ANSI + Windows 32-bit ANSI - Windows 32-bit Unicode - Windows 32-bit Unicode + Windows 32-bit Unicode - Windows 64-bit - Windows 64-bit + Windows 64-bit @@ -1650,52 +1521,52 @@ Options: Defines должны быть разделены точкой с запятой ';' - + Note: Put your own custom .cfg files in the same folder as the project file. You should see them above. Положите свои .cfg-файлы в один каталог с файлом проекта. Вы увидите их сверху. - + Clang (experimental) - + If you want to design your classes to be as flexible and robust as possible then the public interface must be very robust. Cppcheck will asumme that arguments can take *any* value. - + Check code in headers (should be ON normally. if you want a limited quick analysis then turn this OFF) - + Max recursion in template instantiation - + Filepaths in warnings will be relative to this path - + If tags are added, you will be able to right click on warnings and set one of these tags. You can manually categorize warnings. - + Exclude source files - + Exclude folder... - + Exclude file... @@ -1704,17 +1575,17 @@ Options: MISRA C 2012 - + MISRA rule texts Файл с текстами правил MISRA - + <html><head/><body><p>Copy/paste the text from Appendix A &quot;Summary of guidelines&quot; from the MISRA C 2012 pdf to a text file.</p></body></html> <html><head/><body><p>Скопируйте текст из Appendix A &quot;Summary of guidelines&quot; из фала правил MISRA C 2012 pdf в текстовый файл.</p></body></html> - + ... ... @@ -1725,8 +1596,7 @@ Options: - - + Browse... Обзор... @@ -1754,15 +1624,15 @@ Options: - + Edit Изменить - - + + Remove Удалить @@ -1782,124 +1652,134 @@ Options: Пути заголовочных файлов: - + + Include file + + + + + <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.. + + + + Types and Functions - - + + Analysis Анализ - + This is a workfolder that Cppcheck will use for various purposes. - + Parser - + Cppcheck (built in) - + Check level - + Reduced -- meant for usage where developer wants results directly. Limited and faster analysis with fewer results. - + Normal -- meant for normal analysis in CI. Analysis should finish in reasonable time. - + Exhaustive -- meant for nightly builds etc. Analysis time can be longer (10x slower than compilation is OK). - + Check that each class has a safe public interface - + Limit analysis - + Check code in unused templates (should be ON normally, however in theory you can safely ignore warnings in unused templates) Check code in unused templates (slower and less accurate analysis) Проверить код в неиспользуемых шаблонах - + Max CTU depth Максимальная глубина CTU - - Premium License - - - - + Enable inline suppressions Включить inline-подавление ошибок - + 2025 - + Misra C++ - + 2008 - + Cert C - + CERT-INT35-C: int precision (if size equals precision, you can leave empty) - + Autosar - + Safety profiles (defined in C++ core guidelines) - + Bug hunting - + External tools Внешние инструменты @@ -1914,107 +1794,97 @@ Options: Вниз - + Platform Платформа - + Warning options Опции предупреждений - + Root path: Корневой каталог: - + Warning tags (separated by semicolon) Теги предупреждений (через ';') - + Cppcheck build dir (whole program analysis, incremental analysis, statistics, etc) Каталог сборки Cppcheck - + Libraries Библиотеки - + Suppressions Подавления - + Add Добавить - - + + Addons Дополнения - + Note: Addons require <a href="https://www.python.org/">Python</a> being installed. - + Y2038 - + Thread safety - + Coding standards Стандарты кодирования - + Misra C - + 2012 - - + + 2023 - + Cert C++ - + Bug hunting (Premium) - - - Clang analyzer - - - - - Clang-tidy - - Defines: @@ -2024,82 +1894,91 @@ 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 + Visual Studio - + Compile database - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 - + Import Project Импорт проекта - + + C/C++ header + + + + + Include file + + + + Select directory to ignore Выберите директорию, которую надо проигнорировать - + Source files - + + All files - + Exclude file - + Select MISRA rule texts file Выбрать файл текстов правил MISRA - + MISRA rule texts file (%1) Файл текстов правил MISRA (%1) @@ -2134,7 +2013,7 @@ Options: - + (Not found) (Недоступно) @@ -2334,11 +2213,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2469,10 +2343,8 @@ Options: Тег отсутствует - - Cppcheck - Cppcheck + Cppcheck @@ -2555,102 +2427,100 @@ Please check the application path and parameters are correct. ResultsView - + Print Report Распечатать отчет - + No errors found, nothing to print. Ошибок не найдено, нечего распечатывать. - + %p% (%1 of %2 files checked) %p% (%1 из %2 файлов проверено) - - Cppcheck - Cppcheck + Cppcheck - + No errors found. Ошибок не найдено. - + Errors were found, but they are configured to be hidden. To toggle what kind of errors are shown, open view menu. Были обнаружены ошибки, но они настроены быть скрыты. Для переключения какие ошибки отображаются, откройте меню представления. - - + + Failed to read the report. Не удалось прочитать отчет. - + XML format version 1 is no longer supported. XML формат версии 1 больше не поддерживается. - + First included by Только первый включенный - + Id Id - + Clear Log Очистить лог - + Copy this Log entry Скопировать данную запись - + Copy complete Log Скопировать полный лог - + Analysis was stopped - + There was a critical error with id '%1' - + when checking %1 - + when checking a file - + Analysis was aborted. - - + + Failed to save the report. Не удалось сохранить отчет. @@ -2956,14 +2826,14 @@ To toggle what kind of errors are shown, open view menu. - - + + Statistics Статистика - + Project Проект @@ -2994,7 +2864,7 @@ To toggle what kind of errors are shown, open view menu. - + Previous Scan Последнее сканирование @@ -3074,103 +2944,103 @@ To toggle what kind of errors are shown, open view menu. Экспорт PDF - + 1 day 1 день - + %1 days %1 дней - + 1 hour 1 час - + %1 hours %1 часов - + 1 minute 1 минута - + %1 minutes %1 минут - + 1 second 1 секунда - + %1 seconds %1 секунд - + 0.%1 seconds 0.1%1 секунд - + and и - + Export PDF Экспорт PDF - + Project Settings Настройки проекта - + Paths Пути - + Include paths Включенные пути - + Defines Объявленные макроопределения: - + Undefines Удаленные макроопределения: - + Path selected Выбранные пути - + Number of files scanned Количество просканированных файлов - + Scan duration Продолжительность сканирования - - + + Errors Ошибки @@ -3185,32 +3055,32 @@ To toggle what kind of errors are shown, open view menu. Не задана директория сборки - - + + Warnings Предупреждения - - + + Style warnings Стилистические предупреждения - - + + Portability warnings Предупреждения переносимости - - + + Performance warnings Предупреждения производительности - - + + Information messages Информационные сообщения @@ -3247,9 +3117,8 @@ The user interface language has been reset to English. Open the Preferences-dial Язык пользовательского интерфейса был сброшен на английский. Откройте Настройки-диалог для выбора любого из доступных языков. - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_sr.ts b/gui/cppcheck_sr.ts index 70b04dd196f..ebfe46f5ced 100644 --- a/gui/cppcheck_sr.ts +++ b/gui/cppcheck_sr.ts @@ -96,9 +96,8 @@ Parameters: -l(line) (file) Select viewer application - Cppcheck - Cppcheck + Cppcheck @@ -106,70 +105,6 @@ Parameters: -l(line) (file) - - ComplianceReportDialog - - - Compliance Report - - - - - Project name - - - - - Project version - - - - - Coding Standard - - - - - Misra C - - - - - Cert C - - - - - Cert C++ - - - - - List of files with md5 checksums - - - - - Compliance report - - - - - HTML files (*.html) - - - - - - Save compliance report - - - - - Failed to import '%1' (%2), can not show files in compliance report - - - FileViewDialog @@ -178,10 +113,8 @@ Parameters: -l(line) (file) Could not find the file: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -207,14 +140,13 @@ Parameters: -l(line) (file) - + Helpfile '%1' was not found - Cppcheck - Cppcheck + Cppcheck @@ -334,11 +266,8 @@ Parameters: -l(line) (file) - - - Cppcheck - Cppcheck + Cppcheck @@ -476,31 +405,16 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck - + A&nalyze - + Standard Standard @@ -510,149 +424,149 @@ Parameters: -l(line) (file) &File - + &View &View - + &Toolbars - + 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 @@ -663,92 +577,92 @@ Parameters: -l(line) (file) - + 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 @@ -763,326 +677,301 @@ 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: @@ -1155,42 +1044,42 @@ 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! @@ -1220,85 +1109,69 @@ This is probably because the settings were changed between the Cppcheck versions Unknown element - - - 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 @@ -1315,7 +1188,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. @@ -1323,81 +1196,76 @@ 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 @@ -1408,67 +1276,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 @@ -1549,29 +1417,24 @@ Options: - Unix 32-bit - Unix 32-bit + Unix 32-bit - Unix 64-bit - Unix 64-bit + Unix 64-bit - Windows 32-bit ANSI - Windows 32-bit ANSI + Windows 32-bit ANSI - Windows 32-bit Unicode - Windows 32-bit Unicode + Windows 32-bit Unicode - Windows 64-bit - Windows 64-bit + Windows 64-bit @@ -1599,22 +1462,22 @@ Options: - + Note: Put your own custom .cfg files in the same folder as the project file. You should see them above. - + MISRA rule texts - + <html><head/><body><p>Copy/paste the text from Appendix A &quot;Summary of guidelines&quot; from the MISRA C 2012 pdf to a text file.</p></body></html> - + ... @@ -1625,8 +1488,7 @@ Options: - - + Browse... @@ -1654,15 +1516,15 @@ Options: - + Edit - - + + Remove @@ -1692,274 +1554,274 @@ Options: - + + Include file + + + + + <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.. + + + + Platform - - + + Analysis - + This is a workfolder that Cppcheck will use for various purposes. - + Clang (experimental) - + Check level - + Reduced -- meant for usage where developer wants results directly. Limited and faster analysis with fewer results. - + Normal -- meant for normal analysis in CI. Analysis should finish in reasonable time. - + Exhaustive -- meant for nightly builds etc. Analysis time can be longer (10x slower than compilation is OK). - + If you want to design your classes to be as flexible and robust as possible then the public interface must be very robust. Cppcheck will asumme that arguments can take *any* value. - + Check code in unused templates (should be ON normally, however in theory you can safely ignore warnings in unused templates) Check code in unused templates (slower and less accurate analysis) - + Max CTU depth - + Max recursion in template instantiation - - Premium License - - - - + Warning options - + Root path: - + Filepaths in warnings will be relative to this path - + Warning tags (separated by semicolon) - + Enable inline suppressions - + 2025 - + Misra C++ - + 2008 - + Cert C - + CERT-INT35-C: int precision (if size equals precision, you can leave empty) - + Autosar - + Safety profiles (defined in C++ core guidelines) - + Bug hunting - + External tools - + Cppcheck build dir (whole program analysis, incremental analysis, statistics, etc) - + Types and Functions - + Libraries - + Parser - + Cppcheck (built in) - + Check that each class has a safe public interface - + Limit analysis - + Check code in headers (should be ON normally. if you want a limited quick analysis then turn this OFF) - + If tags are added, you will be able to right click on warnings and set one of these tags. You can manually categorize warnings. - + Exclude source files - + Exclude folder... - + Exclude file... - + Suppressions - + Add - - + + Addons - + Note: Addons require <a href="https://www.python.org/">Python</a> being installed. - + Y2038 - + Thread safety - + Coding standards - + Misra C - + 2012 - - + + 2023 - + Cert C++ - + Bug hunting (Premium) - - - Clang analyzer - - - - - Clang-tidy - - Defines: @@ -1969,82 +1831,83 @@ 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 - Compile database + Import Project - - Borland C++ Builder 6 + + C/C++ header - - Import Project + + Include file - + Select directory to ignore - + Source files - + + All files - + Exclude file - + Select MISRA rule texts file - + MISRA rule texts file (%1) @@ -2077,7 +1940,7 @@ Options: - + (Not found) @@ -2277,11 +2140,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2400,10 +2258,8 @@ Options: - - Cppcheck - Cppcheck + Cppcheck @@ -2472,102 +2328,100 @@ Please check the application path and parameters are correct. ResultsView - + Print Report - + No errors found, nothing to print. - + %p% (%1 of %2 files checked) - - Cppcheck - Cppcheck + Cppcheck - + No errors found. No errors found. - + Errors were found, but they are configured to be hidden. To toggle what kind of errors are shown, open view menu. Errors were found, but they are configured to be hidden. To toggle what kind of errors are shown, open view menu. - - + + Failed to read the report. - + XML format version 1 is no longer supported. - + First included by - + Id - + Clear Log - + Copy this Log entry - + Copy complete Log - + Analysis was stopped - + There was a critical error with id '%1' - + when checking %1 - + when checking a file - + Analysis was aborted. - - + + Failed to save the report. Failed to save the report. @@ -2864,14 +2718,14 @@ To toggle what kind of errors are shown, open view menu. - - + + Statistics - + Project @@ -2902,7 +2756,7 @@ To toggle what kind of errors are shown, open view menu. - + Previous Scan @@ -2982,103 +2836,103 @@ To toggle what kind of errors are shown, open view menu. - + 1 day - + %1 days - + 1 hour - + %1 hours - + 1 minute - + %1 minutes - + 1 second - + %1 seconds - + 0.%1 seconds - + and - + Export PDF - + Project Settings - + Paths - + Include paths - + Defines - + Undefines - + Path selected - + Number of files scanned - + Scan duration - - + + Errors @@ -3093,32 +2947,32 @@ To toggle what kind of errors are shown, open view menu. - - + + Warnings - - + + Style warnings - - + + Portability warnings - - + + Performance warnings - - + + Information messages @@ -3151,9 +3005,8 @@ The user interface language has been reset to English. Open the Preferences-dial - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_sv.ts b/gui/cppcheck_sv.ts index f37121c2f2f..43d6886afc0 100644 --- a/gui/cppcheck_sv.ts +++ b/gui/cppcheck_sv.ts @@ -106,9 +106,8 @@ Parametrar: -l(line) (file) Välj program - Cppcheck - Cppcheck + Cppcheck @@ -116,70 +115,6 @@ Parametrar: -l(line) (file) Du måste ange namn, sökväg samt eventuellt parametrar för applikationen! - - ComplianceReportDialog - - - Compliance Report - - - - - Project name - - - - - Project version - - - - - Coding Standard - - - - - Misra C - - - - - Cert C - - - - - Cert C++ - - - - - List of files with md5 checksums - - - - - Compliance report - - - - - HTML files (*.html) - - - - - - Save compliance report - - - - - Failed to import '%1' (%2), can not show files in compliance report - - - FileViewDialog @@ -190,10 +125,8 @@ Parametrar: -l(line) (file) Kunde inte hitta filen: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -219,14 +152,13 @@ Parametrar: -l(line) (file) - + Helpfile '%1' was not found - Cppcheck - Cppcheck + Cppcheck @@ -346,11 +278,8 @@ Parametrar: -l(line) (file) Öppna Library fil - - - Cppcheck - Cppcheck + Cppcheck @@ -494,31 +423,16 @@ Exempel: MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck - + A&nalyze Analysera - + Standard Standard @@ -528,149 +442,149 @@ Exempel: &Arkiv - + &View &Visa - + &Toolbars 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 @@ -681,92 +595,92 @@ Exempel: 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 @@ -781,327 +695,302 @@ Exempel: Dölj - - + + 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: @@ -1182,35 +1071,35 @@ 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. @@ -1219,7 +1108,7 @@ 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! @@ -1245,17 +1134,11 @@ En trolig orsak är att inställningarna ändrats för olika Cppcheck versioner. Unknown element Element hanteras ej - - - Unknown element - Unknown issue - Något problem - - + Error Fel @@ -1264,70 +1147,64 @@ 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 - + Visual Studio - + Select files to analyze Välj filer att analysera - + Select directory to analyze Välj mapp att analysera @@ -1346,7 +1223,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. @@ -1354,7 +1231,7 @@ Do you want to proceed? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1363,109 +1240,104 @@ 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 @@ -1474,22 +1346,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 @@ -1506,12 +1378,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 @@ -1605,29 +1477,24 @@ Options: Native - Unix 32-bit - Unix 32-bit + Unix 32-bit - Unix 64-bit - Unix 64-bit + Unix 64-bit - Windows 32-bit ANSI - Windows 32-bit ANSI + Windows 32-bit ANSI - Windows 32-bit Unicode - Windows 32-bit Unicode + Windows 32-bit Unicode - Windows 64-bit - Windows 64-bit + Windows 64-bit @@ -1655,12 +1522,12 @@ Options: Defines separeras med semicolon ';' - + Note: Put your own custom .cfg files in the same folder as the project file. You should see them above. Obs: Lägg dina egna .cfg filer i samma folder som projekt filen. De skall isåfall visas ovan. - + ... ... @@ -1671,8 +1538,7 @@ Options: - - + Browse... @@ -1700,15 +1566,15 @@ Options: - + Edit Redigera - - + + Remove Ta bort @@ -1728,143 +1594,153 @@ Options: Include sökvägar: - + + Include file + + + + + <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.. + + + + This is a workfolder that Cppcheck will use for various purposes. - + Clang (experimental) - + Check level - + Reduced -- meant for usage where developer wants results directly. Limited and faster analysis with fewer results. - + Normal -- meant for normal analysis in CI. Analysis should finish in reasonable time. - + Exhaustive -- meant for nightly builds etc. Analysis time can be longer (10x slower than compilation is OK). - + If you want to design your classes to be as flexible and robust as possible then the public interface must be very robust. Cppcheck will asumme that arguments can take *any* value. - + Check code in headers (should be ON normally. if you want a limited quick analysis then turn this OFF) - + Max recursion in template instantiation - - Premium License - - - - + Filepaths in warnings will be relative to this path - + If tags are added, you will be able to right click on warnings and set one of these tags. You can manually categorize warnings. - + Exclude source files - + Exclude folder... - + Exclude file... - + Enable inline suppressions Använd inline suppressions - + Misra C - + 2012 - - + + 2023 - + 2025 - + MISRA rule texts - + <html><head/><body><p>Copy/paste the text from Appendix A &quot;Summary of guidelines&quot; from the MISRA C 2012 pdf to a text file.</p></body></html> - + Misra C++ - + 2008 - + Cert C++ - + Safety profiles (defined in C++ core guidelines) - + Bug hunting (Premium) - + External tools @@ -1879,142 +1755,140 @@ Options: Ned - + Platform - - + + Analysis - + Parser - + Cppcheck (built in) - + Check that each class has a safe public interface - + Limit analysis - + Check code in unused templates (should be ON normally, however in theory you can safely ignore warnings in unused templates) Check code in unused templates (slower and less accurate analysis) - + Max CTU depth - + Warning options - + Root path: Bas sökväg: - + Warning tags (separated by semicolon) Varnings taggar (separerade med semikolon) - + Cppcheck build dir (whole program analysis, incremental analysis, statistics, etc) Cppcheck build dir (whole program analys, incremental analys, statistik, etc) - + Types and Functions - + Libraries Libraries - + Suppressions Suppressions - + Add Lägg till - - + + Addons Addons - + Note: Addons require <a href="https://www.python.org/">Python</a> being installed. - + Y2038 Y2038 - + Thread safety Tråd säkerhet - + Coding standards Kodstandarder - + Cert C - + CERT-INT35-C: int precision (if size equals precision, you can leave empty) - + Autosar - + Bug hunting - Clang analyzer - Clang analyzer + Clang analyzer - Clang-tidy - Clang-tidy + Clang-tidy @@ -2025,82 +1899,87 @@ 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 - + + C/C++ header + + + + + Include file + + + + 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 + Visual Studio - + Compile database - - Borland C++ Builder 6 - - - - + Import Project Importera Projekt - + Select directory to ignore Välj sökväg att ignorera @@ -2135,7 +2014,7 @@ Options: - + (Not found) @@ -2335,11 +2214,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2470,10 +2344,8 @@ Options: Ingen tag - - Cppcheck - Cppcheck + Cppcheck @@ -2559,102 +2431,100 @@ Kontrollera att sökvägen och parametrarna är korrekta. ResultsView - + Print Report Skriv ut rapport - + No errors found, nothing to print. Inga fel hittades, inget att skriva ut. - + %p% (%1 of %2 files checked) %p% (%1 av %2 filer analyserade) - - Cppcheck - Cppcheck + Cppcheck - + No errors found. Inga fel hittades. - + Errors were found, but they are configured to be hidden. To toggle what kind of errors are shown, open view menu. Fel hittades, men de visas ej. För att ställa in vilka fel som skall visas använd visa menyn. - - + + Failed to read the report. Misslyckades att läsa rapporten. - + XML format version 1 is no longer supported. XML format version 1 stöds ej längre. - + First included by Först inkluderad av - + Id Id - + Clear Log - + Copy this Log entry - + Copy complete Log - + Analysis was stopped - + There was a critical error with id '%1' - + when checking %1 - + when checking a file - + Analysis was aborted. - - + + Failed to save the report. Misslyckades med att spara rapporten. @@ -2960,14 +2830,14 @@ För att ställa in vilka fel som skall visas använd visa menyn. - - + + Statistics Statistik - + Project Projekt @@ -2998,7 +2868,7 @@ För att ställa in vilka fel som skall visas använd visa menyn. - + Previous Scan Föregående analys @@ -3078,103 +2948,103 @@ För att ställa in vilka fel som skall visas använd visa menyn. Pdf Export - + 1 day 1 dag - + %1 days %1 dagar - + 1 hour 1 timme - + %1 hours %1 timmar - + 1 minute 1 minut - + %1 minutes %1 minuter - + 1 second 1 sekund - + %1 seconds %1 sekunder - + 0.%1 seconds 0.%1 sekunder - + and och - + Export PDF Exportera PDF - + Project Settings Projekt inställningar - + Paths Sökvägar - + Include paths Include sökvägar - + Defines Definitioner - + Undefines - + Path selected Vald sökväg - + Number of files scanned Antal analyserade filer - + Scan duration Tid - - + + Errors Fel @@ -3189,32 +3059,32 @@ För att ställa in vilka fel som skall visas använd visa menyn. Ingen Cppcheck build dir - - + + Warnings Varningar - - + + Style warnings Stil varningar - - + + Portability warnings Portabilitetsvarningar - - + + Performance warnings Prestanda varningar - - + + Information messages Informationsmeddelanden @@ -3251,9 +3121,8 @@ The user interface language has been reset to English. Open the Preferences-dial Språket har nollställts till Engelska. Öppna Preferences och välj något av de tillgängliga språken. - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_zh_CN.ts b/gui/cppcheck_zh_CN.ts index 02477e72e81..5ecaa17a91b 100644 --- a/gui/cppcheck_zh_CN.ts +++ b/gui/cppcheck_zh_CN.ts @@ -105,9 +105,8 @@ Parameters: -l(line) (file) 选择查看应用程序 - Cppcheck - Cppcheck + Cppcheck @@ -115,70 +114,6 @@ Parameters: -l(line) (file) 你必须为应用程序指定名称、路径以及可选参数! - - ComplianceReportDialog - - - Compliance Report - - - - - Project name - - - - - Project version - - - - - Coding Standard - - - - - Misra C - - - - - Cert C - - - - - Cert C++ - - - - - List of files with md5 checksums - - - - - Compliance report - - - - - HTML files (*.html) - - - - - - Save compliance report - - - - - Failed to import '%1' (%2), can not show files in compliance report - - - FileViewDialog @@ -187,10 +122,8 @@ Parameters: -l(line) (file) 无法找到文件: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -216,14 +149,13 @@ Parameters: -l(line) (file) 索引 - + Helpfile '%1' was not found 帮助文件 '%1' 未找到 - Cppcheck - Cppcheck + Cppcheck @@ -343,11 +275,8 @@ Parameters: -l(line) (file) 打开库文件 - - - Cppcheck - Cppcheck + Cppcheck @@ -495,23 +424,8 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck @@ -519,152 +433,152 @@ Parameters: -l(line) (file) 文件(&F) - + &View 查看(&V) - + &Toolbars 工具栏(&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 显示错误 @@ -675,125 +589,125 @@ Parameters: -l(line) (file) 信息 - + 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) @@ -808,299 +722,274 @@ 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. @@ -1109,13 +998,13 @@ 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: 快速滤器: @@ -1180,12 +1069,6 @@ Do you want to load this project file instead? Unknown element 位置元素 - - - Unknown element - Unknown issue - 未知问题 - Failed to load the selected library '%1'. @@ -1197,7 +1080,7 @@ Do you want to load this project file instead? - + Error 错误 @@ -1206,133 +1089,126 @@ 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 + Visual Studio - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 - + Select files to analyze 选择要分析的文件 - + Select directory to analyze 选择要分析的目录 @@ -1381,14 +1257,14 @@ Analysis is aborted. - + %1 Analysis is aborted. - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1399,7 +1275,7 @@ Do you want to proceed? 你想继续吗? - + Analyzer is running. Do you want to stop the analysis and exit Cppcheck? @@ -1408,77 +1284,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 @@ -1487,22 +1363,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 @@ -1606,31 +1482,6 @@ Options: Native 本地 - - - Unix 32-bit - - - - - Unix 64-bit - - - - - Windows 32-bit ANSI - - - - - Windows 32-bit Unicode - - - - - Windows 64-bit - - ProjectFile @@ -1657,27 +1508,27 @@ Options: 定义必须用分号分隔。例如:DEF1;DEF2=5;DEF3=int - + Note: Put your own custom .cfg files in the same folder as the project file. You should see them above. 注意:把你自己的 .cfg 文件放在和项目文件相同的文件夹中。你应该在上面看到它们。 - + If tags are added, you will be able to right click on warnings and set one of these tags. You can manually categorize warnings. 如果添加了标记,您将能够右键单击警告并设置其中一个标记。您可以手动对警告进行分类。 - + Exclude source files 排除源文件 - + Exclude folder... 排除文件夹... - + Exclude file... 排除文件... @@ -1686,17 +1537,17 @@ Options: MISRA C 2012 - + MISRA rule texts MISRA 规则文本 - + <html><head/><body><p>Copy/paste the text from Appendix A &quot;Summary of guidelines&quot; from the MISRA C 2012 pdf to a text file.</p></body></html> <html><head/><body><p>从 MISRA C 2012 PDF 的附录 A &quot;指南摘要&quot; 复制/粘贴文本到一个文本文件。</p></body></html> - + ... ... @@ -1707,8 +1558,7 @@ Options: - - + Browse... 浏览... @@ -1736,15 +1586,15 @@ Options: - + Edit 编辑 - - + + Remove 移除 @@ -1764,124 +1614,134 @@ Options: 包含目录: - + + Include file + + + + + <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.. + + + + Types and Functions 类型和函数 - - + + Analysis 分析 - + This is a workfolder that Cppcheck will use for various purposes. 这是一个 Cppcheck 将用于各种目的的工作文件夹。 - + Parser 解析器 - + Cppcheck (built in) Cppcheck (内建) - + Check level - + Reduced -- meant for usage where developer wants results directly. Limited and faster analysis with fewer results. - + Normal -- meant for normal analysis in CI. Analysis should finish in reasonable time. - + Exhaustive -- meant for nightly builds etc. Analysis time can be longer (10x slower than compilation is OK). - + Check that each class has a safe public interface 检查每个类是否有一个安全的公共接口 - + Limit analysis 极限分析 - + Check code in unused templates (should be ON normally, however in theory you can safely ignore warnings in unused templates) Check code in unused templates (slower and less accurate analysis) 检查未使用模板中的代码(正常情况下应该是打开,但理论上可以忽略未使用模板中的警告) - + Max CTU depth 最大 CTU 深度 - - Premium License - - - - + Enable inline suppressions 启用内联方案 - + 2025 - + Misra C++ - + 2008 - + Cert C - + CERT-INT35-C: int precision (if size equals precision, you can leave empty) - + Autosar - + Safety profiles (defined in C++ core guidelines) - + Bug hunting - + External tools 外部工具 @@ -1896,131 +1756,129 @@ Options: 向下 - + Platform 平台 - + Clang (experimental) Clang (实验性的) - + If you want to design your classes to be as flexible and robust as possible then the public interface must be very robust. Cppcheck will asumme that arguments can take *any* value. 如果你想要设计你的类尽可能的灵活和健壮,那么公共接口必须非常健壮。Cppcheck 将假设参数可以取 *任何* 值。 - + Check code in headers (should be ON normally. if you want a limited quick analysis then turn this OFF) 检查头文件中的代码(通常应该是打开的。如果您想要一个有限的快速分析,那么关掉它)) - + Max recursion in template instantiation 模板实例化中的最大递归 - + Warning options 警告选项 - + Root path: 根路径: - + Filepaths in warnings will be relative to this path 警告中的文件路径将相对于此路径 - + Warning tags (separated by semicolon) 警告标志(用分号隔开) - + Cppcheck build dir (whole program analysis, incremental analysis, statistics, etc) Cppcheck 构建目录 (整个程序分析、增量分析、统计数据等) - + Libraries - + Suppressions 抑制 - + Add 添加 - - + + Addons 插件 - + Note: Addons require <a href="https://www.python.org/">Python</a> being installed. 注意:插件需要安装 <a href="https://www.python.org/">Python</a>。 - + Y2038 Y2038 - + Thread safety 线程安全 - + Coding standards 编码标准 - + Misra C - + 2012 - - + + 2023 - + Cert C++ - + Bug hunting (Premium) - Clang analyzer - Clang analyzer + Clang analyzer - Clang-tidy - Clang-tidy + Clang-tidy @@ -2031,82 +1889,91 @@ 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 + Visual Studio - + Compile database Compile database - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 - + Import Project 导入项目 - + + C/C++ header + + + + + Include file + + + + Select directory to ignore 选择忽略的目录 - + Source files 源文件 - + + All files 全部文件 - + Exclude file 排除文件 - + Select MISRA rule texts file 选择 MISRA 规则文本文件 - + MISRA rule texts file (%1) MISRA 规则文本文件 (%1) @@ -2139,7 +2006,7 @@ Options: 第%1行:在 "%3" 中缺失的必选属性 "%2" - + (Not found) (未找到) @@ -2339,11 +2206,6 @@ Options: Tags - - - CWE - - QPlatformTheme @@ -2474,10 +2336,8 @@ Options: 取消标记 - - Cppcheck - Cppcheck + Cppcheck @@ -2583,62 +2443,60 @@ Please check the application path and parameters are correct. 警告详情 - - + + Failed to save the report. 保存报告失败。 - + Print Report 打印报告 - + No errors found, nothing to print. 没有错误发现,没有可打印内容。 - + %p% (%1 of %2 files checked) %p% (%2 个文件已检查 %1 个) - - Cppcheck - Cppcheck + Cppcheck - + No errors found. 未发现错误。 - + Errors were found, but they are configured to be hidden. To toggle what kind of errors are shown, open view menu. 发现错误,但它们被设为隐藏。 打开“查看”菜单,切换需要显示的错误。 - - + + Failed to read the report. 读取报告失败。 - + XML format version 1 is no longer supported. 不再支持 XML 格式版本 1。 - + First included by 首次包含于 - + Id Id @@ -2647,42 +2505,42 @@ To toggle what kind of errors are shown, open view menu. 错误搜寻分析未完成 - + Clear Log 清空日志 - + Copy this Log entry 复制此日志条目 - + Copy complete Log 复制完整日志 - + Analysis was stopped - + There was a critical error with id '%1' - + when checking %1 - + when checking a file - + Analysis was aborted. @@ -2968,14 +2826,14 @@ To toggle what kind of errors are shown, open view menu. - - + + Statistics 统计 - + Project 项目 @@ -3006,7 +2864,7 @@ To toggle what kind of errors are shown, open view menu. - + Previous Scan 上一次扫描 @@ -3086,103 +2944,103 @@ To toggle what kind of errors are shown, open view menu. 导出 PDF - + 1 day 1 天 - + %1 days %1 天 - + 1 hour 1 小时 - + %1 hours %1 小时 - + 1 minute 1 分钟 - + %1 minutes %1 分钟 - + 1 second 1 秒 - + %1 seconds %1 秒 - + 0.%1 seconds 0.%1 秒 - + and - + Export PDF 导出 PDF - + Project Settings 项目设置 - + Paths 路径 - + Include paths 包含路径 - + Defines 定义 - + Undefines 未定义 - + Path selected 选中的路径 - + Number of files scanned 扫描的文件数 - + Scan duration 扫描时间 - - + + Errors 错误 @@ -3197,32 +3055,32 @@ To toggle what kind of errors are shown, open view menu. 没有 cppcheck 构建目录 - - + + Warnings 警告 - - + + Style warnings 风格警告 - - + + Portability warnings 移植可能性警告 - - + + Performance warnings 性能警告 - - + + Information messages 信息 @@ -3259,9 +3117,8 @@ The user interface language has been reset to English. Open the Preferences-dial 用户界面语言已被重置为英语。打开“首选项”对话框,选择任何可用的语言。 - Cppcheck - Cppcheck + Cppcheck diff --git a/gui/cppcheck_zh_TW.ts b/gui/cppcheck_zh_TW.ts index 644e92e7b49..3c25925c207 100644 --- a/gui/cppcheck_zh_TW.ts +++ b/gui/cppcheck_zh_TW.ts @@ -95,9 +95,8 @@ Parameters: -l(line) (file) 選取檢視器應用程式 - Cppcheck - Cppcheck + Cppcheck @@ -108,65 +107,16 @@ Parameters: -l(line) (file) ComplianceReportDialog - - Compliance Report - - - - Project name - 專案名稱 + 專案名稱 - Project version - 專案版本 + 專案版本 - - Coding Standard - - - - - Misra C - - - - - Cert C - - - - - Cert C++ - - - - - List of files with md5 checksums - - - - - Compliance report - - - - HTML files (*.html) - HTML 檔案 (*.html) - - - - - Save compliance report - - - - - Failed to import '%1' (%2), can not show files in compliance report - + HTML 檔案 (*.html) @@ -177,10 +127,8 @@ Parameters: -l(line) (file) 無法找到檔案: %1 - - Cppcheck - Cppcheck + Cppcheck @@ -206,14 +154,13 @@ Parameters: -l(line) (file) 索引 - + Helpfile '%1' was not found 找不到幫助檔 '%1' - Cppcheck - Cppcheck + Cppcheck @@ -333,11 +280,8 @@ Parameters: -l(line) (file) 開啟程式庫檔案 - - - Cppcheck - Cppcheck + Cppcheck @@ -473,23 +417,8 @@ Parameters: -l(line) (file) MainWindow - - - - - - - - - - - - - - - Cppcheck - Cppcheck + Cppcheck @@ -507,563 +436,546 @@ Parameters: -l(line) (file) 檔案(&F) - + &View 檢視(&V) - + &Toolbars 工具條(&T) - - + + 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 + Misra C++ 2008 - - Cert C - - - - - Cert C++ - - - - Misra C++ 2023 - Misra C++ 2023 + Misra C++ 2023 - + Autosar - + EULA... - + Thread Details - + Show thread details @@ -1091,63 +1003,61 @@ 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 + Visual Studio - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 - + Select files to analyze 選取要分析的檔案 - + Select directory to analyze 選取要分析的目錄 @@ -1232,12 +1142,6 @@ Do you want to proceed analysis without using any of these project files?Unknown element 未知的元素 - - - Unknown element - Unknown issue - 未知的議題 - Failed to load the selected library '%1'. @@ -1259,7 +1163,7 @@ Do you want to proceed analysis without using any of these project files? - + Error 錯誤 @@ -1279,14 +1183,14 @@ Analysis is aborted. - + %1 Analysis is aborted. - + Current results will be cleared. Opening a new XML file will clear current results. @@ -1294,18 +1198,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? @@ -1314,82 +1218,77 @@ 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. @@ -1398,62 +1297,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 @@ -1462,22 +1361,22 @@ Analysis is stopped. 無法匯入 '%1',停止分析 - + Project files (*.cppcheck) 專案檔 (*.cppcheck) - + Select Project Filename 選取專案檔案名稱 - + No project file loaded - + The project file %1 @@ -1494,12 +1393,12 @@ Do you want to remove the file from the recently used projects -list? 您要從最近使用的專案列表中移除該檔案嗎? - + Install 安章 - + New version available: %1. %2 可用的新版本: %1. %2 @@ -1545,29 +1444,24 @@ Do you want to remove the file from the recently used projects -list? 原生 - Unix 32-bit - Unix 32 位元 + Unix 32 位元 - Unix 64-bit - Unix 64 位元 + Unix 64 位元 - Windows 32-bit ANSI - Windows 32 位元 ANSI + Windows 32 位元 ANSI - Windows 32-bit Unicode - Windows 32 位元 Unicode + Windows 32 位元 Unicode - Windows 64-bit - Windows 64 位元 + Windows 64 位元 @@ -1589,8 +1483,7 @@ Do you want to remove the file from the recently used projects -list? - - + Browse... 瀏覽... @@ -1623,15 +1516,15 @@ Do you want to remove the file from the recently used projects -list? - + Edit 編輯 - - + + Remove 移除 @@ -1671,225 +1564,235 @@ Do you want to remove the file from the recently used projects -list? - + + Include file + + + + + <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.. + + + + Types and Functions 型別與函式 - + Platform 平臺 - + Libraries 程式庫 - + Note: Put your own custom .cfg files in the same folder as the project file. You should see them above. - - + + Analysis 分析 - + Cppcheck build dir (whole program analysis, incremental analysis, statistics, etc) - + This is a workfolder that Cppcheck will use for various purposes. - + Parser 剖析器 - + Cppcheck (built in) Cppcheck (內建) - + Clang (experimental) - + Check level - + Reduced -- meant for usage where developer wants results directly. Limited and faster analysis with fewer results. - + Normal -- meant for normal analysis in CI. Analysis should finish in reasonable time. - + Exhaustive -- meant for nightly builds etc. Analysis time can be longer (10x slower than compilation is OK). - + If you want to design your classes to be as flexible and robust as possible then the public interface must be very robust. Cppcheck will asumme that arguments can take *any* value. - + Check that each class has a safe public interface - + Limit analysis - + Check code in headers (should be ON normally. if you want a limited quick analysis then turn this OFF) - + Check code in unused templates (should be ON normally, however in theory you can safely ignore warnings in unused templates) - + Max CTU depth - + Max recursion in template instantiation - - Premium License - - - - + Warning options 警告選項 - + Root path: 根路徑: - + Filepaths in warnings will be relative to this path - + Warning tags (separated by semicolon) 警告標記 (由分號分隔) - + If tags are added, you will be able to right click on warnings and set one of these tags. You can manually categorize warnings. - + Exclude source files 排除來源檔 - + Exclude folder... 排除資料夾... - + Exclude file... 排除檔案... - + Suppressions 抑制 - + Add 新增 - + Enable inline suppressions - - + + Addons - + Note: Addons require <a href="https://www.python.org/">Python</a> being installed. - + Y2038 Y2038 - + Thread safety 執行緒安全 - + Coding standards - + Misra C - + 2012 - - + + 2023 - + 2025 - + Misra C++ - + 2008 @@ -1898,17 +1801,17 @@ Do you want to remove the file from the recently used projects -list? Misra C 2012 - + MISRA rule texts - + <html><head/><body><p>Copy/paste the text from Appendix A &quot;Summary of guidelines&quot; from the MISRA C 2012 pdf to a text file.</p></body></html> - + ... ... @@ -1917,135 +1820,142 @@ Do you want to remove the file from the recently used projects -list? Misra C++ 2008 - + Cert C - + CERT-INT35-C: int precision (if size equals precision, you can leave empty) - + Cert C++ - + Autosar - + Safety profiles (defined in C++ core guidelines) - + Bug hunting (Premium) - + Bug hunting - + External tools 外部工具 - Clang-tidy - Clang-tidy + Clang-tidy - Clang analyzer - Clang 分析器 + Clang 分析器 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 + Visual Studio - + Compile database 編譯資料庫 - Borland C++ Builder 6 - Borland C++ Builder 6 + Borland C++ Builder 6 - + Import Project 匯入專案 - + + C/C++ header + + + + + Include file + + + + 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) @@ -2198,7 +2108,7 @@ Do you want to remove the file from the recently used projects -list? - + (Not found) (找不到) @@ -2277,11 +2187,6 @@ Do you want to remove the file from the recently used projects -list? Tags - - - CWE - - QPlatformTheme @@ -2402,10 +2307,8 @@ Do you want to remove the file from the recently used projects -list? 取消標記 - - Cppcheck - Cppcheck + Cppcheck @@ -2498,101 +2401,99 @@ Please check the application path and parameters are correct. 警告詳細資訊 - - + + Failed to save the report. 無法載入報告。 - + Print Report 列印報告 - + No errors found, nothing to print. - + %p% (%1 of %2 files checked) - - Cppcheck - Cppcheck + Cppcheck - + No errors found. 找不到錯誤。 - + Errors were found, but they are configured to be hidden. To toggle what kind of errors are shown, open view menu. - - + + Failed to read the report. 無法讀取報告。 - + XML format version 1 is no longer supported. 不再支援 XML 格式版本 1。 - + First included by - + Id 識別號 - + Clear Log 清除日誌 - + Copy this Log entry 複製該日誌條目 - + Copy complete Log 複製完整的日誌 - + Analysis was stopped - + There was a critical error with id '%1' - + when checking %1 - + when checking a file - + Analysis was aborted. @@ -2869,14 +2770,14 @@ To toggle what kind of errors are shown, open view menu. - - + + Statistics 統計資料 - + Project 專案 @@ -2907,7 +2808,7 @@ To toggle what kind of errors are shown, open view menu. - + Previous Scan 上一次掃描 @@ -2997,133 +2898,133 @@ To toggle what kind of errors are shown, open view menu. 沒有 cppcheck 建置目錄 - + 1 day 1 天 - + %1 days %1 天 - + 1 hour 1 小時 - + %1 hours %1 小時 - + 1 minute 1 分鐘 - + %1 minutes %1 分鐘 - + 1 second 1 秒鐘 - + %1 seconds %1 秒鐘 - + 0.%1 seconds 0.%1 秒鐘 - + and - - + + Errors 錯誤 - - + + Warnings 警告 - - + + Style warnings 樣式警告 - - + + Portability warnings 可移植性警告 - - + + Performance warnings 效能警告 - - + + Information messages 資訊訊息 - + Export PDF 匯出 PDF - + Project Settings 專案設定 - + Paths 路徑 - + Include paths 包含路徑 - + Defines 定義 - + Undefines 未定義 - + Path selected 選取的路徑 - + Number of files scanned 已掃描的檔案數量 - + Scan duration 掃描時間 @@ -3155,11 +3056,6 @@ To toggle what kind of errors are shown, open view menu. The user interface language has been reset to English. Open the Preferences-dialog to select any of the available languages. - - - Cppcheck - - TxtReport diff --git a/gui/cppchecklibrarydata.h b/gui/cppchecklibrarydata.h index ddccf3b6534..71d8382ef34 100644 --- a/gui/cppchecklibrarydata.h +++ b/gui/cppchecklibrarydata.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/fileviewdialog.cpp b/gui/fileviewdialog.cpp index 3f66f008678..9d453519450 100644 --- a/gui/fileviewdialog.cpp +++ b/gui/fileviewdialog.cpp @@ -54,7 +54,7 @@ void FileViewDialog::loadTextFile(const QString &filename, QTextEdit *edit) msg = msg.arg(filename); QMessageBox msgbox(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", msg, QMessageBox::Ok, this); @@ -68,7 +68,7 @@ void FileViewDialog::loadTextFile(const QString &filename, QTextEdit *edit) msg = msg.arg(filename); QMessageBox msgbox(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", msg, QMessageBox::Ok, this); diff --git a/gui/helpdialog.cpp b/gui/helpdialog.cpp index 0768318531c..bef304c5471 100644 --- a/gui/helpdialog.cpp +++ b/gui/helpdialog.cpp @@ -1,6 +1,6 @@ /* * 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 @@ -84,7 +84,7 @@ HelpDialog::HelpDialog(QWidget *parent) : if (helpFile.isEmpty()) { const QString msg = tr("Helpfile '%1' was not found").arg("online-help.qhc"); QMessageBox msgBox(QMessageBox::Warning, - tr("Cppcheck"), + "Cppcheck", msg, QMessageBox::Ok, this); diff --git a/gui/librarydialog.cpp b/gui/librarydialog.cpp index 3199af9a975..147363a3a25 100644 --- a/gui/librarydialog.cpp +++ b/gui/librarydialog.cpp @@ -107,7 +107,7 @@ void LibraryDialog::openCfg() QFile file(selectedFile); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox msg(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", tr("Cannot open file %1.").arg(selectedFile), QMessageBox::Ok, this); @@ -119,7 +119,7 @@ void LibraryDialog::openCfg() const QString errmsg = tempdata.open(file); if (!errmsg.isNull()) { QMessageBox msg(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", tr("Failed to load %1. %2.").arg(selectedFile).arg(errmsg), QMessageBox::Ok, this); @@ -156,7 +156,7 @@ void LibraryDialog::saveCfg() mUi->buttonSave->setEnabled(false); } else { QMessageBox msg(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", tr("Cannot save file %1.").arg(mFileName), QMessageBox::Ok, this); diff --git a/gui/librarydialog.h b/gui/librarydialog.h index 6737da638c8..c8e522b10d4 100644 --- a/gui/librarydialog.h +++ b/gui/librarydialog.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/main.cpp b/gui/main.cpp index efdb2a33c72..c855b2529f6 100644 --- a/gui/main.cpp +++ b/gui/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/gui/mainwindow.cpp b/gui/mainwindow.cpp index ce1b3ef1508..31f124bc5b0 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -23,7 +23,6 @@ #include "aboutdialog.h" #include "analyzerinfo.h" #include "checkers.h" -#include "checkstatistics.h" #include "checkthread.h" #include "common.h" #include "cppcheck.h" @@ -60,7 +59,6 @@ #include #include -#include #include #include #include @@ -101,7 +99,6 @@ #include #include #include -#include #include #include #include @@ -459,7 +456,7 @@ void MainWindow::loadSettings() "Please check (and fix) the editor application settings, otherwise the editor " "program might not start correctly."); QMessageBox msgBox(QMessageBox::Warning, - tr("Cppcheck"), + "Cppcheck", msg, QMessageBox::Ok, this); @@ -562,13 +559,20 @@ void MainWindow::saveSettings() const mUI->mResults->saveSettings(mSettings); } -void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLib, const bool checkConfig) +void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLib, const bool checkConfig, const QStringList& recheckFiles) { Settings checkSettings; auto supprs = std::make_shared(); if (!getCppcheckSettings(checkSettings, *supprs)) return; + // filter requested files + if (!recheckFiles.isEmpty()) { + p.fileSettings.remove_if([&](const FileSettings& fs) { + return !recheckFiles.contains(QString::fromStdString(fs.filename())); + }); + } + clearResults(); mIsLogfileLoaded = false; @@ -662,7 +666,7 @@ void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLib, c if (fileNames.isEmpty()) { QMessageBox msg(QMessageBox::Warning, - tr("Cppcheck"), + "Cppcheck", tr("No suitable files found to analyze!"), QMessageBox::Ok, this); @@ -747,7 +751,7 @@ QStringList MainWindow::selectFilesToAnalyze(QFileDialog::FileMode mode) { if (mProjectFile) { QMessageBox msgBox(this); - msgBox.setWindowTitle(tr("Cppcheck")); + msgBox.setWindowTitle("Cppcheck"); const QString msg(tr("You must close the project file before selecting new files or directories!")); msgBox.setText(msg); msgBox.setIcon(QMessageBox::Critical); @@ -764,8 +768,8 @@ 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 *.slnx *.vcxproj"; - filters[tr("Borland C++ Builder 6")] = "*.bpr"; + filters["Visual Studio"] = "*.sln *.slnx *.vcxproj"; + filters["Borland C++ Builder 6"] = "*.bpr"; QString lastFilter = mSettings->value(SETTINGS_LAST_ANALYZE_FILES_FILTER).toString(); selected = QFileDialog::getOpenFileNames(this, tr("Select files to analyze"), @@ -853,7 +857,7 @@ void MainWindow::analyzeDirectory() if (projFiles.size() == 1) { // If one project file found, suggest loading it QMessageBox msgBox(this); - msgBox.setWindowTitle(tr("Cppcheck")); + msgBox.setWindowTitle("Cppcheck"); const QString msg(tr("Found project file: %1\n\nDo you want to " "load this project file instead?").arg(projFiles[0])); msgBox.setText(msg); @@ -875,7 +879,7 @@ void MainWindow::analyzeDirectory() // If multiple project files found inform that there are project // files also available. QMessageBox msgBox(this); - msgBox.setWindowTitle(tr("Cppcheck")); + msgBox.setWindowTitle("Cppcheck"); const QString msg(tr("Found project files from the directory.\n\n" "Do you want to proceed analysis without " "using any of these project files?")); @@ -1462,7 +1466,7 @@ void MainWindow::openResults() { if (mUI->mResults->hasResults()) { QMessageBox msgBox(this); - msgBox.setWindowTitle(tr("Cppcheck")); + msgBox.setWindowTitle("Cppcheck"); const QString msg(tr("Current results will be cleared.\n\n" "Opening a new XML file will clear current results.\n" "Do you want to proceed?")); @@ -1587,7 +1591,7 @@ void MainWindow::closeEvent(QCloseEvent *event) "Do you want to stop the analysis and exit Cppcheck?")); QMessageBox msg(QMessageBox::Warning, - tr("Cppcheck"), + "Cppcheck", text, QMessageBox::Yes | QMessageBox::No, this); @@ -1882,7 +1886,7 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringLis buildDir = inf.canonicalPath() + '/' + buildDir; if (!QDir(buildDir).exists()) { QMessageBox msg(QMessageBox::Question, - tr("Cppcheck"), + "Cppcheck", tr("Build dir '%1' does not exist, create it?").arg(buildDir), QMessageBox::Yes | QMessageBox::No, this); @@ -1890,7 +1894,7 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringLis QDir().mkpath(buildDir); } else if (!projectFile->getAddons().isEmpty()) { QMessageBox m(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", tr("To check the project using addons, you need a build directory."), QMessageBox::Ok, this); @@ -1945,7 +1949,7 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringLis if (!errorMessage.isEmpty()) { QMessageBox msg(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", tr("Failed to import '%1': %2\n\nAnalysis is stopped.").arg(prjfile).arg(errorMessage), QMessageBox::Ok, this); @@ -1954,14 +1958,14 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringLis } } catch (InternalError &e) { QMessageBox msg(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", tr("Failed to import '%1' (%2), analysis is stopped").arg(prjfile).arg(QString::fromStdString(e.errorMessage)), QMessageBox::Ok, this); msg.exec(); return; } - doAnalyzeProject(p, checkLib, checkConfig); // TODO: avoid copy + doAnalyzeProject(p, checkLib, checkConfig, recheckFiles); // TODO: avoid copy return; } @@ -2026,7 +2030,7 @@ void MainWindow::editProjectFile() { if (!mProjectFile) { QMessageBox msg(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", tr("No project file loaded"), QMessageBox::Ok, this); @@ -2114,7 +2118,7 @@ void MainWindow::openRecentProject() "used projects -list?").arg(project)); QMessageBox msg(QMessageBox::Warning, - tr("Cppcheck"), + "Cppcheck", text, QMessageBox::Yes | QMessageBox::No, this); diff --git a/gui/mainwindow.h b/gui/mainwindow.h index febd3a41d4c..c654a2c94f0 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -309,7 +309,7 @@ private slots: * @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 checkLib = false, bool checkConfig = false); + void doAnalyzeProject(ImportProject p, bool checkLib = false, bool checkConfig = false, const QStringList& recheckFiles = QStringList()); /** * @brief Analyze all files specified in parameter files diff --git a/gui/mainwindow.ui b/gui/mainwindow.ui index 1f66d1a582a..16577224874 100644 --- a/gui/mainwindow.ui +++ b/gui/mainwindow.ui @@ -23,7 +23,7 @@ - Cppcheck + Cppcheck @@ -684,7 +684,7 @@ :/cppcheck-gui.png:/cppcheck-gui.png - Cppcheck + Cppcheck Show Cppcheck results @@ -992,7 +992,7 @@ true - Misra C + Misra C @@ -1000,7 +1000,7 @@ true - Misra C++ 2008 + Misra C++ 2008 @@ -1008,7 +1008,7 @@ true - Cert C + Cert C @@ -1016,7 +1016,7 @@ true - Cert C++ + Cert C++ @@ -1024,7 +1024,7 @@ true - Misra C++ 2023 + Misra C++ 2023 diff --git a/gui/platforms.cpp b/gui/platforms.cpp index 77683a6ea09..27504006477 100644 --- a/gui/platforms.cpp +++ b/gui/platforms.cpp @@ -36,11 +36,11 @@ void Platforms::add(const QString &title, Platform::Type platform) void Platforms::init() { add(tr("Native"), Platform::Type::Native); - add(tr("Unix 32-bit"), Platform::Type::Unix32); - add(tr("Unix 64-bit"), Platform::Type::Unix64); - add(tr("Windows 32-bit ANSI"), Platform::Type::Win32A); - add(tr("Windows 32-bit Unicode"), Platform::Type::Win32W); - add(tr("Windows 64-bit"), Platform::Type::Win64); + add("Unix 32-bit", Platform::Type::Unix32); + add("Unix 64-bit", Platform::Type::Unix64); + add("Windows 32-bit ANSI", Platform::Type::Win32A); + add("Windows 32-bit Unicode", Platform::Type::Win32W); + add("Windows 64-bit", Platform::Type::Win64); } int Platforms::getCount() const diff --git a/gui/projectfile.ui b/gui/projectfile.ui index 84a1d6e40ec..9f7ad91fa8f 100644 --- a/gui/projectfile.ui +++ b/gui/projectfile.ui @@ -1010,14 +1010,14 @@ - Clang-tidy + Clang-Tidy - Clang analyzer + Clang Static Analyzer diff --git a/gui/projectfiledialog.cpp b/gui/projectfiledialog.cpp index 4e75696484b..72e3d651471 100644 --- a/gui/projectfiledialog.cpp +++ b/gui/projectfiledialog.cpp @@ -23,7 +23,6 @@ #include "importproject.h" #include "library.h" #include "newsuppressiondialog.h" -#include "path.h" #include "platform.h" #include "platforms.h" #include "projectfile.h" @@ -625,9 +624,9 @@ void ProjectFileDialog::browseImportProject() const QFileInfo inf(mProjectFile->getFilename()); const QDir &dir = inf.absoluteDir(); QMap filters; - filters[tr("Visual Studio")] = "*.sln *.slnx *.vcxproj"; + filters["Visual Studio"] = "*.sln *.slnx *.vcxproj"; filters[tr("Compile database")] = "compile_commands.json"; - filters[tr("Borland C++ Builder 6")] = "*.bpr"; + filters["Borland C++ Builder 6"] = "*.bpr"; QString fileName = QFileDialog::getOpenFileName(this, tr("Import Project"), dir.canonicalPath(), toFilterString(filters)); diff --git a/gui/projectfiledialog.h b/gui/projectfiledialog.h index af21685b675..a93d12dc2e2 100644 --- a/gui/projectfiledialog.h +++ b/gui/projectfiledialog.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 c553855e99e..ed8b3c7412e 100644 --- a/gui/resultstree.cpp +++ b/gui/resultstree.cpp @@ -122,7 +122,7 @@ static QStringList getLabels() { QObject::tr("Rule"), QObject::tr("Since date"), QObject::tr("Tags"), - QObject::tr("CWE")}; + "CWE"}; } static Severity getSeverity(ReportType reportType, const ErrorItem& errorItem) { @@ -427,8 +427,8 @@ void ResultsTree::clear(const QString &filename) if (stripped == fileItem->text() || filename == fileItem->errorItem->file0) { - mModel->removeRow(i); mErrorList.removeAll(fileItem->errorItem->toString()); + mModel->removeRow(i); break; } } @@ -445,8 +445,8 @@ void ResultsTree::clearRecheckFile(const QString &filename) QString storedfile = fileItem->getErrorPathItem().file; storedfile = ((!mCheckPath.isEmpty() && storedfile.startsWith(mCheckPath)) ? storedfile.mid(mCheckPath.length() + 1) : storedfile); if (actualfile == storedfile) { - mModel->removeRow(i); mErrorList.removeAll(fileItem->errorItem->toString()); + mModel->removeRow(i); break; } } @@ -741,7 +741,7 @@ void ResultsTree::startApplication(const ResultItem *target, int application) //If there are no applications specified, tell the user about it if (mApplications->getApplicationCount() == 0) { QMessageBox msg(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", tr("No editor application configured.\n\n" "Configure the editor application for Cppcheck in preferences/Applications."), QMessageBox::Ok, @@ -755,7 +755,7 @@ void ResultsTree::startApplication(const ResultItem *target, int application) if (application == -1) { QMessageBox msg(QMessageBox::Critical, - tr("Cppcheck"), + "Cppcheck", tr("No default editor application selected.\n\n" "Please select the default editor application in preferences/Applications."), QMessageBox::Ok, diff --git a/gui/resultsview.cpp b/gui/resultsview.cpp index 496c0793157..55f673ab80c 100644 --- a/gui/resultsview.cpp +++ b/gui/resultsview.cpp @@ -345,7 +345,7 @@ void ResultsView::checkingFinished() //Tell user that we found no errors if (!hasResults()) { QMessageBox msg(QMessageBox::Information, - tr("Cppcheck"), + "Cppcheck", tr("No errors found."), QMessageBox::Ok, this); @@ -356,7 +356,7 @@ void ResultsView::checkingFinished() QString text = tr("Errors were found, but they are configured to be hidden.\n" \ "To toggle what kind of errors are shown, open view menu."); QMessageBox msg(QMessageBox::Information, - tr("Cppcheck"), + "Cppcheck", text, QMessageBox::Ok, this); diff --git a/gui/statsdialog.cpp b/gui/statsdialog.cpp index d3e15d87ad5..bf46abcb2d4 100644 --- a/gui/statsdialog.cpp +++ b/gui/statsdialog.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/test/projectfile/testprojectfile.cpp b/gui/test/projectfile/testprojectfile.cpp index dbc4cb51659..efc1dce6c4f 100644 --- a/gui/test/projectfile/testprojectfile.cpp +++ b/gui/test/projectfile/testprojectfile.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2021 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,12 +18,17 @@ #include "testprojectfile.h" +#include "addoninfo.h" #include "library.h" #include "platform.h" #include "projectfile.h" #include "settings.h" #include "suppressions.h" +#ifdef HAVE_RULES +#include "rule.h" +#endif + #include #include #include @@ -38,6 +43,7 @@ const char Settings::SafeChecks::XmlExternalFunctions[] = "external-functions"; const char Settings::SafeChecks::XmlInternalFunctions[] = "internal-functions"; const char Settings::SafeChecks::XmlExternalVariables[] = "external-variables"; Settings::Settings() : maxCtuDepth(10) {} +Settings::~Settings() = default; Platform::Platform() = default; Library::Library() = default; Library::~Library() = default; diff --git a/gui/test/projectfile/testprojectfile.h b/gui/test/projectfile/testprojectfile.h index 18f38d0eb39..ceda2ff6b96 100644 --- a/gui/test/projectfile/testprojectfile.h +++ b/gui/test/projectfile/testprojectfile.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2021 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/test/resultstree/testresultstree.cpp b/gui/test/resultstree/testresultstree.cpp index afda38e0075..921abd69ff0 100644 --- a/gui/test/resultstree/testresultstree.cpp +++ b/gui/test/resultstree/testresultstree.cpp @@ -22,7 +22,6 @@ // headers that declare mocked functions/variables #include "applicationlist.h" -#include "common.h" #include "filesettings.h" #include "projectfile.h" #include "threadhandler.h" diff --git a/gui/translationhandler.cpp b/gui/translationhandler.cpp index d8160525856..14faedc04a2 100644 --- a/gui/translationhandler.cpp +++ b/gui/translationhandler.cpp @@ -133,7 +133,7 @@ bool TranslationHandler::setLanguage(const QString &code) "the Preferences-dialog to select any of the available " "languages.").arg(error)); QMessageBox msgBox(QMessageBox::Warning, - tr("Cppcheck"), + "Cppcheck", msg, QMessageBox::Ok); msgBox.exec(); diff --git a/lib/analyzer.h b/lib/analyzer.h index a4546eb7dc4..9b87310530f 100644 --- a/lib/analyzer.h +++ b/lib/analyzer.h @@ -153,9 +153,13 @@ struct Analyzer { struct Assume { enum Flags : std::uint8_t { None = 0, - Quiet = (1 << 0), - Absolute = (1 << 1), - ContainerEmpty = (1 << 2), + Quiet = (1u << 0), + Absolute = (1u << 1), + ContainerEmpty = (1u << 2), + // The branch this condition guards is not traversed yet (a separate path walks it), so + // the assume must not record the program state at the branch boundaries - they would be + // premature. When unset, the branch has been traversed and control is leaving it. + Pending = (1u << 3), }; }; diff --git a/lib/analyzerinfo.cpp b/lib/analyzerinfo.cpp index 6f919ec3651..36803b897b1 100644 --- a/lib/analyzerinfo.cpp +++ b/lib/analyzerinfo.cpp @@ -126,7 +126,7 @@ std::string AnalyzerInformation::skipAnalysis(const tinyxml2::XMLDocument &analy return ""; } -std::string AnalyzerInformation::getAnalyzerInfoFileFromFilesTxt(std::istream& filesTxt, const std::string &sourcefile, const std::string &cfg, int fsFileId) +std::string AnalyzerInformation::getAnalyzerInfoFileFromFilesTxt(std::istream& filesTxt, const std::string &sourcefile, const std::string &cfg, size_t fsFileId) { std::string line; while (std::getline(filesTxt,line)) { diff --git a/lib/analyzerinfo.h b/lib/analyzerinfo.h index d2a83c747c3..75674a22f82 100644 --- a/lib/analyzerinfo.h +++ b/lib/analyzerinfo.h @@ -87,7 +87,7 @@ class CPPCHECKLIB AnalyzerInformation { protected: 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 fsFileId); + static std::string getAnalyzerInfoFileFromFilesTxt(std::istream& filesTxt, const std::string &sourcefile, const std::string &cfg, size_t fsFileId); static std::string skipAnalysis(const tinyxml2::XMLDocument &analyzerInfoDoc, std::size_t hash, std::list &errors); diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 56a9489d00e..ea54232b551 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -495,8 +495,6 @@ bool isTemporary(const Token* tok, const Library* library, bool unknown) } return unknown; } - if (tok->isCast()) - return false; // Currying a function is unknown in cppcheck if (Token::simpleMatch(tok, "(") && Token::simpleMatch(tok->astOperand1(), "(")) return unknown; @@ -1543,8 +1541,6 @@ bool isUsedAsBool(const Token* const tok, const Settings& settings) return true; if (parent->isCast()) return !Token::simpleMatch(parent->astOperand1(), "dynamic_cast") && isUsedAsBool(parent, settings); - if (parent->isUnaryOp("*")) - return isUsedAsBool(parent, settings); if (Token::Match(parent, "==|!=") && tok->valueType() && tok->valueType()->pointer && tok->astSibling()->hasKnownIntValue() && tok->astSibling()->getKnownIntValue() == 0) return true; @@ -2157,7 +2153,7 @@ bool isWithoutSideEffects(const Token* tok, bool checkArrayAccess, bool checkRef if (tok && tok->varId()) { const Variable* var = tok->variable(); return var && ((!var->isClass() && (checkReference || !var->isReference())) || var->isPointer() || - (checkArrayAccess ? var->isArray() || (var->isStlType() && !var->isStlType(CheckClass::stl_containers_not_const)) : var->isStlType())); + (checkArrayAccess ? var->isArray() || (var->isStlType() && !var->isStlType(CheckClassImpl::stl_containers_not_const)) : var->isStlType())); } return true; } @@ -2230,21 +2226,18 @@ static bool isEscapedOrJump(const Token* tok, bool functionsScope, const Library return Token::Match(tok, "return|goto|throw|continue|break"); } +static bool isNoreturnFunction(const Token* ftok, const Library& library) +{ + if (const Function* function = ftok->function()) + return function->isEscapeFunction() || function->isAttributeNoreturn(); + return library.isnoreturn(ftok); +} + bool isEscapeFunction(const Token* ftok, const Library& library) { if (!Token::Match(ftok, "%name% (")) return false; - const Function* function = ftok->function(); - if (function) { - if (function->isEscapeFunction()) - return true; - if (function->isAttributeNoreturn()) - return true; - } else { - if (library.isnoreturn(ftok)) - return true; - } - return false; + return isNoreturnFunction(ftok, library); } static bool hasNoreturnFunction(const Token* tok, const Library& library, const Token** unknownFunc) @@ -2255,18 +2248,9 @@ static bool hasNoreturnFunction(const Token* tok, const Library& library, const while (Token::simpleMatch(ftok, "(")) ftok = ftok->astOperand1(); if (ftok) { - const Function * function = ftok->function(); - if (function) { - if (function->isEscapeFunction()) - return true; - if (function->isAttributeNoreturn()) - return true; - } else if (library.isnoreturn(ftok)) { - return true; - } else if (Token::Match(ftok, "exit|abort")) { + if (isNoreturnFunction(ftok, library)) return true; - } - if (unknownFunc && !function && library.functions().count(library.getFunctionName(ftok)) == 0) + if (unknownFunc && !ftok->function() && library.functions().count(library.getFunctionName(ftok)) == 0) *unknownFunc = ftok; return false; } @@ -2338,14 +2322,14 @@ bool isWithinScope(const Token* tok, const Variable* var, ScopeType type) return false; } -bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Settings &settings, bool *inconclusive) +bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Library &library, bool *inconclusive) { if (!tok) return false; if (tok->varId() == varid) - return isVariableChangedByFunctionCall(tok, indirect, settings, inconclusive); - return isVariableChangedByFunctionCall(tok->astOperand1(), indirect, varid, settings, inconclusive) || - isVariableChangedByFunctionCall(tok->astOperand2(), indirect, varid, settings, inconclusive); + return isVariableChangedByFunctionCall(tok, indirect, library, inconclusive); + return isVariableChangedByFunctionCall(tok->astOperand1(), indirect, varid, library, inconclusive) || + isVariableChangedByFunctionCall(tok->astOperand2(), indirect, varid, library, inconclusive); } bool isScopeBracket(const Token* tok) @@ -2526,7 +2510,7 @@ bool isMutableExpression(const Token* tok) return true; } -bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Settings &settings, bool *inconclusive) +bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Library &library, bool *inconclusive) { if (!tok) return false; @@ -2566,13 +2550,13 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti if (!tok->function() && !tok->variable() && tok->isName()) { // Check if direction (in, out, inout) is specified in the library configuration and use that - const Library::ArgumentChecks::Direction argDirection = settings.library.getArgDirection(tok, 1 + argnr, indirect); + const Library::ArgumentChecks::Direction argDirection = 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); + const bool requireNonNull = library.isnullargbad(tok, 1 + argnr); if (Token::simpleMatch(tok->tokAt(-2), "std :: tie")) return true; // if the library says 0 is invalid @@ -2592,6 +2576,8 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti if (const Variable* var = tok->variable()) { if (tok == var->nameToken() && (!var->isReference() || (var->isConst() && var->type() == tok1->type())) && (!var->isClass() || (var->valueType() && var->valueType()->container))) // const ref or passed to (copy) ctor return false; + if (var->isArray() && var->valueType() && var->valueType()->pointer == 0 && var->valueType()->isPrimitive()) + return false; } std::vector args = getArgumentVars(tok, argnr); @@ -2798,7 +2784,7 @@ bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, if (indirect == 0 && astIsLHS(tok2) && Token::Match(ptok, ". %var%") && astIsPointer(ptok->next())) pindirect = 1; bool inconclusive = false; - bool isChanged = isVariableChangedByFunctionCall(ptok, pindirect, settings, &inconclusive); + bool isChanged = isVariableChangedByFunctionCall(ptok, pindirect, settings.library, &inconclusive); isChanged |= inconclusive; if (isChanged) return true; @@ -3015,7 +3001,7 @@ bool isVariableChanged(const Variable * var, const Settings &settings, int depth const Token * start = var->declEndToken(); if (!start) return false; - if (Token::Match(start, "; %varid% =", var->declarationId())) + if (start->isSplittedVarDeclEq() && Token::Match(start, "; %varid% =", var->declarationId())) start = start->tokAt(2); if (Token::simpleMatch(start, "=")) { const Token* next = nextAfterAstRightmostLeafGeneric(start); @@ -3423,7 +3409,7 @@ bool isConstVarExpression(const Token *tok, const std::functionastParent() && tok->astParent()->isUnaryOp("&"); @@ -3485,14 +3471,14 @@ static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings } else if (ftok->str() == "{") { return indirect == 0 ? ExprUsage::Used : ExprUsage::Inconclusive; } else { - const bool isnullbad = settings.library.isnullargbad(ftok, argnr + 1); + const bool isnullbad = library.isnullargbad(ftok, argnr + 1); if (indirect == 0 && astIsPointer(tok) && !addressOf && isnullbad) return ExprUsage::Used; bool hasIndirect = false; - const bool isuninitbad = settings.library.isuninitargbad(ftok, argnr + 1, indirect, &hasIndirect); + const bool isuninitbad = 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); + const Library::ArgumentChecks::Direction argDirection = 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) @@ -3562,7 +3548,7 @@ ExprUsage getExprUsage(const Token* tok, int indirect, const Settings& settings) (astIsLHS(tok) || Token::simpleMatch(parent, "( )"))) return ExprUsage::Used; } - return getFunctionUsage(tok, indirect, settings); + return getFunctionUsage(tok, indirect, settings.library); } static void getLHSVariablesRecursive(std::vector& vars, const Token* tok) @@ -3932,3 +3918,23 @@ const Token *skipUnreachableBranch(const Token *tok) return tok; } + +bool isEscapeKeyword(const Token *tok, const Settings &settings) +{ + if (!tok) + return false; + + if (tok->str() == "return") + return true; + + if (!tok->isCpp()) + return false; + + if (tok->str() == "throw") + return true; + + if (settings.standards.cpp < Standards::CPP20) + return false; + + return tok->str() == "co_return"; +} diff --git a/lib/astutils.h b/lib/astutils.h index 617e01f0415..79a607108fd 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -327,20 +327,20 @@ bool isMutableExpression(const Token* tok); * * @param tok ast tree * @param varid Variable Id - * @param settings program settings + * @param library library configurations * @param inconclusive pointer to output variable which indicates that the answer of the question is inconclusive */ -bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Settings &settings, bool *inconclusive); +bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Library &library, bool *inconclusive); /** Is variable changed by function call? * In case the answer of the question is inconclusive, e.g. because the function declaration is not known * the return value is false and the output parameter inconclusive is set to true * - * @param tok token of variable in function call - * @param settings program settings + * @param tok token of variable in function call + * @param library library configurations * @param inconclusive pointer to output variable which indicates that the answer of the question is inconclusive */ -CPPCHECKLIB bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Settings &settings, bool *inconclusive); +CPPCHECKLIB bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Library &library, bool *inconclusive); /** Is variable changed in block of code? */ CPPCHECKLIB bool isVariableChanged(const Token *start, const Token *end, nonneg int exprid, bool globalvar, const Settings &settings, int depth = 20); @@ -463,4 +463,6 @@ bool isUnreachableOperand(const Token *tok); const Token *skipUnreachableBranch(const Token *tok); +bool isEscapeKeyword(const Token *tok, const Settings &settings); + #endif // astutilsH diff --git a/lib/check.cpp b/lib/check.cpp deleted file mode 100644 index 812c8b02fcd..00000000000 --- a/lib/check.cpp +++ /dev/null @@ -1,136 +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 "check.h" - -#include "errorlogger.h" -#include "settings.h" -#include "token.h" -#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); -} - -void Check::writeToErrorList(const ErrorMessage &errmsg) -{ - std::cout << errmsg.toXML() << std::endl; -} - - -void Check::reportError(const std::list &callstack, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe, Certainty certainty) -{ - // TODO: report debug warning when error is for a disabled severity - const ErrorMessage errmsg(callstack, mTokenizer ? &mTokenizer->list : nullptr, severity, id, msg, cwe, certainty); - if (mErrorLogger) - mErrorLogger->reportErr(errmsg); - else - writeToErrorList(errmsg); -} - -void Check::reportError(ErrorPath errorPath, Severity severity, const char id[], const std::string &msg, const CWE &cwe, Certainty certainty) -{ - // TODO: report debug warning when error is for a disabled severity - const ErrorMessage errmsg(std::move(errorPath), mTokenizer ? &mTokenizer->list : nullptr, severity, id, msg, cwe, certainty); - if (mErrorLogger) - mErrorLogger->reportErr(errmsg); - else - writeToErrorList(errmsg); -} - -bool Check::wrongData(const Token *tok, const char *str) -{ - if (mSettings->daca) - reportError(tok, Severity::debug, "DacaWrongData", "Wrong data detected by condition " + std::string(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) - return id + std::string("Cond"); - if (value.safe) - return std::string("safe") + static_cast(std::toupper(id[0])) + (id + 1); - return id; -} - -ErrorPath Check::getErrorPath(const Token* errtok, const ValueFlow::Value* value, std::string bug) const -{ - ErrorPath errorPath; - if (!value) { - errorPath.emplace_back(errtok, std::move(bug)); - } else if (mSettings->verbose || mSettings->outputFormat == Settings::OutputFormat::xml || !mSettings->templateLocation.empty()) { - errorPath = value->errorPath; - errorPath.emplace_back(errtok, std::move(bug)); - } else { - if (value->condition) - errorPath.emplace_back(value->condition, "condition '" + value->condition->expressionString() + "'"); - //else if (!value->isKnown() || value->defaultArg) - // errorPath = value->callstack; - errorPath.emplace_back(errtok, std::move(bug)); - } - return errorPath; -} - -void Check::logChecker(const char 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..00a360d1bf2 100644 --- a/lib/check.h +++ b/lib/check.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 @@ -22,7 +22,6 @@ //--------------------------------------------------------------------------- #include "config.h" -#include "errortypes.h" #include #include @@ -36,14 +35,8 @@ namespace CTU { class FileInfo; } -namespace ValueFlow { - class Value; -} - class Settings; -class Token; class ErrorLogger; -class ErrorMessage; class Tokenizer; /** Use WRONG_DATA in checkers to mark conditions that check that data is correct */ @@ -57,32 +50,22 @@ class Tokenizer; * All checking classes must inherit from this class */ class CPPCHECKLIB Check { -public: - /** This constructor is used when registering the CheckClass */ - explicit Check(const 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)) {} + /** This constructor is used when registering the check */ + explicit Check(std::string aname) + : mName(std::move(aname)) + {} + virtual ~Check() = default; public: - virtual ~Check() { - if (!mTokenizer) - instances().remove(this); - } - 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; + virtual void runChecks(const Tokenizer &, ErrorLogger&) = 0; /** get error messages */ - virtual void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const = 0; + virtual void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const = 0; /** class name, used to generate documentation */ const std::string& name() const { @@ -92,72 +75,30 @@ class CPPCHECKLIB Check { /** get information about this class, used to generate documentation */ virtual std::string classInfo() const = 0; - /** - * Write given error to stdout in xml format. - * This is for for printout out the error list with --errorlist - * @param errmsg Error message to write - */ - static void writeToErrorList(const ErrorMessage &errmsg); - /** Base class used for whole-program analysis */ class CPPCHECKLIB FileInfo { public: - explicit FileInfo(std::string f0 = {}) : file0(std::move(f0)) {} + explicit FileInfo(std::string f0) : file0(std::move(f0)) {} virtual ~FileInfo() = default; - virtual std::string toString() const { - return std::string(); - } + virtual std::string toString() const = 0; std::string file0; }; - virtual FileInfo * getFileInfo(const Tokenizer& /*tokenizer*/, const Settings& /*settings*/, const std::string& /*currentConfig*/) const { + virtual const FileInfo * getFileInfo(const Tokenizer& /*tokenizer*/, const Settings& /*settings*/, const std::string& /*currentConfig*/) const { return nullptr; } - virtual FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const { + virtual const FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement, const std::string& file0) const { (void)xmlElement; + (void)file0; return nullptr; } // Return true if an error is reported. - virtual bool analyseWholeProgram(const CTU::FileInfo& /*ctu*/, const std::list& /*fileInfo*/, const Settings& /*settings*/, ErrorLogger & /*errorLogger*/) { + virtual bool analyseWholeProgram(const CTU::FileInfo& /*ctu*/, const std::list& /*fileInfo*/, const Settings& /*settings*/, ErrorLogger & /*errorLogger*/) { return false; } -protected: - static std::string getMessageId(const ValueFlow::Value &value, const char id[]); - - const Tokenizer* const mTokenizer{}; - const Settings* const mSettings{}; - ErrorLogger* const mErrorLogger{}; - - /** report an error */ - void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg) { - reportError(tok, severity, id, msg, CWE(0U), Certainty::normal); - } - - /** report an error */ - void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg, const CWE &cwe, Certainty certainty) { - const std::list callstack(1, tok); - reportError(callstack, severity, id, msg, cwe, certainty); - } - - /** report an error */ - void reportError(const std::list &callstack, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe, Certainty certainty); - - void reportError(ErrorPath errorPath, Severity severity, const char id[], const std::string &msg, const CWE &cwe, Certainty certainty); - - /** log checker */ - void logChecker(const char id[]); - - ErrorPath getErrorPath(const Token* errtok, const ValueFlow::Value* value, std::string bug) const; - - /** - * Use WRONG_DATA in checkers when you check for wrong data. That - * will call this method - */ - bool wrongData(const Token *tok, const char *str); - private: const std::string mName; }; diff --git a/lib/check64bit.cpp b/lib/check64bit.cpp index d203eb5f279..174237eef5a 100644 --- a/lib/check64bit.cpp +++ b/lib/check64bit.cpp @@ -36,17 +36,12 @@ // 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) +static bool is32BitIntegerReturn(const Function* func, const Settings& settings) { - if (settings->platform.sizeof_pointer != 8) + if (settings.platform.sizeof_pointer != 8) return false; const ValueType* vt = func->arg->valueType(); - return vt && vt->pointer == 0 && vt->isIntegral() && vt->getSizeOf(*settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer) == 4; + return vt && vt->pointer == 0 && vt->isIntegral() && vt->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer) == 4; } static bool isFunctionPointer(const Token* tok) @@ -56,9 +51,9 @@ static bool isFunctionPointer(const Token* tok) return Tokenizer::isFunctionPointer(tok->variable()->nameToken()); } -void Check64BitPortability::pointerassignment() +void Check64BitPortabilityImpl::pointerassignment() { - if (!mSettings->severity.isEnabled(Severity::portability)) + if (!mSettings.severity.isEnabled(Severity::portability)) return; logChecker("Check64BitPortability::pointerassignment"); // portability @@ -95,11 +90,11 @@ void Check64BitPortability::pointerassignment() if (!returnType) continue; - if (retPointer && !returnType->typeScope && returnType->pointer == 0U) + if (retPointer && !returnType->typeScope && returnType->pointer == 0) returnIntegerError(tok); if (!retPointer) { - bool warn = returnType->pointer >= 1U; + bool warn = returnType->pointer >= 1; if (!warn) { const Token* tok2 = tok->astOperand1(); while (tok2 && tok2->isCast()) @@ -124,17 +119,17 @@ void Check64BitPortability::pointerassignment() continue; // Assign integer to pointer.. - if (lhstype->pointer >= 1U && + if (lhstype->pointer >= 1 && !tok->astOperand2()->isNumber() && - rhstype->pointer == 0U && + rhstype->pointer == 0 && rhstype->originalTypeName.empty() && rhstype->type == ValueType::Type::INT && !isFunctionPointer(tok->astOperand1())) assignmentIntegerToAddressError(tok); // Assign pointer to integer.. - if (rhstype->pointer >= 1U && - lhstype->pointer == 0U && + if (rhstype->pointer >= 1 && + lhstype->pointer == 0 && lhstype->originalTypeName.empty() && lhstype->isIntegral() && lhstype->type >= ValueType::Type::CHAR && @@ -144,7 +139,7 @@ void Check64BitPortability::pointerassignment() } } -void Check64BitPortability::assignmentAddressToIntegerError(const Token *tok) +void Check64BitPortabilityImpl::assignmentAddressToIntegerError(const Token *tok) { reportError(tok, Severity::portability, "AssignmentAddressToInteger", @@ -155,7 +150,7 @@ void Check64BitPortability::assignmentAddressToIntegerError(const Token *tok) "way is to store addresses only in pointer types (or typedefs like uintptr_t).", CWE758, Certainty::normal); } -void Check64BitPortability::assignmentIntegerToAddressError(const Token *tok) +void Check64BitPortabilityImpl::assignmentIntegerToAddressError(const Token *tok) { reportError(tok, Severity::portability, "AssignmentIntegerToAddress", @@ -166,7 +161,7 @@ void Check64BitPortability::assignmentIntegerToAddressError(const Token *tok) "way is to store addresses only in pointer types (or typedefs like uintptr_t).", CWE758, Certainty::normal); } -void Check64BitPortability::returnPointerError(const Token *tok) +void Check64BitPortabilityImpl::returnPointerError(const Token *tok) { reportError(tok, Severity::portability, "CastAddressToIntegerAtReturn", @@ -177,7 +172,7 @@ void Check64BitPortability::returnPointerError(const Token *tok) "to 32-bit integer. The safe way is to return a type such as intptr_t.", CWE758, Certainty::normal); } -void Check64BitPortability::returnIntegerError(const Token *tok) +void Check64BitPortabilityImpl::returnIntegerError(const Token *tok) { reportError(tok, Severity::portability, "CastIntegerToAddressAtReturn", @@ -188,15 +183,15 @@ void Check64BitPortability::returnIntegerError(const Token *tok) "The safe way is to always return a pointer.", CWE758, Certainty::normal); } -void Check64BitPortability::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void Check64BitPortability::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { - Check64BitPortability check64BitPortability(&tokenizer, &tokenizer.getSettings(), errorLogger); + Check64BitPortabilityImpl check64BitPortability(&tokenizer, tokenizer.getSettings(), errorLogger); check64BitPortability.pointerassignment(); } -void Check64BitPortability::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const +void Check64BitPortability::getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const { - Check64BitPortability c(nullptr, settings, errorLogger); + Check64BitPortabilityImpl c(nullptr, settings, errorLogger); c.assignmentAddressToIntegerError(nullptr); c.assignmentIntegerToAddressError(nullptr); c.returnIntegerError(nullptr); diff --git a/lib/check64bit.h b/lib/check64bit.h index 79397e98e5f..cab82cf1148 100644 --- a/lib/check64bit.h +++ b/lib/check64bit.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,6 +23,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include @@ -40,19 +41,28 @@ class Tokenizer; */ class CPPCHECKLIB Check64BitPortability : public Check { - friend class Test64BitPortability; - public: /** This constructor is used when registering the Check64BitPortability */ - Check64BitPortability() : Check(myName()) {} + Check64BitPortability() : Check("64-bit portability") {} private: - /** This constructor is used when running checks. */ - Check64BitPortability(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} - /** @brief Run checks against the normal token list */ - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; + + std::string classInfo() const override { + return "Check if there is 64-bit portability issues:\n" + "- assign address to/from int/long\n" + "- casting address from/to integer when returning from function\n"; + } +}; + +class CPPCHECKLIB Check64BitPortabilityImpl : public CheckImpl { +public: + /** This constructor is used when running checks. */ + Check64BitPortabilityImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} /** Check for pointer assignment */ void pointerassignment(); @@ -61,18 +71,6 @@ class CPPCHECKLIB Check64BitPortability : public Check { void assignmentIntegerToAddressError(const Token *tok); void returnIntegerError(const Token *tok); void returnPointerError(const Token *tok); - - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - static std::string myName() { - return "64-bit portability"; - } - - std::string classInfo() const override { - return "Check if there is 64-bit portability issues:\n" - "- assign address to/from int/long\n" - "- casting address from/to integer when returning from function\n"; - } }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checkassert.cpp b/lib/checkassert.cpp index 3ab55967ede..4578f7395ba 100644 --- a/lib/checkassert.cpp +++ b/lib/checkassert.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,14 +39,9 @@ // 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() +void CheckAssertImpl::assertWithSideEffects() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckAssert::assertWithSideEffects"); // warning @@ -63,7 +58,7 @@ void CheckAssert::assertWithSideEffects() checkVariableAssignment(tmp, tok->scope()); if (tmp->tokType() != Token::eFunction) { - if (const Library::Function* f = mSettings->library.getFunction(tmp)) { + if (const Library::Function* f = mSettings.library.getFunction(tmp)) { if (f->isconst || f->ispure) continue; if (Library::getContainerYield(tmp->next()) != Library::Container::Yield::NO_YIELD) // bailout, assume read access @@ -78,7 +73,7 @@ void CheckAssert::assertWithSideEffects() f->containerYield == Library::Container::Yield::END_ITERATOR || f->containerYield == Library::Container::Yield::ITERATOR) continue; - sideEffectInAssertError(tmp, mSettings->library.getFunctionName(tmp)); + sideEffectInAssertError(tmp, mSettings.library.getFunctionName(tmp)); } continue; } @@ -88,7 +83,7 @@ void CheckAssert::assertWithSideEffects() if (!scope) { // guess that const method doesn't have side effects if (f->nestedIn->isClassOrStruct() && !f->isConst() && !f->isStatic()) - sideEffectInAssertError(tmp, f->name()); // Non-const member function called, assume it has side effects + sideEffectInAssertError(tmp, f->name(), " If there are no side effects, consider declaring the method const."); // Non-const member function called, assume it has side effects continue; } @@ -122,19 +117,19 @@ void CheckAssert::assertWithSideEffects() //--------------------------------------------------------------------------- -void CheckAssert::sideEffectInAssertError(const Token *tok, const std::string& functionName) +void CheckAssertImpl::sideEffectInAssertError(const Token *tok, const std::string& functionName, const std::string &extra) { reportError(tok, Severity::warning, "assertWithSideEffect", "$symbol:" + functionName + "\n" - "Assert statement calls a function which may have desired side effects: '$symbol'.\n" + "Assert statement calls a function which may have desired side effects: '$symbol'." + extra + "\n" "Non-pure function: '$symbol' is called inside assert statement. " "Assert statements are removed from release builds so the code inside " "assert statement is not executed. If the code is needed also in release " "builds, this is a bug.", CWE398, Certainty::normal); } -void CheckAssert::assignmentInAssertError(const Token *tok, const std::string& varname) +void CheckAssertImpl::assignmentInAssertError(const Token *tok, const std::string& varname) { reportError(tok, Severity::warning, "assignmentInAssert", @@ -147,7 +142,7 @@ void CheckAssert::assignmentInAssertError(const Token *tok, const std::string& v } // checks if side effects happen on the variable prior to tmp -void CheckAssert::checkVariableAssignment(const Token* assignTok, const Scope *assertionScope) +void CheckAssertImpl::checkVariableAssignment(const Token* assignTok, const Scope *assertionScope) { if (!assignTok->isAssignmentOp() && assignTok->tokType() != Token::eIncDecOp) return; @@ -177,21 +172,21 @@ void CheckAssert::checkVariableAssignment(const Token* assignTok, const Scope *a // TODO: function calls on var } -bool CheckAssert::inSameScope(const Token* returnTok, const Token* assignTok) +bool CheckAssertImpl::inSameScope(const Token* returnTok, const Token* assignTok) { // TODO: even if a return is in the same scope, the assignment might not affect it. return returnTok->scope() == assignTok->scope(); } -void CheckAssert::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckAssert::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { - CheckAssert checkAssert(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckAssertImpl checkAssert(&tokenizer, tokenizer.getSettings(), errorLogger); checkAssert.assertWithSideEffects(); } -void CheckAssert::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const +void CheckAssert::getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const { - CheckAssert c(nullptr, settings, errorLogger); + CheckAssertImpl c(nullptr, settings, errorLogger); c.sideEffectInAssertError(nullptr, "function"); c.assignmentInAssertError(nullptr, "var"); } diff --git a/lib/checkassert.h b/lib/checkassert.h index b01831a5eec..15f97fb1746 100644 --- a/lib/checkassert.h +++ b/lib/checkassert.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,6 +23,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include @@ -42,32 +43,30 @@ class Tokenizer; class CPPCHECKLIB CheckAssert : public Check { public: - CheckAssert() : Check(myName()) {} + CheckAssert() : Check("Assert") {} private: - CheckAssert(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} - /** run checks, the token list is not simplified */ - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; + + std::string classInfo() const override { + return "Warn if there are side effects in assert statements (since this cause different behaviour in debug/release builds).\n"; + } +}; + +class CPPCHECKLIB CheckAssertImpl : public CheckImpl { +public: + CheckAssertImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} void assertWithSideEffects(); void checkVariableAssignment(const Token* assignTok, const Scope *assertionScope); static bool inSameScope(const Token* returnTok, const Token* assignTok); - void sideEffectInAssertError(const Token *tok, const std::string& functionName); + void sideEffectInAssertError(const Token *tok, const std::string& functionName, const std::string &extra = ""); void assignmentInAssertError(const Token *tok, const std::string &varname); - - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - static std::string myName() { - return "Assert"; - } - - std::string classInfo() const override { - return "Warn if there are side effects in assert statements (since this cause different behaviour in debug/release builds).\n"; - } }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp index e778f3d5959..de70772a279 100644 --- a/lib/checkautovariables.cpp +++ b/lib/checkautovariables.cpp @@ -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 @@ -145,14 +139,14 @@ static bool isAutoVarArray(const Token *tok) return false; } -static bool isLocalContainerBuffer(const Token* tok, const Settings& settings) +static bool isLocalContainerBuffer(const Token* tok, const Library& library) { if (!tok) return false; // x+y if (tok->str() == "+") - return isLocalContainerBuffer(tok->astOperand1(), settings) || isLocalContainerBuffer(tok->astOperand2(), settings); + return isLocalContainerBuffer(tok->astOperand1(), library) || isLocalContainerBuffer(tok->astOperand2(), library); if (tok->str() != "(" || !Token::simpleMatch(tok->astOperand1(), ".")) return false; @@ -163,7 +157,7 @@ static bool isLocalContainerBuffer(const Token* tok, const Settings& settings) if (!var || !var->isLocal() || var->isStatic()) return false; - const Library::Container::Yield yield = astContainerYield(tok, settings.library); + const Library::Container::Yield yield = astContainerYield(tok, library); return yield == Library::Container::Yield::BUFFER || yield == Library::Container::Yield::BUFFER_NT; } @@ -208,11 +202,11 @@ static bool variableIsUsedInScope(const Token* start, nonneg int varId, const Sc return false; } -void CheckAutoVariables::assignFunctionArg() +void CheckAutoVariablesImpl::assignFunctionArg() { - const bool printStyle = mSettings->severity.isEnabled(Severity::style); - const bool printWarning = mSettings->severity.isEnabled(Severity::warning); - if (!printStyle && !printWarning && !mSettings->isPremiumEnabled("uselessAssignmentPtrArg")) + const bool printStyle = mSettings.severity.isEnabled(Severity::style); + const bool printWarning = mSettings.severity.isEnabled(Severity::warning); + if (!printStyle && !printWarning && !mSettings.isPremiumEnabled("uselessAssignmentPtrArg")) return; logChecker("CheckAutoVariables::assignFunctionArg"); // style,warning @@ -239,8 +233,8 @@ void CheckAutoVariables::assignFunctionArg() } } -static bool isAutoVariableRHS(const Token* tok, const Settings& settings) { - return isAddressOfLocalVariable(tok) || isAutoVarArray(tok) || isLocalContainerBuffer(tok, settings); +static bool isAutoVariableRHS(const Token* tok, const Library& library) { + return isAddressOfLocalVariable(tok) || isAutoVarArray(tok) || isLocalContainerBuffer(tok, library); } static bool hasOverloadedAssignment(const Token* tok, bool& inconclusive) @@ -263,7 +257,7 @@ static bool hasOverloadedAssignment(const Token* tok, bool& inconclusive) return true; } -static bool isMemberAssignment(const Token* tok, const Token*& rhs, const Settings& settings) +static bool isMemberAssignment(const Token* tok, const Token*& rhs, const Library& library) { const Token *endBracket = nullptr; if (!Token::Match(tok, "[;{}] %var% . %var%")) { @@ -280,17 +274,17 @@ static bool isMemberAssignment(const Token* tok, const Token*& rhs, const Settin assign = assign->astParent(); if (!Token::simpleMatch(assign, "=")) return false; - if (!isAutoVariableRHS(assign->astOperand2(), settings)) + if (!isAutoVariableRHS(assign->astOperand2(), library)) return false; rhs = assign->astOperand2(); return true; } -void CheckAutoVariables::autoVariables() +void CheckAutoVariablesImpl::autoVariables() { logChecker("CheckAutoVariables::autoVariables"); - const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive); + const bool printInconclusive = mSettings.certainty.isEnabled(Certainty::inconclusive); const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Scope * scope : symbolDatabase->functionScopes) { for (const Token *tok = scope->bodyStart; tok && tok != scope->bodyEnd; tok = tok->next()) { @@ -301,27 +295,27 @@ void CheckAutoVariables::autoVariables() } // Critical assignment const Token* rhs{}; - if (Token::Match(tok, "[;{}] %var% =") && isRefPtrArg(tok->next()) && isAutoVariableRHS(tok->tokAt(2)->astOperand2(), *mSettings)) { + if (Token::Match(tok, "[;{}] %var% =") && isRefPtrArg(tok->next()) && isAutoVariableRHS(tok->tokAt(2)->astOperand2(), mSettings.library)) { checkAutoVariableAssignment(tok->next(), false); - } else if (Token::Match(tok, "[;{}] * %var% =") && isPtrArg(tok->tokAt(2)) && isAutoVariableRHS(tok->tokAt(3)->astOperand2(), *mSettings)) { + } else if (Token::Match(tok, "[;{}] * %var% =") && isPtrArg(tok->tokAt(2)) && isAutoVariableRHS(tok->tokAt(3)->astOperand2(), mSettings.library)) { const Token* lhs = tok->tokAt(2); bool inconclusive = false; if (!hasOverloadedAssignment(lhs, inconclusive) || (printInconclusive && inconclusive)) checkAutoVariableAssignment(tok->next(), inconclusive); tok = tok->tokAt(4); - } else if (isMemberAssignment(tok, rhs, *mSettings)) { + } else if (isMemberAssignment(tok, rhs, mSettings.library)) { const Token* lhs = tok->tokAt(3); bool inconclusive = false; if (!hasOverloadedAssignment(lhs, inconclusive) || (printInconclusive && inconclusive)) checkAutoVariableAssignment(tok->next(), inconclusive); 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)) { + (isPtrArg(tok->next()) || isArrayArg(tok->next(), mSettings)) && + isAutoVariableRHS(tok->linkAt(2)->next()->astOperand2(), mSettings.library)) { errorAutoVariableAssignment(tok->next(), false); } // Invalid pointer deallocation - else if ((Token::Match(tok, "%name% ( %var%|%str% ) ;") && mSettings->library.getDeallocFuncInfo(tok)) || + else if ((Token::Match(tok, "%name% ( %var%|%str% ) ;") && mSettings.library.getDeallocFuncInfo(tok)) || (tok->isCpp() && Token::Match(tok, "delete [| ]| (| %var%|%str% !!["))) { tok = Token::findmatch(tok->next(), "%var%|%str%"); if (Token::simpleMatch(tok->astParent(), ".")) @@ -339,7 +333,7 @@ void CheckAutoVariables::autoVariables() } } } - } else if ((Token::Match(tok, "%name% ( & %var% ) ;") && mSettings->library.getDeallocFuncInfo(tok)) || + } else if ((Token::Match(tok, "%name% ( & %var% ) ;") && mSettings.library.getDeallocFuncInfo(tok)) || (tok->isCpp() && Token::Match(tok, "delete [| ]| (| & %var% !!["))) { tok = Token::findmatch(tok->next(), "%var%"); if (isAutoVar(tok)) @@ -349,7 +343,7 @@ void CheckAutoVariables::autoVariables() } } -bool CheckAutoVariables::checkAutoVariableAssignment(const Token *expr, bool inconclusive, const Token *startToken) +bool CheckAutoVariablesImpl::checkAutoVariableAssignment(const Token *expr, bool inconclusive, const Token *startToken) { if (!startToken) startToken = Token::findsimplematch(expr, "=")->next(); @@ -392,7 +386,7 @@ bool CheckAutoVariables::checkAutoVariableAssignment(const Token *expr, bool inc //--------------------------------------------------------------------------- -void CheckAutoVariables::errorAutoVariableAssignment(const Token *tok, bool inconclusive) +void CheckAutoVariablesImpl::errorAutoVariableAssignment(const Token *tok, bool inconclusive) { diag(tok); @@ -415,7 +409,7 @@ void CheckAutoVariables::errorAutoVariableAssignment(const Token *tok, bool inco } } -void CheckAutoVariables::errorUselessAssignmentArg(const Token *tok) +void CheckAutoVariablesImpl::errorUselessAssignmentArg(const Token *tok) { reportError(tok, Severity::style, @@ -423,7 +417,7 @@ void CheckAutoVariables::errorUselessAssignmentArg(const Token *tok) "Assignment of function parameter has no effect outside the function.", CWE398, Certainty::normal); } -void CheckAutoVariables::errorUselessAssignmentPtrArg(const Token *tok) +void CheckAutoVariablesImpl::errorUselessAssignmentPtrArg(const Token *tok) { reportError(tok, Severity::warning, @@ -431,7 +425,7 @@ void CheckAutoVariables::errorUselessAssignmentPtrArg(const Token *tok) "Assignment of function parameter has no effect outside the function. Did you forget dereferencing it?", CWE398, Certainty::normal); } -bool CheckAutoVariables::diag(const Token* tokvalue) +bool CheckAutoVariablesImpl::diag(const Token* tokvalue) { if (!tokvalue) return true; @@ -568,9 +562,9 @@ static bool isAssignedToNonLocal(const Token* tok) return !var->isLocal() || var->isStatic(); } -void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token * end) +void CheckAutoVariablesImpl::checkVarLifetimeScope(const Token * start, const Token * end) { - const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive); + const bool printInconclusive = mSettings.certainty.isEnabled(Certainty::inconclusive); if (!start) return; const Scope * scope = start->scope(); @@ -583,7 +577,7 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token for (const Token *tok = start; tok && tok != end; tok = tok->next()) { // Return reference from function if (returnRef && Token::simpleMatch(tok->astParent(), "return")) { - for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(tok, *mSettings, true)) { + for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(tok, mSettings, true)) { if (!printInconclusive && lt.inconclusive) continue; const Variable* var = lt.token->variable(); @@ -592,7 +586,7 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token errorReturnReference(tok, lt.errorPath, lt.inconclusive); break; } - if (isDeadTemporary(lt.token, nullptr, mSettings->library)) { + if (isDeadTemporary(lt.token, nullptr, mSettings.library)) { errorReturnTempReference(tok, lt.errorPath, lt.inconclusive); break; } @@ -603,48 +597,51 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token tok->variable()->declarationId() == tok->varId() && tok->variable()->isStatic() && !tok->variable()->isArgument()) { ErrorPath errorPath; - const Variable *var = ValueFlow::getLifetimeVariable(tok, errorPath, *mSettings); + const Variable *var = ValueFlow::getLifetimeVariable(tok, errorPath, mSettings); if (var && isInScope(var->nameToken(), tok->scope())) { errorDanglingReference(tok, var, std::move(errorPath)); continue; } // Reference to temporary } else if (tok->variable() && (tok->variable()->isReference() || tok->variable()->isRValueReference())) { - for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(getParentLifetime(tok), *mSettings)) { + for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(getParentLifetime(tok), mSettings)) { if (!printInconclusive && lt.inconclusive) continue; const Token * tokvalue = lt.token; - if (isDeadTemporary(tokvalue, tok, mSettings->library)) { + if (isDeadTemporary(tokvalue, tok, mSettings.library)) { errorDanglingTempReference(tok, lt.errorPath, lt.inconclusive); break; } } } - const bool escape = Token::simpleMatch(tok->astParent(), "throw") || - (Token::simpleMatch(tok->astParent(), "return") && !Function::returnsStandardType(scope->function)); + const Token* retThrow = tok->astParent(); + if (Token::simpleMatch(retThrow, "new")) + retThrow = retThrow->astParent(); + const bool escape = Token::simpleMatch(retThrow, "throw") || + (Token::simpleMatch(retThrow, "return") && !Function::returnsStandardType(scope->function)); std::unordered_set exprs; for (const ValueFlow::Value& val:tok->values()) { if (!val.isLocalLifetimeValue() && !val.isSubFunctionLifetimeValue()) continue; if (!printInconclusive && val.isInconclusive()) continue; - const Token* parent = getParentLifetime(val.tokvalue, mSettings->library); + const Token* parent = getParentLifetime(val.tokvalue, mSettings.library); if (!exprs.insert(parent).second) continue; - for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(parent, *mSettings, escape || isAssignedToNonLocal(tok))) { + for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(parent, mSettings, escape || isAssignedToNonLocal(tok))) { const Token * tokvalue = lt.token; if (val.isLocalLifetimeValue()) { if (escape) { if (getPointerDepth(tok) < getPointerDepth(tokvalue)) continue; - if (!ValueFlow::isLifetimeBorrowed(tok, *mSettings)) + if (!ValueFlow::isLifetimeBorrowed(tok, mSettings)) continue; if (tokvalue->exprId() == tok->exprId() && !(tok->variable() && tok->variable()->isArray()) && !astIsContainerView(tok->astParent())) continue; if ((tokvalue->variable() && !isEscapedReference(tokvalue->variable()) && isInScope(tokvalue->variable()->nameToken(), scope)) || - isDeadTemporary(tokvalue, nullptr, mSettings->library)) { + isDeadTemporary(tokvalue, nullptr, mSettings.library)) { if (!diag(tokvalue)) errorReturnDanglingLifetime(tok, &val); break; @@ -653,7 +650,7 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token errorInvalidLifetime(tok, &val); break; } else if (!tokvalue->variable() && - isDeadTemporary(tokvalue, tok, mSettings->library)) { + isDeadTemporary(tokvalue, tok, mSettings.library)) { if (!diag(tokvalue)) errorDanglingTemporaryLifetime(tok, &val, tokvalue); break; @@ -671,7 +668,7 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token } else if (tok->variable() && tok->variable()->declarationId() == tok->varId()) { var = tok->variable(); } - if (!ValueFlow::isLifetimeBorrowed(tok, *mSettings)) + if (!ValueFlow::isLifetimeBorrowed(tok, mSettings)) continue; const Token* nextTok = nextAfterAstRightmostLeaf(tok->astTop()); if (!nextTok) @@ -683,7 +680,7 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token var->valueType() ? var->valueType()->pointer : 0, var->declarationId(), var->isGlobal(), - *mSettings)) { + mSettings)) { if (!diag(tok2)) errorDanglngLifetime(tok2, &val, var->isLocal()); break; @@ -711,7 +708,7 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token } } -void CheckAutoVariables::checkVarLifetime() +void CheckAutoVariablesImpl::checkVarLifetime() { logChecker("CheckAutoVariables::checkVarLifetime"); const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -722,7 +719,7 @@ void CheckAutoVariables::checkVarLifetime() } } -void CheckAutoVariables::errorReturnDanglingLifetime(const Token *tok, const ValueFlow::Value *val) +void CheckAutoVariablesImpl::errorReturnDanglingLifetime(const Token *tok, const ValueFlow::Value *val) { const bool inconclusive = val ? val->isInconclusive() : false; ErrorPath errorPath = val ? val->errorPath : ErrorPath(); @@ -731,7 +728,7 @@ void CheckAutoVariables::errorReturnDanglingLifetime(const Token *tok, const Val reportError(std::move(errorPath), Severity::error, "returnDanglingLifetime", msg + " that will be invalid when returning.", CWE562, inconclusive ? Certainty::inconclusive : Certainty::normal); } -void CheckAutoVariables::errorInvalidLifetime(const Token *tok, const ValueFlow::Value* val) +void CheckAutoVariablesImpl::errorInvalidLifetime(const Token *tok, const ValueFlow::Value* val) { const bool inconclusive = val ? val->isInconclusive() : false; ErrorPath errorPath = val ? val->errorPath : ErrorPath(); @@ -740,7 +737,7 @@ void CheckAutoVariables::errorInvalidLifetime(const Token *tok, const ValueFlow: reportError(std::move(errorPath), Severity::error, "invalidLifetime", msg + " that is out of scope.", CWE562, inconclusive ? Certainty::inconclusive : Certainty::normal); } -void CheckAutoVariables::errorDanglingTemporaryLifetime(const Token* tok, const ValueFlow::Value* val, const Token* tempTok) +void CheckAutoVariablesImpl::errorDanglingTemporaryLifetime(const Token* tok, const ValueFlow::Value* val, const Token* tempTok) { const bool inconclusive = val ? val->isInconclusive() : false; ErrorPath errorPath = val ? val->errorPath : ErrorPath(); @@ -755,7 +752,7 @@ void CheckAutoVariables::errorDanglingTemporaryLifetime(const Token* tok, const inconclusive ? Certainty::inconclusive : Certainty::normal); } -void CheckAutoVariables::errorDanglngLifetime(const Token *tok, const ValueFlow::Value *val, bool isStatic) +void CheckAutoVariablesImpl::errorDanglngLifetime(const Token *tok, const ValueFlow::Value *val, bool isStatic) { const bool inconclusive = val ? val->isInconclusive() : false; ErrorPath errorPath = val ? val->errorPath : ErrorPath(); @@ -766,21 +763,21 @@ void CheckAutoVariables::errorDanglngLifetime(const Token *tok, const ValueFlow: reportError(std::move(errorPath), Severity::error, "danglingLifetime", msg + ".", CWE562, inconclusive ? Certainty::inconclusive : Certainty::normal); } -void CheckAutoVariables::errorDanglingTempReference(const Token* tok, ErrorPath errorPath, bool inconclusive) +void CheckAutoVariablesImpl::errorDanglingTempReference(const Token* tok, ErrorPath errorPath, bool inconclusive) { errorPath.emplace_back(tok, ""); reportError( std::move(errorPath), Severity::error, "danglingTempReference", "Using reference to dangling temporary.", CWE562, inconclusive ? Certainty::inconclusive : Certainty::normal); } -void CheckAutoVariables::errorReturnReference(const Token* tok, ErrorPath errorPath, bool inconclusive) +void CheckAutoVariablesImpl::errorReturnReference(const Token* tok, ErrorPath errorPath, bool inconclusive) { errorPath.emplace_back(tok, ""); reportError( std::move(errorPath), Severity::error, "returnReference", "Reference to local variable returned.", CWE562, inconclusive ? Certainty::inconclusive : Certainty::normal); } -void CheckAutoVariables::errorDanglingReference(const Token *tok, const Variable *var, ErrorPath errorPath) +void CheckAutoVariablesImpl::errorDanglingReference(const Token *tok, const Variable *var, ErrorPath errorPath) { std::string tokName = tok ? tok->str() : "x"; std::string varName = var ? var->name() : "y"; @@ -789,14 +786,14 @@ void CheckAutoVariables::errorDanglingReference(const Token *tok, const Variable reportError(std::move(errorPath), Severity::error, "danglingReference", msg, CWE562, Certainty::normal); } -void CheckAutoVariables::errorReturnTempReference(const Token* tok, ErrorPath errorPath, bool inconclusive) +void CheckAutoVariablesImpl::errorReturnTempReference(const Token* tok, ErrorPath errorPath, bool inconclusive) { errorPath.emplace_back(tok, ""); reportError( std::move(errorPath), Severity::error, "returnTempReference", "Reference to temporary returned.", CWE562, inconclusive ? Certainty::inconclusive : Certainty::normal); } -void CheckAutoVariables::errorInvalidDeallocation(const Token *tok, const ValueFlow::Value *val) +void CheckAutoVariablesImpl::errorInvalidDeallocation(const Token *tok, const ValueFlow::Value *val) { const Variable *var = val ? val->tokvalue->variable() : (tok ? tok->variable() : nullptr); @@ -823,17 +820,17 @@ void CheckAutoVariables::errorInvalidDeallocation(const Token *tok, const ValueF "that has been allocated dynamically.", CWE590, Certainty::normal); } -void CheckAutoVariables::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckAutoVariables::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { - CheckAutoVariables checkAutoVariables(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckAutoVariablesImpl checkAutoVariables(&tokenizer, tokenizer.getSettings(), errorLogger); checkAutoVariables.assignFunctionArg(); checkAutoVariables.autoVariables(); checkAutoVariables.checkVarLifetime(); } -void CheckAutoVariables::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const +void CheckAutoVariables::getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const { - CheckAutoVariables c(nullptr,settings,errorLogger); + CheckAutoVariablesImpl c(nullptr,settings,errorLogger); c.errorAutoVariableAssignment(nullptr, false); c.errorReturnReference(nullptr, ErrorPath{}, false); c.errorDanglingReference(nullptr, nullptr, ErrorPath{}); diff --git a/lib/checkautovariables.h b/lib/checkautovariables.h index d94f254508f..23d7a55a488 100644 --- a/lib/checkautovariables.h +++ b/lib/checkautovariables.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,6 +23,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include "errortypes.h" @@ -47,15 +48,32 @@ namespace ValueFlow { class CPPCHECKLIB CheckAutoVariables : public Check { public: /** This constructor is used when registering the CheckClass */ - CheckAutoVariables() : Check(myName()) {} + CheckAutoVariables() : Check("Auto Variables") {} private: - /** This constructor is used when running checks. */ - CheckAutoVariables(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} - /** @brief Run checks against the normal token list */ - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; + + std::string classInfo() const override { + return "A pointer to a variable is only valid as long as the variable is in scope.\n" + "Check:\n" + "- returning a pointer to auto or temporary variable\n" + "- assigning address of an variable to an effective parameter of a function\n" + "- returning reference to local/temporary variable\n" + "- returning address of function parameter\n" + "- suspicious assignment of pointer argument\n" + "- useless assignment of function argument\n"; + } +}; + +class CPPCHECKLIB CheckAutoVariablesImpl : public CheckImpl +{ +public: + /** This constructor is used when running checks. */ + CheckAutoVariablesImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} /** assign function argument */ void assignFunctionArg(); @@ -69,7 +87,6 @@ class CPPCHECKLIB CheckAutoVariables : public Check { bool checkAutoVariableAssignment(const Token *expr, bool inconclusive, const Token *startToken = nullptr); void checkVarLifetime(); - void checkVarLifetimeScope(const Token * start, const Token * end); void errorAutoVariableAssignment(const Token *tok, bool inconclusive); @@ -85,24 +102,8 @@ class CPPCHECKLIB CheckAutoVariables : public Check { void errorUselessAssignmentArg(const Token *tok); void errorUselessAssignmentPtrArg(const Token *tok); - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - static std::string myName() { - return "Auto Variables"; - } - - std::string classInfo() const override { - return "A pointer to a variable is only valid as long as the variable is in scope.\n" - "Check:\n" - "- returning a pointer to auto or temporary variable\n" - "- assigning address of an variable to an effective parameter of a function\n" - "- returning reference to local/temporary variable\n" - "- returning address of function parameter\n" - "- suspicious assignment of pointer argument\n" - "- useless assignment of function argument\n"; - } - /** returns true if tokvalue has already been diagnosed */ +private: bool diag(const Token* tokvalue); std::set mDiagDanglingTemp; diff --git a/lib/checkbool.cpp b/lib/checkbool.cpp index 93e501416aa..3d36c9936a1 100644 --- a/lib/checkbool.cpp +++ b/lib/checkbool.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,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 @@ -48,9 +43,9 @@ static bool isBool(const Variable* var) } //--------------------------------------------------------------------------- -void CheckBool::checkIncrementBoolean() +void CheckBoolImpl::checkIncrementBoolean() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("incrementboolean")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("incrementboolean")) return; logChecker("CheckBool::checkIncrementBoolean"); // style @@ -65,7 +60,7 @@ void CheckBool::checkIncrementBoolean() } } -void CheckBool::incrementBooleanError(const Token *tok) +void CheckBoolImpl::incrementBooleanError(const Token *tok) { reportError( tok, @@ -88,13 +83,13 @@ static bool isConvertedToBool(const Token* tok) // if (bool & bool) -> if (bool && bool) // if (bool | bool) -> if (bool || bool) //--------------------------------------------------------------------------- -void CheckBool::checkBitwiseOnBoolean() +void CheckBoolImpl::checkBitwiseOnBoolean() { - if (!mSettings->isPremiumEnabled("bitwiseOnBoolean") && - !mSettings->severity.isEnabled(Severity::style) && + if (!mSettings.isPremiumEnabled("bitwiseOnBoolean") && + !mSettings.severity.isEnabled(Severity::style) && // danmar: this is inconclusive because I don't like that there are // warnings for calculations. Example: set_flag(a & b); - !mSettings->certainty.isEnabled(Certainty::inconclusive)) + !mSettings.certainty.isEnabled(Certainty::inconclusive)) return; logChecker("CheckBool::checkBitwiseOnBoolean"); // style,inconclusive @@ -121,7 +116,7 @@ void CheckBool::checkBitwiseOnBoolean() if (tok->str() == "|" && !isConvertedToBool(tok) && !(isBoolOp1 && isBoolOp2)) continue; // first operand will always be evaluated - if (!isConstExpression(tok->astOperand2(), mSettings->library)) + if (!isConstExpression(tok->astOperand2(), mSettings.library)) continue; if (tok->astOperand2()->variable() && tok->astOperand2()->variable()->nameToken() == tok->astOperand2()) continue; @@ -132,7 +127,7 @@ void CheckBool::checkBitwiseOnBoolean() } } -void CheckBool::bitwiseOnBooleanError(const Token* tok, const std::string& expression, const std::string& op, bool isCompound) +void CheckBoolImpl::bitwiseOnBooleanError(const Token* tok, const std::string& expression, const std::string& op, bool isCompound) { std::string msg = "Boolean expression '" + expression + "' is used in bitwise operation."; if (!isCompound) @@ -149,9 +144,9 @@ void CheckBool::bitwiseOnBooleanError(const Token* tok, const std::string& expre // if (!x==3) <- Probably meant to be "x!=3" //--------------------------------------------------------------------------- -void CheckBool::checkComparisonOfBoolWithInt() +void CheckBoolImpl::checkComparisonOfBoolWithInt() { - if (!mSettings->severity.isEnabled(Severity::warning) || !mTokenizer->isCPP()) + if (!mSettings.severity.isEnabled(Severity::warning) || !mTokenizer->isCPP()) return; logChecker("CheckBool::checkComparisonOfBoolWithInt"); // warning,c++ @@ -176,7 +171,7 @@ void CheckBool::checkComparisonOfBoolWithInt() } } -void CheckBool::comparisonOfBoolWithInvalidComparator(const Token *tok, const std::string &expression) +void CheckBoolImpl::comparisonOfBoolWithInvalidComparator(const Token *tok, const std::string &expression) { reportError(tok, Severity::warning, "comparisonOfBoolWithInvalidComparator", "Comparison of a boolean value using relational operator (<, >, <= or >=).\n" @@ -200,9 +195,9 @@ static bool tokenIsFunctionReturningBool(const Token* tok) return false; } -void CheckBool::checkComparisonOfFuncReturningBool() +void CheckBoolImpl::checkComparisonOfFuncReturningBool() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings.severity.isEnabled(Severity::style)) return; if (!mTokenizer->isCPP()) @@ -244,7 +239,7 @@ void CheckBool::checkComparisonOfFuncReturningBool() } } -void CheckBool::comparisonOfFuncReturningBoolError(const Token *tok, const std::string &expression) +void CheckBoolImpl::comparisonOfFuncReturningBoolError(const Token *tok, const std::string &expression) { reportError(tok, Severity::style, "comparisonOfFuncReturningBoolError", "Comparison of a function returning boolean value using relational (<, >, <= or >=) operator.\n" @@ -253,7 +248,7 @@ void CheckBool::comparisonOfFuncReturningBoolError(const Token *tok, const std:: " operator could cause unexpected results.", CWE398, Certainty::normal); } -void CheckBool::comparisonOfTwoFuncsReturningBoolError(const Token *tok, const std::string &expression1, const std::string &expression2) +void CheckBoolImpl::comparisonOfTwoFuncsReturningBoolError(const Token *tok, const std::string &expression1, const std::string &expression2) { reportError(tok, Severity::style, "comparisonOfTwoFuncsReturningBoolError", "Comparison of two functions returning boolean value using relational (<, >, <= or >=) operator.\n" @@ -266,9 +261,9 @@ void CheckBool::comparisonOfTwoFuncsReturningBoolError(const Token *tok, const s // Comparison of bool with bool //------------------------------------------------------------------------------- -void CheckBool::checkComparisonOfBoolWithBool() +void CheckBoolImpl::checkComparisonOfBoolWithBool() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings.severity.isEnabled(Severity::style)) return; if (!mTokenizer->isCPP()) @@ -307,7 +302,7 @@ void CheckBool::checkComparisonOfBoolWithBool() } } -void CheckBool::comparisonOfBoolWithBoolError(const Token *tok, const std::string &expression) +void CheckBoolImpl::comparisonOfBoolWithBoolError(const Token *tok, const std::string &expression) { reportError(tok, Severity::style, "comparisonOfBoolWithBoolError", "Comparison of a variable having boolean value using relational (<, >, <= or >=) operator.\n" @@ -317,7 +312,7 @@ void CheckBool::comparisonOfBoolWithBoolError(const Token *tok, const std::strin } //----------------------------------------------------------------------------- -void CheckBool::checkAssignBoolToPointer() +void CheckBoolImpl::checkAssignBoolToPointer() { logChecker("CheckBool::checkAssignBoolToPointer"); const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -330,7 +325,7 @@ void CheckBool::checkAssignBoolToPointer() } } -void CheckBool::assignBoolToPointerError(const Token *tok) +void CheckBoolImpl::assignBoolToPointerError(const Token *tok) { reportError(tok, Severity::error, "assignBoolToPointer", "Boolean value assigned to pointer.", CWE587, Certainty::normal); @@ -338,9 +333,9 @@ void CheckBool::assignBoolToPointerError(const Token *tok) //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -void CheckBool::checkComparisonOfBoolExpressionWithInt() +void CheckBoolImpl::checkComparisonOfBoolExpressionWithInt() { - if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("compareBoolExpressionWithInt")) + if (!mSettings.severity.isEnabled(Severity::warning) && !mSettings.isPremiumEnabled("compareBoolExpressionWithInt")) return; logChecker("CheckBool::checkComparisonOfBoolExpressionWithInt"); // warning @@ -378,13 +373,13 @@ void CheckBool::checkComparisonOfBoolExpressionWithInt() if (astIsBool(numTok)) continue; - const ValueFlow::Value *minval = numTok->getValueLE(0, *mSettings); + const ValueFlow::Value *minval = numTok->getValueLE(0, mSettings); if (minval && minval->intvalue == 0 && (numInRhs ? Token::Match(tok, ">|==|!=") : Token::Match(tok, "<|==|!="))) minval = nullptr; - const ValueFlow::Value *maxval = numTok->getValueGE(1, *mSettings); + const ValueFlow::Value *maxval = numTok->getValueGE(1, mSettings); if (maxval && maxval->intvalue == 1 && (numInRhs ? Token::Match(tok, "<|==|!=") : Token::Match(tok, ">|==|!="))) @@ -398,7 +393,7 @@ void CheckBool::checkComparisonOfBoolExpressionWithInt() } } -void CheckBool::comparisonOfBoolExpressionWithIntError(const Token *tok, bool not0or1) +void CheckBoolImpl::comparisonOfBoolExpressionWithIntError(const Token *tok, bool not0or1) { if (not0or1) reportError(tok, Severity::warning, "compareBoolExpressionWithInt", @@ -409,7 +404,7 @@ void CheckBool::comparisonOfBoolExpressionWithIntError(const Token *tok, bool no } -void CheckBool::pointerArithBool() +void CheckBoolImpl::pointerArithBool() { logChecker("CheckBool::pointerArithBool"); @@ -432,7 +427,7 @@ void CheckBool::pointerArithBool() } } -void CheckBool::pointerArithBoolCond(const Token *tok) +void CheckBoolImpl::pointerArithBoolCond(const Token *tok) { if (!tok) return; @@ -452,7 +447,7 @@ void CheckBool::pointerArithBoolCond(const Token *tok) pointerArithBoolError(tok); } -void CheckBool::pointerArithBoolError(const Token *tok) +void CheckBoolImpl::pointerArithBoolError(const Token *tok) { reportError(tok, Severity::error, @@ -461,11 +456,11 @@ void CheckBool::pointerArithBoolError(const Token *tok) "Converting pointer arithmetic result to bool. The boolean result is always true unless there is pointer arithmetic overflow, and overflow is undefined behaviour. Probably a dereference is forgotten.", CWE571, Certainty::normal); } -void CheckBool::checkAssignBoolToFloat() +void CheckBoolImpl::checkAssignBoolToFloat() { if (!mTokenizer->isCPP()) return; - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings.severity.isEnabled(Severity::style)) return; logChecker("CheckBool::checkAssignBoolToFloat"); // style,c++ const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -478,15 +473,15 @@ void CheckBool::checkAssignBoolToFloat() } } -void CheckBool::assignBoolToFloatError(const Token *tok) +void CheckBoolImpl::assignBoolToFloatError(const Token *tok) { reportError(tok, Severity::style, "assignBoolToFloat", "Boolean value assigned to floating point variable.", CWE704, Certainty::normal); } -void CheckBool::returnValueOfFunctionReturningBool() +void CheckBoolImpl::returnValueOfFunctionReturningBool() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings.severity.isEnabled(Severity::style)) return; logChecker("CheckBool::returnValueOfFunctionReturningBool"); // style @@ -505,21 +500,21 @@ void CheckBool::returnValueOfFunctionReturningBool() else if (tok->scope() && tok->scope()->isClassOrStruct()) tok = tok->scope()->bodyEnd; else if (Token::simpleMatch(tok, "return") && tok->astOperand1() && - (tok->astOperand1()->getValueGE(2, *mSettings) || tok->astOperand1()->getValueLE(-1, *mSettings)) && + (tok->astOperand1()->getValueGE(2, mSettings) || tok->astOperand1()->getValueLE(-1, mSettings)) && !(tok->astOperand1()->astOperand1() && Token::Match(tok->astOperand1(), "&|%or%"))) returnValueBoolError(tok); } } } -void CheckBool::returnValueBoolError(const Token *tok) +void CheckBoolImpl::returnValueBoolError(const Token *tok) { reportError(tok, Severity::style, "returnNonBoolInBooleanFunction", "Non-boolean value returned from function returning bool"); } -void CheckBool::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckBool::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { - CheckBool checkBool(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckBoolImpl checkBool(&tokenizer, tokenizer.getSettings(), errorLogger); // Checks checkBool.checkComparisonOfBoolExpressionWithInt(); @@ -534,9 +529,9 @@ void CheckBool::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) checkBool.checkBitwiseOnBoolean(); } -void CheckBool::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const +void CheckBool::getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const { - CheckBool c(nullptr, settings, errorLogger); + CheckBoolImpl c(nullptr, settings, errorLogger); c.assignBoolToPointerError(nullptr); c.assignBoolToFloatError(nullptr); c.comparisonOfFuncReturningBoolError(nullptr, "func_name"); diff --git a/lib/checkbool.h b/lib/checkbool.h index 65e5d0254ea..53cc19c2486 100644 --- a/lib/checkbool.h +++ b/lib/checkbool.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,6 +23,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include @@ -41,15 +42,33 @@ class Tokenizer; class CPPCHECKLIB CheckBool : public Check { public: /** @brief This constructor is used when registering the CheckClass */ - CheckBool() : Check(myName()) {} + CheckBool() : Check("Boolean") {} private: - /** @brief This constructor is used when running checks. */ - CheckBool(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} - /** @brief Run checks against the normal token list */ - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; + + std::string classInfo() const override { + return "Boolean type checks\n" + "- using increment on boolean\n" + "- comparison of a boolean expression with an integer other than 0 or 1\n" + "- comparison of a function returning boolean value using relational operator\n" + "- comparison of a boolean value with boolean value using relational operator\n" + "- using bool in bitwise expression\n" + "- pointer addition in condition (either dereference is forgot or pointer overflow is required to make the condition false)\n" + "- Assigning bool value to pointer or float\n" + "- Returning an integer other than 0 or 1 from a function with boolean return value\n"; + } +}; + +class CPPCHECKLIB CheckBoolImpl : public CheckImpl +{ +public: + /** @brief This constructor is used when running checks. */ + CheckBoolImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} /** @brief %Check for comparison of function returning bool*/ void checkComparisonOfFuncReturningBool(); @@ -94,24 +113,6 @@ class CPPCHECKLIB CheckBool : public Check { void comparisonOfBoolExpressionWithIntError(const Token *tok, bool not0or1); void pointerArithBoolError(const Token *tok); void returnValueBoolError(const Token *tok); - - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - static std::string myName() { - return "Boolean"; - } - - std::string classInfo() const override { - return "Boolean type checks\n" - "- using increment on boolean\n" - "- comparison of a boolean expression with an integer other than 0 or 1\n" - "- comparison of a function returning boolean value using relational operator\n" - "- comparison of a boolean value with boolean value using relational operator\n" - "- using bool in bitwise expression\n" - "- pointer addition in condition (either dereference is forgot or pointer overflow is required to make the condition false)\n" - "- Assigning bool value to pointer or float\n" - "- Returning an integer other than 0 or 1 from a function with boolean return value\n"; - } }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 642e40bce76..246d428802e 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -50,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 @@ -72,7 +65,10 @@ static const CWE CWE_BUFFER_OVERRUN(788U); // Access of Memory Location After static const ValueFlow::Value *getBufferSizeValue(const Token *tok) { const std::list &tokenValues = tok->values(); - const auto it = std::find_if(tokenValues.cbegin(), tokenValues.cend(), std::mem_fn(&ValueFlow::Value::isBufferSizeValue)); + auto it = std::find_if(tokenValues.cbegin(), tokenValues.cend(), std::mem_fn(&ValueFlow::Value::isBufferSizeValue)); + if (it != tokenValues.cend()) + return &*it; + it = std::find_if(tokenValues.cbegin(), tokenValues.cend(), std::mem_fn(&ValueFlow::Value::isContainerSizeValue)); return it == tokenValues.cend() ? nullptr : &*it; } @@ -140,7 +136,7 @@ static int getMinFormatStringOutputLength(const std::vector ¶m case 's': parameterLength = 0; if (inputArgNr < parameters.size()) - parameterLength = ValueFlow::valueFlowGetStrLength(parameters[inputArgNr], settings); + parameterLength = ValueFlow::valueFlowGetStrLength(parameters[inputArgNr], settings.library); handleNextParameter = true; break; @@ -291,7 +287,7 @@ static std::vector getOverrunIndexValues(const Token* tok, return {}; } -void CheckBufferOverrun::arrayIndex() +void CheckBufferOverrunImpl::arrayIndex() { logChecker("CheckBufferOverrun::arrayIndex"); @@ -330,7 +326,7 @@ void CheckBufferOverrun::arrayIndex() ErrorPath errorPath; bool mightBeLarger = false; MathLib::bigint path = 0; - if (!getDimensionsEtc(tok->astOperand1(), *mSettings, dimensions, errorPath, mightBeLarger, path)) + if (!getDimensionsEtc(tok->astOperand1(), mSettings, dimensions, errorPath, mightBeLarger, path)) continue; const Variable* const var = array->variable(); @@ -338,7 +334,7 @@ void CheckBufferOverrun::arrayIndex() const Token* changeTok = var->scope()->bodyStart; bool isChanged = false; while ((changeTok = findVariableChanged(changeTok->next(), var->scope()->bodyEnd, /*indirect*/ 0, var->declarationId(), - /*globalvar*/ false, *mSettings))) { + /*globalvar*/ false, mSettings))) { if (!Token::simpleMatch(changeTok->astParent(), "[")) { isChanged = true; break; @@ -360,7 +356,7 @@ void CheckBufferOverrun::arrayIndex() bool neg = false; std::vector negativeIndexes; for (const Token * indexToken : indexTokens) { - const ValueFlow::Value *negativeValue = indexToken->getValueLE(-1, *mSettings); + const ValueFlow::Value *negativeValue = indexToken->getValueLE(-1, mSettings); if (negativeValue) { negativeIndexes.emplace_back(*negativeValue); neg = true; @@ -412,9 +408,9 @@ static std::string arrayIndexMessage(const Token* tok, return errmsg.str(); } -void CheckBufferOverrun::arrayIndexError(const Token* tok, - const std::vector& dimensions, - const std::vector& indexes) +void CheckBufferOverrunImpl::arrayIndexError(const Token* tok, + const std::vector& dimensions, + const std::vector& indexes) { if (!tok) { reportError(tok, Severity::error, "arrayIndexOutOfBounds", "Array 'arr[16]' accessed at index 16, which is out of bounds.", CWE_BUFFER_OVERRUN, Certainty::normal); @@ -425,7 +421,7 @@ void CheckBufferOverrun::arrayIndexError(const Token* tok, const Token *condition = nullptr; const ValueFlow::Value *index = nullptr; for (const ValueFlow::Value& indexValue : indexes) { - if (!indexValue.errorSeverity() && !mSettings->severity.isEnabled(Severity::warning)) + if (!indexValue.errorSeverity() && !mSettings.severity.isEnabled(Severity::warning)) return; if (indexValue.condition) condition = indexValue.condition; @@ -441,9 +437,9 @@ void CheckBufferOverrun::arrayIndexError(const Token* tok, index->isInconclusive() ? Certainty::inconclusive : Certainty::normal); } -void CheckBufferOverrun::negativeIndexError(const Token* tok, - const std::vector& dimensions, - const std::vector& indexes) +void CheckBufferOverrunImpl::negativeIndexError(const Token* tok, + const std::vector& dimensions, + const std::vector& indexes) { if (!tok) { reportError(tok, Severity::error, "negativeIndex", "Negative array index", CWE_BUFFER_UNDERRUN, Certainty::normal); @@ -453,7 +449,7 @@ void CheckBufferOverrun::negativeIndexError(const Token* tok, const Token *condition = nullptr; const ValueFlow::Value *negativeValue = nullptr; for (const ValueFlow::Value& indexValue : indexes) { - if (!indexValue.errorSeverity() && !mSettings->severity.isEnabled(Severity::warning)) + if (!indexValue.errorSeverity() && !mSettings.severity.isEnabled(Severity::warning)) return; if (indexValue.condition) condition = indexValue.condition; @@ -471,9 +467,9 @@ void CheckBufferOverrun::negativeIndexError(const Token* tok, //--------------------------------------------------------------------------- -void CheckBufferOverrun::pointerArithmetic() +void CheckBufferOverrunImpl::pointerArithmetic() { - if (!mSettings->severity.isEnabled(Severity::portability) && !mSettings->isPremiumEnabled("pointerOutOfBounds")) + if (!mSettings.severity.isEnabled(Severity::portability) && !mSettings.isPremiumEnabled("pointerOutOfBounds")) return; logChecker("CheckBufferOverrun::pointerArithmetic"); // portability @@ -504,7 +500,7 @@ void CheckBufferOverrun::pointerArithmetic() ErrorPath errorPath; bool mightBeLarger = false; MathLib::bigint path = 0; - if (!getDimensionsEtc(arrayToken, *mSettings, dimensions, errorPath, mightBeLarger, path)) + if (!getDimensionsEtc(arrayToken, mSettings, dimensions, errorPath, mightBeLarger, path)) continue; if (tok->str() == "+") { @@ -517,7 +513,7 @@ void CheckBufferOverrun::pointerArithmetic() pointerArithmeticError(tok, indexToken, &indexValues.front()); } - if (const ValueFlow::Value *neg = indexToken->getValueLE(-1, *mSettings)) + if (const ValueFlow::Value *neg = indexToken->getValueLE(-1, mSettings)) pointerArithmeticError(tok, indexToken, neg); } else if (tok->str() == "-") { if (arrayToken->variable() && arrayToken->variable()->isArgument()) @@ -527,7 +523,7 @@ void CheckBufferOverrun::pointerArithmetic() while (Token::Match(array, ".|::")) array = array->astOperand2(); if (array->variable() && array->variable()->isArray()) { - const ValueFlow::Value *v = indexToken->getValueGE(1, *mSettings); + const ValueFlow::Value *v = indexToken->getValueGE(1, mSettings); if (v) pointerArithmeticError(tok, indexToken, v); } @@ -535,7 +531,7 @@ void CheckBufferOverrun::pointerArithmetic() } } -void CheckBufferOverrun::pointerArithmeticError(const Token *tok, const Token *indexToken, const ValueFlow::Value *indexValue) +void CheckBufferOverrunImpl::pointerArithmeticError(const Token *tok, const Token *indexToken, const ValueFlow::Value *indexValue) { if (!tok) { reportError(tok, Severity::portability, "pointerOutOfBounds", "Pointer arithmetic overflow.", CWE_POINTER_ARITHMETIC_OVERFLOW, Certainty::normal); @@ -559,21 +555,40 @@ void CheckBufferOverrun::pointerArithmeticError(const Token *tok, const Token *i //--------------------------------------------------------------------------- -ValueFlow::Value CheckBufferOverrun::getBufferSize(const Token *bufTok) const +ValueFlow::Value CheckBufferOverrunImpl::getBufferSize(const Token *bufTok, const Settings& settings) const { if (!bufTok->valueType()) return ValueFlow::Value(-1); - if (bufTok->isUnaryOp("&")) + + if (bufTok->isUnaryOp("&")) { bufTok = bufTok->astOperand1(); + if (Token::simpleMatch(bufTok, "[")) { + const Token* index = bufTok->astOperand2(); + if (!(index && index->hasKnownIntValue() && index->getKnownIntValue() == 0)) + return ValueFlow::Value(-1); + bufTok = bufTok->astOperand1(); + } + } const Variable *var = bufTok->variable(); if (!var || var->dimensions().empty()) { - const ValueFlow::Value *value = getBufferSizeValue(bufTok); - if (value) - return *value; + if (const ValueFlow::Value *value = getBufferSizeValue(bufTok)) { + if (value->isBufferSizeValue()) + return *value; + if (value->isContainerSizeValue() && bufTok->valueType() && bufTok->valueType()->containerTypeToken) { + const ValueType vtElement = ValueType::parseDecl(bufTok->valueType()->containerTypeToken, settings); + const size_t elementSize = vtElement.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); + if (elementSize > 0) { + ValueFlow::Value bufSizeVal; + bufSizeVal.valueType = ValueFlow::Value::ValueType::BUFFER_SIZE; + bufSizeVal.intvalue = value->intvalue * elementSize; + return bufSizeVal; + } + } + } } - if (!var || var->isPointer()) + if (!var || var->isPointer() || (astIsContainer(bufTok) && var->getTypeName() != "std::array")) return ValueFlow::Value(-1); const MathLib::bigint dim = std::accumulate(var->dimensions().cbegin(), var->dimensions().cend(), MathLib::bigint(1), [](MathLib::bigint i1, const Dimension &dim) { @@ -585,9 +600,9 @@ ValueFlow::Value CheckBufferOverrun::getBufferSize(const Token *bufTok) const v.valueType = ValueFlow::Value::ValueType::BUFFER_SIZE; if (var->isPointerArray()) - v.intvalue = dim * mSettings->platform.sizeof_pointer; + v.intvalue = dim * mSettings.platform.sizeof_pointer; else { - const size_t typeSize = bufTok->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee); + const size_t typeSize = bufTok->valueType()->getSizeOf(mSettings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee); v.intvalue = dim * typeSize; } @@ -641,7 +656,7 @@ static bool checkBufferSize(const Token *ftok, const Library::ArgumentChecks::Mi } -void CheckBufferOverrun::bufferOverflow() +void CheckBufferOverrunImpl::bufferOverflow() { logChecker("CheckBufferOverrun::bufferOverflow"); @@ -650,13 +665,13 @@ void CheckBufferOverrun::bufferOverflow() for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) { if (!Token::Match(tok, "%name% (") || Token::simpleMatch(tok, ") {")) continue; - if (!mSettings->library.hasminsize(tok)) + if (!mSettings.library.hasminsize(tok)) continue; const std::vector args = getArguments(tok); - for (int argnr = 0; argnr < args.size(); ++argnr) { + for (size_t argnr = 0; argnr < args.size(); ++argnr) { if (!args[argnr]->valueType() || args[argnr]->valueType()->pointer == 0) continue; - const std::vector *minsizes = mSettings->library.argminsizes(tok, argnr + 1); + const std::vector *minsizes = mSettings.library.argminsizes(tok, argnr + 1); if (!minsizes || minsizes->empty()) continue; // Get buffer size.. @@ -670,7 +685,7 @@ void CheckBufferOverrun::bufferOverflow() if (argtok->valueType() && argtok->valueType()->pointer == 0) continue; // TODO: strcpy(buf+10, "hello"); - const ValueFlow::Value bufferSize = getBufferSize(argtok); + const ValueFlow::Value bufferSize = getBufferSize(argtok, mSettings); if (bufferSize.intvalue <= 0) continue; // buffer size == 1 => do not warn for dynamic memory @@ -689,7 +704,7 @@ void CheckBufferOverrun::bufferOverflow() } } const bool error = std::none_of(minsizes->begin(), minsizes->end(), [&](const Library::ArgumentChecks::MinSize &minsize) { - return checkBufferSize(tok, minsize, args, bufferSize.intvalue, *mSettings, mTokenizer); + return checkBufferSize(tok, minsize, args, bufferSize.intvalue, mSettings, mTokenizer); }); if (error) bufferOverflowError(args[argnr], &bufferSize, Certainty::normal); @@ -698,16 +713,16 @@ void CheckBufferOverrun::bufferOverflow() } } -void CheckBufferOverrun::bufferOverflowError(const Token *tok, const ValueFlow::Value *value, Certainty certainty) +void CheckBufferOverrunImpl::bufferOverflowError(const Token *tok, const ValueFlow::Value *value, Certainty certainty) { reportError(getErrorPath(tok, value, "Buffer overrun"), Severity::error, "bufferAccessOutOfBounds", "Buffer is accessed out of bounds: " + (tok ? getRealBufferTok(tok)->expressionString() : "buf"), CWE_BUFFER_OVERRUN, certainty); } //--------------------------------------------------------------------------- -void CheckBufferOverrun::arrayIndexThenCheck() +void CheckBufferOverrunImpl::arrayIndexThenCheck() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings.severity.isEnabled(Severity::style)) return; logChecker("CheckBufferOverrun::arrayIndexThenCheck"); // style @@ -749,7 +764,7 @@ void CheckBufferOverrun::arrayIndexThenCheck() } } -void CheckBufferOverrun::arrayIndexThenCheckError(const Token *tok, const std::string &indexName) +void CheckBufferOverrunImpl::arrayIndexThenCheckError(const Token *tok, const std::string &indexName) { reportError(tok, Severity::style, "arrayIndexThenCheck", "$symbol:" + indexName + "\n" @@ -762,10 +777,10 @@ void CheckBufferOverrun::arrayIndexThenCheckError(const Token *tok, const std::s //--------------------------------------------------------------------------- -void CheckBufferOverrun::stringNotZeroTerminated() +void CheckBufferOverrunImpl::stringNotZeroTerminated() { // this is currently 'inconclusive'. See TestBufferOverrun::terminateStrncpy3 - if (!mSettings->severity.isEnabled(Severity::warning) || !mSettings->certainty.isEnabled(Certainty::inconclusive)) + if (!mSettings.severity.isEnabled(Severity::warning) || !mSettings.certainty.isEnabled(Certainty::inconclusive)) return; logChecker("CheckBufferOverrun::stringNotZeroTerminated"); // warning,inconclusive @@ -781,7 +796,7 @@ void CheckBufferOverrun::stringNotZeroTerminated() const Token *sizeToken = args[2]; if (!sizeToken->hasKnownIntValue()) continue; - const ValueFlow::Value &bufferSize = getBufferSize(args[0]); + const ValueFlow::Value &bufferSize = getBufferSize(args[0], mSettings); if (bufferSize.intvalue < 0 || sizeToken->getKnownIntValue() < bufferSize.intvalue) continue; if (Token::simpleMatch(args[1], "(") && Token::simpleMatch(args[1]->astOperand1(), ". c_str") && args[1]->astOperand1()->astOperand1()) { @@ -804,7 +819,7 @@ void CheckBufferOverrun::stringNotZeroTerminated() const Token *rhs = tok2->next()->astOperand2(); if (!rhs || !rhs->hasKnownIntValue() || rhs->getKnownIntValue() != 0) continue; - if (isSameExpression(false, args[0], tok2->link()->astOperand1(), *mSettings, false, false)) + if (isSameExpression(false, args[0], tok2->link()->astOperand1(), mSettings, false, false)) isZeroTerminated = true; } if (isZeroTerminated) @@ -815,7 +830,7 @@ void CheckBufferOverrun::stringNotZeroTerminated() } } -void CheckBufferOverrun::terminateStrncpyError(const Token *tok, const std::string &varname) +void CheckBufferOverrunImpl::terminateStrncpyError(const Token *tok, const std::string &varname) { const std::string shortMessage = "The buffer '$symbol' may not be null-terminated after the call to strncpy()."; reportError(tok, Severity::warning, "terminateStrncpy", @@ -828,10 +843,10 @@ void CheckBufferOverrun::terminateStrncpyError(const Token *tok, const std::stri } //--------------------------------------------------------------------------- -void CheckBufferOverrun::argumentSize() +void CheckBufferOverrunImpl::argumentSize() { // Check '%type% x[10]' arguments - if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("argumentSize")) + if (!mSettings.severity.isEnabled(Severity::warning) && !mSettings.isPremiumEnabled("argumentSize")) return; logChecker("CheckBufferOverrun::argumentSize"); // warning @@ -845,7 +860,7 @@ void CheckBufferOverrun::argumentSize() // If argument is '%type% a[num]' then check bounds against num const Function *callfunc = tok->function(); const std::vector callargs = getArguments(tok); - for (nonneg int paramIndex = 0; paramIndex < callargs.size() && paramIndex < callfunc->argCount(); ++paramIndex) { + for (size_t paramIndex = 0; paramIndex < callargs.size() && paramIndex < callfunc->argCount(); ++paramIndex) { const Variable* const argument = callfunc->getArgumentVar(paramIndex); if (!argument || !argument->nameToken() || !argument->isArray()) continue; @@ -876,7 +891,7 @@ void CheckBufferOverrun::argumentSize() } } -void CheckBufferOverrun::argumentSizeError(const Token *tok, const std::string &functionName, nonneg int paramIndex, const std::string ¶mExpression, const Variable *paramVar, const Variable *functionArg) +void CheckBufferOverrunImpl::argumentSizeError(const Token *tok, const std::string &functionName, nonneg int paramIndex, const std::string ¶mExpression, const Variable *paramVar, const Variable *functionArg) { const std::string strParamNum = std::to_string(paramIndex + 1) + getOrdinalText(paramIndex + 1); ErrorPath errorPath; @@ -907,6 +922,8 @@ namespace /** data for multifile checking */ class MyFileInfo : public Check::FileInfo { public: + explicit MyFileInfo(std::string f0) : Check::FileInfo(std::move(f0)) {} + using Check::FileInfo::FileInfo; /** unsafe array index usage */ std::list unsafeArrayIndex; @@ -927,7 +944,7 @@ namespace }; } -bool CheckBufferOverrun::isCtuUnsafeBufferUsage(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset, int type) +bool CheckBufferOverrunImpl::isCtuUnsafeBufferUsage(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset, int type) { if (!offset) return false; @@ -948,21 +965,21 @@ bool CheckBufferOverrun::isCtuUnsafeBufferUsage(const Settings &settings, const return true; } -bool CheckBufferOverrun::isCtuUnsafeArrayIndex(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset) +bool CheckBufferOverrunImpl::isCtuUnsafeArrayIndex(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset) { return isCtuUnsafeBufferUsage(settings, argtok, offset, 1); } -bool CheckBufferOverrun::isCtuUnsafePointerArith(const Settings &settings, const Token *argtok, CTU::FileInfo::Value* offset) +bool CheckBufferOverrunImpl::isCtuUnsafePointerArith(const Settings &settings, const Token *argtok, CTU::FileInfo::Value* offset) { return isCtuUnsafeBufferUsage(settings, argtok, offset, 2); } /** @brief Parse current TU and extract file info */ -Check::FileInfo *CheckBufferOverrun::getFileInfo(const Tokenizer &tokenizer, const Settings &settings, const std::string& /*currentConfig*/) const +const Check::FileInfo *CheckBufferOverrun::getFileInfo(const Tokenizer &tokenizer, const Settings &settings, const std::string& /*currentConfig*/) const { - const std::list &unsafeArrayIndex = CTU::getUnsafeUsage(tokenizer, settings, isCtuUnsafeArrayIndex); - const std::list &unsafePointerArith = CTU::getUnsafeUsage(tokenizer, settings, isCtuUnsafePointerArith); + const std::list &unsafeArrayIndex = CTU::getUnsafeUsage(tokenizer, settings, CheckBufferOverrunImpl::isCtuUnsafeArrayIndex); + const std::list &unsafePointerArith = CTU::getUnsafeUsage(tokenizer, settings, CheckBufferOverrunImpl::isCtuUnsafePointerArith); if (unsafeArrayIndex.empty() && unsafePointerArith.empty()) { return nullptr; } @@ -972,13 +989,12 @@ Check::FileInfo *CheckBufferOverrun::getFileInfo(const Tokenizer &tokenizer, con return fileInfo; } -Check::FileInfo * CheckBufferOverrun::loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const +const Check::FileInfo * CheckBufferOverrun::loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement, const std::string& file0) const { - // cppcheck-suppress shadowFunction - TODO: fix this const std::string arrayIndex("array-index"); const std::string pointerArith("pointer-arith"); - auto *fileInfo = new MyFileInfo; + auto *fileInfo = new MyFileInfo(file0); for (const tinyxml2::XMLElement *e = xmlElement->FirstChildElement(); e; e = e->NextSiblingElement()) { const char* name = e->Name(); if (name == arrayIndex) @@ -996,9 +1012,9 @@ Check::FileInfo * CheckBufferOverrun::loadFileInfoFromXml(const tinyxml2::XMLEle } /** @brief Analyse all file infos for all TU */ -bool CheckBufferOverrun::analyseWholeProgram(const CTU::FileInfo &ctu, const std::list &fileInfo, const Settings& settings, ErrorLogger &errorLogger) +bool CheckBufferOverrun::analyseWholeProgram(const CTU::FileInfo &ctu, const std::list &fileInfo, const Settings& settings, ErrorLogger &errorLogger) { - CheckBufferOverrun dummy(nullptr, &settings, &errorLogger); + CheckBufferOverrunImpl dummy(nullptr, settings, errorLogger); dummy. logChecker("CheckBufferOverrun::analyseWholeProgram"); @@ -1065,7 +1081,7 @@ bool CheckBufferOverrun::analyseWholeProgram1(const std::mapgetSymbolDatabase(); @@ -1084,9 +1100,15 @@ void CheckBufferOverrun::objectIndex() std::vector values = ValueFlow::getLifetimeObjValues(obj, false, -1); for (const ValueFlow::Value& v:values) { - if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address) + if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address && v.lifetimeKind != ValueFlow::Value::LifetimeKind::Object) continue; - const Variable *var = v.tokvalue->variable(); + const Token* varTok = v.tokvalue; + if (Token::simpleMatch(varTok->astParent(), ".")) { + varTok = varTok->astParent(); + while (Token::simpleMatch(varTok, ".")) + varTok = varTok->astOperand2(); + } + const Variable *var = varTok ? varTok->variable() : nullptr; if (!var) continue; if (var->isReference()) @@ -1104,7 +1126,7 @@ void CheckBufferOverrun::objectIndex() continue; } if (obj->valueType() && var->valueType() && (obj->isCast() || (obj->isCpp() && isCPPCast(obj)) || obj->valueType()->pointer)) { // allow cast to a different type - const auto varSize = var->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee); + const auto varSize = var->valueType()->getSizeOf(mSettings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee); if (varSize == 0) continue; if (obj->valueType()->type != var->valueType()->type) { @@ -1137,7 +1159,7 @@ void CheckBufferOverrun::objectIndex() } } -void CheckBufferOverrun::objectIndexError(const Token *tok, const ValueFlow::Value *v, bool known) +void CheckBufferOverrunImpl::objectIndexError(const Token *tok, const ValueFlow::Value *v, bool known) { ErrorPath errorPath; std::string name; @@ -1174,7 +1196,7 @@ static bool isVLAIndex(const Token* tok) return isVLAIndex(tok->astOperand1()) || isVLAIndex(tok->astOperand2()); } -void CheckBufferOverrun::negativeArraySize() +void CheckBufferOverrunImpl::negativeArraySize() { logChecker("CheckBufferOverrun::negativeArraySize"); const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -1184,7 +1206,7 @@ void CheckBufferOverrun::negativeArraySize() const Token* const nameToken = var->nameToken(); if (!Token::Match(nameToken, "%var% [") || !nameToken->next()->astOperand2()) continue; - const ValueFlow::Value* sz = nameToken->next()->astOperand2()->getValueLE(-1, *mSettings); + const ValueFlow::Value* sz = nameToken->next()->astOperand2()->getValueLE(-1, mSettings); // don't warn about constant negative index because that is a compiler error if (sz && isVLAIndex(nameToken->next()->astOperand2())) negativeArraySizeError(nameToken); @@ -1197,14 +1219,14 @@ void CheckBufferOverrun::negativeArraySize() const Token* valOperand = tok->astOperand1()->astOperand2(); if (!valOperand) continue; - const ValueFlow::Value* sz = valOperand->getValueLE(-1, *mSettings); + const ValueFlow::Value* sz = valOperand->getValueLE(-1, mSettings); if (sz) negativeMemoryAllocationSizeError(tok, sz); } } } -void CheckBufferOverrun::negativeArraySizeError(const Token* tok) +void CheckBufferOverrunImpl::negativeArraySizeError(const Token* tok) { const std::string arrayName = tok ? tok->expressionString() : std::string(); const std::string line1 = arrayName.empty() ? std::string() : ("$symbol:" + arrayName + '\n'); @@ -1213,7 +1235,7 @@ void CheckBufferOverrun::negativeArraySizeError(const Token* tok) "Declaration of array '" + arrayName + "' with negative size is undefined behaviour", CWE758, Certainty::normal); } -void CheckBufferOverrun::negativeMemoryAllocationSizeError(const Token* tok, const ValueFlow::Value* value) +void CheckBufferOverrunImpl::negativeMemoryAllocationSizeError(const Token* tok, const ValueFlow::Value* value) { const std::string msg = "Memory allocation size is negative."; ErrorPath errorPath = getErrorPath(tok, value, msg); @@ -1222,9 +1244,9 @@ void CheckBufferOverrun::negativeMemoryAllocationSizeError(const Token* tok, con msg, CWE131, inconclusive ? Certainty::inconclusive : Certainty::normal); } -void CheckBufferOverrun::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckBufferOverrun::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { - CheckBufferOverrun checkBufferOverrun(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckBufferOverrunImpl checkBufferOverrun(&tokenizer, tokenizer.getSettings(), errorLogger); checkBufferOverrun.arrayIndex(); checkBufferOverrun.pointerArithmetic(); checkBufferOverrun.bufferOverflow(); @@ -1235,9 +1257,9 @@ void CheckBufferOverrun::runChecks(const Tokenizer &tokenizer, ErrorLogger *erro checkBufferOverrun.negativeArraySize(); } -void CheckBufferOverrun::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const +void CheckBufferOverrun::getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const { - CheckBufferOverrun c(nullptr, settings, errorLogger); + CheckBufferOverrunImpl c(nullptr, settings, errorLogger); c.arrayIndexError(nullptr, std::vector(), std::vector()); c.pointerArithmeticError(nullptr, nullptr, nullptr); c.negativeIndexError(nullptr, std::vector(), std::vector()); diff --git a/lib/checkbufferoverrun.h b/lib/checkbufferoverrun.h index 9c6e1f0386d..b9b82c897e0 100644 --- a/lib/checkbufferoverrun.h +++ b/lib/checkbufferoverrun.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,6 +23,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include "ctu.h" @@ -60,22 +61,43 @@ namespace ValueFlow class CPPCHECKLIB CheckBufferOverrun : public Check { public: /** This constructor is used when registering the CheckClass */ - CheckBufferOverrun() : Check(myName()) {} + CheckBufferOverrun() : Check("Bounds checking") {} private: - /** This constructor is used when running checks. */ - CheckBufferOverrun(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} - - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; - - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; /** @brief Parse current TU and extract file info */ - Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings &settings, const std::string& /*currentConfig*/) const override; + const Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings &settings, const std::string& /*currentConfig*/) const override; /** @brief Analyse all file infos for all TU */ - bool analyseWholeProgram(const CTU::FileInfo &ctu, const std::list &fileInfo, const Settings& settings, ErrorLogger &errorLogger) override; + bool analyseWholeProgram(const CTU::FileInfo &ctu, const std::list &fileInfo, const Settings& settings, ErrorLogger &errorLogger) override; + + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; + + const Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement, const std::string& file0) const override; + + std::string classInfo() const override { + return "Out of bounds checking:\n" + "- Array index out of bounds\n" + "- Pointer arithmetic overflow\n" + "- Buffer overflow\n" + "- Dangerous usage of strncat()\n" + "- Using array index before checking it\n" + "- Partial string write that leads to buffer that is not zero terminated.\n" + "- Check for large enough arrays being passed to functions\n" + "- Allocating memory with a negative size\n"; + } + + static bool analyseWholeProgram1(const std::map> &callsMap, const CTU::FileInfo::UnsafeUsage &unsafeUsage, + int type, ErrorLogger &errorLogger, int maxCtuDepth, const std::string& file0); +}; + +class CPPCHECKLIB CheckBufferOverrunImpl : public CheckImpl +{ +public: + /** This constructor is used when running checks. */ + CheckBufferOverrunImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} void arrayIndex(); void arrayIndexError(const Token* tok, @@ -107,33 +129,12 @@ class CPPCHECKLIB CheckBufferOverrun : public Check { void objectIndex(); void objectIndexError(const Token *tok, const ValueFlow::Value *v, bool known); - ValueFlow::Value getBufferSize(const Token *bufTok) const; + ValueFlow::Value getBufferSize(const Token *bufTok, const Settings& settings) const; // CTU static bool isCtuUnsafeBufferUsage(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset, int type); static bool isCtuUnsafeArrayIndex(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset); static bool isCtuUnsafePointerArith(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset); - - Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override; - static bool analyseWholeProgram1(const std::map> &callsMap, const CTU::FileInfo::UnsafeUsage &unsafeUsage, - int type, ErrorLogger &errorLogger, int maxCtuDepth, const std::string& file0); - - - static std::string myName() { - return "Bounds checking"; - } - - std::string classInfo() const override { - return "Out of bounds checking:\n" - "- Array index out of bounds\n" - "- Pointer arithmetic overflow\n" - "- Buffer overflow\n" - "- Dangerous usage of strncat()\n" - "- Using array index before checking it\n" - "- Partial string write that leads to buffer that is not zero terminated.\n" - "- Check for large enough arrays being passed to functions\n" - "- Allocating memory with a negative size\n"; - } }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 9fc9bdc7863..51d5718159f 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -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 @@ -111,12 +106,12 @@ static bool isVclTypeInit(const Type *type) } //--------------------------------------------------------------------------- -CheckClass::CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger), +CheckClassImpl::CheckClassImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger), mSymbolDatabase(tokenizer?tokenizer->getSymbolDatabase():nullptr) {} -bool CheckClass::isInitialized(const CheckClass::Usage& usage, FunctionType funcType) const +bool CheckClassImpl::isInitialized(const Usage& usage, FunctionType funcType) const { const Variable& var = *usage.var; @@ -145,7 +140,7 @@ bool CheckClass::isInitialized(const CheckClass::Usage& usage, FunctionType func 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 + !mSettings.library.podtype(ctt->str())) // TODO: handle complex type expression return true; } else @@ -175,7 +170,7 @@ bool CheckClass::isInitialized(const CheckClass::Usage& usage, FunctionType func return false; } -void CheckClass::handleUnionMembers(std::vector& usageList) +void CheckClassImpl::handleUnionMembers(std::vector& usageList) { // Assign 1 union member => assign all union members for (const Usage& usage : usageList) { @@ -204,18 +199,18 @@ void CheckClass::handleUnionMembers(std::vector& usageList) // ClassCheck: Check that all class constructors are ok. //--------------------------------------------------------------------------- -void CheckClass::constructors() +void CheckClassImpl::constructors() { - const bool printStyle = mSettings->severity.isEnabled(Severity::style); - const bool printWarnings = mSettings->severity.isEnabled(Severity::warning); - if (!printStyle && !printWarnings && !mSettings->isPremiumEnabled("uninitMemberVar")) + const bool printStyle = mSettings.severity.isEnabled(Severity::style); + const bool printWarnings = mSettings.severity.isEnabled(Severity::warning); + if (!printStyle && !printWarnings && !mSettings.isPremiumEnabled("uninitMemberVar")) return; logChecker("CheckClass::checkConstructors"); // style,warning - const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive); + const bool printInconclusive = mSettings.certainty.isEnabled(Certainty::inconclusive); for (const Scope * scope : mSymbolDatabase->classAndStructScopes) { - if (mSettings->hasLib("vcl") && isVclTypeInit(scope->definedType)) + if (mSettings.hasLib("vcl") && isVclTypeInit(scope->definedType)) continue; const bool unusedTemplate = Token::simpleMatch(scope->classDef->previous(), ">"); @@ -320,9 +315,9 @@ void CheckClass::constructors() } } - if (classNameUsed && mSettings->library.getTypeCheck("operatorEqVarError", var.getTypeName()) != Library::TypeCheck::suppress) + if (classNameUsed && mSettings.library.getTypeCheck("operatorEqVarError", var.getTypeName()) != Library::TypeCheck::suppress) operatorEqVarError(func.token, scope->className, var.name(), missingCopy); - } else if (func.access != AccessControl::Private || mSettings->standards.cpp >= Standards::CPP11) { + } else if (func.access != AccessControl::Private || mSettings.standards.cpp >= Standards::CPP11) { // If constructor is not in scope then we maybe using a constructor from a different template specialization if (!precedes(scope->bodyStart, func.tokenDef)) continue; @@ -351,6 +346,8 @@ void CheckClass::constructors() // 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; @@ -358,9 +355,11 @@ void CheckClass::constructors() if (var.hasDefault()) { usage.init = true; hasAnyDefaultInit = true; + } else if (cpp14OrLater && !hasAnySelfInit && isInitialized(usage, FunctionType::eConstructor)) { + hasAnySelfInit = true; } } - if (!hasAnyDefaultInit) + if (!hasAnyDefaultInit && !hasAnySelfInit) continue; handleUnionMembers(usageList); @@ -371,8 +370,11 @@ void CheckClass::constructors() continue; const Variable& var = *usage.var; + if (var.typeScope() && var.typeScope()->numConstructors > 0) + continue; + if (diagVars.count(&var) == 0) - uninitVarError(scope->bodyStart, false, FunctionType::eConstructor, var.scope()->className, var.name(), false, false, true); + uninitVarError(var.nameToken(), false, FunctionType::eConstructor, var.scope()->className, var.name(), false, false, true); } } } @@ -383,9 +385,9 @@ static bool isPermissibleConversion(const std::string& type) return type == "std::initializer_list" || type == "std::nullptr_t"; } -void CheckClass::checkExplicitConstructors() +void CheckClassImpl::checkExplicitConstructors() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("noExplicitConstructor")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("noExplicitConstructor")) return; logChecker("CheckClass::checkExplicitConstructors"); // style @@ -403,7 +405,7 @@ void CheckClass::checkExplicitConstructors() // Abstract classes can't be instantiated. But if there is C++11 // "misuse" by derived classes then these constructors must be explicit. - if (isAbstractClass && mSettings->standards.cpp >= Standards::CPP11) + if (isAbstractClass && mSettings.standards.cpp >= Standards::CPP11) continue; for (const Function &func : scope->functionList) { @@ -452,9 +454,9 @@ static bool hasNonCopyableBase(const Scope *scope, bool *unknown) return false; } -void CheckClass::copyconstructors() +void CheckClassImpl::copyconstructors() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckClass::checkCopyConstructors"); // warning @@ -469,7 +471,7 @@ void CheckClass::copyconstructors() const Token* tok = func.token->linkAt(1); for (const Token* const end = func.functionScope->bodyStart; tok != end; tok = tok->next()) { if (Token::Match(tok, "%var% ( new") || - (Token::Match(tok, "%var% ( %name% (") && mSettings->library.getAllocFuncInfo(tok->tokAt(2)))) { + (Token::Match(tok, "%var% ( %name% (") && mSettings.library.getAllocFuncInfo(tok->tokAt(2)))) { const Variable* var = tok->variable(); if (var && var->isPointer() && var->scope() == scope) allocatedVars[tok->varId()] = tok; @@ -477,7 +479,7 @@ void CheckClass::copyconstructors() } for (const Token* const end = func.functionScope->bodyEnd; tok != end; tok = tok->next()) { if (Token::Match(tok, "%var% = new") || - (Token::Match(tok, "%var% = %name% (") && mSettings->library.getAllocFuncInfo(tok->tokAt(2)))) { + (Token::Match(tok, "%var% = %name% (") && mSettings.library.getAllocFuncInfo(tok->tokAt(2)))) { const Variable* var = tok->variable(); if (var && var->isPointer() && var->scope() == scope && !var->isStatic()) allocatedVars[tok->varId()] = tok; @@ -488,7 +490,7 @@ void CheckClass::copyconstructors() const Token* tok = func.functionScope->bodyStart; for (const Token* const end = func.functionScope->bodyEnd; tok != end; tok = tok->next()) { if (Token::Match(tok, "delete %var%") || - (Token::Match(tok, "%name% ( %var%") && mSettings->library.getDeallocFuncInfo(tok))) { + (Token::Match(tok, "%name% ( %var%") && mSettings.library.getDeallocFuncInfo(tok))) { const Token *vartok = tok->str() == "delete" ? tok->next() : tok->tokAt(2); const Variable* var = vartok->variable(); if (var && var->isPointer() && var->scope() == scope && !var->isStatic()) @@ -578,7 +580,7 @@ void CheckClass::copyconstructors() } for (tok = func.functionScope->bodyStart; tok != func.functionScope->bodyEnd; tok = tok->next()) { if ((tok->isCpp() && Token::Match(tok, "%var% = new")) || - (Token::Match(tok, "%var% = %name% (") && (mSettings->library.getAllocFuncInfo(tok->tokAt(2)) || mSettings->library.getReallocFuncInfo(tok->tokAt(2))))) { + (Token::Match(tok, "%var% = %name% (") && (mSettings.library.getAllocFuncInfo(tok->tokAt(2)) || mSettings.library.getReallocFuncInfo(tok->tokAt(2))))) { allocatedVars.erase(tok->varId()); } else if (Token::Match(tok, "%var% = %name% . %name% ;") && allocatedVars.find(tok->varId()) != allocatedVars.end()) { copiedVars.insert(tok); @@ -609,7 +611,7 @@ void CheckClass::copyconstructors() } */ -void CheckClass::copyConstructorShallowCopyError(const Token *tok, const std::string& varname) +void CheckClassImpl::copyConstructorShallowCopyError(const Token *tok, const std::string& varname) { reportError(tok, Severity::warning, "copyCtorPointerCopying", "$symbol:" + varname + "\nValue of pointer '$symbol', which points to allocated memory, is copied in copy constructor instead of allocating new memory.", CWE398, Certainty::normal); @@ -635,22 +637,22 @@ static std::string noMemberErrorMessage(const Scope *scope, const char function[ return errmsg; } -void CheckClass::noCopyConstructorError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive) +void CheckClassImpl::noCopyConstructorError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive) { reportError(alloc, Severity::warning, "noCopyConstructor", noMemberErrorMessage(scope, "copy constructor", isdefault), CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal); } -void CheckClass::noOperatorEqError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive) +void CheckClassImpl::noOperatorEqError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive) { reportError(alloc, Severity::warning, "noOperatorEq", noMemberErrorMessage(scope, "operator=", isdefault), CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal); } -void CheckClass::noDestructorError(const Scope *scope, bool isdefault, const Token *alloc) +void CheckClassImpl::noDestructorError(const Scope *scope, bool isdefault, const Token *alloc) { reportError(alloc, Severity::warning, "noDestructor", noMemberErrorMessage(scope, "destructor", isdefault), CWE398, Certainty::normal); } -bool CheckClass::canNotCopy(const Scope *scope) +bool CheckClassImpl::canNotCopy(const Scope *scope) { bool constructor = false; bool publicAssign = false; @@ -674,7 +676,7 @@ bool CheckClass::canNotCopy(const Scope *scope) return constructor && !(publicAssign || publicCopy); } -bool CheckClass::canNotMove(const Scope *scope) +bool CheckClassImpl::canNotMove(const Scope *scope) { bool constructor = false; bool publicAssign = false; @@ -719,7 +721,7 @@ static void getAllVariableMembers(const Scope *scope, std::vector CheckClass::createUsageList(const Scope *scope) +std::vector CheckClassImpl::createUsageList(const Scope *scope) { std::vector ret; std::vector varlist; @@ -731,7 +733,7 @@ std::vector CheckClass::createUsageList(const Scope *scope) return ret; } -void CheckClass::assignVar(std::vector &usageList, nonneg int varid) +void CheckClassImpl::assignVar(std::vector &usageList, nonneg int varid) { auto it = std::find_if(usageList.begin(), usageList.end(), [varid](const Usage& usage) { return usage.var->declarationId() == varid; @@ -740,7 +742,7 @@ void CheckClass::assignVar(std::vector &usageList, nonneg int varid) it->assign = true; } -void CheckClass::assignVar(std::vector &usageList, const Token* vartok) +void CheckClassImpl::assignVar(std::vector &usageList, const Token* vartok) { if (vartok->varId() > 0) { assignVar(usageList, vartok->varId()); @@ -754,7 +756,7 @@ void CheckClass::assignVar(std::vector &usageList, const Token* vartok) it->assign = true; } -void CheckClass::initVar(std::vector &usageList, nonneg int varid) +void CheckClassImpl::initVar(std::vector &usageList, nonneg int varid) { auto it = std::find_if(usageList.begin(), usageList.end(), [varid](const Usage& usage) { return usage.var->declarationId() == varid; @@ -763,13 +765,13 @@ void CheckClass::initVar(std::vector &usageList, nonneg int varid) it->init = true; } -void CheckClass::assignAllVar(std::vector &usageList) +void CheckClassImpl::assignAllVar(std::vector &usageList) { for (Usage & i : usageList) i.assign = true; } -void CheckClass::assignAllVarsVisibleFromScope(std::vector& usageList, const Scope* scope) +void CheckClassImpl::assignAllVarsVisibleFromScope(std::vector& usageList, const Scope* scope) { for (Usage& usage : usageList) { if (usage.var->scope() == scope) @@ -785,7 +787,7 @@ void CheckClass::assignAllVarsVisibleFromScope(std::vector& usageList, co } } -void CheckClass::clearAllVar(std::vector &usageList) +void CheckClassImpl::clearAllVar(std::vector &usageList) { for (Usage & i : usageList) { i.assign = false; @@ -793,7 +795,7 @@ void CheckClass::clearAllVar(std::vector &usageList) } } -bool CheckClass::isBaseClassMutableMemberFunc(const Token *tok, const Scope *scope) +bool CheckClassImpl::isBaseClassMutableMemberFunc(const Token *tok, const Scope *scope) { // Iterate through each base class... for (const Type::BaseInfo & i : scope->definedType->derivedFrom) { @@ -820,7 +822,7 @@ bool CheckClass::isBaseClassMutableMemberFunc(const Token *tok, const Scope *sco return false; } -void CheckClass::initializeVarList(const Function &func, std::list &callstack, const Scope *scope, std::vector &usage) const +void CheckClassImpl::initializeVarList(const Function &func, std::list &callstack, const Scope *scope, std::vector &usage) const { if (!func.functionScope) return; @@ -1057,7 +1059,7 @@ void CheckClass::initializeVarList(const Function &func, std::listnext(); if (tok2->str() == "&") tok2 = tok2->next(); - if (isVariableChangedByFunctionCall(tok2, tok2->strAt(-1) == "&", tok2->varId(), *mSettings, nullptr)) + if (isVariableChangedByFunctionCall(tok2, tok2->strAt(-1) == "&", tok2->varId(), mSettings.library, nullptr)) assignVar(usage, tok2->varId()); } } @@ -1152,7 +1154,7 @@ void CheckClass::initializeVarList(const Function &func, std::listseverity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedPrivateFunction")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("unusedPrivateFunction")) return; logChecker("CheckClass::privateFunctions"); // style @@ -1420,7 +1422,7 @@ void CheckClass::privateFunctions() } } -void CheckClass::unusedPrivateFunctionError(const Token* tok1, const Token *tok2, const std::string &classname, const std::string &funcname) +void CheckClassImpl::unusedPrivateFunctionError(const Token* tok1, const Token *tok2, const std::string &classname, const std::string &funcname) { std::list toks{ tok1 }; if (tok2) @@ -1442,10 +1444,10 @@ static const Scope* findFunctionOf(const Scope* scope) return nullptr; } -void CheckClass::checkMemset() +void CheckClassImpl::checkMemset() { logChecker("CheckClass::checkMemset"); - const bool printWarnings = mSettings->severity.isEnabled(Severity::warning); + const bool printWarnings = mSettings.severity.isEnabled(Severity::warning); for (const Scope *scope : mSymbolDatabase->functionScopes) { for (const Token *tok = scope->bodyStart; tok && tok != scope->bodyEnd; tok = tok->next()) { if (Token::Match(tok, "memset|memcpy|memmove (")) { @@ -1503,7 +1505,7 @@ void CheckClass::checkMemset() type = var->typeScope(); if (!type && !var->isPointer() && !Token::simpleMatch(var->typeStartToken(), "std :: array") && - mSettings->library.detectContainerOrIterator(var->typeStartToken())) { + mSettings.library.detectContainerOrIterator(var->typeStartToken())) { memsetError(tok, tok->str(), var->getTypeName(), {}, /*isContainer*/ true); } } @@ -1523,9 +1525,9 @@ void CheckClass::checkMemset() checkMemsetType(scope, tok, type, false, {}); } } else if (tok->variable() && tok->variable()->isPointer() && tok->variable()->typeScope() && Token::Match(tok, "%var% = %name% (")) { - const Library::AllocFunc* alloc = mSettings->library.getAllocFuncInfo(tok->tokAt(2)); + const Library::AllocFunc* alloc = mSettings.library.getAllocFuncInfo(tok->tokAt(2)); if (!alloc) - alloc = mSettings->library.getReallocFuncInfo(tok->tokAt(2)); + alloc = mSettings.library.getReallocFuncInfo(tok->tokAt(2)); if (!alloc || alloc->bufferSize == Library::AllocFunc::BufferSize::none) continue; std::set parsedTypes; @@ -1538,14 +1540,14 @@ void CheckClass::checkMemset() } } -void CheckClass::checkMemsetType(const Scope *start, const Token *tok, const Scope *type, bool allocation, std::set parsedTypes) +void CheckClassImpl::checkMemsetType(const Scope *start, const Token *tok, const Scope *type, bool allocation, std::set parsedTypes) { // If type has been checked there is no need to check it again if (parsedTypes.find(type) != parsedTypes.end()) return; parsedTypes.insert(type); - const bool printPortability = mSettings->severity.isEnabled(Severity::portability); + const bool printPortability = mSettings.severity.isEnabled(Severity::portability); // recursively check all parent classes for (const Type::BaseInfo & i : type->definedType->derivedFrom) { @@ -1586,7 +1588,7 @@ void CheckClass::checkMemsetType(const Scope *start, const Token *tok, const Sco } // check for std:: type - if (var.isStlType() && typeName != "std::array" && !mSettings->library.podtype(typeName)) { + if (var.isStlType() && typeName != "std::array" && !mSettings.library.podtype(typeName)) { if (allocation) mallocOnClassError(tok, tok->str(), type->classDef, "'" + typeName + "'"); else @@ -1604,7 +1606,7 @@ void CheckClass::checkMemsetType(const Scope *start, const Token *tok, const Sco } } -void CheckClass::mallocOnClassWarning(const Token* tok, const std::string &memfunc, const Token* classTok) +void CheckClassImpl::mallocOnClassWarning(const Token* tok, const std::string &memfunc, const Token* classTok) { std::list toks = { tok, classTok }; reportError(toks, Severity::warning, "mallocOnClassWarning", @@ -1614,7 +1616,7 @@ void CheckClass::mallocOnClassWarning(const Token* tok, const std::string &memfu "since no constructor is called and class members remain uninitialized. Consider using 'new' instead.", CWE762, Certainty::normal); } -void CheckClass::mallocOnClassError(const Token* tok, const std::string &memfunc, const Token* classTok, const std::string &classname) +void CheckClassImpl::mallocOnClassError(const Token* tok, const std::string &memfunc, const Token* classTok, const std::string &classname) { std::list toks = { tok, classTok }; reportError(toks, Severity::error, "mallocOnClassError", @@ -1625,7 +1627,7 @@ void CheckClass::mallocOnClassError(const Token* tok, const std::string &memfunc "since no constructor is called and class members remain uninitialized. Consider using 'new' instead.", CWE665, Certainty::normal); } -void CheckClass::memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type, bool isContainer) +void CheckClassImpl::memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type, bool isContainer) { const std::string typeStr = isContainer ? std::string() : (type + " that contains a "); const std::string msg = "$symbol:" + memfunc + "\n" @@ -1637,14 +1639,14 @@ void CheckClass::memsetError(const Token *tok, const std::string &memfunc, const reportError(tok, Severity::error, "memsetClass", msg, CWE762, Certainty::normal); } -void CheckClass::memsetErrorReference(const Token *tok, const std::string &memfunc, const std::string &type) +void CheckClassImpl::memsetErrorReference(const Token *tok, const std::string &memfunc, const std::string &type) { reportError(tok, Severity::error, "memsetClassReference", "$symbol:" + memfunc +"\n" "Using '" + memfunc + "' on " + type + " that contains a reference.", CWE665, Certainty::normal); } -void CheckClass::memsetErrorFloat(const Token *tok, const std::string &type) +void CheckClassImpl::memsetErrorFloat(const Token *tok, const std::string &type) { reportError(tok, Severity::portability, "memsetClassFloat", "Using memset() on " + type + " which contains a floating point number.\n" "Using memset() on " + type + " which contains a floating point number." @@ -1659,9 +1661,9 @@ void CheckClass::memsetErrorFloat(const Token *tok, const std::string &type) // operator= should return a reference to *this //--------------------------------------------------------------------------- -void CheckClass::operatorEqRetRefThis() +void CheckClassImpl::operatorEqRetRefThis() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("operatorEqRetRefThis")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("operatorEqRetRefThis")) return; logChecker("CheckClass::operatorEqRetRefThis"); // style @@ -1678,13 +1680,13 @@ void CheckClass::operatorEqRetRefThis() } } -void CheckClass::checkReturnPtrThis(const Scope *scope, const Function *func, const Token *tok, const Token *last) +void CheckClassImpl::checkReturnPtrThis(const Scope *scope, const Function *func, const Token *tok, const Token *last) { std::set analyzedFunctions; checkReturnPtrThis(scope, func, tok, last, analyzedFunctions); } -void CheckClass::checkReturnPtrThis(const Scope *scope, const Function *func, const Token *tok, const Token *last, std::set& analyzedFunctions) +void CheckClassImpl::checkReturnPtrThis(const Scope *scope, const Function *func, const Token *tok, const Token *last, std::set& analyzedFunctions) { bool foundReturn = false; @@ -1760,7 +1762,7 @@ void CheckClass::checkReturnPtrThis(const Scope *scope, const Function *func, co } return; } - if (mSettings->library.isScopeNoReturn(last, nullptr)) { + if (mSettings.library.isScopeNoReturn(last, nullptr)) { // Typical wrong way to prohibit default assignment operator // by always throwing an exception or calling a noreturn function operatorEqShouldBeLeftUnimplementedError(func->token); @@ -1770,17 +1772,17 @@ void CheckClass::checkReturnPtrThis(const Scope *scope, const Function *func, co operatorEqMissingReturnStatementError(func->token, func->access == AccessControl::Public); } -void CheckClass::operatorEqRetRefThisError(const Token *tok) +void CheckClassImpl::operatorEqRetRefThisError(const Token *tok) { reportError(tok, Severity::style, "operatorEqRetRefThis", "'operator=' should return reference to 'this' instance.", CWE398, Certainty::normal); } -void CheckClass::operatorEqShouldBeLeftUnimplementedError(const Token *tok) +void CheckClassImpl::operatorEqShouldBeLeftUnimplementedError(const Token *tok) { reportError(tok, Severity::style, "operatorEqShouldBeLeftUnimplemented", "'operator=' should either return reference to 'this' instance or be declared private and left unimplemented.", CWE398, Certainty::normal); } -void CheckClass::operatorEqMissingReturnStatementError(const Token *tok, bool error) +void CheckClassImpl::operatorEqMissingReturnStatementError(const Token *tok, bool error) { if (error) { reportError(tok, Severity::error, "operatorEqMissingReturnStatement", "No 'return' statement in non-void function causes undefined behavior.", CWE398, Certainty::normal); @@ -1803,9 +1805,9 @@ void CheckClass::operatorEqMissingReturnStatementError(const Token *tok, bool er // assignment to self. //--------------------------------------------------------------------------- -void CheckClass::operatorEqToSelf() +void CheckClassImpl::operatorEqToSelf() { - if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("operatorEqToSelf")) + if (!mSettings.severity.isEnabled(Severity::warning) && !mSettings.isPremiumEnabled("operatorEqToSelf")) return; logChecker("CheckClass::operatorEqToSelf"); // warning @@ -1844,7 +1846,7 @@ void CheckClass::operatorEqToSelf() } } -bool CheckClass::hasAllocationInIfScope(const Function *func, const Scope* scope, const Token *ifStatementScopeStart) const +bool CheckClassImpl::hasAllocationInIfScope(const Function *func, const Scope* scope, const Token *ifStatementScopeStart) const { const Token *end; if (ifStatementScopeStart->str() == "{") @@ -1854,24 +1856,24 @@ bool CheckClass::hasAllocationInIfScope(const Function *func, const Scope* scope return hasAllocation(func, scope, ifStatementScopeStart, end); } -bool CheckClass::hasAllocation(const Function *func, const Scope* scope) const +bool CheckClassImpl::hasAllocation(const Function *func, const Scope* scope) const { return hasAllocation(func, scope, func->functionScope->bodyStart, func->functionScope->bodyEnd); } -bool CheckClass::hasAllocation(const Function *func, const Scope* scope, const Token *start, const Token *end) const +bool CheckClassImpl::hasAllocation(const Function *func, const Scope* scope, const Token *start, const Token *end) const { if (!end) end = func->functionScope->bodyEnd; for (const Token *tok = start; tok && (tok != end); tok = tok->next()) { if (((tok->isCpp() && Token::Match(tok, "%var% = new")) || - (Token::Match(tok, "%var% = %name% (") && mSettings->library.getAllocFuncInfo(tok->tokAt(2)))) && + (Token::Match(tok, "%var% = %name% (") && mSettings.library.getAllocFuncInfo(tok->tokAt(2)))) && isMemberVar(scope, tok)) return true; // check for deallocating memory const Token *var; - if (Token::Match(tok, "%name% ( %var%") && mSettings->library.getDeallocFuncInfo(tok)) + if (Token::Match(tok, "%name% ( %var%") && mSettings.library.getDeallocFuncInfo(tok)) var = tok->tokAt(2); else if (tok->isCpp() && Token::Match(tok, "delete [ ] %var%")) var = tok->tokAt(3); @@ -1905,7 +1907,7 @@ static bool isFalseKeyword(const Token* tok) * Checks if self-assignment test is inverse * For example 'if (this == &rhs)' */ -CheckClass::Bool CheckClass::isInverted(const Token *tok, const Token *rhs) +CheckClassImpl::Bool CheckClassImpl::isInverted(const Token *tok, const Token *rhs) { bool res = true; for (const Token *itr = tok; itr && itr->str()!="("; itr=itr->astParent()) { @@ -1934,7 +1936,7 @@ CheckClass::Bool CheckClass::isInverted(const Token *tok, const Token *rhs) return Bool::False; } -const Token * CheckClass::getIfStmtBodyStart(const Token *tok, const Token *rhs) +const Token * CheckClassImpl::getIfStmtBodyStart(const Token *tok, const Token *rhs) { const Token *top = tok->astTop(); if (Token::simpleMatch(top->link(), ") {")) { @@ -1950,7 +1952,7 @@ const Token * CheckClass::getIfStmtBodyStart(const Token *tok, const Token *rhs) return nullptr; } -bool CheckClass::hasAssignSelf(const Function *func, const Token *rhs, const Token *&out_ifStatementScopeStart) +bool CheckClassImpl::hasAssignSelf(const Function *func, const Token *rhs, const Token *&out_ifStatementScopeStart) { if (!rhs) return false; @@ -1984,7 +1986,7 @@ bool CheckClass::hasAssignSelf(const Function *func, const Token *rhs, const Tok return false; } -void CheckClass::operatorEqToSelfError(const Token *tok) +void CheckClassImpl::operatorEqToSelfError(const Token *tok) { reportError(tok, Severity::warning, "operatorEqToSelf", "'operator=' should check for assignment to self to avoid problems with dynamic memory.\n" @@ -1996,7 +1998,7 @@ void CheckClass::operatorEqToSelfError(const Token *tok) // A destructor in a base class should be virtual //--------------------------------------------------------------------------- -void CheckClass::virtualDestructor() +void CheckClassImpl::virtualDestructor() { // This error should only be given if: // * base class doesn't have virtual destructor @@ -2004,7 +2006,7 @@ void CheckClass::virtualDestructor() // * base class is deleted // unless inconclusive in which case: // * A class with any virtual functions should have a destructor that is either public and virtual or protected - const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive); + const bool printInconclusive = mSettings.certainty.isEnabled(Certainty::inconclusive); std::list inconclusiveErrors; @@ -2027,7 +2029,7 @@ void CheckClass::virtualDestructor() } // Check if destructor is empty and non-empty .. - if (mSettings->standards.cpp <= Standards::CPP03) { + if (mSettings.standards.cpp <= Standards::CPP03) { // Find the destructor const Function *destructor = scope->getDestructor(); @@ -2131,10 +2133,10 @@ void CheckClass::virtualDestructor() virtualDestructorError(func->tokenDef, func->name(), "", true); } -void CheckClass::virtualDestructorError(const Token *tok, const std::string &Base, const std::string &Derived, bool inconclusive) +void CheckClassImpl::virtualDestructorError(const Token *tok, const std::string &Base, const std::string &Derived, bool inconclusive) { if (inconclusive) { - if (mSettings->severity.isEnabled(Severity::warning)) + if (mSettings.severity.isEnabled(Severity::warning)) reportError(tok, Severity::warning, "virtualDestructor", "$symbol:" + Base + "\nClass '$symbol' which has virtual members does not have a virtual destructor.", CWE404, Certainty::inconclusive); } else { reportError(tok, Severity::error, "virtualDestructor", @@ -2152,9 +2154,9 @@ void CheckClass::virtualDestructorError(const Token *tok, const std::string &Bas // warn for "this-x". The indented code may be "this->x" //--------------------------------------------------------------------------- -void CheckClass::thisSubtraction() +void CheckClassImpl::thisSubtraction() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckClass::thisSubtraction"); // warning @@ -2172,7 +2174,7 @@ void CheckClass::thisSubtraction() } } -void CheckClass::thisSubtractionError(const Token *tok) +void CheckClassImpl::thisSubtractionError(const Token *tok) { reportError(tok, Severity::warning, "thisSubtraction", "Suspicious pointer subtraction. Did you intend to write '->'?", CWE398, Certainty::normal); } @@ -2181,11 +2183,11 @@ void CheckClass::thisSubtractionError(const Token *tok) // can member function be const? //--------------------------------------------------------------------------- -void CheckClass::checkConst() +void CheckClassImpl::checkConst() { - if (!mSettings->severity.isEnabled(Severity::style) && - !mSettings->isPremiumEnabled("functionConst") && - !mSettings->isPremiumEnabled("functionStatic")) + if (!mSettings.severity.isEnabled(Severity::style) && + !mSettings.isPremiumEnabled("functionConst") && + !mSettings.isPremiumEnabled("functionStatic")) return; logChecker("CheckClass::checkConst"); // style,inconclusive @@ -2246,7 +2248,7 @@ void CheckClass::checkConst() const std::string& opName = func.tokenDef->str(); if (opName.compare(8, 5, "const") != 0 && (endsWith(opName,'&') || endsWith(opName,'*'))) continue; - } else if (mSettings->library.isSmartPointer(func.retDef)) { + } else if (mSettings.library.isSmartPointer(func.retDef)) { // Don't warn if a std::shared_ptr etc is returned continue; } else { @@ -2269,7 +2271,7 @@ void CheckClass::checkConst() const bool suggestStatic = memberAccessed != MemberAccess::MEMBER && !func.isOperator(); if ((returnsPtrOrRef || func.isConst() || func.hasLvalRefQualifier()) && !suggestStatic) continue; - if (!suggestStatic && !mSettings->certainty.isEnabled(Certainty::inconclusive)) + if (!suggestStatic && !mSettings.certainty.isEnabled(Certainty::inconclusive)) // functionConst is inconclusive. False positives: #3322. continue; if (suggestStatic && func.isConst()) { @@ -2317,7 +2319,7 @@ static const Token* getFuncTokFromThis(const Token* tok) { return Token::Match(tok, "%name% (") ? tok : nullptr; } -bool CheckClass::isMemberVar(const Scope *scope, const Token *tok) const +bool CheckClassImpl::isMemberVar(const Scope *scope, const Token *tok) const { bool again = false; @@ -2404,7 +2406,7 @@ bool CheckClass::isMemberVar(const Scope *scope, const Token *tok) const return false; } -bool CheckClass::isMemberFunc(const Scope *scope, const Token *tok) +bool CheckClassImpl::isMemberFunc(const Scope *scope, const Token *tok) { if (!tok->function()) { if (Token::simpleMatch(tok->astParent(), ".") && Token::simpleMatch(tok->astParent()->astOperand1(), "this")) @@ -2412,7 +2414,7 @@ bool CheckClass::isMemberFunc(const Scope *scope, const Token *tok) for (const Function &func : scope->functionList) { if (func.name() == tok->str()) { const Token* tok2 = tok->tokAt(2); - int argsPassed = tok2->str() == ")" ? 0 : 1; + size_t argsPassed = tok2->str() == ")" ? 0 : 1; for (;;) { tok2 = tok2->nextArgument(); if (tok2) @@ -2447,7 +2449,7 @@ bool CheckClass::isMemberFunc(const Scope *scope, const Token *tok) return false; } -bool CheckClass::isConstMemberFunc(const Scope *scope, const Token *tok) +bool CheckClassImpl::isConstMemberFunc(const Scope *scope, const Token *tok) { if (!tok->function()) return false; @@ -2472,7 +2474,7 @@ bool CheckClass::isConstMemberFunc(const Scope *scope, const Token *tok) return false; } -const std::set CheckClass::stl_containers_not_const = { "map", "unordered_map", "std :: map|unordered_map <" }; // start pattern +const std::set CheckClassImpl::stl_containers_not_const = { "map", "unordered_map", "std :: map|unordered_map <" }; // start pattern static bool isNonConstPtrCast(const Token* tok) { @@ -2482,7 +2484,7 @@ static bool isNonConstPtrCast(const Token* tok) return !vt || (vt->pointer > 0 && !vt->isConst(vt->pointer)); } -bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, MemberAccess& memberAccessed) const +bool CheckClassImpl::checkConstFunc(const Scope *scope, const Function *func, MemberAccess& memberAccessed) const { if (mTokenizer->hasIfdef(func->functionScope->bodyStart, func->functionScope->bodyEnd)) return false; @@ -2509,9 +2511,9 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, Member if (const Function* f = funcTok->function()) { // check known function const std::vector args = getArguments(funcTok); - const auto argMax = std::min(args.size(), f->argCount()); + const auto argMax = std::min(args.size(), f->argCount()); - for (nonneg int argIndex = 0; argIndex < argMax; ++argIndex) { + for (size_t argIndex = 0; argIndex < argMax; ++argIndex) { const Variable* const argVar = f->getArgumentVar(argIndex); if (!argVar || ((argVar->isArrayOrPointer() || argVar->isReference()) && !(argVar->valueType() && argVar->valueType()->isConst(argVar->valueType()->pointer)))) { // argument might be modified @@ -2533,7 +2535,7 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, Member return true; } - if (const Library::Function* fLib = mSettings->library.getFunction(funcTok)) + if (const Library::Function* fLib = mSettings.library.getFunction(funcTok)) if (fLib->isconst || fLib->ispure) return true; @@ -2606,9 +2608,12 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, Member return false; } else { if (lhs->isAssignmentOp()) { - const Variable* lhsVar = lhs->previous()->variable(); - if (lhsVar && !lhsVar->isConst() && lhsVar->isReference() && lhs == lhsVar->nameToken()->next()) - return false; + if (const Variable* lhsVar = lhs->previous()->variable()) { + if (!lhsVar->isConst() && lhsVar->isReference() && lhs == lhsVar->nameToken()->next()) + return false; + if (lhsVar->isPointer() && v && v->isArray() && !(lhsVar->valueType() && lhsVar->valueType()->isConst(/*indirect*/ 1))) + return false; + } } } @@ -2694,12 +2699,12 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, Member } else if (var->smartPointerType() && var->smartPointerType()->classScope && isConstMemberFunc(var->smartPointerType()->classScope, end)) { // empty body - } else if (var->isSmartPointer() && Token::simpleMatch(tok1->next(), ".") && tok1->next()->originalName().empty() && mSettings->library.isFunctionConst(end)) { + } else if (var->isSmartPointer() && Token::simpleMatch(tok1->next(), ".") && tok1->next()->originalName().empty() && mSettings.library.isFunctionConst(end)) { // empty body } else if (hasOverloadedMemberAccess(end, var->typeScope())) { // empty body } else if (!var->typeScope() || (end->function() != func && !isConstMemberFunc(var->typeScope(), end))) { - if (!mSettings->library.isFunctionConst(end)) + if (!mSettings.library.isFunctionConst(end)) return false; } } @@ -2756,12 +2761,12 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, Member return true; } -void CheckClass::checkConstError(const Token *tok, const std::string &classname, const std::string &funcname, bool suggestStatic, bool foundAllBaseClasses) +void CheckClassImpl::checkConstError(const Token *tok, const std::string &classname, const std::string &funcname, bool suggestStatic, bool foundAllBaseClasses) { checkConstError2(tok, nullptr, classname, funcname, suggestStatic, foundAllBaseClasses); } -void CheckClass::checkConstError2(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &funcname, bool suggestStatic, bool foundAllBaseClasses) +void CheckClassImpl::checkConstError2(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &funcname, bool suggestStatic, bool foundAllBaseClasses) { std::list toks{ tok1 }; if (tok2) @@ -2802,17 +2807,17 @@ namespace { // avoid one-definition-rule violation }; } -void CheckClass::initializerListOrder() +void CheckClassImpl::initializerListOrder() { - if (!mSettings->isPremiumEnabled("initializerList")) { - if (!mSettings->severity.isEnabled(Severity::style)) + 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)) + if (!mSettings.certainty.isEnabled(Certainty::inconclusive)) return; } @@ -2881,7 +2886,7 @@ void CheckClass::initializerListOrder() } } -void CheckClass::initializerListError(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &varname, const std::string& argname) +void CheckClassImpl::initializerListError(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &varname, const std::string& argname) { std::list toks = { tok1, tok2 }; const std::string msg = argname.empty() ? @@ -2902,7 +2907,7 @@ void CheckClass::initializerListError(const Token *tok1, const Token *tok2, cons // Check for self initialization in initialization list //--------------------------------------------------------------------------- -void CheckClass::checkSelfInitialization() +void CheckClassImpl::checkSelfInitialization() { logChecker("CheckClass::checkSelfInitialization"); @@ -2931,7 +2936,7 @@ void CheckClass::checkSelfInitialization() } } -void CheckClass::selfInitializationError(const Token* tok, const std::string& varname) +void CheckClassImpl::selfInitializationError(const Token* tok, const std::string& varname) { reportError(tok, Severity::error, "selfInitialization", "$symbol:" + varname + "\nMember variable '$symbol' is initialized by itself.", CWE665, Certainty::normal); } @@ -2941,9 +2946,9 @@ void CheckClass::selfInitializationError(const Token* tok, const std::string& va // Check for virtual function calls in constructor/destructor //--------------------------------------------------------------------------- -void CheckClass::checkVirtualFunctionCallInConstructor() +void CheckClassImpl::checkVirtualFunctionCallInConstructor() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckClass::checkVirtualFunctionCallInConstructor"); // warning std::map> virtualFunctionCallsMap; @@ -2971,8 +2976,8 @@ void CheckClass::checkVirtualFunctionCallInConstructor() } } -const std::list & CheckClass::getVirtualFunctionCalls(const Function & function, - std::map> & virtualFunctionCallsMap) +const std::list & CheckClassImpl::getVirtualFunctionCalls(const Function & function, + std::map> & virtualFunctionCallsMap) { const auto found = utils::as_const(virtualFunctionCallsMap).find(&function); if (found != virtualFunctionCallsMap.end()) @@ -3010,8 +3015,8 @@ const std::list & CheckClass::getVirtualFunctionCalls(const Funct tok->strAt(-1) == "(") { const Token * prev = tok->previous(); if (prev->previous() && - (mSettings->library.ignorefunction(tok->str()) - || mSettings->library.ignorefunction(prev->strAt(-1)))) + (mSettings.library.ignorefunction(tok->str()) + || mSettings.library.ignorefunction(prev->strAt(-1)))) continue; } @@ -3029,7 +3034,7 @@ const std::list & CheckClass::getVirtualFunctionCalls(const Funct return virtualFunctionCalls; } -void CheckClass::getFirstVirtualFunctionCallStack( +void CheckClassImpl::getFirstVirtualFunctionCallStack( std::map> & virtualFunctionCallsMap, const Token * callToken, std::list & pureFuncStack) @@ -3049,12 +3054,12 @@ void CheckClass::getFirstVirtualFunctionCallStack( getFirstVirtualFunctionCallStack(virtualFunctionCallsMap, firstCall, pureFuncStack); } -void CheckClass::virtualFunctionCallInConstructorError( +void CheckClassImpl::virtualFunctionCallInConstructorError( const Function * scopeFunction, const std::list & tokStack, const std::string &funcname) { - if (scopeFunction && !mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("virtualCallInConstructor")) + if (scopeFunction && !mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("virtualCallInConstructor")) return; const char * scopeFunctionTypeName = scopeFunction ? getFunctionTypeName(scopeFunction->type) : "constructor"; @@ -3087,7 +3092,7 @@ void CheckClass::virtualFunctionCallInConstructorError( "Virtual function '" + funcname + "' is called from " + scopeFunctionTypeName + " '" + constructorName + "' at line " + std::to_string(lineNumber) + ". Dynamic binding is not used.", CWE(0U), Certainty::normal); } -void CheckClass::pureVirtualFunctionCallInConstructorError( +void CheckClassImpl::pureVirtualFunctionCallInConstructorError( const Function * scopeFunction, const std::list & tokStack, const std::string &purefuncname) @@ -3112,9 +3117,9 @@ void CheckClass::pureVirtualFunctionCallInConstructorError( // Check for members hiding inherited members with the same name //--------------------------------------------------------------------------- -void CheckClass::checkDuplInheritedMembers() +void CheckClassImpl::checkDuplInheritedMembers() { - if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("duplInheritedMember")) + if (!mSettings.severity.isEnabled(Severity::warning) && !mSettings.isPremiumEnabled("duplInheritedMember")) return; logChecker("CheckClass::checkDuplInheritedMembers"); // warning @@ -3201,7 +3206,7 @@ static std::vector getDuplInheritedMemberFunctionsRecursive( return results; } -void CheckClass::checkDuplInheritedMembersRecursive(const Type* typeCurrent, const Type* typeBase) +void CheckClassImpl::checkDuplInheritedMembersRecursive(const Type* typeCurrent, const Type* typeBase) { const auto resultsVar = getDuplInheritedMembersRecursive(typeCurrent, typeBase); for (const auto& r : resultsVar) { @@ -3220,9 +3225,9 @@ void CheckClass::checkDuplInheritedMembersRecursive(const Type* typeCurrent, con } } -void CheckClass::duplInheritedMembersError(const Token *tok1, const Token* tok2, - const std::string &derivedName, const std::string &baseName, - const std::string &memberName, bool derivedIsStruct, bool baseIsStruct, bool isFunction) +void CheckClassImpl::duplInheritedMembersError(const Token *tok1, const Token* tok2, + const std::string &derivedName, const std::string &baseName, + const std::string &memberName, bool derivedIsStruct, bool baseIsStruct, bool isFunction) { ErrorPath errorPath; const std::string member = isFunction ? "function" : "variable"; @@ -3248,11 +3253,11 @@ enum class CtorType : std::uint8_t { WITH_BODY }; -void CheckClass::checkCopyCtorAndEqOperator() +void CheckClassImpl::checkCopyCtorAndEqOperator() { // TODO: This is disabled because of #8388 // The message must be clarified. How is the behaviour different? - if ((true) || !mSettings->severity.isEnabled(Severity::warning)) // NOLINT(readability-simplify-boolean-expr,readability-redundant-parentheses) + if ((true) || !mSettings.severity.isEnabled(Severity::warning)) // NOLINT(readability-simplify-boolean-expr,readability-redundant-parentheses) return; // logChecker @@ -3300,7 +3305,7 @@ void CheckClass::checkCopyCtorAndEqOperator() } } -void CheckClass::copyCtorAndEqOperatorError(const Token *tok, const std::string &classname, bool isStruct, bool hasCopyCtor) +void CheckClassImpl::copyCtorAndEqOperatorError(const Token *tok, const std::string &classname, bool isStruct, bool hasCopyCtor) { const std::string message = "$symbol:" + classname + "\n" "The " + std::string(isStruct ? "struct" : "class") + " '$symbol' has '" + @@ -3310,11 +3315,11 @@ void CheckClass::copyCtorAndEqOperatorError(const Token *tok, const std::string reportError(tok, Severity::warning, "copyCtorAndEqOperator", message); } -void CheckClass::checkOverride() +void CheckClassImpl::checkOverride() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("missingOverride")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("missingOverride")) return; - if (mSettings->standards.cpp < Standards::CPP11) + if (mSettings.standards.cpp < Standards::CPP11) return; logChecker("CheckClass::checkMissingOverride"); // style,c++03 for (const Scope * classScope : mSymbolDatabase->classAndStructScopes) { @@ -3334,7 +3339,7 @@ void CheckClass::checkOverride() } } -void CheckClass::overrideError(const Function *funcInBase, const Function *funcInDerived) +void CheckClassImpl::overrideError(const Function *funcInBase, const Function *funcInDerived) { const std::string functionName = funcInDerived ? ((funcInDerived->isDestructor() ? "~" : "") + funcInDerived->name()) : ""; const std::string funcType = (funcInDerived && funcInDerived->isDestructor()) ? "destructor" : "function"; @@ -3352,7 +3357,7 @@ void CheckClass::overrideError(const Function *funcInBase, const Function *funcI Certainty::normal); } -void CheckClass::uselessOverrideError(const Function *funcInBase, const Function *funcInDerived, bool isSameCode) +void CheckClassImpl::uselessOverrideError(const Function *funcInBase, const Function *funcInDerived, bool isSameCode) { const std::string functionName = funcInDerived ? ((funcInDerived->isDestructor() ? "~" : "") + funcInDerived->name()) : ""; const std::string funcType = (funcInDerived && funcInDerived->isDestructor()) ? "destructor" : "function"; @@ -3416,9 +3421,9 @@ static bool compareTokenRanges(const Token* start1, const Token* end1, const Tok return isEqual; } -void CheckClass::checkUselessOverride() +void CheckClassImpl::checkUselessOverride() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("uselessOverride")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("uselessOverride")) return; logChecker("CheckClass::checkUselessOverride"); // style @@ -3450,9 +3455,14 @@ void CheckClass::checkUselessOverride() if (isSameCode) { // bailout for shadowed members - if (!classScope->definedType || - !getDuplInheritedMembersRecursive(classScope->definedType, classScope->definedType, /*skipPrivate*/ false).empty() || - !getDuplInheritedMemberFunctionsRecursive(classScope->definedType, classScope->definedType, /*skipPrivate*/ false).empty()) + if (!getDuplInheritedMembersRecursive(classScope->definedType, + classScope->definedType, + /*skipPrivate*/ false) + .empty() || + !getDuplInheritedMemberFunctionsRecursive(classScope->definedType, + classScope->definedType, + /*skipPrivate*/ false) + .empty()) continue; uselessOverrideError(baseFunc, &func, true); continue; @@ -3497,9 +3507,9 @@ static const Variable* getSingleReturnVar(const Scope* scope) { return tok->variable(); } -void CheckClass::checkReturnByReference() +void CheckClassImpl::checkReturnByReference() { - if (!mSettings->severity.isEnabled(Severity::performance) && !mSettings->isPremiumEnabled("returnByReference")) + if (!mSettings.severity.isEnabled(Severity::performance) && !mSettings.isPremiumEnabled("returnByReference")) return; logChecker("CheckClass::checkReturnByReference"); // performance @@ -3514,7 +3524,7 @@ void CheckClass::checkReturnByReference() continue; if (func.functionPointerUsage) continue; - if (const Library::Container* container = mSettings->library.detectContainer(func.retDef)) + if (const Library::Container* container = mSettings.library.detectContainer(func.retDef)) if (container->view) continue; if (!func.isConst() && func.hasRvalRefQualifier()) @@ -3529,8 +3539,8 @@ void CheckClass::checkReturnByReference() const bool isView = isContainer && var->valueType()->container->view; bool warn = isContainer && !isView; if (!warn && !isView) { - const std::size_t size = var->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer); - if (size > 2 * mSettings->platform.sizeof_pointer) + const std::size_t size = var->valueType()->getSizeOf(mSettings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer); + if (size > 2 * mSettings.platform.sizeof_pointer) warn = true; } if (warn) @@ -3540,16 +3550,16 @@ void CheckClass::checkReturnByReference() } } -void CheckClass::returnByReferenceError(const Function* func, const Variable* var) +void CheckClassImpl::returnByReferenceError(const Function* func, const Variable* var) { const Token* tok = func ? func->tokenDef : nullptr; const std::string message = "Function '" + (func ? func->name() : "func") + "()' should return member '" + (var ? var->name() : "var") + "' by const reference."; reportError(tok, Severity::performance, "returnByReference", message); } -void CheckClass::checkThisUseAfterFree() +void CheckClassImpl::checkThisUseAfterFree() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckClass::checkThisUseAfterFree"); // warning @@ -3559,7 +3569,7 @@ void CheckClass::checkThisUseAfterFree() for (const Variable &var : classScope->varlist) { // Find possible "self pointer".. pointer/smartpointer member variable of "self" type. if (var.valueType() && var.valueType()->smartPointerType != classScope->definedType && var.valueType()->typeScope != classScope) { - const ValueType valueType = ValueType::parseDecl(var.typeStartToken(), *mSettings); + const ValueType valueType = ValueType::parseDecl(var.typeStartToken(), mSettings); if (valueType.smartPointerType != classScope->definedType) continue; } @@ -3596,7 +3606,7 @@ void CheckClass::checkThisUseAfterFree() } } -bool CheckClass::checkThisUseAfterFreeRecursive(const Scope *classScope, const Function *func, const Variable *selfPointer, std::set callstack, const Token *&freeToken) +bool CheckClassImpl::checkThisUseAfterFreeRecursive(const Scope *classScope, const Function *func, const Variable *selfPointer, std::set callstack, const Token *&freeToken) { if (!func || !func->functionScope) return false; @@ -3635,7 +3645,7 @@ bool CheckClass::checkThisUseAfterFreeRecursive(const Scope *classScope, const F return false; } -void CheckClass::thisUseAfterFree(const Token *self, const Token *free, const Token *use) +void CheckClassImpl::thisUseAfterFree(const Token *self, const Token *free, const Token *use) { std::string selfPointer = self ? self->str() : "ptr"; ErrorPath errorPath = { ErrorPathItem(self, "Assuming '" + selfPointer + "' is used as 'this'"), ErrorPathItem(free, "Delete '" + selfPointer + "', invalidating 'this'"), ErrorPathItem(use, "Call method when 'this' is invalid") }; @@ -3647,9 +3657,9 @@ void CheckClass::thisUseAfterFree(const Token *self, const Token *free, const To CWE(0), Certainty::normal); } -void CheckClass::checkUnsafeClassRefMember() +void CheckClassImpl::checkUnsafeClassRefMember() { - if (!mSettings->safeChecks.classes || !mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.safeChecks.classes || !mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckClass::checkUnsafeClassRefMember"); // warning,safeChecks for (const Scope * classScope : mSymbolDatabase->classAndStructScopes) { @@ -3671,7 +3681,7 @@ void CheckClass::checkUnsafeClassRefMember() } } -void CheckClass::unsafeClassRefMemberError(const Token *tok, const std::string &varname) +void CheckClassImpl::unsafeClassRefMemberError(const Token *tok, const std::string &varname) { reportError(tok, Severity::warning, "unsafeClassRefMember", "$symbol:" + varname + "\n" @@ -3691,6 +3701,8 @@ namespace /* multifile checking; one definition rule violations */ class MyFileInfo : public Check::FileInfo { public: + explicit MyFileInfo(std::string f0) : Check::FileInfo(std::move(f0)) {} + using Check::FileInfo::FileInfo; struct NameLoc { std::string className; @@ -3726,7 +3738,7 @@ namespace }; } -Check::FileInfo *CheckClass::getFileInfo(const Tokenizer &tokenizer, const Settings& /*settings*/, const std::string& currentConfig) const +const Check::FileInfo *CheckClass::getFileInfo(const Tokenizer &tokenizer, const Settings& /*settings*/, const std::string& currentConfig) const { if (!tokenizer.isCPP()) return nullptr; @@ -3796,9 +3808,9 @@ Check::FileInfo *CheckClass::getFileInfo(const Tokenizer &tokenizer, const Setti return fileInfo; } -Check::FileInfo * CheckClass::loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const +const Check::FileInfo * CheckClass::loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement, const std::string& file0) const { - auto *fileInfo = new MyFileInfo; + auto *fileInfo = new MyFileInfo(file0); for (const tinyxml2::XMLElement *e = xmlElement->FirstChildElement(); e; e = e->NextSiblingElement()) { if (std::strcmp(e->Name(), "class") != 0) continue; @@ -3826,12 +3838,12 @@ Check::FileInfo * CheckClass::loadFileInfoFromXml(const tinyxml2::XMLElement *xm return fileInfo; } -bool CheckClass::analyseWholeProgram(const CTU::FileInfo &ctu, const std::list &fileInfo, const Settings& settings, ErrorLogger &errorLogger) +bool CheckClass::analyseWholeProgram(const CTU::FileInfo &ctu, const std::list &fileInfo, const Settings& settings, ErrorLogger &errorLogger) { (void)ctu; (void)settings; - CheckClass dummy(nullptr, &settings, &errorLogger); + CheckClassImpl dummy(nullptr, settings, errorLogger); dummy. logChecker("CheckClass::analyseWholeProgram"); @@ -3880,12 +3892,12 @@ bool CheckClass::analyseWholeProgram(const CTU::FileInfo &ctu, const std::list @@ -48,23 +49,57 @@ enum class FunctionType : std::uint8_t; /** @brief %Check classes. Uninitialized member variables, non-conforming operators, missing virtual destructor, etc */ class CPPCHECKLIB CheckClass : public Check { - friend class TestClass; - friend class TestConstructors; - friend class TestUnusedPrivateFunction; - public: /** @brief This constructor is used when registering the CheckClass */ - CheckClass() : Check(myName()) {} + CheckClass() : Check("Class") {} - /** @brief Set of the STL types whose operator[] is not const */ - static const std::set stl_containers_not_const; + /** @brief Run checks on the normal token list */ + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + + /** @brief Parse current TU and extract file info */ + const Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings& /*settings*/, const std::string& currentConfig) const override; -private: - /** @brief This constructor is used when running checks. */ - CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger); + const Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement, const std::string& file0) const override; - /** @brief Run checks on the normal token list */ - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + /** @brief Analyse all file infos for all TU */ + bool analyseWholeProgram(const CTU::FileInfo &ctu, const std::list &fileInfo, const Settings& settings, ErrorLogger &errorLogger) override; + + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; + + std::string classInfo() const override { + return "Check the code for each class.\n" + "- Missing constructors and copy constructors\n" + //"- Missing allocation of memory in copy constructor\n" + "- Constructors which should be explicit\n" + "- Are all variables initialized by the constructors?\n" + "- Are all variables assigned by 'operator='?\n" + "- Warn if memset, memcpy etc are used on a class\n" + "- Warn if memory for classes is allocated with malloc()\n" + "- If it's a base class, check that the destructor is virtual\n" + "- Are there unused private functions?\n" + "- 'operator=' should check for assignment to self\n" + "- Constness for member functions\n" + "- Order of initializations\n" + "- Suggest usage of initialization list\n" + "- Initialization of a member with itself\n" + "- Suspicious subtraction from 'this'\n" + "- Call of pure virtual function in constructor/destructor\n" + "- Duplicated inherited data members\n" + // disabled for now "- If 'copy constructor' defined, 'operator=' also should be defined and vice versa\n" + "- Check that arbitrary usage of public interface does not result in division by zero\n" + "- Delete \"self pointer\" and then access 'this'\n" + "- Check that the 'override' keyword is used when overriding virtual functions\n" + "- Check that the 'one definition rule' is not violated\n"; + } +}; + +class CPPCHECKLIB CheckClassImpl : public CheckImpl { +public: + /** This constructor is used when running checks. */ + CheckClassImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger); + + /** @brief Set of the STL types whose operator[] is not const */ + static const std::set stl_containers_not_const; /** @brief %Check that all class constructors are ok */ void constructors(); @@ -137,14 +172,6 @@ class CPPCHECKLIB CheckClass : public Check { /** @brief Unsafe class check - const reference member */ 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 * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override; - - /** @brief Analyse all file infos for all TU */ - bool analyseWholeProgram(const CTU::FileInfo &ctu, const std::list &fileInfo, const Settings& settings, ErrorLogger &errorLogger) override; - const SymbolDatabase* mSymbolDatabase{}; // Reporting errors.. @@ -187,38 +214,6 @@ class CPPCHECKLIB CheckClass : public Check { void unsafeClassRefMemberError(const Token *tok, const std::string &varname); void checkDuplInheritedMembersRecursive(const Type* typeCurrent, const Type* typeBase); - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - static std::string myName() { - return "Class"; - } - - std::string classInfo() const override { - return "Check the code for each class.\n" - "- Missing constructors and copy constructors\n" - //"- Missing allocation of memory in copy constructor\n" - "- Constructors which should be explicit\n" - "- Are all variables initialized by the constructors?\n" - "- Are all variables assigned by 'operator='?\n" - "- Warn if memset, memcpy etc are used on a class\n" - "- Warn if memory for classes is allocated with malloc()\n" - "- If it's a base class, check that the destructor is virtual\n" - "- Are there unused private functions?\n" - "- 'operator=' should check for assignment to self\n" - "- Constness for member functions\n" - "- Order of initializations\n" - "- Suggest usage of initialization list\n" - "- Initialization of a member with itself\n" - "- Suspicious subtraction from 'this'\n" - "- Call of pure virtual function in constructor/destructor\n" - "- Duplicated inherited data members\n" - // disabled for now "- If 'copy constructor' defined, 'operator=' also should be defined and vice versa\n" - "- Check that arbitrary usage of public interface does not result in division by zero\n" - "- Delete \"self pointer\" and then access 'this'\n" - "- Check that the 'override' keyword is used when overriding virtual functions\n" - "- Check that the 'one definition rule' is not violated\n"; - } - // operatorEqRetRefThis helper functions void checkReturnPtrThis(const Scope *scope, const Function *func, const Token *tok, const Token *last); void checkReturnPtrThis(const Scope *scope, const Function *func, const Token *tok, const Token *last, std::set& analyzedFunctions); diff --git a/lib/checkcondition.cpp b/lib/checkcondition.cpp index d0913963cca..e77641f89e7 100644 --- a/lib/checkcondition.cpp +++ b/lib/checkcondition.cpp @@ -52,12 +52,7 @@ 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) +bool CheckConditionImpl::diag(const Token* tok, bool insert) { if (!tok) return false; @@ -78,14 +73,14 @@ bool CheckCondition::diag(const Token* tok, bool insert) return true; } -bool CheckCondition::diag(const Token* tok1, const Token* tok2) +bool CheckConditionImpl::diag(const Token* tok1, const Token* tok2) { const bool b1 = diag(tok1); const bool b2 = diag(tok2); return b1 && b2; } -bool CheckCondition::isAliased(const std::set &vars) const +bool CheckConditionImpl::isAliased(const std::set &vars) const { for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) { if (Token::Match(tok, "= & %var% ;") && vars.find(tok->tokAt(2)->varId()) != vars.end()) @@ -94,9 +89,9 @@ bool CheckCondition::isAliased(const std::set &vars) const return false; } -void CheckCondition::assignIf() +void CheckConditionImpl::assignIf() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("assignIfError")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("assignIfError")) return; logChecker("CheckCondition::assignIf"); // style @@ -167,12 +162,12 @@ static bool isParameterChanged(const Token *partok) } /** parse scopes recursively */ -bool CheckCondition::assignIfParseScope(const Token * const assignTok, - const Token * const startTok, - const nonneg int varid, - const bool islocal, - const char bitop, - const MathLib::bigint num) +bool CheckConditionImpl::assignIfParseScope(const Token * const assignTok, + const Token * const startTok, + const nonneg int varid, + const bool islocal, + const char bitop, + const MathLib::bigint num) { bool ret = false; @@ -209,7 +204,7 @@ bool CheckCondition::assignIfParseScope(const Token * const assignTok, // is variable changed in loop? const Token *bodyStart = tok2->linkAt(1)->next(); const Token *bodyEnd = bodyStart ? bodyStart->link() : nullptr; - if (!bodyEnd || bodyEnd->str() != "}" || isVariableChanged(bodyStart, bodyEnd, varid, !islocal, *mSettings)) + if (!bodyEnd || bodyEnd->str() != "}" || isVariableChanged(bodyStart, bodyEnd, varid, !islocal, mSettings)) continue; } @@ -245,7 +240,7 @@ bool CheckCondition::assignIfParseScope(const Token * const assignTok, return false; } -void CheckCondition::assignIfError(const Token *tok1, const Token *tok2, const std::string &condition, bool result) +void CheckConditionImpl::assignIfError(const Token *tok1, const Token *tok2, const std::string &condition, bool result) { if (tok2 && diag(tok2->tokAt(2))) return; @@ -257,7 +252,7 @@ void CheckCondition::assignIfError(const Token *tok1, const Token *tok2, const s } -void CheckCondition::mismatchingBitAndError(const Token *tok1, const MathLib::bigint num1, const Token *tok2, const MathLib::bigint num2) +void CheckConditionImpl::mismatchingBitAndError(const Token *tok1, const MathLib::bigint num1, const Token *tok2, const MathLib::bigint num2) { std::list locations = { tok1, tok2 }; @@ -313,9 +308,9 @@ static bool isOperandExpanded(const Token *tok) return false; } -void CheckCondition::checkBadBitmaskCheck() +void CheckConditionImpl::checkBadBitmaskCheck() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("badBitmaskCheck")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("badBitmaskCheck")) return; logChecker("CheckCondition::checkBadBitmaskCheck"); // style @@ -353,7 +348,7 @@ void CheckCondition::checkBadBitmaskCheck() } } -void CheckCondition::badBitmaskCheckError(const Token *tok, bool isNoOp) +void CheckConditionImpl::badBitmaskCheckError(const Token *tok, bool isNoOp) { if (isNoOp) reportError(tok, Severity::style, "badBitmaskCheck", "Operator '|' with one operand equal to zero is redundant.", CWE571, Certainty::normal); @@ -361,9 +356,9 @@ void CheckCondition::badBitmaskCheckError(const Token *tok, bool isNoOp) reportError(tok, Severity::warning, "badBitmaskCheck", "Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'?", CWE571, Certainty::normal); } -void CheckCondition::comparison() +void CheckConditionImpl::comparison() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("comparisonError")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("comparisonError")) return; logChecker("CheckCondition::comparison"); // style @@ -426,7 +421,7 @@ void CheckCondition::comparison() } } -void CheckCondition::comparisonError(const Token *tok, const std::string &bitop, MathLib::bigint value1, const std::string &op, MathLib::bigint value2, bool result) +void CheckConditionImpl::comparisonError(const Token *tok, const std::string &bitop, MathLib::bigint value1, const std::string &op, MathLib::bigint value2, bool result) { std::ostringstream expression; expression << std::hex << "(X " << bitop << " 0x" << value1 << ") " << op << " 0x" << value2; @@ -440,13 +435,13 @@ void CheckCondition::comparisonError(const Token *tok, const std::string &bitop, reportError(tok, Severity::style, "comparisonError", errmsg, CWE398, Certainty::normal); } -bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token * const cond2, bool pure) const +bool CheckConditionImpl::isOverlappingCond(const Token * const cond1, const Token * const cond2, bool pure) const { if (!cond1 || !cond2) return false; // same expressions - if (isSameExpression(true, cond1, cond2, *mSettings, pure, false)) + if (isSameExpression(true, cond1, cond2, mSettings, pure, false)) return true; // bitwise overlap for example 'x&7' and 'x==1' @@ -460,7 +455,7 @@ bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token * if (!num1->isNumber() || MathLib::isNegative(num1->str())) return false; - if (!Token::Match(cond2, "&|==") || !cond2->astOperand1() || !cond2->astOperand2()) + if (!Token::Match(cond2, "&|==") || !cond2->astOperand1()) return false; const Token *expr2 = cond2->astOperand1(); const Token *num2 = cond2->astOperand2(); @@ -469,7 +464,7 @@ bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token * if (!num2->isNumber() || MathLib::isNegative(num2->str())) return false; - if (!isSameExpression(true, expr1, expr2, *mSettings, pure, false)) + if (!isSameExpression(true, expr1, expr2, mSettings, pure, false)) return false; const MathLib::bigint value1 = MathLib::toBigNumber(num1); @@ -481,9 +476,9 @@ bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token * return false; } -void CheckCondition::duplicateCondition() +void CheckConditionImpl::duplicateCondition() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("duplicateCondition")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("duplicateCondition")) return; logChecker("CheckCondition::duplicateCondition"); // style @@ -514,13 +509,13 @@ void CheckCondition::duplicateCondition() continue; ErrorPath errorPath; - if (!findExpressionChanged(cond1, scope.classDef->next(), cond2, *mSettings) && - isSameExpression(true, cond1, cond2, *mSettings, true, true, &errorPath)) + if (!findExpressionChanged(cond1, scope.classDef->next(), cond2, mSettings) && + isSameExpression(true, cond1, cond2, mSettings, true, true, &errorPath)) duplicateConditionError(cond1, cond2, std::move(errorPath)); } } -void CheckCondition::duplicateConditionError(const Token *tok1, const Token *tok2, ErrorPath errorPath) +void CheckConditionImpl::duplicateConditionError(const Token *tok1, const Token *tok2, ErrorPath errorPath) { if (diag(tok1, tok2)) return; @@ -532,9 +527,9 @@ void CheckCondition::duplicateConditionError(const Token *tok1, const Token *tok reportError(std::move(errorPath), Severity::style, "duplicateCondition", msg, CWE398, Certainty::normal); } -void CheckCondition::multiCondition() +void CheckConditionImpl::multiCondition() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("multiCondition")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("multiCondition")) return; logChecker("CheckCondition::multiCondition"); // style @@ -564,18 +559,18 @@ void CheckCondition::multiCondition() if (tok2->astOperand2()) { ErrorPath errorPath; if (isOverlappingCond(cond1, tok2->astOperand2(), true) && - !findExpressionChanged(cond1, cond1, tok2->astOperand2(), *mSettings)) + !findExpressionChanged(cond1, cond1, tok2->astOperand2(), mSettings)) overlappingElseIfConditionError(tok2->astOperand2(), cond1->linenr()); else if (isOppositeCond( - true, cond1, tok2->astOperand2(), *mSettings, true, true, &errorPath) && - !findExpressionChanged(cond1, cond1, tok2->astOperand2(), *mSettings)) + true, cond1, tok2->astOperand2(), mSettings, true, true, &errorPath) && + !findExpressionChanged(cond1, cond1, tok2->astOperand2(), mSettings)) oppositeElseIfConditionError(cond1, tok2->astOperand2(), std::move(errorPath)); } } } } -void CheckCondition::overlappingElseIfConditionError(const Token *tok, nonneg int line1) +void CheckConditionImpl::overlappingElseIfConditionError(const Token *tok, nonneg int line1) { if (diag(tok)) return; @@ -586,7 +581,7 @@ void CheckCondition::overlappingElseIfConditionError(const Token *tok, nonneg in reportError(tok, Severity::style, "multiCondition", errmsg.str(), CWE398, Certainty::normal); } -void CheckCondition::oppositeElseIfConditionError(const Token *ifCond, const Token *elseIfCond, ErrorPath errorPath) +void CheckConditionImpl::oppositeElseIfConditionError(const Token *ifCond, const Token *elseIfCond, ErrorPath errorPath) { if (diag(ifCond, elseIfCond)) return; @@ -634,11 +629,11 @@ static bool isNestedInLambda(const Scope* inner, const Scope* outer) return false; } -void CheckCondition::multiCondition2() +void CheckConditionImpl::multiCondition2() { - if (!mSettings->severity.isEnabled(Severity::warning) && - !mSettings->isPremiumEnabled("identicalConditionAfterEarlyExit") && - !mSettings->isPremiumEnabled("identicalInnerCondition")) + if (!mSettings.severity.isEnabled(Severity::warning) && + !mSettings.isPremiumEnabled("identicalConditionAfterEarlyExit") && + !mSettings.isPremiumEnabled("identicalInnerCondition")) return; logChecker("CheckCondition::multiCondition2"); // warning @@ -673,7 +668,7 @@ void CheckCondition::multiCondition2() [&](const Token *cond) { if (Token::Match(cond, "%name% (")) { functionCall = true; - nonConstFunctionCall = isNonConstFunctionCall(cond, mSettings->library); + nonConstFunctionCall = isNonConstFunctionCall(cond, mSettings.library); if (nonConstFunctionCall) return ChildrenToVisit::done; } @@ -730,13 +725,13 @@ void CheckCondition::multiCondition2() for (; tok && tok != endToken; tok = tok->next()) { if (isNestedInLambda(tok->scope(), cond1->scope())) continue; - if (isExpressionChangedAt(cond1, tok, 0, false, *mSettings)) + if (isExpressionChangedAt(cond1, tok, 0, false, mSettings)) break; if (Token::Match(tok, "if|return")) { const Token * condStartToken = tok->str() == "if" ? tok->next() : tok; const Token * condEndToken = tok->str() == "if" ? condStartToken->link() : Token::findsimplematch(condStartToken, ";"); // Does condition modify tracked variables? - if (findExpressionChanged(cond1, condStartToken, condEndToken, *mSettings)) + if (findExpressionChanged(cond1, condStartToken, condEndToken, mSettings)) break; // Condition.. @@ -750,14 +745,14 @@ void CheckCondition::multiCondition2() if (!firstCondition) return ChildrenToVisit::none; if (firstCondition->str() == "&&") { - if (!isOppositeCond(false, firstCondition, cond2, *mSettings, true, true)) + if (!isOppositeCond(false, firstCondition, cond2, mSettings, true, true)) return ChildrenToVisit::op1_and_op2; } if (!firstCondition->hasKnownIntValue()) { - if (!isReturnVar && isOppositeCond(false, firstCondition, cond2, *mSettings, true, true, &errorPath)) { + if (!isReturnVar && isOppositeCond(false, firstCondition, cond2, mSettings, true, true, &errorPath)) { if (!isAliased(vars)) oppositeInnerConditionError(firstCondition, cond2, errorPath); - } else if (!isReturnVar && isSameExpression(true, firstCondition, cond2, *mSettings, true, true, &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); @@ -771,7 +766,7 @@ void CheckCondition::multiCondition2() return ChildrenToVisit::op1_and_op2; if ((!cond1->hasKnownIntValue() || !secondCondition->hasKnownIntValue()) && - isSameExpression(true, cond1, secondCondition, *mSettings, true, true, &errorPath)) { + isSameExpression(true, cond1, secondCondition, mSettings, true, true, &errorPath)) { if (!isAliased(vars) && !mTokenizer->hasIfdef(cond1, secondCondition)) { identicalConditionAfterEarlyExitError(cond1, secondCondition, errorPath); return ChildrenToVisit::done; @@ -782,10 +777,10 @@ void CheckCondition::multiCondition2() } } if (Token::Match(tok, "%name% (") && - isVariablesChanged(tok, tok->linkAt(1), 0, varsInCond, *mSettings)) { + isVariablesChanged(tok, tok->linkAt(1), 0, varsInCond, mSettings)) { break; } - if (Token::Match(tok, "%type% (") && nonlocal && isNonConstFunctionCall(tok, mSettings->library)) // non const function call -> bailout if there are nonlocal variables + if (Token::Match(tok, "%type% (") && nonlocal && isNonConstFunctionCall(tok, mSettings.library)) // non const function call -> bailout if there are nonlocal variables break; if (Token::Match(tok, "case|break|continue|return|throw") && tok->scope() == endToken->scope()) break; @@ -811,7 +806,7 @@ void CheckCondition::multiCondition2() break; } const bool changed = std::any_of(vars.cbegin(), vars.cend(), [&](int varid) { - return isVariableChanged(tok1, tok2, varid, nonlocal, *mSettings); + return isVariableChanged(tok1, tok2, varid, nonlocal, mSettings); }); if (changed) break; @@ -866,7 +861,7 @@ static std::string innerSmtString(const Token * tok) return top->str(); } -void CheckCondition::oppositeInnerConditionError(const Token *tok1, const Token* tok2, ErrorPath errorPath) +void CheckConditionImpl::oppositeInnerConditionError(const Token *tok1, const Token* tok2, ErrorPath errorPath) { if (diag(tok1, tok2)) return; @@ -881,7 +876,7 @@ 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) +void CheckConditionImpl::overlappingInnerConditionError(const Token *tok1, const Token* tok2, ErrorPath errorPath) { if (diag(tok1, tok2)) return; @@ -896,7 +891,7 @@ void CheckCondition::overlappingInnerConditionError(const Token *tok1, const To reportError(std::move(errorPath), Severity::warning, "overlappingInnerCondition", msg, CWE398, Certainty::normal); } -void CheckCondition::identicalInnerConditionError(const Token *tok1, const Token* tok2, ErrorPath errorPath) +void CheckConditionImpl::identicalInnerConditionError(const Token *tok1, const Token* tok2, ErrorPath errorPath) { if (diag(tok1, tok2)) return; @@ -911,7 +906,7 @@ void CheckCondition::identicalInnerConditionError(const Token *tok1, const Token reportError(std::move(errorPath), Severity::warning, "identicalInnerCondition", msg, CWE398, Certainty::normal); } -void CheckCondition::identicalConditionAfterEarlyExitError(const Token *cond1, const Token* cond2, ErrorPath errorPath) +void CheckConditionImpl::identicalConditionAfterEarlyExitError(const Token *cond1, const Token* cond2, ErrorPath errorPath) { if (diag(cond1, cond2)) return; @@ -1161,13 +1156,13 @@ static bool isIfConstexpr(const Token* tok) { return Token::simpleMatch(top->astOperand1(), "if") && top->astOperand1()->isConstexpr(); } -void CheckCondition::checkIncorrectLogicOperator() +void CheckConditionImpl::checkIncorrectLogicOperator() { - const bool printStyle = mSettings->severity.isEnabled(Severity::style); - const bool printWarning = mSettings->severity.isEnabled(Severity::warning); - if (!printWarning && !printStyle && !mSettings->isPremiumEnabled("incorrectLogicOperator")) + const bool printStyle = mSettings.severity.isEnabled(Severity::style); + const bool printWarning = mSettings.severity.isEnabled(Severity::warning); + if (!printWarning && !printStyle && !mSettings.isPremiumEnabled("incorrectLogicOperator")) return; - const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive); + const bool printInconclusive = mSettings.certainty.isEnabled(Certainty::inconclusive); logChecker("CheckCondition::checkIncorrectLogicOperator"); // style,warning @@ -1187,7 +1182,7 @@ void CheckCondition::checkIncorrectLogicOperator() ((tok->str() == "||" && tok->astOperand2()->str() == "&&") || (tok->str() == "&&" && tok->astOperand2()->str() == "||"))) { const Token* tok2 = tok->astOperand2()->astOperand1(); - if (isOppositeCond(true, tok->astOperand1(), tok2, *mSettings, true, false)) { + if (isOppositeCond(true, tok->astOperand1(), tok2, mSettings, true, false)) { std::string expr1(tok->astOperand1()->expressionString()); std::string expr2(tok->astOperand2()->astOperand1()->expressionString()); std::string expr3(tok->astOperand2()->astOperand2()->expressionString()); @@ -1219,7 +1214,7 @@ void CheckCondition::checkIncorrectLogicOperator() redundantConditionError(tok, msg, false); continue; } - if (isSameExpression(false, tok->astOperand1(), tok2, *mSettings, true, true)) { + if (isSameExpression(false, tok->astOperand1(), tok2, mSettings, true, true)) { std::string expr1(tok->astOperand1()->expressionString()); std::string expr2(tok->astOperand2()->astOperand1()->expressionString()); std::string expr3(tok->astOperand2()->astOperand2()->expressionString()); @@ -1284,7 +1279,7 @@ void CheckCondition::checkIncorrectLogicOperator() // Opposite comparisons around || or && => always true or always false const bool isLogicalOr(tok->str() == "||"); - if (!isfloat && isOppositeCond(isLogicalOr, tok->astOperand1(), tok->astOperand2(), *mSettings, true, true, &errorPath)) { + if (!isfloat && isOppositeCond(isLogicalOr, tok->astOperand1(), tok->astOperand2(), mSettings, true, true, &errorPath)) { if (!isIfConstexpr(tok)) { const bool alwaysTrue(isLogicalOr); incorrectLogicOperatorError(tok, conditionString(tok), alwaysTrue, inconclusive, std::move(errorPath)); @@ -1295,9 +1290,9 @@ void CheckCondition::checkIncorrectLogicOperator() if (!parseable) continue; - if (isSameExpression(true, comp1, comp2, *mSettings, true, true)) + if (isSameExpression(true, comp1, comp2, mSettings, true, true)) continue; // same expressions => only report that there are same expressions - if (!isSameExpression(true, expr1, expr2, *mSettings, true, true)) + if (!isSameExpression(true, expr1, expr2, mSettings, true, true)) continue; @@ -1372,7 +1367,7 @@ void CheckCondition::checkIncorrectLogicOperator() } } -void CheckCondition::incorrectLogicOperatorError(const Token *tok, const std::string &condition, bool always, bool inconclusive, ErrorPath errors) +void CheckConditionImpl::incorrectLogicOperatorError(const Token *tok, const std::string &condition, bool always, bool inconclusive, ErrorPath errors) { if (diag(tok)) return; @@ -1389,7 +1384,7 @@ void CheckCondition::incorrectLogicOperatorError(const Token *tok, const std::st "Are these conditions necessary? Did you intend to use || instead? Are the numbers correct? Are you comparing the correct variables?", CWE570, inconclusive ? Certainty::inconclusive : Certainty::normal); } -void CheckCondition::redundantConditionError(const Token *tok, const std::string &text, bool inconclusive) +void CheckConditionImpl::redundantConditionError(const Token *tok, const std::string &text, bool inconclusive) { if (diag(tok)) return; @@ -1399,9 +1394,9 @@ void CheckCondition::redundantConditionError(const Token *tok, const std::string //----------------------------------------------------------------------------- // Detect "(var % val1) > val2" where val2 is >= val1. //----------------------------------------------------------------------------- -void CheckCondition::checkModuloAlwaysTrueFalse() +void CheckConditionImpl::checkModuloAlwaysTrueFalse() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckCondition::checkModuloAlwaysTrueFalse"); // warning @@ -1429,7 +1424,7 @@ void CheckCondition::checkModuloAlwaysTrueFalse() } } -void CheckCondition::moduloAlwaysTrueFalseError(const Token* tok, const std::string& maxVal) +void CheckConditionImpl::moduloAlwaysTrueFalseError(const Token* tok, const std::string& maxVal) { if (diag(tok)) return; @@ -1455,9 +1450,9 @@ static int countPar(const Token *tok1, const Token *tok2) // Clarify condition '(x = a < 0)' into '((x = a) < 0)' or '(x = (a < 0))' // Clarify condition '(a & b == c)' into '((a & b) == c)' or '(a & (b == c))' //--------------------------------------------------------------------------- -void CheckCondition::clarifyCondition() +void CheckConditionImpl::clarifyCondition() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("clarifyCondition")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("clarifyCondition")) return; logChecker("CheckCondition::clarifyCondition"); // style @@ -1496,7 +1491,7 @@ void CheckCondition::clarifyCondition() } } -void CheckCondition::clarifyConditionError(const Token *tok, bool assign, bool boolop) +void CheckConditionImpl::clarifyConditionError(const Token *tok, bool assign, bool boolop) { std::string errmsg; @@ -1519,13 +1514,13 @@ void CheckCondition::clarifyConditionError(const Token *tok, bool assign, bool b errmsg, CWE398, Certainty::normal); } -void CheckCondition::alwaysTrueFalse() +void CheckConditionImpl::alwaysTrueFalse() { - const bool pedantic = 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)) + if (!pedantic && !mSettings.severity.isEnabled(Severity::style)) return; logChecker("CheckCondition::alwaysTrueFalse"); // style @@ -1545,8 +1540,11 @@ void CheckCondition::alwaysTrueFalse() { // is this a condition.. const Token *parent = tok->astParent(); - while (Token::Match(parent, "%oror%|&&")) + bool hasComp = false; + while (Token::Match(parent, "%oror%|&&")) { + hasComp = true; parent = parent->astParent(); + } if (!parent) continue; if (parent->str() == "?" && precedes(tok, parent)) @@ -1560,17 +1558,18 @@ 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%")) + else if ((tok->str() == "(" || (hasComp && Token::Match(tok, "!|%var%"))) && astIsBool(parent) && Token::Match(parent, "%assign%")) condition = tok; else continue; + } // Skip already diagnosed values if (diag(tok, false)) continue; if (condition->isConstexpr()) continue; - if (!isUsedAsBool(tok, *mSettings)) + if (!isUsedAsBool(tok, mSettings)) continue; if (Token::simpleMatch(condition, "return") && Token::Match(tok, "%assign%")) continue; @@ -1599,7 +1598,7 @@ void CheckCondition::alwaysTrueFalse() isSameExpression(true, tok->astOperand1(), tok->astOperand2(), - *mSettings, + mSettings, true, true)) continue; @@ -1614,8 +1613,8 @@ void CheckCondition::alwaysTrueFalse() { const ValueFlow::Value *zeroValue = nullptr; const Token *nonZeroExpr = nullptr; - if (CheckOther::comparisonNonZeroExpressionLessThanZero(tok, zeroValue, nonZeroExpr, /*suppress*/ true) || - CheckOther::testIfNonZeroExpressionIsPositive(tok, zeroValue, nonZeroExpr)) + if (CheckOtherImpl::comparisonNonZeroExpressionLessThanZero(tok, zeroValue, nonZeroExpr, /*suppress*/ true) || + CheckOtherImpl::testIfNonZeroExpressionIsPositive(tok, zeroValue, nonZeroExpr)) continue; } @@ -1674,7 +1673,7 @@ static std::string getConditionString(const Token* condition) return "Condition"; } -void CheckCondition::alwaysTrueFalseError(const Token* tok, const Token* condition, const ValueFlow::Value* value) +void CheckConditionImpl::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"); @@ -1688,7 +1687,7 @@ void CheckCondition::alwaysTrueFalseError(const Token* tok, const Token* conditi (alwaysTrue ? CWE571 : CWE570), Certainty::normal); } -void CheckCondition::checkInvalidTestForOverflow() +void CheckConditionImpl::checkInvalidTestForOverflow() { // Interesting blogs: // https://www.airs.com/blog/archives/120 @@ -1703,7 +1702,7 @@ void CheckCondition::checkInvalidTestForOverflow() // x + y < x -> y < 0 - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckCondition::checkInvalidTestForOverflow"); // warning @@ -1737,7 +1736,7 @@ void CheckCondition::checkInvalidTestForOverflow() if (!isSameExpression(true, expr, lhs->astSibling(), - *mSettings, + mSettings, true, false)) continue; @@ -1776,7 +1775,7 @@ void CheckCondition::checkInvalidTestForOverflow() } } -void CheckCondition::invalidTestForOverflow(const Token* tok, const ValueType *valueType, const std::string &replace) +void CheckConditionImpl::invalidTestForOverflow(const Token* tok, const ValueType *valueType, const std::string &replace) { const std::string expr = (tok ? tok->expressionString() : std::string("x + c < x")); const std::string overflow = (valueType && valueType->pointer) ? "pointer overflow" : "signed integer overflow"; @@ -1791,9 +1790,9 @@ void CheckCondition::invalidTestForOverflow(const Token* tok, const ValueType *v } -void CheckCondition::checkPointerAdditionResultNotNull() +void CheckConditionImpl::checkPointerAdditionResultNotNull() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckCondition::checkPointerAdditionResultNotNull"); // warning @@ -1832,15 +1831,15 @@ void CheckCondition::checkPointerAdditionResultNotNull() } } -void CheckCondition::pointerAdditionResultNotNullError(const Token *tok, const Token *calc) +void CheckConditionImpl::pointerAdditionResultNotNullError(const Token *tok, const Token *calc) { const std::string s = calc ? calc->expressionString() : "ptr+1"; reportError(tok, Severity::warning, "pointerAdditionResultNotNull", "Comparison is wrong. Result of '" + s + "' can't be 0 unless there is pointer overflow, and pointer overflow is undefined behaviour."); } -void CheckCondition::checkDuplicateConditionalAssign() +void CheckConditionImpl::checkDuplicateConditionalAssign() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("duplicateConditionalAssign")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("duplicateConditionalAssign")) return; logChecker("CheckCondition::checkDuplicateConditionalAssign"); // style @@ -1884,10 +1883,10 @@ void CheckCondition::checkDuplicateConditionalAssign() isRedundant = (isNegation && val == 0) || (!isNegation && val == 1); } else { // comparison if (!isSameExpression( - true, condTok->astOperand1(), assignTok->astOperand1(), *mSettings, true, true)) + true, condTok->astOperand1(), assignTok->astOperand1(), mSettings, true, true)) continue; if (!isSameExpression( - true, condTok->astOperand2(), assignTok->astOperand2(), *mSettings, true, true)) + true, condTok->astOperand2(), assignTok->astOperand2(), mSettings, true, true)) continue; } duplicateConditionalAssignError(condTok, assignTok, isRedundant); @@ -1895,7 +1894,7 @@ void CheckCondition::checkDuplicateConditionalAssign() } } -void CheckCondition::duplicateConditionalAssignError(const Token *condTok, const Token* assignTok, bool isRedundant) +void CheckConditionImpl::duplicateConditionalAssignError(const Token *condTok, const Token* assignTok, bool isRedundant) { ErrorPath errors; std::string msg = "Duplicate expression for the condition and assignment."; @@ -1917,9 +1916,9 @@ void CheckCondition::duplicateConditionalAssignError(const Token *condTok, const } -void CheckCondition::checkAssignmentInCondition() +void CheckConditionImpl::checkAssignmentInCondition() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("assignmentInCondition")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("assignmentInCondition")) return; logChecker("CheckCondition::checkAssignmentInCondition"); // style @@ -1951,7 +1950,7 @@ void CheckCondition::checkAssignmentInCondition() } } -void CheckCondition::assignmentInCondition(const Token *eq) +void CheckConditionImpl::assignmentInCondition(const Token *eq) { std::string expr = eq ? eq->expressionString() : "x=y"; @@ -1964,12 +1963,12 @@ void CheckCondition::assignmentInCondition(const Token *eq) Certainty::normal); } -void CheckCondition::checkCompareValueOutOfTypeRange() +void CheckConditionImpl::checkCompareValueOutOfTypeRange() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("compareValueOutOfTypeRangeError")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("compareValueOutOfTypeRangeError")) return; - if (mSettings->platform.type == Platform::Type::Unspecified) + if (mSettings.platform.type == Platform::Type::Unspecified) return; logChecker("CheckCondition::checkCompareValueOutOfTypeRange"); // style,platform @@ -1995,19 +1994,19 @@ void CheckCondition::checkCompareValueOutOfTypeRange() bits = 1; break; case ValueType::Type::CHAR: - bits = mSettings->platform.char_bit; + bits = mSettings.platform.char_bit; break; case ValueType::Type::SHORT: - bits = mSettings->platform.short_bit; + bits = mSettings.platform.short_bit; break; case ValueType::Type::INT: - bits = mSettings->platform.int_bit; + bits = mSettings.platform.int_bit; break; case ValueType::Type::LONG: - bits = mSettings->platform.long_bit; + bits = mSettings.platform.long_bit; break; case ValueType::Type::LONGLONG: - bits = mSettings->platform.long_long_bit; + bits = mSettings.platform.long_long_bit; break; default: break; @@ -2020,7 +2019,7 @@ void CheckCondition::checkCompareValueOutOfTypeRange() long long typeMaxValue; if (typeTok->valueType()->sign != ValueType::Sign::SIGNED) typeMaxValue = unsignedTypeMaxValue; - else if (bits >= mSettings->platform.int_bit && (!valueTok->valueType() || valueTok->valueType()->sign != ValueType::Sign::SIGNED)) + else if (bits >= mSettings.platform.int_bit && (!valueTok->valueType() || valueTok->valueType()->sign != ValueType::Sign::SIGNED)) typeMaxValue = unsignedTypeMaxValue; else typeMaxValue = unsignedTypeMaxValue / 2; @@ -2085,7 +2084,7 @@ void CheckCondition::checkCompareValueOutOfTypeRange() } } -void CheckCondition::compareValueOutOfTypeRangeError(const Token *comparisonTok, const std::string &type, MathLib::bigint value, bool result) +void CheckConditionImpl::compareValueOutOfTypeRangeError(const Token *comparisonTok, const std::string &type, MathLib::bigint value, bool result) { reportError( comparisonTok, @@ -2096,9 +2095,9 @@ void CheckCondition::compareValueOutOfTypeRangeError(const Token *comparisonTok, Certainty::normal); } -void CheckCondition::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckCondition::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { - CheckCondition checkCondition(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckConditionImpl checkCondition(&tokenizer, tokenizer.getSettings(), errorLogger); checkCondition.multiCondition(); checkCondition.clarifyCondition(); // not simplified because ifAssign checkCondition.multiCondition2(); @@ -2116,9 +2115,9 @@ void CheckCondition::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLog checkCondition.alwaysTrueFalse(); } -void CheckCondition::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const +void CheckCondition::getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const { - CheckCondition c(nullptr, settings, errorLogger); + CheckConditionImpl c(nullptr, settings, errorLogger); c.assignIfError(nullptr, nullptr, "", false); c.badBitmaskCheckError(nullptr); diff --git a/lib/checkcondition.h b/lib/checkcondition.h index 2ea20158b11..232b2b5b340 100644 --- a/lib/checkcondition.h +++ b/lib/checkcondition.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,6 +23,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include "mathlib.h" #include "errortypes.h" @@ -50,14 +51,38 @@ namespace ValueFlow { class CPPCHECKLIB CheckCondition : public Check { public: /** This constructor is used when registering the CheckAssignIf */ - CheckCondition() : Check(myName()) {} + CheckCondition() : Check("Condition") {} private: - /** This constructor is used when running checks. */ - CheckCondition(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; + + std::string classInfo() const override { + return "Match conditions with assignments and other conditions:\n" + "- Mismatching assignment and comparison => comparison is always true/false\n" + "- Mismatching lhs and rhs in comparison => comparison is always true/false\n" + "- Detect usage of | where & should be used\n" + "- Duplicate condition and assignment\n" + "- Detect matching 'if' and 'else if' conditions\n" + "- Mismatching bitand (a &= 0xf0; a &= 1; => a = 0)\n" + "- Opposite inner condition is always false\n" + "- Identical condition after early exit is always false\n" + "- Condition that is always true/false\n" + "- Mutual exclusion over || always evaluating to true\n" + "- Comparisons of modulo results that are always true/false.\n" + "- Known variable values => condition is always true/false\n" + "- Invalid test for overflow. Some mainstream compilers remove such overflow tests when optimising code.\n" + "- Suspicious assignment of container/iterator in condition => condition is always true.\n"; + } +}; + + +class CPPCHECKLIB CheckConditionImpl : public CheckImpl { +public: + /** This constructor is used when running checks. */ + CheckConditionImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} /** mismatching assignment / comparison */ void assignIf(); @@ -157,30 +182,6 @@ class CPPCHECKLIB CheckCondition : public Check { void checkCompareValueOutOfTypeRange(); void compareValueOutOfTypeRangeError(const Token *comparisonTok, const std::string &type, MathLib::bigint value, bool result); - - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - static std::string myName() { - return "Condition"; - } - - std::string classInfo() const override { - return "Match conditions with assignments and other conditions:\n" - "- Mismatching assignment and comparison => comparison is always true/false\n" - "- Mismatching lhs and rhs in comparison => comparison is always true/false\n" - "- Detect usage of | where & should be used\n" - "- Duplicate condition and assignment\n" - "- Detect matching 'if' and 'else if' conditions\n" - "- Mismatching bitand (a &= 0xf0; a &= 1; => a = 0)\n" - "- Opposite inner condition is always false\n" - "- Identical condition after early exit is always false\n" - "- Condition that is always true/false\n" - "- Mutual exclusion over || always evaluating to true\n" - "- Comparisons of modulo results that are always true/false.\n" - "- Known variable values => condition is always true/false\n" - "- Invalid test for overflow. Some mainstream compilers remove such overflow tests when optimising code.\n" - "- Suspicious assignment of container/iterator in condition => condition is always true.\n"; - } }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checkers.cpp b/lib/checkers.cpp index f7d7f913da6..56d91cc4f05 100644 --- a/lib/checkers.cpp +++ b/lib/checkers.cpp @@ -101,6 +101,7 @@ namespace checkers { {"CheckFunctions::useStandardLibrary","style"}, {"CheckIO::checkCoutCerrMisusage","c"}, {"CheckIO::checkFileUsage",""}, + {"CheckIO::checkWrongfeofUsage",""}, {"CheckIO::checkWrongPrintfScanfArguments",""}, {"CheckIO::invalidScanf",""}, {"CheckLeakAutoVar::check","notclang"}, @@ -109,7 +110,7 @@ namespace checkers { {"CheckMemoryLeakNoVar::check",""}, {"CheckMemoryLeakNoVar::checkForUnsafeArgAlloc",""}, {"CheckMemoryLeakStructMember::check",""}, - {"CheckNullPointer::analyseWholeProgram","unusedfunctions"}, + {"CheckNullPointer::analyseWholeProgram",""}, {"CheckNullPointer::arithmetic",""}, {"CheckNullPointer::nullConstantDereference",""}, {"CheckNullPointer::nullPointer",""}, @@ -166,6 +167,7 @@ namespace checkers { {"CheckSizeof::sizeofVoid","portability"}, {"CheckSizeof::sizeofsizeof","warning"}, {"CheckSizeof::suspiciousSizeofCalculation","warning,inconclusive"}, + {"CheckStl::algorithmOutOfBounds",""}, {"CheckStl::checkDereferenceInvalidIterator","warning"}, {"CheckStl::checkDereferenceInvalidIterator2",""}, {"CheckStl::checkFindInsert","performance"}, @@ -1677,9 +1679,25 @@ std::vector checkers::autosarInfo{ }; std::vector checkers::certCInfo{ - {"PRE30-C", "L3"}, - {"PRE31-C", "L3"}, - {"PRE32-C", "L3"}, + {"ARR30-C", "L2"}, + {"ARR32-C", "L2"}, + {"ARR36-C", "L3"}, + {"ARR37-C", "L2"}, + {"ARR38-C", "L2"}, + {"ARR39-C", "L2"}, + {"CON30-C", "L3"}, + {"CON31-C", "L3"}, + {"CON32-C", "L3"}, + {"CON33-C", "L3"}, + {"CON34-C", "L3"}, + {"CON35-C", "L3"}, + {"CON36-C", "L3"}, + {"CON37-C", "L3"}, + {"CON38-C", "L3"}, + {"CON39-C", "L3"}, + {"CON40-C", "L2"}, + {"CON41-C", "L3"}, + {"CON43-C", "L3"}, {"DCL30-C", "L2"}, {"DCL31-C", "L3"}, {"DCL36-C", "L2"}, @@ -1688,6 +1706,15 @@ std::vector checkers::certCInfo{ {"DCL39-C", "L3"}, {"DCL40-C", "L3"}, {"DCL41-C", "L2"}, + {"ENV30-C", "L3"}, + {"ENV31-C", "L3"}, + {"ENV32-C", "L1"}, + {"ENV33-C", "L1"}, + {"ENV34-C", "L3"}, + {"ERR30-C", "L1"}, + {"ERR32-C", "L3"}, + {"ERR33-C", "L1"}, + {"ERR34-C", "L2"}, {"EXP30-C", "L2"}, {"EXP32-C", "L2"}, {"EXP33-C", "L1"}, @@ -1695,7 +1722,7 @@ std::vector checkers::certCInfo{ {"EXP35-C", "L2"}, {"EXP36-C", "L3"}, {"EXP37-C", "L3"}, - {"EXP39-C", "L2"}, + {"EXP39-C", "L3"}, {"EXP40-C", "L3"}, {"EXP42-C", "L1"}, {"EXP43-C", "L3"}, @@ -1703,36 +1730,6 @@ std::vector checkers::certCInfo{ {"EXP45-C", "L2"}, {"EXP46-C", "L2"}, {"EXP47-C", "L2"}, - {"INT30-C", "L2"}, - {"INT31-C", "L1"}, - {"INT32-C", "L1"}, - {"INT33-C", "L2"}, - {"INT34-C", "L3"}, - {"INT35-C", "L3"}, - {"INT36-C", "L3"}, - {"FLP30-C", "L2"}, - {"FLP32-C", "L1"}, - {"FLP34-C", "L3"}, - {"FLP36-C", "L3"}, - {"FLP37-C", "L3"}, - {"ARR30-C", "L2"}, - {"ARR32-C", "L2"}, - {"ARR36-C", "L3"}, - {"ARR37-C", "L2"}, - {"ARR38-C", "L2"}, - {"ARR39-C", "L2"}, - {"STR30-C", "L2"}, - {"STR31-C", "L2"}, - {"STR32-C", "L1"}, - {"STR34-C", "L2"}, - {"STR37-C", "L3"}, - {"STR38-C", "L1"}, - {"MEM30-C", "L2"}, - {"MEM31-C", "L3"}, - {"MEM33-C", "L3"}, - {"MEM34-C", "L2"}, - {"MEM35-C", "L2"}, - {"MEM36-C", "L3"}, {"FIO30-C", "L1"}, {"FIO32-C", "L3"}, {"FIO34-C", "L1"}, @@ -1746,32 +1743,24 @@ std::vector checkers::certCInfo{ {"FIO45-C", "L2"}, {"FIO46-C", "L3"}, {"FIO47-C", "L2"}, - {"ENV30-C", "L3"}, - {"ENV31-C", "L3"}, - {"ENV32-C", "L1"}, - {"ENV33-C", "L1"}, - {"ENV34-C", "L3"}, - {"SIG30-C", "L1"}, - {"SIG31-C", "L1"}, - {"SIG34-C", "L3"}, - {"SIG35-C", "L3"}, - {"ERR30-C", "L1"}, - {"ERR32-C", "L3"}, - {"ERR33-C", "L1"}, - {"ERR34-C", "L2"}, - {"CON30-C", "L3"}, - {"CON31-C", "L3"}, - {"CON32-C", "L3"}, - {"CON33-C", "L3"}, - {"CON34-C", "L3"}, - {"CON35-C", "L3"}, - {"CON36-C", "L3"}, - {"CON37-C", "L3"}, - {"CON38-C", "L3"}, - {"CON39-C", "L3"}, - {"CON40-C", "L2"}, - {"CON41-C", "L3"}, - {"CON43-C", "L3"}, + {"FLP30-C", "L2"}, + {"FLP32-C", "L1"}, + {"FLP34-C", "L3"}, + {"FLP36-C", "L3"}, + {"FLP37-C", "L3"}, + {"INT30-C", "L2"}, + {"INT31-C", "L1"}, + {"INT32-C", "L1"}, + {"INT33-C", "L2"}, + {"INT34-C", "L3"}, + {"INT35-C", "L3"}, + {"INT36-C", "L3"}, + {"MEM30-C", "L2"}, + {"MEM31-C", "L3"}, + {"MEM33-C", "L3"}, + {"MEM34-C", "L2"}, + {"MEM35-C", "L2"}, + {"MEM36-C", "L3"}, {"MSC30-C", "L3"}, {"MSC32-C", "L1"}, {"MSC33-C", "L2"}, @@ -1796,21 +1785,42 @@ std::vector checkers::certCInfo{ {"POS52-C", "L3"}, {"POS53-C", "L2"}, {"POS54-C", "L1"}, + {"PRE30-C", "L3"}, + {"PRE31-C", "L3"}, + {"PRE32-C", "L3"}, + {"SIG30-C", "L1"}, + {"SIG31-C", "L1"}, + {"SIG34-C", "L3"}, + {"SIG35-C", "L3"}, + {"STR30-C", "L2"}, + {"STR31-C", "L2"}, + {"STR32-C", "L1"}, + {"STR34-C", "L2"}, + {"STR37-C", "L3"}, + {"STR38-C", "L1"}, {"WIN30-C", "L3"}, // Recommendations - {"PRE00-C", "L3"}, - {"PRE01-C", "L1"}, - {"PRE02-C", "L1"}, - {"PRE04-C", "L3"}, - {"PRE05-C", "L3"}, - {"PRE06-C", "L3"}, - {"PRE07-C", "L3"}, - {"PRE08-C", "L3"}, - {"PRE09-C", "L1"}, - {"PRE10-C", "L1"}, - {"PRE11-C", "L2"}, - {"PRE12-C", "L3"}, - {"PRE13-C", "L3"}, + {"API00-C", "L3"}, + {"API01-C", "L1"}, + {"API02-C", "L1"}, + {"API03-C", "L3"}, + {"API04-C", "L3"}, + {"API05-C", "L1"}, + {"API07-C", "L3"}, + {"API09-C", "L3"}, + {"API10-C", "L3"}, + {"ARR00-C", "L2"}, + {"ARR01-C", "L1"}, + {"ARR02-C", "L2"}, + {"CON01-C", "L3"}, + {"CON02-C", "L3"}, + {"CON03-C", "L3"}, + {"CON04-C", "L3"}, + {"CON05-C", "L3"}, + {"CON06-C", "L3"}, + {"CON07-C", "L2"}, + {"CON08-C", "L3"}, + {"CON09-C", "L3"}, {"DCL00-C", "L3"}, {"DCL01-C", "L3"}, {"DCL02-C", "L3"}, @@ -1834,6 +1844,16 @@ std::vector checkers::certCInfo{ {"DCL21-C", "L3"}, {"DCL22-C", "L3"}, {"DCL23-C", "L2"}, + {"ENV01-C", "L2"}, + {"ENV02-C", "L3"}, + {"ENV03-C", "L2"}, + {"ERR00-C", "L3"}, + {"ERR01-C", "L2"}, + {"ERR02-C", "L3"}, + {"ERR04-C", "L3"}, + {"ERR05-C", "L2"}, + {"ERR06-C", "L3"}, + {"ERR07-C", "L1"}, {"EXP00-C", "L2"}, {"EXP02-C", "L3"}, {"EXP03-C", "L3"}, @@ -1850,44 +1870,6 @@ std::vector checkers::certCInfo{ {"EXP16-C", "L2"}, {"EXP19-C", "L1"}, {"EXP20-C", "L1"}, - {"INT00-C", "L3"}, - {"INT01-C", "L2"}, - {"INT02-C", "L3"}, - {"INT04-C", "L1"}, - {"INT05-C", "L2"}, - {"INT07-C", "L1"}, - {"INT08-C", "L3"}, - {"INT09-C", "L3"}, - {"INT10-C", "L3"}, - {"INT12-C", "L3"}, - {"INT13-C", "L2"}, - {"INT14-C", "L3"}, - {"INT15-C", "L2"}, - {"INT16-C", "L3"}, - {"INT17-C", "L3"}, - {"INT18-C", "L1"}, - {"FLP00-C", "L3"}, - {"FLP01-C", "L3"}, - {"FLP02-C", "L3"}, - {"FLP03-C", "L3"}, - {"FLP04-C", "L3"}, - {"FLP05-C", "L3"}, - {"FLP06-C", "L3"}, - {"FLP07-C", "L3"}, - {"ARR00-C", "L2"}, - {"ARR01-C", "L1"}, - {"ARR02-C", "L2"}, - {"STR00-C", "L3"}, - {"STR01-C", "L3"}, - {"STR02-C", "L2"}, - {"STR03-C", "L3"}, - {"STR04-C", "L3"}, - {"STR05-C", "L3"}, - {"STR06-C", "L2"}, - {"STR08-C", "L2"}, - {"STR09-C", "L3"}, - {"STR10-C", "L3"}, - {"STR11-C", "L2"}, {"FIO01-C", "L1"}, {"FIO02-C", "L3"}, {"FIO03-C", "L3"}, @@ -1908,36 +1890,41 @@ std::vector checkers::certCInfo{ {"FIO22-C", "L3"}, {"FIO23-C", "L3"}, {"FIO24-C", "L3"}, - {"ENV01-C", "L2"}, - {"ENV02-C", "L3"}, - {"ENV03-C", "L2"}, - {"SIG00-C", "L2"}, - {"SIG01-C", "L3"}, - {"SIG02-C", "L2"}, - {"ERR00-C", "L3"}, - {"ERR01-C", "L2"}, - {"ERR02-C", "L3"}, - {"ERR04-C", "L3"}, - {"ERR05-C", "L2"}, - {"ERR06-C", "L3"}, - {"ERR07-C", "L1"}, - {"API00-C", "L3"}, - {"API01-C", "L1"}, - {"API02-C", "L1"}, - {"API03-C", "L3"}, - {"API04-C", "L3"}, - {"API05-C", "L1"}, - {"API07-C", "L3"}, - {"API09-C", "L3"}, - {"API10-C", "L3"}, - {"CON01-C", "L3"}, - {"CON02-C", "L3"}, - {"CON04-C", "L3"}, - {"CON05-C", "L3"}, - {"CON06-C", "L3"}, - {"CON07-C", "L2"}, - {"CON08-C", "L3"}, - {"CON09-C", "L3"}, + {"FLP00-C", "L3"}, + {"FLP01-C", "L3"}, + {"FLP02-C", "L3"}, + {"FLP03-C", "L3"}, + {"FLP04-C", "L3"}, + {"FLP05-C", "L3"}, + {"FLP06-C", "L3"}, + {"FLP07-C", "L3"}, + {"INT00-C", "L3"}, + {"INT01-C", "L2"}, + {"INT02-C", "L3"}, + {"INT04-C", "L1"}, + {"INT05-C", "L2"}, + {"INT07-C", "L1"}, + {"INT08-C", "L3"}, + {"INT09-C", "L3"}, + {"INT10-C", "L3"}, + {"INT12-C", "L3"}, + {"INT13-C", "L2"}, + {"INT14-C", "L3"}, + {"INT15-C", "L2"}, + {"INT16-C", "L3"}, + {"INT17-C", "L3"}, + {"INT18-C", "L1"}, + {"MEM00-C", "L1"}, + {"MEM01-C", "L2"}, + {"MEM02-C", "L3"}, + {"MEM03-C", "L3"}, + {"MEM04-C", "L2"}, + {"MEM05-C", "L2"}, + {"MEM06-C", "L3"}, + {"MEM07-C", "L2"}, + {"MEM10-C", "L3"}, + {"MEM11-C", "L3"}, + {"MEM12-C", "L3"}, {"MSC00-C", "L3"}, {"MSC01-C", "L3"}, {"MSC04-C", "L3"}, @@ -1964,6 +1951,32 @@ std::vector checkers::certCInfo{ {"POS02-C", "L2"}, {"POS04-C", "L3"}, {"POS05-C", "L3"}, + {"PRE00-C", "L3"}, + {"PRE01-C", "L1"}, + {"PRE02-C", "L1"}, + {"PRE04-C", "L3"}, + {"PRE05-C", "L3"}, + {"PRE06-C", "L3"}, + {"PRE07-C", "L3"}, + {"PRE08-C", "L3"}, + {"PRE09-C", "L1"}, + {"PRE10-C", "L1"}, + {"PRE11-C", "L2"}, + {"PRE12-C", "L3"}, + {"PRE13-C", "L3"}, + {"SIG00-C", "L2"}, + {"SIG01-C", "L3"}, + {"SIG02-C", "L2"}, + {"STR00-C", "L3"}, + {"STR01-C", "L3"}, + {"STR02-C", "L2"}, + {"STR03-C", "L3"}, + {"STR04-C", "L3"}, + {"STR05-C", "L3"}, + {"STR06-C", "L2"}, + {"STR09-C", "L3"}, + {"STR10-C", "L3"}, + {"STR11-C", "L2"}, {"WIN00-C", "L2"}, {"WIN01-C", "L1"}, {"WIN02-C", "L1"}, @@ -1972,6 +1985,22 @@ std::vector checkers::certCInfo{ }; std::vector checkers::certCppInfo{ + {"CON50-CPP", "L3"}, + {"CON51-CPP", "L2"}, + {"CON52-CPP", "L3"}, + {"CON53-CPP", "L3"}, + {"CON54-CPP", "L3"}, + {"CON55-CPP", "L3"}, + {"CON56-CPP", "L3"}, + {"CTR50-CPP", "L2"}, + {"CTR51-CPP", "L2"}, + {"CTR52-CPP", "L2"}, + {"CTR53-CPP", "L2"}, + {"CTR54-CPP", "L3"}, + {"CTR55-CPP", "L2"}, + {"CTR56-CPP", "L2"}, + {"CTR57-CPP", "L3"}, + {"CTR58-CPP", "L2"}, {"DCL50-CPP", "L1"}, {"DCL51-CPP", "L3"}, {"DCL52-CPP", "L3"}, @@ -1983,6 +2012,19 @@ std::vector checkers::certCppInfo{ {"DCL58-CPP", "L2"}, {"DCL59-CPP", "L3"}, {"DCL60-CPP", "L2"}, + {"ERR50-CPP", "L3"}, + {"ERR51-CPP", "L2"}, + {"ERR52-CPP", "L3"}, + {"ERR53-CPP", "L3"}, + {"ERR54-CPP", "L1"}, + {"ERR55-CPP", "L2"}, + {"ERR56-CPP", "L2"}, + {"ERR57-CPP", "L3"}, + {"ERR58-CPP", "L2"}, + {"ERR59-CPP", "L2"}, + {"ERR60-CPP", "L3"}, + {"ERR61-CPP", "L3"}, + {"ERR62-CPP", "L3"}, {"EXP50-CPP", "L2"}, {"EXP51-CPP", "L3"}, {"EXP52-CPP", "L3"}, @@ -1997,20 +2039,9 @@ std::vector checkers::certCppInfo{ {"EXP61-CPP", "L2"}, {"EXP62-CPP", "L1"}, {"EXP63-CPP", "L2"}, + {"FIO50-CPP", "L2"}, + {"FIO51-CPP", "L3"}, {"INT50-CPP", "L3"}, - {"CTR50-CPP", "L2"}, - {"CTR51-CPP", "L2"}, - {"CTR52-CPP", "L2"}, - {"CTR53-CPP", "L2"}, - {"CTR54-CPP", "L3"}, - {"CTR55-CPP", "L2"}, - {"CTR56-CPP", "L2"}, - {"CTR57-CPP", "L3"}, - {"CTR58-CPP", "L2"}, - {"STR50-CPP", "L2"}, - {"STR51-CPP", "L1"}, - {"STR52-CPP", "L2"}, - {"STR53-CPP", "L3"}, {"MEM50-CPP", "L2"}, {"MEM51-CPP", "L2"}, {"MEM52-CPP", "L1"}, @@ -2019,21 +2050,11 @@ std::vector checkers::certCppInfo{ {"MEM55-CPP", "L2"}, {"MEM56-CPP", "L2"}, {"MEM57-CPP", "L3"}, - {"FIO50-CPP", "L2"}, - {"FIO51-CPP", "L3"}, - {"ERR50-CPP", "L3"}, - {"ERR51-CPP", "L2"}, - {"ERR52-CPP", "L3"}, - {"ERR53-CPP", "L3"}, - {"ERR54-CPP", "L1"}, - {"ERR55-CPP", "L2"}, - {"ERR56-CPP", "L2"}, - {"ERR57-CPP", "L3"}, - {"ERR58-CPP", "L2"}, - {"ERR59-CPP", "L2"}, - {"ERR60-CPP", "L3"}, - {"ERR61-CPP", "L3"}, - {"ERR62-CPP", "L3"}, + {"MSC50-CPP", "L3"}, + {"MSC51-CPP", "L1"}, + {"MSC52-CPP", "L2"}, + {"MSC53-CPP", "L3"}, + {"MSC54-CPP", "L2"}, {"OOP50-CPP", "L3"}, {"OOP51-CPP", "L3"}, {"OOP52-CPP", "L3"}, @@ -2043,17 +2064,9 @@ std::vector checkers::certCppInfo{ {"OOP56-CPP", "L3"}, {"OOP57-CPP", "L1"}, {"OOP58-CPP", "L2"}, - {"CON50-CPP", "L3"}, - {"CON51-CPP", "L2"}, - {"CON52-CPP", "L3"}, - {"CON53-CPP", "L3"}, - {"CON54-CPP", "L3"}, - {"CON55-CPP", "L3"}, - {"CON56-CPP", "L3"}, - {"MSC50-CPP", "L3"}, - {"MSC51-CPP", "L1"}, - {"MSC52-CPP", "L2"}, - {"MSC53-CPP", "L3"}, - {"MSC54-CPP", "L2"}, + {"STR50-CPP", "L2"}, + {"STR51-CPP", "L1"}, + {"STR52-CPP", "L2"}, + {"STR53-CPP", "L3"}, }; diff --git a/lib/checkexceptionsafety.cpp b/lib/checkexceptionsafety.cpp index 34303cc0f4a..29342fb4dbc 100644 --- a/lib/checkexceptionsafety.cpp +++ b/lib/checkexceptionsafety.cpp @@ -34,20 +34,15 @@ //--------------------------------------------------------------------------- -// 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 //--------------------------------------------------------------------------- -void CheckExceptionSafety::destructors() +void CheckExceptionSafetyImpl::destructors() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckExceptionSafety::destructors"); // warning @@ -83,7 +78,7 @@ void CheckExceptionSafety::destructors() } } -void CheckExceptionSafety::destructorsError(const Token * const tok, const std::string &className) +void CheckExceptionSafetyImpl::destructorsError(const Token * const tok, const std::string &className) { reportError(tok, Severity::warning, "exceptThrowInDestructor", "Class " + className + " is not safe, destructor throws exception\n" @@ -93,14 +88,14 @@ void CheckExceptionSafety::destructorsError(const Token * const tok, const std:: } -void CheckExceptionSafety::deallocThrow() +void CheckExceptionSafetyImpl::deallocThrow() { - if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("exceptDeallocThrow")) + if (!mSettings.severity.isEnabled(Severity::warning) && !mSettings.isPremiumEnabled("exceptDeallocThrow")) return; logChecker("CheckExceptionSafety::deallocThrow"); // warning - const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive); + const bool printInconclusive = mSettings.certainty.isEnabled(Certainty::inconclusive); const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase(); // Deallocate a global/member pointer and then throw exception @@ -156,7 +151,7 @@ void CheckExceptionSafety::deallocThrow() } } -void CheckExceptionSafety::deallocThrowError(const Token * const tok, const std::string &varname) +void CheckExceptionSafetyImpl::deallocThrowError(const Token * const tok, const std::string &varname) { reportError(tok, Severity::warning, "exceptDeallocThrow", "Exception thrown in invalid state, '" + varname + "' points at deallocated memory.", CWE398, Certainty::normal); @@ -168,9 +163,9 @@ void CheckExceptionSafety::deallocThrowError(const Token * const tok, const std: // throw err; // <- should be just "throw;" // } //--------------------------------------------------------------------------- -void CheckExceptionSafety::checkRethrowCopy() +void CheckExceptionSafetyImpl::checkRethrowCopy() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("exceptRethrowCopy")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("exceptRethrowCopy")) return; logChecker("CheckExceptionSafety::checkRethrowCopy"); // style @@ -201,7 +196,7 @@ void CheckExceptionSafety::checkRethrowCopy() } } -void CheckExceptionSafety::rethrowCopyError(const Token * const tok, const std::string &varname) +void CheckExceptionSafetyImpl::rethrowCopyError(const Token * const tok, const std::string &varname) { reportError(tok, Severity::style, "exceptRethrowCopy", "Throwing a copy of the caught exception instead of rethrowing the original exception.\n" @@ -212,9 +207,9 @@ void CheckExceptionSafety::rethrowCopyError(const Token * const tok, const std:: //--------------------------------------------------------------------------- // try {} catch (std::exception err) {} <- Should be "std::exception& err" //--------------------------------------------------------------------------- -void CheckExceptionSafety::checkCatchExceptionByValue() +void CheckExceptionSafetyImpl::checkCatchExceptionByValue() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("catchExceptionByValue")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("catchExceptionByValue")) return; logChecker("CheckExceptionSafety::checkCatchExceptionByValue"); // style @@ -233,7 +228,7 @@ void CheckExceptionSafety::checkCatchExceptionByValue() } } -void CheckExceptionSafety::catchExceptionByValueError(const Token *tok) +void CheckExceptionSafetyImpl::catchExceptionByValueError(const Token *tok) { reportError(tok, Severity::style, "catchExceptionByValue", "Exception should be caught by reference.\n" @@ -286,7 +281,7 @@ static const Token * functionThrows(const Function * function) // void func() throw() { throw x; } // void func() __attribute__((nothrow)); void func() { throw x; } //-------------------------------------------------------------------------- -void CheckExceptionSafety::nothrowThrows() +void CheckExceptionSafetyImpl::nothrowThrows() { logChecker("CheckExceptionSafety::nothrowThrows"); @@ -303,7 +298,7 @@ void CheckExceptionSafety::nothrowThrows() function->isAttributeNothrow()) { // __attribute__((nothrow)) or __declspec(nothrow) functions isNoExcept = true; } - else if (mSettings->library.isentrypoint(function->name())) { + else if (mSettings.library.isentrypoint(function->name())) { isEntryPoint = true; } if (!isNoExcept && !isEntryPoint) @@ -318,12 +313,12 @@ void CheckExceptionSafety::nothrowThrows() } } -void CheckExceptionSafety::noexceptThrowError(const Token * const tok) +void CheckExceptionSafetyImpl::noexceptThrowError(const Token * const tok) { reportError(tok, Severity::error, "throwInNoexceptFunction", "Unhandled exception thrown in function declared not to throw exceptions.", CWE398, Certainty::normal); } -void CheckExceptionSafety::entryPointThrowError(const Token * const tok) +void CheckExceptionSafetyImpl::entryPointThrowError(const Token * const tok) { reportError(tok, Severity::error, "throwInEntryPoint", "Unhandled exception thrown in function that is an entry point.", CWE398, Certainty::normal); } @@ -331,10 +326,10 @@ void CheckExceptionSafety::entryPointThrowError(const Token * const tok) //-------------------------------------------------------------------------- // void func() { functionWithExceptionSpecification(); } //-------------------------------------------------------------------------- -void CheckExceptionSafety::unhandledExceptionSpecification() +void CheckExceptionSafetyImpl::unhandledExceptionSpecification() { - if ((!mSettings->severity.isEnabled(Severity::style) || !mSettings->certainty.isEnabled(Certainty::inconclusive)) && - !mSettings->isPremiumEnabled("unhandledExceptionSpecification")) + if ((!mSettings.severity.isEnabled(Severity::style) || !mSettings.certainty.isEnabled(Certainty::inconclusive)) && + !mSettings.isPremiumEnabled("unhandledExceptionSpecification")) return; logChecker("CheckExceptionSafety::unhandledExceptionSpecification"); // style,inconclusive @@ -343,7 +338,7 @@ void CheckExceptionSafety::unhandledExceptionSpecification() for (const Scope * scope : symbolDatabase->functionScopes) { // only check functions without exception specification - if (scope->function && !scope->function->isThrow() && !mSettings->library.isentrypoint(scope->className)) { + if (scope->function && !scope->function->isThrow() && !mSettings.library.isentrypoint(scope->className)) { for (const Token *tok = scope->function->functionScope->bodyStart->next(); tok != scope->function->functionScope->bodyEnd; tok = tok->next()) { if (tok->str() == "try") @@ -361,7 +356,7 @@ void CheckExceptionSafety::unhandledExceptionSpecification() } } -void CheckExceptionSafety::unhandledExceptionSpecificationError(const Token * const tok1, const Token * const tok2, const std::string & funcname) +void CheckExceptionSafetyImpl::unhandledExceptionSpecificationError(const Token * const tok1, const Token * const tok2, const std::string & funcname) { const std::string str1(tok1 ? tok1->str() : "foo"); const std::list locationList = { tok1, tok2 }; @@ -374,7 +369,7 @@ void CheckExceptionSafety::unhandledExceptionSpecificationError(const Token * co //-------------------------------------------------------------------------- // 7.6.18.4 If no exception is presently being handled, evaluating a throw-expression with no operand calls std​::​​terminate(). //-------------------------------------------------------------------------- -void CheckExceptionSafety::rethrowNoCurrentException() +void CheckExceptionSafetyImpl::rethrowNoCurrentException() { logChecker("CheckExceptionSafety::rethrowNoCurrentException"); const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -405,7 +400,7 @@ void CheckExceptionSafety::rethrowNoCurrentException() } } -void CheckExceptionSafety::rethrowNoCurrentExceptionError(const Token *tok) +void CheckExceptionSafetyImpl::rethrowNoCurrentExceptionError(const Token *tok) { reportError(tok, Severity::error, "rethrowNoCurrentException", "Rethrowing current exception with 'throw;', it seems there is no current exception to rethrow." @@ -414,12 +409,12 @@ void CheckExceptionSafety::rethrowNoCurrentExceptionError(const Token *tok) CWE480, Certainty::normal); } -void CheckExceptionSafety::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckExceptionSafety::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { if (tokenizer.isC()) return; - CheckExceptionSafety checkExceptionSafety(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckExceptionSafetyImpl checkExceptionSafety(&tokenizer, tokenizer.getSettings(), errorLogger); checkExceptionSafety.destructors(); checkExceptionSafety.deallocThrow(); checkExceptionSafety.checkRethrowCopy(); @@ -429,9 +424,9 @@ void CheckExceptionSafety::runChecks(const Tokenizer &tokenizer, ErrorLogger *er checkExceptionSafety.rethrowNoCurrentException(); } -void CheckExceptionSafety::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const +void CheckExceptionSafety::getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const { - CheckExceptionSafety c(nullptr, settings, errorLogger); + CheckExceptionSafetyImpl c(nullptr, settings, errorLogger); c.destructorsError(nullptr, "Class"); c.deallocThrowError(nullptr, "p"); c.rethrowCopyError(nullptr, "varname"); diff --git a/lib/checkexceptionsafety.h b/lib/checkexceptionsafety.h index 7c5a52b5605..8b52d773a93 100644 --- a/lib/checkexceptionsafety.h +++ b/lib/checkexceptionsafety.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 @@ -22,6 +22,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include @@ -46,14 +47,32 @@ class Tokenizer; class CPPCHECKLIB CheckExceptionSafety : public Check { public: /** This constructor is used when registering the CheckClass */ - CheckExceptionSafety() : Check(myName()) {} + CheckExceptionSafety() : Check("Exception Safety") {} private: - /** This constructor is used when running checks. */ - CheckExceptionSafety(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + + /** Generate all possible errors (for --errorlist) */ + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + /** wiki formatted description of the class (for --doc) */ + std::string classInfo() const override { + return "Checking exception safety\n" + "- Throwing exceptions in destructors\n" + "- Throwing exception during invalid state\n" + "- Throwing a copy of a caught exception instead of rethrowing the original exception\n" + "- Exception caught by value instead of by reference\n" + "- Throwing exception in noexcept, nothrow(), __attribute__((nothrow)) or __declspec(nothrow) function\n" + "- Unhandled exception specification when calling function foo()\n" + "- Rethrow without currently handled exception\n"; + } +}; + +class CPPCHECKLIB CheckExceptionSafetyImpl : public CheckImpl { +public: + /** This constructor is used when running checks. */ + CheckExceptionSafetyImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} /** Don't throw exceptions in destructors */ void destructors(); @@ -87,26 +106,6 @@ class CPPCHECKLIB CheckExceptionSafety : public Check { void unhandledExceptionSpecificationError(const Token * tok1, const Token * tok2, const std::string & funcname); /** Rethrow without currently handled exception */ void rethrowNoCurrentExceptionError(const Token *tok); - - /** Generate all possible errors (for --errorlist) */ - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - /** Short description of class (for --doc) */ - static std::string myName() { - return "Exception Safety"; - } - - /** wiki formatted description of the class (for --doc) */ - std::string classInfo() const override { - return "Checking exception safety\n" - "- Throwing exceptions in destructors\n" - "- Throwing exception during invalid state\n" - "- Throwing a copy of a caught exception instead of rethrowing the original exception\n" - "- Exception caught by value instead of by reference\n" - "- Throwing exception in noexcept, nothrow(), __attribute__((nothrow)) or __declspec(nothrow) function\n" - "- Unhandled exception specification when calling function foo()\n" - "- Rethrow without currently handled exception\n"; - } }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checkfunctions.cpp b/lib/checkfunctions.cpp index 7611ea7eee4..1edfdfab6ac 100644 --- a/lib/checkfunctions.cpp +++ b/lib/checkfunctions.cpp @@ -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 @@ -58,9 +52,9 @@ static const CWE CWE686(686U); // Function Call With Incorrect Argument Type static const CWE CWE687(687U); // Function Call With Incorrectly Specified Argument Value static const CWE CWE688(688U); // Function Call With Incorrect Variable or Reference as Argument -void CheckFunctions::checkProhibitedFunctions() +void CheckFunctionsImpl::checkProhibitedFunctions() { - const bool checkAlloca = mSettings->severity.isEnabled(Severity::warning) && ((mTokenizer->isC() && mSettings->standards.c >= Standards::C99) || mSettings->standards.cpp >= Standards::CPP11); + const bool checkAlloca = mSettings.severity.isEnabled(Severity::warning) && ((mTokenizer->isC() && mSettings.standards.c >= Standards::C99) || mSettings.standards.cpp >= Standards::CPP11); logChecker("CheckFunctions::checkProhibitedFunctions"); @@ -72,7 +66,7 @@ void CheckFunctions::checkProhibitedFunctions() // alloca() is special as it depends on the code being C or C++, so it is not in Library if (checkAlloca && Token::simpleMatch(tok, "alloca (") && (!tok->function() || tok->function()->nestedIn->type == ScopeType::eGlobal)) { if (tok->isC()) { - if (mSettings->standards.c > Standards::C89) + if (mSettings.standards.c > Standards::C89) reportError(tok, Severity::warning, "allocaCalled", "$symbol:alloca\n" "Obsolete function 'alloca' called. In C99 and later it is recommended to use a variable length array instead.\n" @@ -90,11 +84,12 @@ void CheckFunctions::checkProhibitedFunctions() if (tok->function() && tok->function()->hasBody()) continue; - const Library::WarnInfo* wi = mSettings->library.getWarnInfo(tok); + const Library::WarnInfo* wi = mSettings.library.getWarnInfo(tok); if (wi) { - if (mSettings->severity.isEnabled(wi->severity) && ((tok->isC() && mSettings->standards.c >= wi->standards.c) || (tok->isCpp() && mSettings->standards.cpp >= wi->standards.cpp))) { - const std::string daca = mSettings->daca ? "prohibited" : ""; - reportError(tok, wi->severity, daca + tok->str() + "Called", wi->message, CWE477, Certainty::normal); + if (mSettings.severity.isEnabled(wi->severity) && ((tok->isC() && mSettings.standards.c >= wi->standards.c) || (tok->isCpp() && mSettings.standards.cpp >= wi->standards.cpp))) { + const std::string daca = mSettings.daca ? "prohibited" : ""; + const std::string prefix = daca + tok->str(); + functionCalledError(tok, wi->severity, prefix, wi->message); } } } @@ -102,10 +97,15 @@ void CheckFunctions::checkProhibitedFunctions() } } +void CheckFunctionsImpl::functionCalledError(const Token* tok, Severity severity, const std::string& prefix, const std::string& msg) +{ + reportError(tok, severity, prefix + "Called", msg, CWE477, Certainty::normal); +} + //--------------------------------------------------------------------------- // Check , and //--------------------------------------------------------------------------- -void CheckFunctions::invalidFunctionUsage() +void CheckFunctionsImpl::invalidFunctionUsage() { logChecker("CheckFunctions::invalidFunctionUsage"); const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -116,28 +116,28 @@ void CheckFunctions::invalidFunctionUsage() continue; const Token * const functionToken = tok; const std::vector arguments = getArguments(tok); - for (int argnr = 1; argnr <= arguments.size(); ++argnr) { + for (size_t argnr = 1; argnr <= arguments.size(); ++argnr) { const Token * const argtok = arguments[argnr-1]; // check ... - const ValueFlow::Value *invalidValue = argtok->getInvalidValue(functionToken,argnr,*mSettings); + const ValueFlow::Value *invalidValue = argtok->getInvalidValue(functionToken,argnr,mSettings); if (invalidValue) { - invalidFunctionArgError(argtok, functionToken->next()->astOperand1()->expressionString(), argnr, invalidValue, mSettings->library.validarg(functionToken, argnr)); + invalidFunctionArgError(argtok, functionToken->next()->astOperand1()->expressionString(), argnr, invalidValue, mSettings.library.validarg(functionToken, argnr)); } if (astIsBool(argtok)) { // check - if (mSettings->library.isboolargbad(functionToken, argnr)) + if (mSettings.library.isboolargbad(functionToken, argnr)) invalidFunctionArgBoolError(argtok, functionToken->str(), argnr); // Are the values 0 and 1 valid? - else if (!mSettings->library.isIntArgValid(functionToken, argnr, 0, *mSettings)) - invalidFunctionArgError(argtok, functionToken->str(), argnr, nullptr, mSettings->library.validarg(functionToken, argnr)); - else if (!mSettings->library.isIntArgValid(functionToken, argnr, 1, *mSettings)) - invalidFunctionArgError(argtok, functionToken->str(), argnr, nullptr, mSettings->library.validarg(functionToken, argnr)); + else if (!mSettings.library.isIntArgValid(functionToken, argnr, 0, mSettings)) + invalidFunctionArgError(argtok, functionToken->str(), argnr, nullptr, mSettings.library.validarg(functionToken, argnr)); + else if (!mSettings.library.isIntArgValid(functionToken, argnr, 1, mSettings)) + invalidFunctionArgError(argtok, functionToken->str(), argnr, nullptr, mSettings.library.validarg(functionToken, argnr)); } // check - if (mSettings->library.isargstrz(functionToken, argnr)) { + if (mSettings.library.isargstrz(functionToken, argnr)) { if (Token::Match(argtok, "& %var% !![") && argtok->next() && argtok->next()->valueType()) { const ValueType * valueType = argtok->next()->valueType(); const Variable * variable = argtok->next()->variable(); @@ -153,7 +153,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, valueType->pointer, { 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(), "[")) @@ -183,7 +183,7 @@ void CheckFunctions::invalidFunctionUsage() invalidFunctionArgStrError(argtok, functionToken->str(), argnr); } } else if (count > -1 && Token::Match(varTok, "= %str%")) { - const Token* strTok = varTok->getValueTokenMinStrSize(*mSettings); + const Token* strTok = varTok->getValueTokenMinStrSize(mSettings); if (strTok) { const int strSize = Token::getStrArraySize(strTok); if (strSize > count && strTok->str().find('\0') == std::string::npos) @@ -197,7 +197,7 @@ void CheckFunctions::invalidFunctionUsage() } } -void CheckFunctions::invalidFunctionArgError(const Token *tok, const std::string &functionName, int argnr, const ValueFlow::Value *invalidValue, const std::string &validstr) +void CheckFunctionsImpl::invalidFunctionArgError(const Token *tok, const std::string &functionName, int argnr, const ValueFlow::Value *invalidValue, const std::string &validstr) { std::ostringstream errmsg; errmsg << "$symbol:" << functionName << '\n'; @@ -226,7 +226,7 @@ void CheckFunctions::invalidFunctionArgError(const Token *tok, const std::string Certainty::normal); } -void CheckFunctions::invalidFunctionArgBoolError(const Token *tok, const std::string &functionName, int argnr) +void CheckFunctionsImpl::invalidFunctionArgBoolError(const Token *tok, const std::string &functionName, int argnr) { std::ostringstream errmsg; errmsg << "$symbol:" << functionName << '\n'; @@ -234,7 +234,7 @@ void CheckFunctions::invalidFunctionArgBoolError(const Token *tok, const std::st reportError(tok, Severity::error, "invalidFunctionArgBool", errmsg.str(), CWE628, Certainty::normal); } -void CheckFunctions::invalidFunctionArgStrError(const Token *tok, const std::string &functionName, nonneg int argnr) +void CheckFunctionsImpl::invalidFunctionArgStrError(const Token *tok, const std::string &functionName, nonneg int argnr) { std::ostringstream errmsg; errmsg << "$symbol:" << functionName << '\n'; @@ -245,11 +245,11 @@ void CheckFunctions::invalidFunctionArgStrError(const Token *tok, const std::str //--------------------------------------------------------------------------- // Check for ignored return values. //--------------------------------------------------------------------------- -void CheckFunctions::checkIgnoredReturnValue() +void CheckFunctionsImpl::checkIgnoredReturnValue() { - if (!mSettings->severity.isEnabled(Severity::warning) && - !mSettings->severity.isEnabled(Severity::style) && - !mSettings->isPremiumEnabled("ignoredReturnValue")) + if (!mSettings.severity.isEnabled(Severity::warning) && + !mSettings.severity.isEnabled(Severity::style) && + !mSettings.isPremiumEnabled("ignoredReturnValue")) return; logChecker("CheckFunctions::checkIgnoredReturnValue"); // style,warning @@ -282,13 +282,13 @@ void CheckFunctions::checkIgnoredReturnValue() if ((!tok->function() || !Token::Match(tok->function()->retDef, "void %name%")) && tok->next()->astOperand1()) { - const Library::UseRetValType retvalTy = mSettings->library.getUseRetValType(tok); + const Library::UseRetValType retvalTy = mSettings.library.getUseRetValType(tok); const bool warn = (tok->function() && (tok->function()->isAttributeNodiscard() || tok->function()->isAttributePure() || tok->function()->isAttributeConst())) || // avoid duplicate warnings for resource-allocating functions - (retvalTy == Library::UseRetValType::DEFAULT && mSettings->library.getAllocFuncInfo(tok) == nullptr); - if (mSettings->severity.isEnabled(Severity::warning) && warn) + (retvalTy == Library::UseRetValType::DEFAULT && mSettings.library.getAllocFuncInfo(tok) == nullptr); + if (mSettings.severity.isEnabled(Severity::warning) && warn) ignoredReturnValueError(tok, tok->next()->astOperand1()->expressionString()); - else if (mSettings->severity.isEnabled(Severity::style) && + else if (mSettings.severity.isEnabled(Severity::style) && retvalTy == Library::UseRetValType::ERROR_CODE) ignoredReturnErrorCode(tok, tok->next()->astOperand1()->expressionString()); } @@ -296,13 +296,13 @@ void CheckFunctions::checkIgnoredReturnValue() } } -void CheckFunctions::ignoredReturnValueError(const Token* tok, const std::string& function) +void CheckFunctionsImpl::ignoredReturnValueError(const Token* tok, const std::string& function) { reportError(tok, Severity::warning, "ignoredReturnValue", "$symbol:" + function + "\nReturn value of function $symbol() is not used.", CWE252, Certainty::normal); } -void CheckFunctions::ignoredReturnErrorCode(const Token* tok, const std::string& function) +void CheckFunctionsImpl::ignoredReturnErrorCode(const Token* tok, const std::string& function) { reportError(tok, Severity::style, "ignoredReturnErrorCode", "$symbol:" + function + "\nError code from the return value of function $symbol() is not used.", CWE252, Certainty::normal); @@ -313,7 +313,7 @@ void CheckFunctions::ignoredReturnErrorCode(const Token* tok, const std::string& //--------------------------------------------------------------------------- static const Token *checkMissingReturnScope(const Token *tok, const Library &library); -void CheckFunctions::checkMissingReturn() +void CheckFunctionsImpl::checkMissingReturn() { logChecker("CheckFunctions::checkMissingReturn"); const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -321,7 +321,7 @@ void CheckFunctions::checkMissingReturn() const Function *function = scope->function; if (!function || !function->hasBody()) continue; - if (function->name() == "main" && !(mTokenizer->isC() && mSettings->standards.c < Standards::C99)) + if (function->name() == "main" && !(mTokenizer->isC() && mSettings.standards.c < Standards::C99)) continue; if (function->type != FunctionType::eFunction && function->type != FunctionType::eOperatorEqual) continue; @@ -329,7 +329,9 @@ void CheckFunctions::checkMissingReturn() continue; if (Function::returnsVoid(function, true)) continue; - const Token *errorToken = checkMissingReturnScope(scope->bodyEnd, mSettings->library); + if (Function::isCoroutine(function, mSettings.standards, *mTokenizer)) + continue; + const Token *errorToken = checkMissingReturnScope(scope->bodyEnd, mSettings.library); if (errorToken) missingReturnError(errorToken); } @@ -431,7 +433,7 @@ static const Token *checkMissingReturnScope(const Token *tok, const Library &lib return nullptr; } -void CheckFunctions::missingReturnError(const Token* tok) +void CheckFunctionsImpl::missingReturnError(const Token* tok) { reportError(tok, Severity::error, "missingReturn", "Found an exit path from function with non-void return type that has missing return statement", CWE758, Certainty::normal); @@ -439,12 +441,12 @@ void CheckFunctions::missingReturnError(const Token* tok) //--------------------------------------------------------------------------- // Detect passing wrong values to functions like atan(0, x); //--------------------------------------------------------------------------- -void CheckFunctions::checkMathFunctions() +void CheckFunctionsImpl::checkMathFunctions() { - const bool styleC99 = mSettings->severity.isEnabled(Severity::style) && ((mTokenizer->isC() && mSettings->standards.c != Standards::C89) || (mTokenizer->isCPP() && mSettings->standards.cpp != Standards::CPP03)); - const bool printWarnings = mSettings->severity.isEnabled(Severity::warning); + const bool styleC99 = mSettings.severity.isEnabled(Severity::style) && ((mTokenizer->isC() && mSettings.standards.c != Standards::C89) || (mTokenizer->isCPP() && mSettings.standards.cpp != Standards::CPP03)); + const bool printWarnings = mSettings.severity.isEnabled(Severity::warning); - if (!styleC99 && !printWarnings && !mSettings->isPremiumEnabled("wrongmathcall")) + if (!styleC99 && !printWarnings && !mSettings.isPremiumEnabled("wrongmathcall")) return; logChecker("CheckFunctions::checkMathFunctions"); // style,warning,c99,c++11 @@ -500,7 +502,7 @@ void CheckFunctions::checkMathFunctions() } } -void CheckFunctions::mathfunctionCallWarning(const Token *tok, const nonneg int numParam) +void CheckFunctionsImpl::mathfunctionCallWarning(const Token *tok, const nonneg int numParam) { if (tok) { if (numParam == 1) @@ -511,7 +513,7 @@ void CheckFunctions::mathfunctionCallWarning(const Token *tok, const nonneg int reportError(tok, Severity::warning, "wrongmathcall", "Passing value '#' to #() leads to implementation-defined result.", CWE758, Certainty::normal); } -void CheckFunctions::mathfunctionCallWarning(const Token *tok, const std::string& oldexp, const std::string& newexp) +void CheckFunctionsImpl::mathfunctionCallWarning(const Token *tok, const std::string& oldexp, const std::string& newexp) { reportError(tok, Severity::style, "unpreciseMathCall", "Expression '" + oldexp + "' can be replaced by '" + newexp + "' to avoid loss of precision.", CWE758, Certainty::normal); } @@ -519,7 +521,7 @@ void CheckFunctions::mathfunctionCallWarning(const Token *tok, const std::string //--------------------------------------------------------------------------- // memset(p, y, 0 /* bytes to fill */) <- 2nd and 3rd arguments inverted //--------------------------------------------------------------------------- -void CheckFunctions::memsetZeroBytes() +void CheckFunctionsImpl::memsetZeroBytes() { // FIXME: // Replace this with library configuration. @@ -528,7 +530,7 @@ void CheckFunctions::memsetZeroBytes() // // - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckFunctions::memsetZeroBytes"); // warning @@ -548,7 +550,7 @@ void CheckFunctions::memsetZeroBytes() } } -void CheckFunctions::memsetZeroBytesError(const Token *tok) +void CheckFunctionsImpl::memsetZeroBytesError(const Token *tok) { const std::string summary("memset() called to fill 0 bytes."); const std::string verbose(summary + " The second and third arguments might be inverted." @@ -557,7 +559,7 @@ void CheckFunctions::memsetZeroBytesError(const Token *tok) reportError(tok, Severity::warning, "memsetZeroBytes", summary + "\n" + verbose, CWE687, Certainty::normal); } -void CheckFunctions::memsetInvalid2ndParam() +void CheckFunctionsImpl::memsetInvalid2ndParam() { // FIXME: // Replace this with library configuration. @@ -567,8 +569,8 @@ void CheckFunctions::memsetInvalid2ndParam() // // - const bool printPortability = mSettings->severity.isEnabled(Severity::portability); - const bool printWarning = mSettings->severity.isEnabled(Severity::warning); + const bool printPortability = mSettings.severity.isEnabled(Severity::portability); + const bool printWarning = mSettings.severity.isEnabled(Severity::warning); if (!printWarning && !printPortability) return; @@ -596,8 +598,8 @@ void CheckFunctions::memsetInvalid2ndParam() if (printWarning && secondParamTok->isNumber()) { // Check if the second parameter is a literal and is out of range const MathLib::bigint value = MathLib::toBigNumber(secondParamTok); - const long long sCharMin = mSettings->platform.signedCharMin(); - const long long uCharMax = mSettings->platform.unsignedCharMax(); + const long long sCharMin = mSettings.platform.signedCharMin(); + const long long uCharMax = mSettings.platform.unsignedCharMax(); if (value < sCharMin || value > uCharMax) memsetValueOutOfRangeError(secondParamTok, secondParamTok->str()); } @@ -605,7 +607,7 @@ void CheckFunctions::memsetInvalid2ndParam() } } -void CheckFunctions::memsetFloatError(const Token *tok, const std::string &var_value) +void CheckFunctionsImpl::memsetFloatError(const Token *tok, const std::string &var_value) { const std::string message("The 2nd memset() argument '" + var_value + "' is a float, its representation is implementation defined."); @@ -614,7 +616,7 @@ void CheckFunctions::memsetFloatError(const Token *tok, const std::string &var_v reportError(tok, Severity::portability, "memsetFloat", message + "\n" + verbose, CWE688, Certainty::normal); } -void CheckFunctions::memsetValueOutOfRangeError(const Token *tok, const std::string &value) +void CheckFunctionsImpl::memsetValueOutOfRangeError(const Token *tok, const std::string &value) { const std::string message("The 2nd memset() argument '" + value + "' doesn't fit into an 'unsigned char'."); const std::string verbose(message + " The 2nd parameter is passed as an 'int', but the function fills the block of memory using the 'unsigned char' conversion of this value."); @@ -625,9 +627,9 @@ void CheckFunctions::memsetValueOutOfRangeError(const Token *tok, const std::str // --check-library => warn for unconfigured functions //--------------------------------------------------------------------------- -void CheckFunctions::checkLibraryMatchFunctions() +void CheckFunctionsImpl::checkLibraryMatchFunctions() { - if (!mSettings->checkLibrary) + if (!mSettings.checkLibrary) return; bool insideNew = false; @@ -665,32 +667,32 @@ void CheckFunctions::checkLibraryMatchFunctions() if (Token::simpleMatch(tok->astParent(), ".")) { const Token* contTok = tok->astParent()->astOperand1(); - if (astContainerAction(contTok, mSettings->library) != Library::Container::Action::NO_ACTION) + if (astContainerAction(contTok, mSettings.library) != Library::Container::Action::NO_ACTION) continue; - if (astContainerYield(contTok, mSettings->library) != Library::Container::Yield::NO_YIELD) + if (astContainerYield(contTok, mSettings.library) != Library::Container::Yield::NO_YIELD) continue; } - if (!mSettings->library.isNotLibraryFunction(tok)) + if (!mSettings.library.isNotLibraryFunction(tok)) continue; - const std::string &functionName = mSettings->library.getFunctionName(tok); + const std::string &functionName = mSettings.library.getFunctionName(tok); if (functionName.empty()) continue; - if (mSettings->library.functions().find(functionName) != mSettings->library.functions().end()) + if (mSettings.library.functions().find(functionName) != mSettings.library.functions().end()) continue; - if (mSettings->library.podtype(tok->expressionString())) + if (mSettings.library.podtype(tok->expressionString())) continue; - if (mSettings->library.getTypeCheck("unusedvar", functionName) != Library::TypeCheck::def) + if (mSettings.library.getTypeCheck("unusedvar", functionName) != Library::TypeCheck::def) continue; const Token* start = tok; while (Token::Match(start->tokAt(-2), "%name% ::") && !start->tokAt(-2)->isKeyword()) start = start->tokAt(-2); - if (mSettings->library.detectContainerOrIterator(start)) + if (mSettings.library.detectContainerOrIterator(start)) continue; reportError(tok, @@ -703,12 +705,12 @@ void CheckFunctions::checkLibraryMatchFunctions() // Check for problems to compiler apply (Named) Return Value Optimization for local variable // Technically we have different guarantees between standard versions // details: https://en.cppreference.com/w/cpp/language/copy_elision -void CheckFunctions::returnLocalStdMove() +void CheckFunctionsImpl::returnLocalStdMove() { - if (!mTokenizer->isCPP() || mSettings->standards.cpp < Standards::CPP11) + if (!mTokenizer->isCPP() || mSettings.standards.cpp < Standards::CPP11) return; - if (!mSettings->severity.isEnabled(Severity::performance)) + if (!mSettings.severity.isEnabled(Severity::performance)) return; logChecker("CheckFunctions::returnLocalStdMove"); // performance,c++11 @@ -733,7 +735,7 @@ void CheckFunctions::returnLocalStdMove() } } -void CheckFunctions::copyElisionError(const Token *tok) +void CheckFunctionsImpl::copyElisionError(const Token *tok) { reportError(tok, Severity::performance, @@ -742,9 +744,9 @@ void CheckFunctions::copyElisionError(const Token *tok) " More: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-return-move-local"); } -void CheckFunctions::useStandardLibrary() +void CheckFunctionsImpl::useStandardLibrary() { - if (!mSettings->severity.isEnabled(Severity::style)) + if (!mSettings.severity.isEnabled(Severity::style)) return; logChecker("CheckFunctions::useStandardLibrary"); // style @@ -780,10 +782,10 @@ void CheckFunctions::useStandardLibrary() const auto& secondOp = condToken->str(); const bool isLess = "<" == secondOp && - isConstExpression(condToken->astOperand2(), mSettings->library) && + isConstExpression(condToken->astOperand2(), mSettings.library) && condToken->astOperand1()->varId() == idxVarId; const bool isMore = ">" == secondOp && - isConstExpression(condToken->astOperand1(), mSettings->library) && + isConstExpression(condToken->astOperand1(), mSettings.library) && condToken->astOperand2()->varId() == idxVarId; if (!(isLess || isMore)) @@ -846,16 +848,16 @@ void CheckFunctions::useStandardLibrary() } } -void CheckFunctions::useStandardLibraryError(const Token *tok, const std::string& expected) +void CheckFunctionsImpl::useStandardLibraryError(const Token *tok, const std::string& expected) { reportError(tok, Severity::style, "useStandardLibrary", "Consider using " + expected + " instead of loop."); } -void CheckFunctions::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckFunctions::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { - CheckFunctions checkFunctions(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckFunctionsImpl checkFunctions(&tokenizer, tokenizer.getSettings(), errorLogger); checkFunctions.checkIgnoredReturnValue(); checkFunctions.checkMissingReturn(); // Missing "return" in exit path @@ -872,12 +874,12 @@ void CheckFunctions::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLog checkFunctions.useStandardLibrary(); } -void CheckFunctions::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const +void CheckFunctions::getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const { - CheckFunctions c(nullptr, settings, errorLogger); + CheckFunctionsImpl c(nullptr, settings, errorLogger); - for (auto i = settings->library.functionwarn().cbegin(); i != settings->library.functionwarn().cend(); ++i) { - c.reportError(nullptr, Severity::style, i->first+"Called", i->second.message); + for (auto i = settings.library.functionwarn().cbegin(); i != settings.library.functionwarn().cend(); ++i) { + c.functionCalledError(nullptr, Severity::style, i->first, i->second.message); } c.invalidFunctionArgError(nullptr, "func_name", 1, nullptr,"1:4"); diff --git a/lib/checkfunctions.h b/lib/checkfunctions.h index f5954d14043..ea7278bf0c8 100644 --- a/lib/checkfunctions.h +++ b/lib/checkfunctions.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,6 +23,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include @@ -47,15 +48,33 @@ namespace ValueFlow { class CPPCHECKLIB CheckFunctions : public Check { public: /** This constructor is used when registering the CheckFunctions */ - CheckFunctions() : Check(myName()) {} + CheckFunctions() : Check("Check function usage") {} private: - /** This constructor is used when running checks. */ - CheckFunctions(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} - /** @brief Run checks against the normal token list */ - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; + + std::string classInfo() const override { + return "Check function usage:\n" + "- missing 'return' in non-void function\n" + "- return value of certain functions not used\n" + "- invalid input values for functions\n" + "- Warn if a function is called whose usage is discouraged\n" + "- memset() third argument is zero\n" + "- memset() with a value out of range as the 2nd parameter\n" + "- memset() with a float as the 2nd parameter\n" + "- copy elision optimization for returning value affected by std::move\n" + "- use memcpy()/memset() instead of for loop\n"; + } +}; + +class CPPCHECKLIB CheckFunctionsImpl : public CheckImpl { +public: + /** This constructor is used when running checks. */ + CheckFunctionsImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} /** Check for functions that should not be used */ void checkProhibitedFunctions(); @@ -106,25 +125,7 @@ class CPPCHECKLIB CheckFunctions : public Check { void missingReturnError(const Token *tok); void copyElisionError(const Token *tok); void useStandardLibraryError(const Token *tok, const std::string& expected); - - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - static std::string myName() { - return "Check function usage"; - } - - std::string classInfo() const override { - return "Check function usage:\n" - "- missing 'return' in non-void function\n" - "- return value of certain functions not used\n" - "- invalid input values for functions\n" - "- Warn if a function is called whose usage is discouraged\n" - "- memset() third argument is zero\n" - "- memset() with a value out of range as the 2nd parameter\n" - "- memset() with a float as the 2nd parameter\n" - "- copy elision optimization for returning value affected by std::move\n" - "- use memcpy()/memset() instead of for loop\n"; - } + void functionCalledError(const Token* tok, Severity severity, const std::string& prefix, const std::string& msg); }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checkimpl.cpp b/lib/checkimpl.cpp new file mode 100644 index 00000000000..fb1c71a66b3 --- /dev/null +++ b/lib/checkimpl.cpp @@ -0,0 +1,72 @@ +/* + * 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 "checkimpl.h" + +#include "errorlogger.h" +#include "settings.h" +#include "token.h" +#include "tokenize.h" +#include "vfvalue.h" + +#include + +void CheckImpl::reportError(const std::list &callstack, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe, Certainty certainty) +{ + // TODO: report debug warning when error is for a disabled severity + const ErrorMessage errmsg(callstack, mTokenizer ? &mTokenizer->list : nullptr, severity, id, msg, cwe, certainty); + mErrorLogger.reportErr(errmsg); +} + +void CheckImpl::reportError(ErrorPath errorPath, Severity severity, const char id[], const std::string &msg, const CWE &cwe, Certainty certainty) +{ + // TODO: report debug warning when error is for a disabled severity + const ErrorMessage errmsg(std::move(errorPath), mTokenizer ? &mTokenizer->list : nullptr, severity, id, msg, cwe, certainty); + mErrorLogger.reportErr(errmsg); +} + +bool CheckImpl::wrongData(const Token *tok, const char *str) +{ + if (mSettings.daca) + reportError(tok, Severity::debug, "DacaWrongData", "Wrong data detected by condition " + std::string(str)); + return true; +} + +ErrorPath CheckImpl::getErrorPath(const Token* errtok, const ValueFlow::Value* value, std::string bug) const +{ + ErrorPath errorPath; + if (!value) { + errorPath.emplace_back(errtok, std::move(bug)); + } else if (mSettings.verbose || mSettings.outputFormat == Settings::OutputFormat::xml || !mSettings.templateLocation.empty()) { + errorPath = value->errorPath; + errorPath.emplace_back(errtok, std::move(bug)); + } else { + if (value->condition) + errorPath.emplace_back(value->condition, "condition '" + value->condition->expressionString() + "'"); + //else if (!value->isKnown() || value->defaultArg) + // errorPath = value->callstack; + errorPath.emplace_back(errtok, std::move(bug)); + } + return errorPath; +} + +void CheckImpl::logChecker(const char id[]) +{ + if (!mSettings.buildDir.empty() || mSettings.collectLogCheckers()) + reportError(nullptr, Severity::internal, "logChecker", id); +} diff --git a/lib/checkimpl.h b/lib/checkimpl.h new file mode 100644 index 00000000000..17f92da8553 --- /dev/null +++ b/lib/checkimpl.h @@ -0,0 +1,85 @@ +/* + * 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 checkimplH +#define checkimplH + +#include "config.h" +#include "errortypes.h" + +#include +#include + +class Settings; +class ErrorLogger; +class Tokenizer; +class Token; +namespace ValueFlow { + class Value; +} + +class CPPCHECKLIB CheckImpl +{ +protected: + /** This constructor is used when running checks. */ + CheckImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : mTokenizer(tokenizer), mSettings(settings), mErrorLogger(errorLogger) {} + +public: + CheckImpl(const CheckImpl &) = delete; + CheckImpl& operator=(const CheckImpl &) = delete; + +protected: + const Tokenizer* const mTokenizer{}; + const Settings& mSettings; + ErrorLogger& mErrorLogger; + + /** report an error */ + void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg) { + reportError(tok, severity, id, msg, CWE(0U), Certainty::normal); + } + + /** report an error */ + void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg, const CWE &cwe, Certainty certainty) { + const std::list callstack(1, tok); + reportError(callstack, severity, id, msg, cwe, certainty); + } + + /** report an error */ + void reportError(const std::list &callstack, Severity severity, const std::string &id, const std::string &msg) { + reportError(callstack, severity, id, msg, CWE(0U), Certainty::normal); + } + + /** report an error */ + void reportError(const std::list &callstack, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe, Certainty certainty); + + void reportError(ErrorPath errorPath, Severity severity, const char id[], const std::string &msg, const CWE &cwe, Certainty certainty); + + ErrorPath getErrorPath(const Token* errtok, const ValueFlow::Value* value, std::string bug) const; + + /** + * Use WRONG_DATA in checkers when you check for wrong data. That + * will call this method + */ + bool wrongData(const Token *tok, const char *str); + +public: // TODO: should be protected + void logChecker(const char id[]); +}; + +#endif // checkimplH diff --git a/lib/checkinternal.cpp b/lib/checkinternal.cpp index f289044b102..93b10210404 100644 --- a/lib/checkinternal.cpp +++ b/lib/checkinternal.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,13 +31,7 @@ #include #include -// Register this check class (by creating a static instance of it). -// Disabled in release builds -namespace { - CheckInternal instance; -} - -void CheckInternal::checkTokenMatchPatterns() +void CheckInternalImpl::checkTokenMatchPatterns() { const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Scope *scope : symbolDatabase->functionScopes) { @@ -88,7 +82,7 @@ void CheckInternal::checkTokenMatchPatterns() } } -void CheckInternal::checkRedundantTokCheck() +void CheckInternalImpl::checkRedundantTokCheck() { for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) { if (Token::Match(tok, "&& Token :: simpleMatch|Match|findsimplematch|findmatch (")) { @@ -123,13 +117,13 @@ void CheckInternal::checkRedundantTokCheck() } -void CheckInternal::checkRedundantTokCheckError(const Token* tok) +void CheckInternalImpl::checkRedundantTokCheckError(const Token* tok) { reportError(tok, Severity::style, "redundantTokCheck", "Unnecessary check of \"" + (tok? tok->expressionString(): "") + "\", match-function already checks if it is null."); } -void CheckInternal::checkTokenSimpleMatchPatterns() +void CheckInternalImpl::checkTokenSimpleMatchPatterns() { const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Scope* scope : symbolDatabase->functionScopes) { @@ -213,7 +207,7 @@ namespace { }; } -void CheckInternal::checkMissingPercentCharacter() +void CheckInternalImpl::checkMissingPercentCharacter() { const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Scope* scope : symbolDatabase->functionScopes) { @@ -254,7 +248,7 @@ void CheckInternal::checkMissingPercentCharacter() } } -void CheckInternal::checkUnknownPattern() +void CheckInternalImpl::checkUnknownPattern() { const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Scope* scope : symbolDatabase->functionScopes) { @@ -288,7 +282,7 @@ void CheckInternal::checkUnknownPattern() } } -void CheckInternal::checkRedundantNextPrevious() +void CheckInternalImpl::checkRedundantNextPrevious() { const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Scope* scope : symbolDatabase->functionScopes) { @@ -311,7 +305,7 @@ void CheckInternal::checkRedundantNextPrevious() } } -void CheckInternal::checkExtraWhitespace() +void CheckInternalImpl::checkExtraWhitespace() { const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Scope* scope : symbolDatabase->functionScopes) { @@ -337,58 +331,58 @@ void CheckInternal::checkExtraWhitespace() } } -void CheckInternal::simplePatternError(const Token* tok, const std::string& pattern, const std::string &funcname) +void CheckInternalImpl::simplePatternError(const Token* tok, const std::string& pattern, const std::string &funcname) { reportError(tok, Severity::warning, "simplePatternError", "Found simple pattern inside Token::" + funcname + "() call: \"" + pattern + "\"" ); } -void CheckInternal::complexPatternError(const Token* tok, const std::string& pattern, const std::string &funcname) +void CheckInternalImpl::complexPatternError(const Token* tok, const std::string& pattern, const std::string &funcname) { reportError(tok, Severity::error, "complexPatternError", "Found complex pattern inside Token::" + funcname + "() call: \"" + pattern + "\"" ); } -void CheckInternal::missingPercentCharacterError(const Token* tok, const std::string& pattern, const std::string& funcname) +void CheckInternalImpl::missingPercentCharacterError(const Token* tok, const std::string& pattern, const std::string& funcname) { reportError(tok, Severity::error, "missingPercentCharacter", "Missing percent end character in Token::" + funcname + "() pattern: \"" + pattern + "\"" ); } -void CheckInternal::unknownPatternError(const Token* tok, const std::string& pattern) +void CheckInternalImpl::unknownPatternError(const Token* tok, const std::string& pattern) { reportError(tok, Severity::error, "unknownPattern", "Unknown pattern used: \"" + pattern + "\""); } -void CheckInternal::redundantNextPreviousError(const Token* tok, const std::string& func1, const std::string& func2) +void CheckInternalImpl::redundantNextPreviousError(const Token* tok, const std::string& func1, const std::string& func2) { reportError(tok, Severity::style, "redundantNextPrevious", "Call to 'Token::" + func1 + "()' followed by 'Token::" + func2 + "()' can be simplified."); } -void CheckInternal::orInComplexPattern(const Token* tok, const std::string& pattern, const std::string &funcname) +void CheckInternalImpl::orInComplexPattern(const Token* tok, const std::string& pattern, const std::string &funcname) { reportError(tok, Severity::error, "orInComplexPattern", "Token::" + funcname + "() pattern \"" + pattern + "\" contains \"||\" or \"|\". Replace it by \"%oror%\" or \"%or%\"."); } -void CheckInternal::extraWhitespaceError(const Token* tok, const std::string& pattern, const std::string &funcname) +void CheckInternalImpl::extraWhitespaceError(const Token* tok, const std::string& pattern, const std::string &funcname) { reportError(tok, Severity::warning, "extraWhitespaceError", "Found extra whitespace inside Token::" + funcname + "() call: \"" + pattern + "\"" ); } -void CheckInternal::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckInternal::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { if (!tokenizer.getSettings().checks.isEnabled(Checks::internalCheck)) return; - CheckInternal checkInternal(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckInternalImpl checkInternal(&tokenizer, tokenizer.getSettings(), errorLogger); checkInternal.checkTokenMatchPatterns(); checkInternal.checkTokenSimpleMatchPatterns(); @@ -399,9 +393,9 @@ void CheckInternal::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogg checkInternal.checkRedundantTokCheck(); } -void CheckInternal::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const +void CheckInternal::getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const { - CheckInternal c(nullptr, settings, errorLogger); + CheckInternalImpl c(nullptr, settings, errorLogger); c.simplePatternError(nullptr, "class {", "Match"); c.complexPatternError(nullptr, "%type% ( )", "Match"); c.missingPercentCharacterError(nullptr, "%num", "Match"); diff --git a/lib/checkinternal.h b/lib/checkinternal.h index 1fc97bcb247..18a1535a73f 100644 --- a/lib/checkinternal.h +++ b/lib/checkinternal.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 @@ -22,7 +22,10 @@ #define checkinternalH //--------------------------------------------------------------------------- +#ifdef CHECK_INTERNAL + #include "check.h" +#include "checkimpl.h" #include "config.h" #include @@ -40,14 +43,25 @@ class Settings; class CPPCHECKLIB CheckInternal : public Check { public: /** This constructor is used when registering the CheckClass */ - CheckInternal() : Check(myName()) {} + CheckInternal() : Check("cppcheck internal API usage") {} private: - /** This constructor is used when running checks. */ - CheckInternal(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; + + std::string classInfo() const override { + // Don't include these checks on the WIKI where people can read what + // checks there are. These checks are not intended for users. + return ""; + } +}; - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; +class CPPCHECKLIB CheckInternalImpl : public CheckImpl { +public: + /** This constructor is used when running checks. */ + CheckInternalImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} /** @brief %Check if a simple pattern is used inside Token::Match or Token::findmatch */ void checkTokenMatchPatterns(); @@ -78,19 +92,10 @@ class CPPCHECKLIB CheckInternal : public Check { void orInComplexPattern(const Token *tok, const std::string &pattern, const std::string &funcname); void extraWhitespaceError(const Token *tok, const std::string &pattern, const std::string &funcname); void checkRedundantTokCheckError(const Token *tok); - - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - static std::string myName() { - return "cppcheck internal API usage"; - } - - std::string classInfo() const override { - // Don't include these checks on the WIKI where people can read what - // checks there are. These checks are not intended for users. - return ""; - } }; /// @} //--------------------------------------------------------------------------- + +#endif // CHECK_INTERNAL + #endif // checkinternalH diff --git a/lib/checkio.cpp b/lib/checkio.cpp index 8b3c835caf3..0a0ca70a833 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -45,14 +45,10 @@ //--------------------------------------------------------------------------- -// 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 +static const CWE CWE474(474U); // Use of Function with Inconsistent Implementations static const CWE CWE664(664U); // Improper Control of a Resource Through its Lifetime static const CWE CWE685(685U); // Function Call With Incorrect Number of Arguments static const CWE CWE686(686U); // Function Call With Incorrect Argument Type @@ -63,7 +59,7 @@ static const CWE CWE910(910U); // Use of Expired File Descriptor //--------------------------------------------------------------------------- // std::cout << std::cout; //--------------------------------------------------------------------------- -void CheckIO::checkCoutCerrMisusage() +void CheckIOImpl::checkCoutCerrMisusage() { if (mTokenizer->isC()) return; @@ -85,7 +81,7 @@ void CheckIO::checkCoutCerrMisusage() } } -void CheckIO::coutCerrMisusageError(const Token* tok, const std::string& streamName) +void CheckIOImpl::coutCerrMisusageError(const Token* tok, const std::string& streamName) { reportError(tok, Severity::error, "coutCerrMisusage", "Invalid usage of output stream: '<< std::" + streamName + "'.", CWE398, Certainty::normal); } @@ -116,6 +112,8 @@ namespace { nonneg int op_indent{}; enum class AppendMode : std::uint8_t { UNKNOWN_AM, APPEND, APPEND_EX }; AppendMode append_mode = AppendMode::UNKNOWN_AM; + enum class ReadMode : std::uint8_t { READ_TEXT, READ_BIN }; + ReadMode read_mode = ReadMode::READ_BIN; std::string filename; explicit Filepointer(OpenMode mode_ = OpenMode::UNKNOWN_OM) : mode(mode_) {} @@ -124,11 +122,11 @@ namespace { const std::unordered_set whitelist = { "clearerr", "feof", "ferror", "fgetpos", "ftell", "setbuf", "setvbuf", "ungetc", "ungetwc" }; } -void CheckIO::checkFileUsage() +void CheckIOImpl::checkFileUsage() { - const bool windows = mSettings->platform.isWindows(); - const bool printPortability = mSettings->severity.isEnabled(Severity::portability); - const bool printWarnings = mSettings->severity.isEnabled(Severity::warning); + const bool windows = mSettings.platform.isWindows(); + const bool printPortability = mSettings.severity.isEnabled(Severity::portability); + const bool printWarnings = mSettings.severity.isEnabled(Severity::warning); std::map filepointers; @@ -157,6 +155,8 @@ void CheckIO::checkFileUsage() tok = tok->linkAt(1); continue; } + if (tok->function() && tok->function()->nestedIn) + continue; if (tok->str() == "{") indent++; else if (tok->str() == "}") { @@ -171,7 +171,7 @@ void CheckIO::checkFileUsage() filepointer.second.lastOperation = Filepointer::Operation::UNKNOWN_OP; } } - } else if (tok->str() == "return" || tok->str() == "continue" || tok->str() == "break" || mSettings->library.isnoreturn(tok)) { // Reset upon return, continue or break + } else if (tok->str() == "return" || tok->str() == "continue" || tok->str() == "break" || mSettings.library.isnoreturn(tok)) { // Reset upon return, continue or break for (std::pair& filepointer : filepointers) { filepointer.second.mode_indent = 0; filepointer.second.mode = OpenMode::UNKNOWN_OM; @@ -188,6 +188,7 @@ void CheckIO::checkFileUsage() } } else if (Token::Match(tok, "%name% (") && tok->previous() && (!tok->previous()->isName() || Token::Match(tok->previous(), "return|throw"))) { std::string mode; + bool isftell = false; const Token* fileTok = nullptr; const Token* fileNameTok = nullptr; Filepointer::Operation operation = Filepointer::Operation::NONE; @@ -245,12 +246,37 @@ 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) fileTok = fileTok->nextArgument(); + else if (tok->str() == "ftell") { + isftell = true; + } operation = Filepointer::Operation::UNIMPORTANT; - } else if (!Token::Match(tok, "if|for|while|catch|switch") && !mSettings->library.isFunctionConst(tok->str(), true)) { + } else if (!Token::Match(tok, "if|for|while|catch|switch") && !mSettings.library.isFunctionConst(tok->str(), true)) { const Token* const end2 = tok->linkAt(1); if (scope->functionOf && scope->functionOf->isClassOrStruct() && !scope->function->isStatic() && ((tok->strAt(-1) != "::" && tok->strAt(-1) != ".") || tok->strAt(-2) == "this")) { if (!tok->function() || (tok->function()->nestedIn && tok->function()->nestedIn->isClassOrStruct())) { @@ -304,10 +330,15 @@ void CheckIO::checkFileUsage() f.append_mode = Filepointer::AppendMode::APPEND_EX; else f.append_mode = Filepointer::AppendMode::APPEND; + } + else if (mode.find('r') != std::string::npos && + mode.find('t') != std::string::npos) { + f.read_mode = Filepointer::ReadMode::READ_TEXT; } else f.append_mode = Filepointer::AppendMode::UNKNOWN_AM; f.mode_indent = indent; break; + case Filepointer::Operation::POSITIONING: if (f.mode == OpenMode::CLOSED) useClosedFileError(tok); @@ -340,6 +371,8 @@ void CheckIO::checkFileUsage() case Filepointer::Operation::UNIMPORTANT: if (f.mode == OpenMode::CLOSED) useClosedFileError(tok); + if (isftell && f.read_mode == Filepointer::ReadMode::READ_TEXT && printPortability) + ftellFileError(tok); break; case Filepointer::Operation::UNKNOWN_OP: f.mode = OpenMode::UNKNOWN_OM; @@ -362,43 +395,58 @@ void CheckIO::checkFileUsage() } } -void CheckIO::fflushOnInputStreamError(const Token *tok, const std::string &varname) +void CheckIOImpl::fflushOnInputStreamError(const Token *tok, const std::string &varname) { reportError(tok, Severity::portability, "fflushOnInputStream", "fflush() called on input stream '" + varname + "' may result in undefined behaviour on non-linux systems.", CWE398, Certainty::normal); } -void CheckIO::ioWithoutPositioningError(const Token *tok) +void CheckIOImpl::ioWithoutPositioningError(const Token *tok) { reportError(tok, Severity::error, "IOWithoutPositioning", "Read and write operations without a call to a positioning function (fseek, fsetpos or rewind) or fflush in between result in undefined behaviour.", CWE664, Certainty::normal); } -void CheckIO::readWriteOnlyFileError(const Token *tok) +void CheckIOImpl::readWriteOnlyFileError(const Token *tok) { reportError(tok, Severity::error, "readWriteOnlyFile", "Read operation on a file that was opened only for writing.", CWE664, Certainty::normal); } -void CheckIO::writeReadOnlyFileError(const Token *tok) +void CheckIOImpl::writeReadOnlyFileError(const Token *tok) { reportError(tok, Severity::error, "writeReadOnlyFile", "Write operation on a file that was opened only for reading.", CWE664, Certainty::normal); } -void CheckIO::useClosedFileError(const Token *tok) +void CheckIOImpl::useClosedFileError(const Token *tok) { reportError(tok, Severity::error, "useClosedFile", "Used file that is not opened.", CWE910, Certainty::normal); } -void CheckIO::seekOnAppendedFileError(const Token *tok) +void CheckIOImpl::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 CheckIOImpl::seekOnAppendedFileError(const Token *tok) { reportError(tok, Severity::warning, "seekOnAppendedFile", "Repositioning operation performed on a file opened in append mode has no effect.", CWE398, Certainty::normal); } -void CheckIO::incompatibleFileOpenError(const Token *tok, const std::string &filename) +void CheckIOImpl::ftellFileError(const Token *tok) +{ + reportError(tok, Severity::portability, + "ftellTextModeFile", "ftell() result is unspecified when file is opened in mode \"t\"", CWE474, Certainty::normal); +} + +void CheckIOImpl::incompatibleFileOpenError(const Token *tok, const std::string &filename) { reportError(tok, Severity::warning, "incompatibleFileOpen", "The file '" + filename + "' is opened for read and write access at the same time on different streams", CWE664, Certainty::normal); @@ -408,9 +456,9 @@ void CheckIO::incompatibleFileOpenError(const Token *tok, const std::string &fil //--------------------------------------------------------------------------- // scanf without field width limits can crash with huge input data //--------------------------------------------------------------------------- -void CheckIO::invalidScanf() +void CheckIOImpl::invalidScanf() { - if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("invalidscanf")) + if (!mSettings.severity.isEnabled(Severity::warning) && !mSettings.isPremiumEnabled("invalidscanf")) return; logChecker("CheckIO::invalidScanf"); @@ -455,7 +503,7 @@ void CheckIO::invalidScanf() } } -void CheckIO::invalidScanfError(const Token *tok) +void CheckIOImpl::invalidScanfError(const Token *tok) { const std::string fname = (tok ? tok->str() : std::string("scanf")); reportError(tok, Severity::warning, @@ -481,6 +529,137 @@ void CheckIO::invalidScanfError(const Token *tok) CWE119, Certainty::normal); } +static const Token* findFileReadCall(const Token *start, const Token *end, int varid) +{ + const Token* found = Token::findmatch(start, "fgets|fgetc|getc|fread|fscanf (", end); + while (found) { + const std::vector args = getArguments(found); + if (!args.empty()) { + const bool match = (found->str() == "fscanf") + ? args.front()->varId() == varid + : args.back()->varId() == varid; + if (match) + return found; + } + found = Token::findmatch(found->next(), "fgets|fgetc|getc|fread|fscanf (", end); + } + return nullptr; +} + +void CheckIOImpl::checkWrongfeofUsage() +{ + const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); + + logChecker("CheckIO::checkWrongfeofUsage"); + + for (const Scope * scope : symbolDatabase->functionScopes) { + for (const Token *tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) { + // TODO: Handle for loops + if (!Token::Match(tok, "while ( ! feof ( %var% )")) + continue; + + // Bail out if we cannot identify file pointer + const int fpVarId = tok->tokAt(5)->varId(); + if (fpVarId == 0) + continue; + + const Token *endCond = tok->linkAt(1); + const Token *bodyStart; + const Token *bodyEnd; + + if (Token::simpleMatch(tok->previous(), "}") && tok->previous()->scope()->type == ScopeType::eDo) { + bodyEnd = tok->previous(); + bodyStart = bodyEnd->link(); + } else { + if (!Token::simpleMatch(endCond, ") {")) + continue; + bodyEnd = endCond->linkAt(1); + bodyStart = endCond->next(); + } + + // Bail out if the loop contains control flow (too complex to analyze) + if (Token::findmatch(bodyStart, "return|break|goto|continue|throw", bodyEnd)) + continue; + + // Bail out if fp is used outside of known file I/O functions. + // If it is passed to an unknown function, reads may occur there. + bool fpUsedElsewhere = false; + for (const Token *t = bodyStart->next(); t && t != bodyEnd; t = t->next()) { + if (t->varId() != fpVarId) + continue; + const Token *p = t->astParent(); + while (p && p->str() == ",") + p = p->astParent(); + if (!p || !Token::Match(p->astOperand1(), "fgets|fgetc|getc|fread|fscanf|fprintf|fwrite|fputs|fputc|putc")) { + fpUsedElsewhere = true; + break; + } + } + if (fpUsedElsewhere) + continue; + + // No file read call in the loop: feof can never become true inside it + const Token *loopFileReadCallTok = findFileReadCall(bodyStart, bodyEnd, fpVarId); + if (!loopFileReadCallTok) { + // TODO: Warn about infinite loop + continue; + } + + // Find last file read + const Token *lastLoopFileReadCallTok = loopFileReadCallTok; + while (loopFileReadCallTok) { + lastLoopFileReadCallTok = loopFileReadCallTok; + loopFileReadCallTok = findFileReadCall(lastLoopFileReadCallTok->next(), bodyEnd, fpVarId); + } + + // Warn if the destination of the last file read is used after the call before bodyEnd. + // If it is not, the stale buffer is never accessed on the extra iteration at EOF. + + if (lastLoopFileReadCallTok->str() == "fgetc" || lastLoopFileReadCallTok->str() == "getc") { + // Warn if the return value feeds into an expression (astParent of the call node) + if (lastLoopFileReadCallTok->astParent() && lastLoopFileReadCallTok->astParent()->astParent()) + wrongfeofUsage(getCondTok(tok)); + } else { + const std::vector args = getArguments(lastLoopFileReadCallTok); + // Collect destination varIds + std::vector destVarIds; + if (lastLoopFileReadCallTok->str() == "fscanf") { + // args[0]=fp, args[1]=format, args[2+]=destinations (typically &var) + for (std::size_t i = 2; i < args.size(); ++i) { + const Token *destTok = Token::Match(args[i], "& %var%") ? args[i]->next() : args[i]; + if (destTok->varId() != 0) + destVarIds.push_back(destTok->varId()); + } + } else { + // Handle fgets, fread + // First argument is the destination buffer + if (!args.empty() && args.front()->varId() != 0) + destVarIds.push_back(args.front()->varId()); + } + + // Search for any destination use between this call's ';' and endBody + const Token *semiColonTok = lastLoopFileReadCallTok->linkAt(1)->next(); + for (const Token *t = semiColonTok; t && t != bodyEnd; t = t->next()) { + if (std::find(destVarIds.begin(), destVarIds.end(), t->varId()) != destVarIds.end()) { + wrongfeofUsage(getCondTok(tok)); + break; + } + } + } + } + } +} + +void CheckIOImpl::wrongfeofUsage(const Token * tok) +{ + reportError(tok, Severity::warning, + "wrongfeofUsage", + "Using feof() as a loop condition causes the last line to be processed twice.\n" + "feof() returns true only after a read has failed due to end-of-file, so the loop " + "body executes once more after the last successful read. Check the return value of " + "the read function instead (e.g. fgets, fread, fscanf)."); +} + //--------------------------------------------------------------------------- // printf("%u", "xyz"); // Wrong argument type // printf("%u%s", 1); // Too few arguments @@ -527,10 +706,10 @@ static inline bool typesMatch(const std::string& iToTest, const std::string& iTy return (iToTest == iTypename) || (iToTest == iOptionalPrefix + iTypename); } -void CheckIO::checkWrongPrintfScanfArguments() +void CheckIOImpl::checkWrongPrintfScanfArguments() { const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); - const bool isWindows = mSettings->platform.isWindows(); + const bool isWindows = mSettings.platform.isWindows(); logChecker("CheckIO::checkWrongPrintfScanfArguments"); @@ -545,10 +724,10 @@ void CheckIO::checkWrongPrintfScanfArguments() bool scanf_s = false; int formatStringArgNo = -1; - if (tok->strAt(1) == "(" && mSettings->library.formatstr_function(tok)) { - formatStringArgNo = mSettings->library.formatstr_argno(tok); - scan = mSettings->library.formatstr_scan(tok); - scanf_s = mSettings->library.formatstr_secure(tok); + if (tok->strAt(1) == "(" && mSettings.library.formatstr_function(tok)) { + formatStringArgNo = mSettings.library.formatstr_argno(tok); + scan = mSettings.library.formatstr_scan(tok); + scanf_s = mSettings.library.formatstr_secure(tok); } if (formatStringArgNo >= 0) { @@ -599,14 +778,14 @@ void CheckIO::checkWrongPrintfScanfArguments() } } -void CheckIO::checkFormatString(const Token * const tok, - const Token * const formatStringTok, - const Token * argListTok, - const bool scan, - const bool scanf_s) +void CheckIOImpl::checkFormatString(const Token * const tok, + const Token * const formatStringTok, + const Token * argListTok, + const bool scan, + const bool scanf_s) { - const bool isWindows = mSettings->platform.isWindows(); - const bool printWarning = mSettings->severity.isEnabled(Severity::warning); + const bool isWindows = mSettings.platform.isWindows(); + const bool printWarning = mSettings.severity.isEnabled(Severity::warning); const std::string &formatString = formatStringTok->str(); // Count format string parameters.. @@ -664,6 +843,8 @@ void CheckIO::checkFormatString(const Token * const tok, } ++i; } + while (!width.empty() && width[0] == '0') + width = width.substr(1); auto bracketBeg = formatString.cend(); if (i != formatString.cend() && *i == '[') { bracketBeg = i; @@ -696,9 +877,9 @@ void CheckIO::checkFormatString(const Token * const tok, } // Perform type checks - ArgumentInfo argInfo(argListTok, *mSettings, mTokenizer->isCPP()); + ArgumentInfo argInfo(argListTok, mSettings, mTokenizer->isCPP()); - if ((argInfo.typeToken && !argInfo.isLibraryType(*mSettings)) || *i == ']') { + if ((argInfo.typeToken && !argInfo.isLibraryType(mSettings.library)) || *i == ']') { if (scan) { std::string specifier; bool done = false; @@ -1342,7 +1523,7 @@ void CheckIO::checkFormatString(const Token * const tok, // We currently only support string literals, variables, and functions. /// @todo add non-string literals, and generic expressions -CheckIO::ArgumentInfo::ArgumentInfo(const Token * arg, const Settings &settings, bool _isCPP) +CheckIOImpl::ArgumentInfo::ArgumentInfo(const Token * arg, const Settings &settings, bool _isCPP) : isCPP(_isCPP) { if (!arg) @@ -1556,7 +1737,7 @@ CheckIO::ArgumentInfo::ArgumentInfo(const Token * arg, const Settings &settings, } } -CheckIO::ArgumentInfo::~ArgumentInfo() +CheckIOImpl::ArgumentInfo::~ArgumentInfo() { if (tempToken) { while (tempToken->next()) @@ -1571,7 +1752,7 @@ namespace { const std::set stl_string = { "string", "u16string", "u32string", "wstring" }; } -bool CheckIO::ArgumentInfo::isStdVectorOrString() +bool CheckIOImpl::ArgumentInfo::isStdVectorOrString() { if (!isCPP) return false; @@ -1633,7 +1814,7 @@ static const std::set stl_container = { "unordered_map", "unordered_multimap", "unordered_multiset", "unordered_set", "vector" }; -bool CheckIO::ArgumentInfo::isStdContainer(const Token *tok) +bool CheckIOImpl::ArgumentInfo::isStdContainer(const Token *tok) { if (!isCPP) return false; @@ -1665,7 +1846,7 @@ bool CheckIO::ArgumentInfo::isStdContainer(const Token *tok) return false; } -bool CheckIO::ArgumentInfo::isArrayOrPointer() const +bool CheckIOImpl::ArgumentInfo::isArrayOrPointer() const { if (address) return true; @@ -1678,7 +1859,7 @@ bool CheckIO::ArgumentInfo::isArrayOrPointer() const return tok && tok->strAt(1) == "*"; } -bool CheckIO::ArgumentInfo::isComplexType() const +bool CheckIOImpl::ArgumentInfo::isComplexType() const { if (variableInfo->type()) return true; @@ -1690,7 +1871,7 @@ bool CheckIO::ArgumentInfo::isComplexType() const return ((variableInfo->isStlStringType() || (varTypeTok->strAt(1) == "<" && varTypeTok->linkAt(1) && varTypeTok->linkAt(1)->strAt(1) != "::")) && !variableInfo->isArrayOrPointer()); } -bool CheckIO::ArgumentInfo::isKnownType() const +bool CheckIOImpl::ArgumentInfo::isKnownType() const { if (variableInfo) return (typeToken->isStandardType() || typeToken->next()->isStandardType() || isComplexType()); @@ -1700,18 +1881,18 @@ bool CheckIO::ArgumentInfo::isKnownType() const return typeToken->isStandardType() || Token::Match(typeToken, "std :: string|wstring"); } -bool CheckIO::ArgumentInfo::isLibraryType(const Settings &settings) const +bool CheckIOImpl::ArgumentInfo::isLibraryType(const Library &library) const { - return typeToken && typeToken->isStandardType() && settings.library.podtype(typeToken->str()); + return typeToken && typeToken->isStandardType() && library.podtype(typeToken->str()); } -void CheckIO::wrongPrintfScanfArgumentsError(const Token* tok, - const std::string &functionName, - nonneg int numFormat, - nonneg int numFunction) +void CheckIOImpl::wrongPrintfScanfArgumentsError(const Token* tok, + const std::string &functionName, + nonneg int numFormat, + nonneg int numFunction) { const Severity severity = numFormat > numFunction ? Severity::error : Severity::warning; - if (severity != Severity::error && !mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("wrongPrintfScanfArgNum")) + if (severity != Severity::error && !mSettings.severity.isEnabled(Severity::warning) && !mSettings.isPremiumEnabled("wrongPrintfScanfArgNum")) return; std::ostringstream errmsg; @@ -1727,10 +1908,10 @@ void CheckIO::wrongPrintfScanfArgumentsError(const Token* tok, reportError(tok, severity, "wrongPrintfScanfArgNum", errmsg.str(), CWE685, Certainty::normal); } -void CheckIO::wrongPrintfScanfPosixParameterPositionError(const Token* tok, const std::string& functionName, - nonneg int index, nonneg int numFunction) +void CheckIOImpl::wrongPrintfScanfPosixParameterPositionError(const Token* tok, const std::string& functionName, + nonneg int index, nonneg int numFunction) { - if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("wrongPrintfScanfParameterPositionError")) + if (!mSettings.severity.isEnabled(Severity::warning) && !mSettings.isPremiumEnabled("wrongPrintfScanfParameterPositionError")) return; std::ostringstream errmsg; errmsg << functionName << ": "; @@ -1742,10 +1923,10 @@ void CheckIO::wrongPrintfScanfPosixParameterPositionError(const Token* tok, cons reportError(tok, Severity::warning, "wrongPrintfScanfParameterPositionError", errmsg.str(), CWE685, Certainty::normal); } -void CheckIO::invalidScanfArgTypeError_s(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo) +void CheckIOImpl::invalidScanfArgTypeError_s(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo) { const Severity severity = getSeverity(argInfo); - if (!mSettings->severity.isEnabled(severity)) + if (!mSettings.severity.isEnabled(severity)) return; std::ostringstream errmsg; errmsg << "%" << specifier << " in format string (no. " << numFormat << ") requires a \'"; @@ -1758,10 +1939,10 @@ void CheckIO::invalidScanfArgTypeError_s(const Token* tok, nonneg int numFormat, errmsg << "."; reportError(tok, severity, "invalidScanfArgType_s", errmsg.str(), CWE686, Certainty::normal); } -void CheckIO::invalidScanfArgTypeError_int(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo, bool isUnsigned) +void CheckIOImpl::invalidScanfArgTypeError_int(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo, bool isUnsigned) { const Severity severity = getSeverity(argInfo); - if (!mSettings->severity.isEnabled(severity)) + if (!mSettings.severity.isEnabled(severity)) return; std::ostringstream errmsg; errmsg << "%" << specifier << " in format string (no. " << numFormat << ") requires \'"; @@ -1803,10 +1984,10 @@ void CheckIO::invalidScanfArgTypeError_int(const Token* tok, nonneg int numForma errmsg << "."; reportError(tok, severity, "invalidScanfArgType_int", errmsg.str(), CWE686, Certainty::normal); } -void CheckIO::invalidScanfArgTypeError_float(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo) +void CheckIOImpl::invalidScanfArgTypeError_float(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo) { const Severity severity = getSeverity(argInfo); - if (!mSettings->severity.isEnabled(severity)) + if (!mSettings.severity.isEnabled(severity)) return; std::ostringstream errmsg; errmsg << "%" << specifier << " in format string (no. " << numFormat << ") requires \'"; @@ -1822,10 +2003,10 @@ void CheckIO::invalidScanfArgTypeError_float(const Token* tok, nonneg int numFor reportError(tok, severity, "invalidScanfArgType_float", errmsg.str(), CWE686, Certainty::normal); } -void CheckIO::invalidPrintfArgTypeError_s(const Token* tok, nonneg int numFormat, const ArgumentInfo* argInfo) +void CheckIOImpl::invalidPrintfArgTypeError_s(const Token* tok, nonneg int numFormat, const ArgumentInfo* argInfo) { const Severity severity = getSeverity(argInfo); - if (!mSettings->severity.isEnabled(severity)) + if (!mSettings.severity.isEnabled(severity)) return; std::ostringstream errmsg; errmsg << "%s in format string (no. " << numFormat << ") requires \'char *\' but the argument type is "; @@ -1833,10 +2014,10 @@ void CheckIO::invalidPrintfArgTypeError_s(const Token* tok, nonneg int numFormat errmsg << "."; reportError(tok, severity, "invalidPrintfArgType_s", errmsg.str(), CWE686, Certainty::normal); } -void CheckIO::invalidPrintfArgTypeError_n(const Token* tok, nonneg int numFormat, const ArgumentInfo* argInfo) +void CheckIOImpl::invalidPrintfArgTypeError_n(const Token* tok, nonneg int numFormat, const ArgumentInfo* argInfo) { const Severity severity = getSeverity(argInfo); - if (!mSettings->severity.isEnabled(severity)) + if (!mSettings.severity.isEnabled(severity)) return; std::ostringstream errmsg; errmsg << "%n in format string (no. " << numFormat << ") requires \'int *\' but the argument type is "; @@ -1844,10 +2025,10 @@ void CheckIO::invalidPrintfArgTypeError_n(const Token* tok, nonneg int numFormat errmsg << "."; reportError(tok, severity, "invalidPrintfArgType_n", errmsg.str(), CWE686, Certainty::normal); } -void CheckIO::invalidPrintfArgTypeError_p(const Token* tok, nonneg int numFormat, const ArgumentInfo* argInfo) +void CheckIOImpl::invalidPrintfArgTypeError_p(const Token* tok, nonneg int numFormat, const ArgumentInfo* argInfo) { const Severity severity = getSeverity(argInfo); - if (!mSettings->severity.isEnabled(severity)) + if (!mSettings.severity.isEnabled(severity)) return; std::ostringstream errmsg; errmsg << "%p in format string (no. " << numFormat << ") requires an address but the argument type is "; @@ -1894,10 +2075,10 @@ static void printfFormatType(std::ostream& os, const std::string& specifier, boo os << "\'"; } -void CheckIO::invalidPrintfArgTypeError_uint(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo) +void CheckIOImpl::invalidPrintfArgTypeError_uint(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo) { const Severity severity = getSeverity(argInfo); - if (!mSettings->severity.isEnabled(severity)) + if (!mSettings.severity.isEnabled(severity)) return; std::ostringstream errmsg; errmsg << "%" << specifier << " in format string (no. " << numFormat << ") requires "; @@ -1908,10 +2089,10 @@ void CheckIO::invalidPrintfArgTypeError_uint(const Token* tok, nonneg int numFor reportError(tok, severity, "invalidPrintfArgType_uint", errmsg.str(), CWE686, Certainty::normal); } -void CheckIO::invalidPrintfArgTypeError_sint(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo) +void CheckIOImpl::invalidPrintfArgTypeError_sint(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo) { const Severity severity = getSeverity(argInfo); - if (!mSettings->severity.isEnabled(severity)) + if (!mSettings.severity.isEnabled(severity)) return; std::ostringstream errmsg; errmsg << "%" << specifier << " in format string (no. " << numFormat << ") requires "; @@ -1921,10 +2102,10 @@ void CheckIO::invalidPrintfArgTypeError_sint(const Token* tok, nonneg int numFor errmsg << "."; reportError(tok, severity, "invalidPrintfArgType_sint", errmsg.str(), CWE686, Certainty::normal); } -void CheckIO::invalidPrintfArgTypeError_float(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo) +void CheckIOImpl::invalidPrintfArgTypeError_float(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo) { const Severity severity = getSeverity(argInfo); - if (!mSettings->severity.isEnabled(severity)) + if (!mSettings.severity.isEnabled(severity)) return; std::ostringstream errmsg; errmsg << "%" << specifier << " in format string (no. " << numFormat << ") requires \'"; @@ -1936,12 +2117,12 @@ void CheckIO::invalidPrintfArgTypeError_float(const Token* tok, nonneg int numFo reportError(tok, severity, "invalidPrintfArgType_float", errmsg.str(), CWE686, Certainty::normal); } -Severity CheckIO::getSeverity(const CheckIO::ArgumentInfo *argInfo) +Severity CheckIOImpl::getSeverity(const ArgumentInfo *argInfo) { return (argInfo && argInfo->typeToken && !argInfo->typeToken->originalName().empty()) ? Severity::portability : Severity::warning; } -void CheckIO::argumentType(std::ostream& os, const ArgumentInfo * argInfo) +void CheckIOImpl::argumentType(std::ostream& os, const ArgumentInfo * argInfo) { if (argInfo) { os << "\'"; @@ -1991,16 +2172,16 @@ void CheckIO::argumentType(std::ostream& os, const ArgumentInfo * argInfo) os << "Unknown"; } -void CheckIO::invalidLengthModifierError(const Token* tok, nonneg int numFormat, const std::string& modifier) +void CheckIOImpl::invalidLengthModifierError(const Token* tok, nonneg int numFormat, const std::string& modifier) { - if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("invalidLengthModifierError")) + if (!mSettings.severity.isEnabled(Severity::warning) && !mSettings.isPremiumEnabled("invalidLengthModifierError")) return; std::ostringstream errmsg; errmsg << "'" << modifier << "' in format string (no. " << numFormat << ") is a length modifier and cannot be used without a conversion specifier."; reportError(tok, Severity::warning, "invalidLengthModifierError", errmsg.str(), CWE704, Certainty::normal); } -void CheckIO::invalidScanfFormatWidthError(const Token* tok, nonneg int numFormat, int width, const Variable *var, const std::string& specifier) +void CheckIOImpl::invalidScanfFormatWidthError(const Token* tok, nonneg int numFormat, int width, const Variable *var, const std::string& specifier) { MathLib::bigint arrlen = 0; std::string varname; @@ -2012,7 +2193,7 @@ void CheckIO::invalidScanfFormatWidthError(const Token* tok, nonneg int numForma std::ostringstream errmsg; if (arrlen > width) { - if (tok != nullptr && (!mSettings->certainty.isEnabled(Certainty::inconclusive) || !mSettings->severity.isEnabled(Severity::warning))) + if (tok != nullptr && (!mSettings.certainty.isEnabled(Certainty::inconclusive) || !mSettings.severity.isEnabled(Severity::warning))) return; errmsg << "Width " << width << " given in format string (no. " << numFormat << ") is smaller than destination buffer" << " '" << varname << "[" << arrlen << "]'."; @@ -2024,27 +2205,30 @@ void CheckIO::invalidScanfFormatWidthError(const Token* tok, nonneg int numForma } } -void CheckIO::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckIO::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { - CheckIO checkIO(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckIOImpl checkIO(&tokenizer, tokenizer.getSettings(), errorLogger); checkIO.checkWrongPrintfScanfArguments(); checkIO.checkCoutCerrMisusage(); checkIO.checkFileUsage(); + checkIO.checkWrongfeofUsage(); checkIO.invalidScanf(); } -void CheckIO::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const +void CheckIO::getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const { - CheckIO c(nullptr, settings, errorLogger); + CheckIOImpl c(nullptr, settings, errorLogger); c.coutCerrMisusageError(nullptr, "cout"); c.fflushOnInputStreamError(nullptr, "stdin"); c.ioWithoutPositioningError(nullptr); c.readWriteOnlyFileError(nullptr); c.writeReadOnlyFileError(nullptr); c.useClosedFileError(nullptr); + c.fcloseInLoopConditionError(nullptr, "fp"); c.seekOnAppendedFileError(nullptr); c.incompatibleFileOpenError(nullptr, "tmp"); + c.wrongfeofUsage(nullptr); c.invalidScanfError(nullptr); c.wrongPrintfScanfArgumentsError(nullptr, "printf",3,2); c.invalidScanfArgTypeError_s(nullptr, 1, "s", nullptr); diff --git a/lib/checkio.h b/lib/checkio.h index e37a942770b..06c6d8d973b 100644 --- a/lib/checkio.h +++ b/lib/checkio.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 @@ -22,6 +22,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include @@ -34,6 +35,7 @@ class Token; class Variable; class ErrorLogger; class Tokenizer; +class Library; enum class Severity : std::uint8_t; /// @addtogroup Checks @@ -41,19 +43,36 @@ enum class Severity : std::uint8_t; /** @brief %Check input output operations. */ class CPPCHECKLIB CheckIO : public Check { - friend class TestIO; - public: /** @brief This constructor is used when registering CheckIO */ - CheckIO() : Check(myName()) {} + CheckIO() : Check("IO using format string") {} private: - /** @brief This constructor is used when running checks. */ - CheckIO(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} - /** @brief Run checks on the normal token list */ - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; + + std::string classInfo() const override { + return "Check format string input/output operations.\n" + "- Bad usage of the function 'sprintf' (overlapping data)\n" + "- Missing or wrong width specifiers in 'scanf' format string\n" + "- Use a file that has been closed\n" + "- File input/output without positioning results in undefined behaviour\n" + "- Read to a file that has only been opened for writing (or vice versa)\n" + "- Repositioning operation on a file opened in append mode\n" + "- The same file can't be open for read and write at the same time on different streams\n" + "- Using fflush() on an input stream\n" + "- Invalid usage of output stream. For example: 'std::cout << std::cout;'\n" + "- Wrong number of arguments given to 'printf' or 'scanf;'\n"; + } +}; + +class CPPCHECKLIB CheckIOImpl : public CheckImpl { +public: + /** @brief This constructor is used when running checks. */ + CheckIOImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} /** @brief %Check for missusage of std::cout */ void checkCoutCerrMisusage(); @@ -64,6 +83,9 @@ class CPPCHECKLIB CheckIO : public Check { /** @brief scanf can crash if width specifiers are not used */ void invalidScanf(); + /** @brief %Check wrong usage of feof */ + void checkWrongfeofUsage(); + /** @brief %Checks type and number of arguments given to functions like printf or scanf*/ void checkWrongPrintfScanfArguments(); @@ -80,7 +102,7 @@ class CPPCHECKLIB CheckIO : public Check { bool isKnownType() const; bool isStdVectorOrString(); bool isStdContainer(const Token *tok); - bool isLibraryType(const Settings &settings) const; + bool isLibraryType(const Library &library) const; const Variable* variableInfo{}; const Token* typeToken{}; @@ -105,9 +127,12 @@ 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 ftellFileError(const Token *tok); void incompatibleFileOpenError(const Token *tok, const std::string &filename); void invalidScanfError(const Token *tok); + void wrongfeofUsage(const Token *tok); void wrongPrintfScanfArgumentsError(const Token* tok, const std::string &functionName, nonneg int numFormat, @@ -127,26 +152,6 @@ class CPPCHECKLIB CheckIO : public Check { void invalidScanfFormatWidthError(const Token* tok, nonneg int numFormat, int width, const Variable *var, const std::string& specifier); static void argumentType(std::ostream & os, const ArgumentInfo * argInfo); static Severity getSeverity(const ArgumentInfo *argInfo); - - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - static std::string myName() { - return "IO using format string"; - } - - std::string classInfo() const override { - return "Check format string input/output operations.\n" - "- Bad usage of the function 'sprintf' (overlapping data)\n" - "- Missing or wrong width specifiers in 'scanf' format string\n" - "- Use a file that has been closed\n" - "- File input/output without positioning results in undefined behaviour\n" - "- Read to a file that has only been opened for writing (or vice versa)\n" - "- Repositioning operation on a file opened in append mode\n" - "- The same file can't be open for read and write at the same time on different streams\n" - "- Using fflush() on an input stream\n" - "- Invalid usage of output stream. For example: 'std::cout << std::cout;'\n" - "- Wrong number of arguments given to 'printf' or 'scanf;'\n"; - } }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 803ea9967a3..e8271f9eed0 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -45,11 +45,6 @@ //--------------------------------------------------------------------------- -// Register this check class (by creating a static instance of it) -namespace { - CheckLeakAutoVar instance; -} - static const CWE CWE672(672U); static const CWE CWE415(415U); @@ -112,39 +107,39 @@ void VarInfo::possibleUsageAll(const std::pair& functionUsa } -void CheckLeakAutoVar::leakError(const Token *tok, const std::string &varname, int type) const +void CheckLeakAutoVarImpl::leakError(const Token *tok, const std::string &varname, int type) const { - const CheckMemoryLeak checkmemleak(mTokenizer, mErrorLogger, mSettings); + const CheckMemoryLeakImpl checkmemleak(mTokenizer, mSettings, mErrorLogger); if (Library::isresource(type)) checkmemleak.resourceLeakError(tok, varname); else checkmemleak.memleakError(tok, varname); } -void CheckLeakAutoVar::mismatchError(const Token *deallocTok, const Token *allocTok, const std::string &varname) const +void CheckLeakAutoVarImpl::mismatchError(const Token *deallocTok, const Token *allocTok, const std::string &varname) const { - const CheckMemoryLeak c(mTokenizer, mErrorLogger, mSettings); + const CheckMemoryLeakImpl c(mTokenizer, mSettings, mErrorLogger); const std::list callstack = { allocTok, deallocTok }; c.mismatchAllocDealloc(callstack, varname); } -void CheckLeakAutoVar::deallocUseError(const Token *tok, const std::string &varname) const +void CheckLeakAutoVarImpl::deallocUseError(const Token *tok, const std::string &varname) const { - const CheckMemoryLeak c(mTokenizer, mErrorLogger, mSettings); + const CheckMemoryLeakImpl c(mTokenizer, mSettings, mErrorLogger); c.deallocuseError(tok, varname); } -void CheckLeakAutoVar::deallocReturnError(const Token *tok, const Token *deallocTok, const std::string &varname) +void CheckLeakAutoVarImpl::deallocReturnError(const Token *tok, const Token *deallocTok, const std::string &varname) { const std::list locations = { deallocTok, tok }; reportError(locations, Severity::error, "deallocret", "$symbol:" + varname + "\nReturning/dereferencing '$symbol' after it is deallocated / released", CWE672, Certainty::normal); } -void CheckLeakAutoVar::configurationInfo(const Token* tok, const std::pair& functionUsage) +void CheckLeakAutoVarImpl::configurationInfo(const Token* tok, const std::pair& functionUsage) { - if (mSettings->checkLibrary && functionUsage.second == VarInfo::USED && + if (mSettings.checkLibrary && functionUsage.second == VarInfo::USED && (!functionUsage.first || !functionUsage.first->function() || !functionUsage.first->function()->hasBody())) { - std::string funcStr = functionUsage.first ? mSettings->library.getFunctionName(functionUsage.first) : "f"; + std::string funcStr = functionUsage.first ? mSettings.library.getFunctionName(functionUsage.first) : "f"; if (funcStr.empty()) funcStr = "unknown::" + functionUsage.first->str(); reportError(tok, @@ -154,7 +149,7 @@ void CheckLeakAutoVar::configurationInfo(const Token* tok, const std::pair locations = { prevFreeTok, tok }; @@ -165,9 +160,9 @@ void CheckLeakAutoVar::doubleFreeError(const Token *tok, const Token *prevFreeTo } -void CheckLeakAutoVar::check() +void CheckLeakAutoVarImpl::check() { - if (mSettings->clang) + if (mSettings.clang) return; logChecker("CheckLeakAutoVar::check"); // notclang @@ -272,7 +267,7 @@ static const Token * isFunctionCall(const Token * nameToken) return nullptr; } -static const Token* getOutparamAllocation(const Token* tok, const Settings& settings) +static const Token* getOutparamAllocation(const Token* tok, const Library& library) { if (!tok) return nullptr; @@ -280,16 +275,16 @@ static const Token* getOutparamAllocation(const Token* tok, const Settings& sett const Token* ftok = getTokenArgumentFunction(tok, argn); if (!ftok) return nullptr; - if (const Library::AllocFunc* allocFunc = settings.library.getAllocFuncInfo(ftok)) { + if (const Library::AllocFunc* allocFunc = library.getAllocFuncInfo(ftok)) { if (allocFunc->arg == argn + 1) return ftok; } return nullptr; } -static const Token* getReturnValueFromOutparamAlloc(const Token* alloc, const Settings& settings) +static const Token* getReturnValueFromOutparamAlloc(const Token* alloc, const Library& library) { - if (const Token* ftok = getOutparamAllocation(alloc, settings)) { + if (const Token* ftok = getOutparamAllocation(alloc, library)) { if (Token::simpleMatch(ftok->astParent()->astParent(), "=")) return ftok->next()->astParent()->astOperand1(); } @@ -308,10 +303,10 @@ static std::vector getComparisonTokens(const Token* tok) return result; } -bool CheckLeakAutoVar::checkScope(const Token * const startToken, - VarInfo &varInfo, - std::set notzero, - nonneg int recursiveCount) +bool CheckLeakAutoVarImpl::checkScope(const Token * const startToken, + VarInfo &varInfo, + std::set notzero, + nonneg int recursiveCount) { #if ASAN static const nonneg int recursiveLimit = 300; @@ -386,7 +381,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, ftok = ftok->tokAt(2); // bailout for variable passed to library function with out parameter - if (const Library::Function *libFunc = mSettings->library.getFunction(ftok)) { + if (const Library::Function *libFunc = mSettings.library.getFunction(ftok)) { using ArgumentChecks = Library::ArgumentChecks; using Direction = ArgumentChecks::Direction; const std::vector args = getArguments(ftok); @@ -397,7 +392,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, }); }); if (hasOutParam) { - for (int i = 0; i < args.size(); i++) { + for (size_t i = 0; i < args.size(); i++) { if (!argChecks.count(i + 1)) continue; const ArgumentChecks argCheck = argChecks.at(i + 1); @@ -484,7 +479,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, // allocation? const Token *const fTok = tokRightAstOperand ? tokRightAstOperand->previous() : nullptr; if (Token::Match(fTok, "%type% (")) { - const Library::AllocFunc* f = mSettings->library.getAllocFuncInfo(fTok); + const Library::AllocFunc* f = mSettings.library.getAllocFuncInfo(fTok); if (f && f->arg == -1) { VarInfo::AllocInfo& varAlloc = alloctype[varTok->varId()]; varAlloc.type = f->groupId; @@ -550,7 +545,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, tokRightAstOperand = tokRightAstOperand->astOperand2() ? tokRightAstOperand->astOperand2() : tokRightAstOperand->astOperand1(); if (tokRightAstOperand && Token::Match(tokRightAstOperand->previous(), "%type% (")) { const Token * fTok = tokRightAstOperand->previous(); - const Library::AllocFunc* f = mSettings->library.getAllocFuncInfo(fTok); + const Library::AllocFunc* f = mSettings.library.getAllocFuncInfo(fTok); if (f && f->arg == -1) { VarInfo::AllocInfo& varAlloc = alloctype[innerTok->varId()]; varAlloc.type = f->groupId; @@ -573,7 +568,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, // check for function call if (openingPar) { - const Library::AllocFunc* allocFunc = mSettings->library.getDeallocFuncInfo(innerTok); + const Library::AllocFunc* allocFunc = mSettings.library.getDeallocFuncInfo(innerTok); // innerTok is a function name const VarInfo::AllocInfo allocation(0, VarInfo::NOALLOC); functionCall(innerTok, openingPar, varInfo, allocation, allocFunc); @@ -628,7 +623,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, 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); + const Token* ret = getReturnValueFromOutparamAlloc(info.second.allocTok, mSettings.library); return ret && vartok && ret->varId() && ret->varId() == vartok->varId(); })) { varInfo1.clear(); @@ -760,7 +755,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, // Function call.. else if (const Token* openingPar = isFunctionCall(ftok)) { - const Library::AllocFunc* af = mSettings->library.getDeallocFuncInfo(ftok); + const Library::AllocFunc* af = mSettings.library.getDeallocFuncInfo(ftok); VarInfo::AllocInfo allocation(af ? af->groupId : 0, VarInfo::DEALLOC, ftok); if (allocation.type == 0) allocation.status = VarInfo::NOALLOC; @@ -781,8 +776,8 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, if (ftok->function() && !ftok->function()->isAttributeNoreturn() && !(ftok->function()->functionScope && mTokenizer->isScopeNoReturn(ftok->function()->functionScope->bodyEnd))) // check function scope continue; - const std::string functionName(mSettings->library.getFunctionName(ftok)); - if (!mSettings->library.isLeakIgnore(functionName) && !mSettings->library.isUse(functionName)) { + const std::string functionName(mSettings.library.getFunctionName(ftok)); + if (!mSettings.library.isLeakIgnore(functionName) && !mSettings.library.isUse(functionName)) { const VarInfo::Usage usage = Token::simpleMatch(openingPar, "( )") ? VarInfo::NORET : VarInfo::USED; // TODO: check parameters passed to function varInfo.possibleUsageAll({ ftok, usage }); } @@ -805,7 +800,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, } // Check smart pointer - else if (Token::Match(ftok, "%name% <") && mSettings->library.isSmartPointer(tok)) { + else if (Token::Match(ftok, "%name% <") && mSettings.library.isSmartPointer(tok)) { const Token * typeEndTok = ftok->linkAt(1); if (!Token::Match(typeEndTok, "> %var% {|( %var% ,|)|}")) continue; @@ -840,7 +835,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, const Token * dtok = Token::findmatch(deleterToken, "& %name%", endDeleterToken); if (dtok) { dtok = dtok->next(); - af = mSettings->library.getDeallocFuncInfo(dtok); + af = mSettings.library.getDeallocFuncInfo(dtok); } if (!dtok || !af) { const Token * tscopeStart = nullptr; @@ -870,7 +865,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, if (tscopeStart && tscopeEnd) { for (const Token *tok2 = tscopeStart; tok2 != tscopeEnd; tok2 = tok2->next()) { - af = mSettings->library.getDeallocFuncInfo(tok2); + af = mSettings.library.getDeallocFuncInfo(tok2); if (af) break; } @@ -892,7 +887,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, } -const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const tok, VarInfo &varInfo, bool inFuncCall) +const Token * CheckLeakAutoVarImpl::checkTokenInsideExpression(const Token * const tok, VarInfo &varInfo, bool inFuncCall) { // Deallocation and then dereferencing pointer.. if (tok->varId() > 0) { @@ -901,7 +896,7 @@ const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const t if (var != varInfo.alloctype.end()) { bool unknown = false; if (var->second.status == VarInfo::DEALLOC && tok->valueType() && tok->valueType()->pointer && - CheckNullPointer::isPointerDeRef(tok, unknown, *mSettings, /*checkNullArg*/ false) && !unknown) { + CheckNullPointerImpl::isPointerDeRef(tok, unknown, mSettings.library, /*checkNullArg*/ false) && !unknown) { deallocUseError(tok, tok->str()); } else if (Token::simpleMatch(tok->tokAt(-2), "= &")) { varInfo.erase(tok->varId()); @@ -922,9 +917,9 @@ const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const t if ((rhs->str() == "." || rhs->varId() == tok->varId()) && isAssignment) { // simple assignment varInfo.erase(tok->varId()); - } else if (rhs->astParent() && rhs->str() == "(" && !mSettings->library.returnValue(rhs->astOperand1()).empty()) { + } else if (rhs->astParent() && rhs->str() == "(" && !mSettings.library.returnValue(rhs->astOperand1()).empty()) { // #9298, assignment through return value of a function - const std::string &returnValue = mSettings->library.returnValue(rhs->astOperand1()); + const std::string &returnValue = mSettings.library.returnValue(rhs->astOperand1()); if (startsWith(returnValue, "arg")) { int argn; const Token *func = getTokenArgumentFunction(tok, argn); @@ -945,12 +940,12 @@ const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const t // check for function call const Token * const openingPar = inFuncCall ? nullptr : isFunctionCall(tok); if (openingPar) { - const Library::AllocFunc* allocFunc = mSettings->library.getDeallocFuncInfo(tok); + const Library::AllocFunc* allocFunc = mSettings.library.getDeallocFuncInfo(tok); VarInfo::AllocInfo alloc(allocFunc ? allocFunc->groupId : 0, VarInfo::DEALLOC, tok); if (alloc.type == 0) alloc.status = VarInfo::NOALLOC; functionCall(tok, openingPar, varInfo, alloc, nullptr); - const std::string &returnValue = mSettings->library.returnValue(tok); + const std::string &returnValue = mSettings.library.returnValue(tok); if (startsWith(returnValue, "arg")) // the function returns one of its argument, we need to process a potential assignment return openingPar; @@ -961,9 +956,9 @@ const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const t } -void CheckLeakAutoVar::changeAllocStatusIfRealloc(std::map &alloctype, const Token *fTok, const Token *retTok) const +void CheckLeakAutoVarImpl::changeAllocStatusIfRealloc(std::map &alloctype, const Token *fTok, const Token *retTok) const { - const Library::AllocFunc* f = mSettings->library.getReallocFuncInfo(fTok); + const Library::AllocFunc* f = mSettings.library.getReallocFuncInfo(fTok); if (f && f->arg == -1 && f->reallocArg > 0 && f->reallocArg <= numberOfArguments(fTok)) { const Token* argTok = getArguments(fTok).at(f->reallocArg - 1); if (alloctype.find(argTok->varId()) != alloctype.end()) { @@ -982,14 +977,14 @@ void CheckLeakAutoVar::changeAllocStatusIfRealloc(std::map &alloctype = varInfo.alloctype; const auto var = alloctype.find(arg->varId()); if (var != alloctype.end()) { // bailout if function is also allocating, since the argument might be moved // to the return value, such as in fdopen - if (allocation.allocTok && mSettings->library.getAllocFuncInfo(allocation.allocTok)) { + if (allocation.allocTok && mSettings.library.getAllocFuncInfo(allocation.allocTok)) { varInfo.erase(arg->varId()); return; } @@ -1019,11 +1014,11 @@ void CheckLeakAutoVar::changeAllocStatus(VarInfo &varInfo, const VarInfo::AllocI } } -void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpeningPar, VarInfo &varInfo, const VarInfo::AllocInfo& allocation, const Library::AllocFunc* af) +void CheckLeakAutoVarImpl::functionCall(const Token *tokName, const Token *tokOpeningPar, VarInfo &varInfo, const VarInfo::AllocInfo& allocation, const Library::AllocFunc* af) { // Ignore function call? - const bool isLeakIgnore = mSettings->library.isLeakIgnore(mSettings->library.getFunctionName(tokName)); - if (mSettings->library.getReallocFuncInfo(tokName)) + const bool isLeakIgnore = mSettings.library.isLeakIgnore(mSettings.library.getFunctionName(tokName)); + if (mSettings.library.getReallocFuncInfo(tokName)) return; if (tokName->next()->valueType() && tokName->next()->valueType()->container && tokName->next()->valueType()->container->stdStringLike) return; @@ -1074,10 +1069,10 @@ void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpenin // Is variable allocated? if (!isnull && (!af || af->arg == argNr)) { - const Library::AllocFunc* deallocFunc = mSettings->library.getDeallocFuncInfo(tokName); + const Library::AllocFunc* deallocFunc = mSettings.library.getDeallocFuncInfo(tokName); VarInfo::AllocInfo dealloc(deallocFunc ? deallocFunc->groupId : 0, VarInfo::DEALLOC, tokName); - if (const Library::AllocFunc* allocFunc = mSettings->library.getAllocFuncInfo(tokName)) { - if (mSettings->library.getDeallocFuncInfo(tokName)) { + if (const Library::AllocFunc* allocFunc = mSettings.library.getAllocFuncInfo(tokName)) { + if (mSettings.library.getDeallocFuncInfo(tokName)) { changeAllocStatus(varInfo, dealloc.type == 0 ? allocation : dealloc, tokName, arg); } if (allocFunc->arg == argNr && @@ -1097,7 +1092,7 @@ void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpenin } } // Check smart pointer - else if (Token::Match(arg, "%name% < %type%") && mSettings->library.isSmartPointer(argTypeStartTok)) { + else if (Token::Match(arg, "%name% < %type%") && mSettings.library.isSmartPointer(argTypeStartTok)) { const Token * typeEndTok = arg->linkAt(1); const Token * allocTok = nullptr; if (!Token::Match(typeEndTok, "> {|( %var% ,|)|}")) @@ -1122,14 +1117,14 @@ void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpenin // Check if its a pointer to a function const Token * dtok = Token::findmatch(deleterToken, "& %name%", endDeleterToken); if (dtok) { - sp_af = mSettings->library.getDeallocFuncInfo(dtok->tokAt(1)); + sp_af = mSettings.library.getDeallocFuncInfo(dtok->tokAt(1)); } else { // If the deleter is a class, check if class calls the dealloc function dtok = Token::findmatch(deleterToken, "%type%", endDeleterToken); if (dtok && dtok->type()) { const Scope * tscope = dtok->type()->classScope; for (const Token *tok2 = tscope->bodyStart; tok2 != tscope->bodyEnd; tok2 = tok2->next()) { - sp_af = mSettings->library.getDeallocFuncInfo(tok2); + sp_af = mSettings.library.getDeallocFuncInfo(tok2); if (sp_af) { allocTok = tok2; break; @@ -1158,8 +1153,8 @@ void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpenin } -void CheckLeakAutoVar::leakIfAllocated(const Token *vartok, - const VarInfo &varInfo) +void CheckLeakAutoVarImpl::leakIfAllocated(const Token *vartok, + const VarInfo &varInfo) { const std::map &alloctype = varInfo.alloctype; const auto& possibleUsage = varInfo.possibleUsage; @@ -1181,7 +1176,7 @@ static bool isSafeCast(const ValueType* vt, const Settings& settings) return sizeOf == 0 || sizeOf >= settings.platform.sizeof_pointer; } -void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndOfScope) +void CheckLeakAutoVarImpl::ret(const Token *tok, VarInfo &varInfo, const bool isEndOfScope) { const std::map &alloctype = varInfo.alloctype; const auto& possibleUsage = varInfo.possibleUsage; @@ -1214,7 +1209,7 @@ void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndO while (tok3 && tok3->isCast() && (!tok3->valueType() || tok3->valueType()->pointer || - isSafeCast(tok3->valueType(), *mSettings))) + isSafeCast(tok3->valueType(), mSettings))) tok3 = tok3->astOperand2() ? tok3->astOperand2() : tok3->astOperand1(); if (tok3 && tok3->varId() == varid) tok2 = tok3->next(); @@ -1237,7 +1232,7 @@ void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndO // don't warn when returning after checking return value of outparam allocation const Token* outparamFunc{}; if ((tok->scope()->type == ScopeType::eIf || tok->scope()->type== ScopeType::eElse) && - (outparamFunc = getOutparamAllocation(it->second.allocTok, *mSettings))) { + (outparamFunc = getOutparamAllocation(it->second.allocTok, mSettings.library))) { const Scope* scope = tok->scope(); if (scope->type == ScopeType::eElse) { scope = scope->bodyStart->tokAt(-2)->scope(); @@ -1283,15 +1278,15 @@ void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndO varInfo.erase(varId); } -void CheckLeakAutoVar::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckLeakAutoVar::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { - CheckLeakAutoVar checkLeakAutoVar(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckLeakAutoVarImpl checkLeakAutoVar(&tokenizer, tokenizer.getSettings(), errorLogger); checkLeakAutoVar.check(); } -void CheckLeakAutoVar::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const +void CheckLeakAutoVar::getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const { - CheckLeakAutoVar c(nullptr, settings, errorLogger); + CheckLeakAutoVarImpl c(nullptr, settings, errorLogger); c.deallocReturnError(nullptr, nullptr, "p"); c.configurationInfo(nullptr, { nullptr, VarInfo::USED }); // user configuration is needed to complete analysis c.doubleFreeError(nullptr, nullptr, "varname", 0); diff --git a/lib/checkleakautovar.h b/lib/checkleakautovar.h index d7d8d390b3d..b613b357119 100644 --- a/lib/checkleakautovar.h +++ b/lib/checkleakautovar.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,6 +23,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include "library.h" @@ -107,14 +108,23 @@ class CPPCHECKLIB VarInfo { class CPPCHECKLIB CheckLeakAutoVar : public Check { public: /** This constructor is used when registering the CheckLeakAutoVar */ - CheckLeakAutoVar() : Check(myName()) {} + CheckLeakAutoVar() : Check("Leaks (auto variables)") {} private: - /** This constructor is used when running checks. */ - CheckLeakAutoVar(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; + + std::string classInfo() const override { + return "Detect when a auto variable is allocated but not deallocated or deallocated twice.\n"; + } +}; - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; +class CPPCHECKLIB CheckLeakAutoVarImpl : public CheckImpl { +public: + /** This constructor is used when running checks. */ + CheckLeakAutoVarImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} /** check for leaks in all scopes */ void check(); @@ -157,16 +167,6 @@ class CPPCHECKLIB CheckLeakAutoVar : public Check { /** message: user configuration is needed to complete analysis */ void configurationInfo(const Token* tok, const std::pair& functionUsage); - - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - static std::string myName() { - return "Leaks (auto variables)"; - } - - std::string classInfo() const override { - return "Detect when a auto variable is allocated but not deallocated or deallocated twice.\n"; - } }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index 1a6ef787eb6..cc8b6853f11 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -37,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') @@ -53,7 +45,8 @@ static const CWE CWE772(772U); // Missing Release of Resource after Effective L //--------------------------------------------------------------------------- -CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2, nonneg int varid, std::list *callstack) const + +CheckMemoryLeakImpl::AllocType CheckMemoryLeakImpl::getAllocationType(const Token *tok2, nonneg int varid, std::list *callstack) const { // What we may have... // * var = (char *)malloc(10); @@ -101,7 +94,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2, return New; } - if (mSettings_->hasLib("posix")) { + if (mSettings.hasLib("posix")) { if (Token::Match(tok2, "open|openat|creat|mkstemp|mkostemp|socket (")) { // simple sanity check of function parameters.. // TODO: Make such check for all these functions @@ -120,11 +113,11 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2, } // Does tok2 point on a Library allocation function? - const int alloctype = mSettings_->library.getAllocId(tok2, -1); + const int alloctype = mSettings.library.getAllocId(tok2, -1); if (alloctype > 0) { - if (alloctype == mSettings_->library.deallocId("free")) + if (alloctype == mSettings.library.deallocId("free")) return Malloc; - if (alloctype == mSettings_->library.deallocId("fclose")) + if (alloctype == mSettings.library.deallocId("fclose")) return File; return Library::ismemory(alloctype) ? OtherMem : OtherRes; } @@ -151,7 +144,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2, } -CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok2, nonneg int varid) const +CheckMemoryLeakImpl::AllocType CheckMemoryLeakImpl::getReallocationType(const Token *tok2, nonneg int varid) const { // What we may have... // * var = (char *)realloc(..; @@ -165,7 +158,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok if (!Token::Match(tok2, "%name% (")) return No; - const Library::AllocFunc *f = mSettings_->library.getReallocFuncInfo(tok2); + const Library::AllocFunc *f = mSettings.library.getReallocFuncInfo(tok2); if (!(f && f->reallocArg > 0 && f->reallocArg <= numberOfArguments(tok2))) return No; const auto args = getArguments(tok2); @@ -179,11 +172,11 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok if (varid > 0 && !Token::Match(arg, "%varid% [,)]", varid)) return No; - const int realloctype = mSettings_->library.getReallocId(tok2, -1); + const int realloctype = mSettings.library.getReallocId(tok2, -1); if (realloctype > 0) { - if (realloctype == mSettings_->library.deallocId("free")) + if (realloctype == mSettings.library.deallocId("free")) return Malloc; - if (realloctype == mSettings_->library.deallocId("fclose")) + if (realloctype == mSettings.library.deallocId("fclose")) return File; return Library::ismemory(realloctype) ? OtherMem : OtherRes; } @@ -191,7 +184,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok } -CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok, nonneg int varid) const +CheckMemoryLeakImpl::AllocType CheckMemoryLeakImpl::getDeallocationType(const Token *tok, nonneg int varid) const { if (tok->isCpp() && tok->str() == "delete" && tok->astOperand1()) { const Token* vartok = tok->astOperand1(); @@ -222,7 +215,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok if (tok->str() == "realloc" && Token::simpleMatch(vartok->next(), ", 0 )")) return Malloc; - if (mSettings_->hasLib("posix")) { + if (mSettings.hasLib("posix")) { if (tok->str() == "close") return Fd; if (tok->str() == "pclose") @@ -230,11 +223,11 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok } // Does tok point on a Library deallocation function? - const int dealloctype = mSettings_->library.getDeallocId(tok, argNr); + const int dealloctype = mSettings.library.getDeallocId(tok, argNr); if (dealloctype > 0) { - if (dealloctype == mSettings_->library.deallocId("free")) + if (dealloctype == mSettings.library.deallocId("free")) return Malloc; - if (dealloctype == mSettings_->library.deallocId("fclose")) + if (dealloctype == mSettings.library.deallocId("fclose")) return File; return Library::ismemory(dealloctype) ? OtherMem : OtherRes; } @@ -246,10 +239,10 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok return No; } -bool CheckMemoryLeak::isReopenStandardStream(const Token *tok) const +bool CheckMemoryLeakImpl::isReopenStandardStream(const Token *tok) const { if (getReallocationType(tok, 0) == File) { - const Library::AllocFunc *f = mSettings_->library.getReallocFuncInfo(tok); + const Library::AllocFunc *f = mSettings.library.getReallocFuncInfo(tok); if (f && f->reallocArg > 0 && f->reallocArg <= numberOfArguments(tok)) { const Token* arg = getArguments(tok).at(f->reallocArg - 1); if (Token::Match(arg, "stdin|stdout|stderr")) @@ -259,9 +252,9 @@ bool CheckMemoryLeak::isReopenStandardStream(const Token *tok) const return false; } -bool CheckMemoryLeak::isOpenDevNull(const Token *tok) const +bool CheckMemoryLeakImpl::isOpenDevNull(const Token *tok) const { - if (mSettings_->hasLib("posix") && tok->str() == "open" && numberOfArguments(tok) == 2) { + if (mSettings.hasLib("posix") && tok->str() == "open" && numberOfArguments(tok) == 2) { const Token* arg = getArguments(tok).at(0); if (Token::simpleMatch(arg, "\"/dev/null\"")) return true; @@ -269,24 +262,18 @@ bool CheckMemoryLeak::isOpenDevNull(const Token *tok) const return false; } -//-------------------------------------------------------------------------- - - -//-------------------------------------------------------------------------- - -void CheckMemoryLeak::memoryLeak(const Token *tok, const std::string &varname, AllocType alloctype) const +void CheckMemoryLeakImpl::memoryLeak(const Token *tok, const std::string &varname, AllocType alloctype) const { - if (alloctype == CheckMemoryLeak::File || - alloctype == CheckMemoryLeak::Pipe || - alloctype == CheckMemoryLeak::Fd || - alloctype == CheckMemoryLeak::OtherRes) + if (alloctype == File || + alloctype == Pipe || + alloctype == Fd || + alloctype == OtherRes) resourceLeakError(tok, varname); else memleakError(tok, varname); } -//--------------------------------------------------------------------------- -void CheckMemoryLeak::reportErr(const Token *tok, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe) const +void CheckMemoryLeakImpl::reportErr(const Token *tok, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe) const { std::list callstack; @@ -296,26 +283,23 @@ void CheckMemoryLeak::reportErr(const Token *tok, Severity severity, const std:: reportErr(callstack, severity, id, msg, cwe); } -void CheckMemoryLeak::reportErr(const std::list &callstack, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe) const +void CheckMemoryLeakImpl::reportErr(const std::list &callstack, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe) const { - const ErrorMessage errmsg(callstack, mTokenizer_ ? &mTokenizer_->list : nullptr, severity, id, msg, cwe, Certainty::normal); - if (mErrorLogger_) - mErrorLogger_->reportErr(errmsg); - else - Check::writeToErrorList(errmsg); + const ErrorMessage errmsg(callstack, mTokenizer ? &mTokenizer->list : nullptr, severity, id, msg, cwe, Certainty::normal); + mErrorLogger.reportErr(errmsg); } -void CheckMemoryLeak::memleakError(const Token *tok, const std::string &varname) const +void CheckMemoryLeakImpl::memleakError(const Token *tok, const std::string &varname) const { reportErr(tok, Severity::error, "memleak", "$symbol:" + varname + "\nMemory leak: $symbol", CWE(401U)); } -void CheckMemoryLeak::memleakUponReallocFailureError(const Token *tok, const std::string &reallocfunction, const std::string &varname) const +void CheckMemoryLeakImpl::memleakUponReallocFailureError(const Token *tok, const std::string &reallocfunction, const std::string &varname) const { reportErr(tok, Severity::error, "memleakOnRealloc", "$symbol:" + varname + "\nCommon " + reallocfunction + " mistake: \'$symbol\' nulled but not freed upon failure", CWE(401U)); } -void CheckMemoryLeak::resourceLeakError(const Token *tok, const std::string &varname) const +void CheckMemoryLeakImpl::resourceLeakError(const Token *tok, const std::string &varname) const { std::string errmsg("Resource leak"); if (!varname.empty()) @@ -323,17 +307,17 @@ void CheckMemoryLeak::resourceLeakError(const Token *tok, const std::string &var reportErr(tok, Severity::error, "resourceLeak", errmsg, CWE(775U)); } -void CheckMemoryLeak::deallocuseError(const Token *tok, const std::string &varname) const +void CheckMemoryLeakImpl::deallocuseError(const Token *tok, const std::string &varname) const { reportErr(tok, Severity::error, "deallocuse", "$symbol:" + varname + "\nDereferencing '$symbol' after it is deallocated / released", CWE(416U)); } -void CheckMemoryLeak::mismatchAllocDealloc(const std::list &callstack, const std::string &varname) const +void CheckMemoryLeakImpl::mismatchAllocDealloc(const std::list &callstack, const std::string &varname) const { reportErr(callstack, Severity::error, "mismatchAllocDealloc", "$symbol:" + varname + "\nMismatching allocation and deallocation: $symbol", CWE(762U)); } -CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Function* func, std::list *callstack) const +CheckMemoryLeakImpl::AllocType CheckMemoryLeakImpl::functionReturnType(const Function* func, std::list *callstack) const { if (!func || !func->hasBody() || !func->functionScope) return No; @@ -431,7 +415,7 @@ static bool ifvar(const Token *tok, nonneg int varid, const std::string &comp, c // a = malloc(10); a = realloc(a, 100); //--------------------------------------------------------------------------- -void CheckMemoryLeakInFunction::checkReallocUsage() +void CheckMemoryLeakInFunctionImpl::checkReallocUsage() { logChecker("CheckMemoryLeakInFunction::checkReallocUsage"); @@ -453,8 +437,8 @@ void CheckMemoryLeakInFunction::checkReallocUsage() const Token *const reallocTok = parTok->astOperand1(); if (!reallocTok) continue; - const Library::AllocFunc* f = mSettings->library.getReallocFuncInfo(reallocTok); - if (!(f && f->arg == -1 && mSettings->library.isnotnoreturn(reallocTok))) + const Library::AllocFunc* f = mSettings.library.getReallocFuncInfo(reallocTok); + if (!(f && f->arg == -1 && mSettings.library.isnotnoreturn(reallocTok))) continue; const AllocType allocType = getReallocationType(reallocTok, tok->varId()); @@ -480,7 +464,7 @@ void CheckMemoryLeakInFunction::checkReallocUsage() 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))) + 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 @@ -502,17 +486,16 @@ void CheckMemoryLeakInFunction::checkReallocUsage() } } } -//--------------------------------------------------------------------------- -void CheckMemoryLeakInFunction::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckMemoryLeakInFunction::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { - CheckMemoryLeakInFunction checkMemoryLeak(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckMemoryLeakInFunctionImpl checkMemoryLeak(&tokenizer, tokenizer.getSettings(), errorLogger); checkMemoryLeak.checkReallocUsage(); } -void CheckMemoryLeakInFunction::getErrorMessages(ErrorLogger *e, const Settings *settings) const +void CheckMemoryLeakInFunction::getErrorMessages(ErrorLogger& e, const Settings &settings) const { - CheckMemoryLeakInFunction c(nullptr, settings, e); + CheckMemoryLeakInFunctionImpl c(nullptr, settings, e); c.memleakError(nullptr, "varname"); c.resourceLeakError(nullptr, "varname"); c.deallocuseError(nullptr, "varname"); @@ -525,8 +508,7 @@ void CheckMemoryLeakInFunction::getErrorMessages(ErrorLogger *e, const Settings // Checks for memory leaks in classes.. //--------------------------------------------------------------------------- - -void CheckMemoryLeakInClass::check() +void CheckMemoryLeakInClassImpl::check() { logChecker("CheckMemoryLeakInClass::check"); @@ -551,15 +533,15 @@ void CheckMemoryLeakInClass::check() } -void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarname) +void CheckMemoryLeakInClassImpl::variable(const Scope *scope, const Token *tokVarname) { const std::string& varname = tokVarname->str(); const int varid = tokVarname->varId(); const std::string& classname = scope->className; // Check if member variable has been allocated and deallocated.. - CheckMemoryLeak::AllocType memberAlloc = CheckMemoryLeak::No; - CheckMemoryLeak::AllocType memberDealloc = CheckMemoryLeak::No; + AllocType memberAlloc = AllocType::No; + AllocType memberDealloc = AllocType::No; bool allocInConstructor = false; bool deallocInDestructor = false; @@ -571,7 +553,7 @@ void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarnam if (!func.hasBody()) { if (destructor && !func.isDefault()) { // implementation for destructor is not seen and not defaulted => assume it deallocates all variables properly deallocInDestructor = true; - memberDealloc = CheckMemoryLeak::Many; + memberDealloc = AllocType::Many; } continue; } @@ -604,14 +586,14 @@ void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarnam allocTok = tok->astParent()->astParent()->astOperand2(); AllocType alloc = getAllocationType(allocTok, 0); - if (alloc != CheckMemoryLeak::No) { + if (alloc != AllocType::No) { if (constructor) allocInConstructor = true; - if (memberAlloc != No && memberAlloc != alloc) - alloc = CheckMemoryLeak::Many; + if (memberAlloc != AllocType::No && memberAlloc != alloc) + alloc = AllocType::Many; - if (alloc != CheckMemoryLeak::Many && memberDealloc != CheckMemoryLeak::No && memberDealloc != CheckMemoryLeak::Many && memberDealloc != alloc) { + if (alloc != AllocType::Many && memberDealloc != AllocType::No && memberDealloc != AllocType::Many && memberDealloc != alloc) { mismatchAllocDealloc({tok}, classname + "::" + varname); } @@ -627,24 +609,24 @@ void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarnam // some usage in the destructor => assume it's related // to deallocation if (destructor && tok->str() == varname) - dealloc = CheckMemoryLeak::Many; - if (dealloc != CheckMemoryLeak::No) { + dealloc = AllocType::Many; + if (dealloc != AllocType::No) { if (destructor) deallocInDestructor = true; - if (dealloc != CheckMemoryLeak::Many && memberAlloc != CheckMemoryLeak::No && memberAlloc != Many && memberAlloc != dealloc) { + if (dealloc != AllocType::Many && memberAlloc != AllocType::No && memberAlloc != Many && memberAlloc != dealloc) { mismatchAllocDealloc({tok}, classname + "::" + varname); } // several types of allocation/deallocation? - if (memberDealloc != CheckMemoryLeak::No && memberDealloc != dealloc) - dealloc = CheckMemoryLeak::Many; + if (memberDealloc != AllocType::No && memberDealloc != dealloc) + dealloc = AllocType::Many; memberDealloc = dealloc; } // Function call .. possible deallocation - else if (Token::Match(tok->previous(), "[{};] %name% (") && !tok->isKeyword() && !mSettings->library.isLeakIgnore(tok->str())) { + else if (Token::Match(tok->previous(), "[{};] %name% (") && !tok->isKeyword() && !mSettings.library.isLeakIgnore(tok->str())) { return; } } @@ -653,14 +635,14 @@ void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarnam if (allocInConstructor && !deallocInDestructor) { unsafeClassError(tokVarname, classname, classname + "::" + varname /*, memberAlloc*/); - } else if (memberAlloc != CheckMemoryLeak::No && memberDealloc == CheckMemoryLeak::No) { + } else if (memberAlloc != AllocType::No && memberDealloc == AllocType::No) { unsafeClassError(tokVarname, classname, classname + "::" + varname /*, memberAlloc*/); } } -void CheckMemoryLeakInClass::unsafeClassError(const Token *tok, const std::string &classname, const std::string &varname) +void CheckMemoryLeakInClassImpl::unsafeClassError(const Token *tok, const std::string &classname, const std::string &varname) { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unsafeClassCanLeak")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("unsafeClassCanLeak")) return; reportError(tok, Severity::style, "unsafeClassCanLeak", @@ -671,12 +653,12 @@ void CheckMemoryLeakInClass::unsafeClassError(const Token *tok, const std::strin } -void CheckMemoryLeakInClass::checkPublicFunctions(const Scope *scope, const Token *classtok) +void CheckMemoryLeakInClassImpl::checkPublicFunctions(const Scope *scope, const Token *classtok) { // Check that public functions deallocate the pointers that they allocate. // There is no checking how these functions are used and therefore it // isn't established if there is real leaks or not. - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; const int varid = classtok->varId(); @@ -688,44 +670,43 @@ void CheckMemoryLeakInClass::checkPublicFunctions(const Scope *scope, const Toke func.access == AccessControl::Public && func.hasBody()) { const Token *tok2 = func.functionScope->bodyStart->next(); if (Token::Match(tok2, "%varid% =", varid)) { - const CheckMemoryLeak::AllocType alloc = getAllocationType(tok2->tokAt(2), varid); - if (alloc != CheckMemoryLeak::No) + const AllocType alloc = getAllocationType(tok2->tokAt(2), varid); + if (alloc != AllocType::No) publicAllocationError(tok2, tok2->str()); } else if (Token::Match(tok2, "%type% :: %varid% =", varid) && tok2->str() == scope->className) { - const CheckMemoryLeak::AllocType alloc = getAllocationType(tok2->tokAt(4), varid); - if (alloc != CheckMemoryLeak::No) + const AllocType alloc = getAllocationType(tok2->tokAt(4), varid); + if (alloc != AllocType::No) publicAllocationError(tok2, tok2->strAt(2)); } } } } -void CheckMemoryLeakInClass::publicAllocationError(const Token *tok, const std::string &varname) +void CheckMemoryLeakInClassImpl::publicAllocationError(const Token *tok, const std::string &varname) { reportError(tok, Severity::warning, "publicAllocationError", "$symbol:" + varname + "\nPossible leak in public function. The pointer '$symbol' is not deallocated before it is allocated.", CWE398, Certainty::normal); } -void CheckMemoryLeakInClass::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckMemoryLeakInClass::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { if (!tokenizer.isCPP()) return; - CheckMemoryLeakInClass checkMemoryLeak(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckMemoryLeakInClassImpl checkMemoryLeak(&tokenizer, tokenizer.getSettings(), errorLogger); checkMemoryLeak.check(); } -void CheckMemoryLeakInClass::getErrorMessages(ErrorLogger *e, const Settings *settings) const +void CheckMemoryLeakInClass::getErrorMessages(ErrorLogger& e, const Settings &settings) const { - CheckMemoryLeakInClass c(nullptr, settings, e); + CheckMemoryLeakInClassImpl c(nullptr, settings, e); c.publicAllocationError(nullptr, "varname"); c.unsafeClassError(nullptr, "class", "class::varname"); } - -void CheckMemoryLeakStructMember::check() +void CheckMemoryLeakStructMemberImpl::check() { - if (mSettings->clang) + if (mSettings.clang) return; logChecker("CheckMemoryLeakStructMember::check"); @@ -742,7 +723,7 @@ void CheckMemoryLeakStructMember::check() } } -bool CheckMemoryLeakStructMember::isMalloc(const Variable *variable) const +bool CheckMemoryLeakStructMemberImpl::isMalloc(const Variable *variable) const { if (!variable) return false; @@ -755,7 +736,7 @@ bool CheckMemoryLeakStructMember::isMalloc(const Variable *variable) const const Token* tok3 = tok2->tokAt(1)->astOperand2(); while (tok3 && tok3->isCast()) tok3 = tok3->astOperand2() ? tok3->astOperand2() : tok3->astOperand1(); - if ((tok3 && Token::Match(tok3->tokAt(-1), "%name% (") && mSettings->library.getAllocFuncInfo(tok3->tokAt(-1))) || + if ((tok3 && Token::Match(tok3->tokAt(-1), "%name% (") && mSettings.library.getAllocFuncInfo(tok3->tokAt(-1))) || (Token::simpleMatch(tok3, "new") && tok3->isCpp())) { alloc = true; } @@ -764,7 +745,7 @@ bool CheckMemoryLeakStructMember::isMalloc(const Variable *variable) const return alloc; } -void CheckMemoryLeakStructMember::checkStructVariable(const Variable* const variable) const +void CheckMemoryLeakStructMemberImpl::checkStructVariable(const Variable* const variable) const { if (!variable) return; @@ -783,7 +764,7 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable* const vari auto deallocInFunction = [this](const Token* tok, int structid) -> bool { // Calling non-function / function that doesn't deallocate? - if (tok->isKeyword() || mSettings->library.isLeakIgnore(tok->str())) + if (tok->isKeyword() || mSettings.library.isLeakIgnore(tok->str())) return false; // Check if the struct is used.. @@ -905,7 +886,7 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable* const vari } // Deallocating the struct.. - else if (Token::Match(tok3, "%name% ( %varid% )", structid) && mSettings->library.getDeallocFuncInfo(tok3)) { + else if (Token::Match(tok3, "%name% ( %varid% )", structid) && mSettings.library.getDeallocFuncInfo(tok3)) { if (indentlevel2 == 0) memoryLeak(tok3, variable->name() + "." + tok2->strAt(2), allocType); break; @@ -939,7 +920,7 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable* const vari --indentlevel4; if (indentlevel4 == 0) break; - } else if (Token::Match(tok4, "%name% ( %var% . %varid% )", structmemberid) && mSettings->library.getDeallocFuncInfo(tok4)) { + } else if (Token::Match(tok4, "%name% ( %var% . %varid% )", structmemberid) && mSettings.library.getDeallocFuncInfo(tok4)) { break; } } @@ -982,17 +963,19 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable* const vari } } -void CheckMemoryLeakStructMember::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckMemoryLeakStructMember::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { - CheckMemoryLeakStructMember checkMemoryLeak(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckMemoryLeakStructMemberImpl checkMemoryLeak(&tokenizer, tokenizer.getSettings(), errorLogger); checkMemoryLeak.check(); } -void CheckMemoryLeakStructMember::getErrorMessages(ErrorLogger * /*errorLogger*/, const Settings * /*settings*/) const -{} - +void CheckMemoryLeakStructMember::getErrorMessages(ErrorLogger& errorLogger, const Settings & settings) const +{ + (void)&errorLogger; + (void)settings; +} -void CheckMemoryLeakNoVar::check() +void CheckMemoryLeakNoVarImpl::check() { logChecker("CheckMemoryLeakNoVar::check"); @@ -1018,7 +1001,7 @@ void CheckMemoryLeakNoVar::check() // Checks if an input argument to a function is the return value of an allocation function // like malloc(), and the function does not release it. //--------------------------------------------------------------------------- -void CheckMemoryLeakNoVar::checkForUnreleasedInputArgument(const Scope *scope) +void CheckMemoryLeakNoVarImpl::checkForUnreleasedInputArgument(const Scope *scope) { // parse the executable scope until tok is reached... for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) { @@ -1030,10 +1013,8 @@ void CheckMemoryLeakNoVar::checkForUnreleasedInputArgument(const Scope *scope) const Token* tok2 = tok->next()->astParent(); while (tok2 && (tok2->isCast() || Token::Match(tok2, "?|:"))) tok2 = tok2->astParent(); - if (Token::Match(tok2, "%assign%")) // TODO: check if function returns allocated resource - continue; - if (Token::simpleMatch(tok->astTop(), "return")) - continue; + const bool hasAssign = Token::Match(tok2, "%assign%"); + const bool hasReturn = Token::simpleMatch(tok->astTop(), "return"); const std::string& functionName = tok->str(); if ((tok->isCpp() && functionName == "delete") || @@ -1042,9 +1023,15 @@ void CheckMemoryLeakNoVar::checkForUnreleasedInputArgument(const Scope *scope) if (Token::simpleMatch(tok->next()->astParent(), "(")) // passed to another function continue; - if (!tok->isKeyword() && !tok->function() && !mSettings->library.isLeakIgnore(functionName)) + if (!tok->isKeyword() && !tok->function() && !mSettings.library.isLeakIgnore(functionName)) continue; + if ((hasAssign || hasReturn) && !tok->function()) { + const std::string& ret = mSettings.library.returnValueType(tok); + if (ret.empty() || endsWith(ret, "*")) + continue; + } + const std::vector args = getArguments(tok); int argnr = -1; for (const Token* arg : args) { @@ -1062,8 +1049,11 @@ void CheckMemoryLeakNoVar::checkForUnreleasedInputArgument(const Scope *scope) if (alloc == New || alloc == NewArray) { const Token* typeTok = arg->next(); bool bail = !typeTok->isStandardType() && - !mSettings->library.detectContainerOrIterator(typeTok) && - !mSettings->library.podtype(typeTok->expressionString()); + (!typeTok->valueType() || + (typeTok->valueType()->type < ValueType::Type::SMART_POINTER && + typeTok->valueType()->type != ValueType::Type::POD)) && + !mSettings.library.detectContainerOrIterator(typeTok) && + !mSettings.library.podtype(typeTok->expressionString()); if (bail && typeTok->type() && typeTok->type()->classScope && typeTok->type()->classScope->numConstructors == 0 && typeTok->type()->classScope->getDestructor() == nullptr) { @@ -1078,8 +1068,8 @@ void CheckMemoryLeakNoVar::checkForUnreleasedInputArgument(const Scope *scope) const Variable* argvar = tok->function()->getArgumentVar(argnr); if (!argvar || !argvar->valueType()) continue; - const size_t argSize = argvar->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); - if (argSize == 0 || argSize >= mSettings->platform.sizeof_pointer) + const size_t argSize = argvar->valueType()->getSizeOf(mSettings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); + if (argSize == 0 || argSize >= mSettings.platform.sizeof_pointer) continue; } functionCallLeak(arg, arg->str(), functionName); @@ -1091,7 +1081,7 @@ void CheckMemoryLeakNoVar::checkForUnreleasedInputArgument(const Scope *scope) //--------------------------------------------------------------------------- // Checks if a call to an allocation function like malloc() is made and its return value is not assigned. //--------------------------------------------------------------------------- -void CheckMemoryLeakNoVar::checkForUnusedReturnValue(const Scope *scope) +void CheckMemoryLeakNoVarImpl::checkForUnusedReturnValue(const Scope *scope) { for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) { const bool isNew = tok->isCpp() && tok->str() == "new"; @@ -1124,7 +1114,7 @@ void CheckMemoryLeakNoVar::checkForUnusedReturnValue(const Scope *scope) bool warn = true; if (isNew) { const Token* typeTok = tok->next(); - warn = typeTok && (typeTok->isStandardType() || mSettings->library.detectContainer(typeTok)); + warn = typeTok && (typeTok->isStandardType() || mSettings.library.detectContainer(typeTok)); } if (!parent && warn) { @@ -1158,13 +1148,13 @@ void CheckMemoryLeakNoVar::checkForUnusedReturnValue(const Scope *scope) // f(shared_ptr(new int(42)), g()); // } //--------------------------------------------------------------------------- -void CheckMemoryLeakNoVar::checkForUnsafeArgAlloc(const Scope *scope) +void CheckMemoryLeakNoVarImpl::checkForUnsafeArgAlloc(const Scope *scope) { // This test only applies to C++ source if (!mTokenizer->isCPP()) return; - if (!mSettings->isPremiumEnabled("leakUnsafeArgAlloc") && (!mSettings->certainty.isEnabled(Certainty::inconclusive) || !mSettings->severity.isEnabled(Severity::warning))) + if (!mSettings.isPremiumEnabled("leakUnsafeArgAlloc") && (!mSettings.certainty.isEnabled(Certainty::inconclusive) || !mSettings.severity.isEnabled(Severity::warning))) return; logChecker("CheckMemoryLeakNoVar::checkForUnsafeArgAlloc"); @@ -1208,17 +1198,17 @@ void CheckMemoryLeakNoVar::checkForUnsafeArgAlloc(const Scope *scope) } } -void CheckMemoryLeakNoVar::functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall) +void CheckMemoryLeakNoVarImpl::functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall) { reportError(loc, Severity::error, "leakNoVarFunctionCall", "Allocation with " + alloc + ", " + functionCall + " doesn't release it.", CWE772, Certainty::normal); } -void CheckMemoryLeakNoVar::returnValueNotUsedError(const Token *tok, const std::string &alloc) +void CheckMemoryLeakNoVarImpl::returnValueNotUsedError(const Token *tok, const std::string &alloc) { reportError(tok, Severity::error, "leakReturnValNotUsed", "$symbol:" + alloc + "\nReturn value of allocation function '$symbol' is not stored.", CWE771, Certainty::normal); } -void CheckMemoryLeakNoVar::unsafeArgAllocError(const Token *tok, const std::string &funcName, const std::string &ptrType, const std::string& objType) +void CheckMemoryLeakNoVarImpl::unsafeArgAllocError(const Token *tok, const std::string &funcName, const std::string &ptrType, const std::string& objType) { const std::string factoryFunc = ptrType == "shared_ptr" ? "make_shared" : "make_unique"; reportError(tok, Severity::warning, "leakUnsafeArgAlloc", @@ -1228,15 +1218,15 @@ void CheckMemoryLeakNoVar::unsafeArgAllocError(const Token *tok, const std::stri Certainty::inconclusive); // Inconclusive because funcName may never throw } -void CheckMemoryLeakNoVar::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckMemoryLeakNoVar::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { - CheckMemoryLeakNoVar checkMemoryLeak(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckMemoryLeakNoVarImpl checkMemoryLeak(&tokenizer, tokenizer.getSettings(), errorLogger); checkMemoryLeak.check(); } -void CheckMemoryLeakNoVar::getErrorMessages(ErrorLogger *e, const Settings *settings) const +void CheckMemoryLeakNoVar::getErrorMessages(ErrorLogger& e, const Settings &settings) const { - CheckMemoryLeakNoVar c(nullptr, settings, e); + CheckMemoryLeakNoVarImpl c(nullptr, settings, e); c.functionCallLeak(nullptr, "funcName", "funcName"); c.returnValueNotUsedError(nullptr, "funcName"); c.unsafeArgAllocError(nullptr, "funcName", "shared_ptr", "int"); diff --git a/lib/checkmemoryleak.h b/lib/checkmemoryleak.h index c9fb2274252..fdb7748f9ed 100644 --- a/lib/checkmemoryleak.h +++ b/lib/checkmemoryleak.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 @@ -33,6 +33,7 @@ */ #include "check.h" +#include "checkimpl.h" #include "config.h" #include @@ -52,18 +53,95 @@ enum class Severity : std::uint8_t; /// @addtogroup Core /// @{ -/** @brief Base class for memory leaks checking */ -class CPPCHECKLIB CheckMemoryLeak { + +/** + * @brief %CheckMemoryLeakInFunction detects when a function variable is allocated but not deallocated properly. + * + * The checking is done by looking at each function variable separately. By repeating these 4 steps over and over: + * -# locate a function variable + * -# create a simple token list that describes the usage of the function variable. + * -# simplify the token list. + * -# finally, check if the simplified token list contain any leaks. + */ + +class CPPCHECKLIB CheckMemoryLeakInFunction : public Check { +public: + /** @brief This constructor is used when registering this class */ + CheckMemoryLeakInFunction() : Check("Memory leaks (function variables)") {} + +private: + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + + /** Report all possible errors (for the --errorlist) */ + void getErrorMessages(ErrorLogger& e, const Settings &settings) const override; + + /** + * Get class information (--doc) + * @return Wiki formatted information about this class + */ + std::string classInfo() const override { + return "Is there any allocated memory when a function goes out of scope\n"; + } +}; + + +/** + * @brief %Check class variables, variables that are allocated in the constructor should be deallocated in the destructor + */ + +class CPPCHECKLIB CheckMemoryLeakInClass : public Check { +public: + CheckMemoryLeakInClass() : Check("Memory leaks (class variables)") {} + +private: + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + + void getErrorMessages(ErrorLogger& e, const Settings &settings) const override; + + std::string classInfo() const override { + return "If the constructor allocate memory then the destructor must deallocate it.\n"; + } +}; + + + +/** @brief detect simple memory leaks for struct members */ + +class CPPCHECKLIB CheckMemoryLeakStructMember : public Check { +public: + CheckMemoryLeakStructMember() : Check("Memory leaks (struct members)") {} + +private: + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + + void getErrorMessages(ErrorLogger& errorLogger, const Settings & settings) const override; + + std::string classInfo() const override { + return "Don't forget to deallocate struct members\n"; + } +}; + + + +/** @brief detect simple memory leaks (address not taken) */ + +class CPPCHECKLIB CheckMemoryLeakNoVar : public Check { +public: + CheckMemoryLeakNoVar() : Check("Memory leaks (address not taken)") {} + private: - /** For access to the tokens */ - const Tokenizer * const mTokenizer_; + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; - /** ErrorLogger used to report errors */ - ErrorLogger * const mErrorLogger_; + void getErrorMessages(ErrorLogger& e, const Settings &settings) const override; - /** Enabled standards */ - const Settings * const mSettings_; + std::string classInfo() const override { + return "Not taking the address to allocated memory\n"; + } +}; +/** @brief Base class for memory leaks checking */ +class CPPCHECKLIB CheckMemoryLeakImpl : public CheckImpl { +private: /** * Report error. Similar with the function Check::reportError * @param tok the token where the error occurs @@ -85,12 +163,12 @@ class CPPCHECKLIB CheckMemoryLeak { void reportErr(const std::list &callstack, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe) const; public: - CheckMemoryLeak() = delete; - CheckMemoryLeak(const CheckMemoryLeak &) = delete; - CheckMemoryLeak& operator=(const CheckMemoryLeak &) = delete; + CheckMemoryLeakImpl() = delete; + CheckMemoryLeakImpl(const CheckMemoryLeakImpl &) = delete; + CheckMemoryLeakImpl& operator=(const CheckMemoryLeakImpl &) = delete; - CheckMemoryLeak(const Tokenizer *t, ErrorLogger *e, const Settings *s) - : mTokenizer_(t), mErrorLogger_(e), mSettings_(s) {} + CheckMemoryLeakImpl(const Tokenizer *t, const Settings &s, ErrorLogger &e) + : CheckImpl(t, s, e) {} /** @brief What type of allocation are used.. the "Many" means that several types of allocation and deallocation are used */ enum AllocType : std::uint8_t { No, Malloc, New, NewArray, File, Fd, Pipe, OtherMem, OtherRes, Many }; @@ -165,43 +243,16 @@ class CPPCHECKLIB CheckMemoryLeak { * -# finally, check if the simplified token list contain any leaks. */ -class CPPCHECKLIB CheckMemoryLeakInFunction : public Check, public CheckMemoryLeak { - friend class TestMemleakInFunction; - +class CPPCHECKLIB CheckMemoryLeakInFunctionImpl : public CheckMemoryLeakImpl { public: - /** @brief This constructor is used when registering this class */ - CheckMemoryLeakInFunction() : Check(myName()), CheckMemoryLeak(nullptr, nullptr, nullptr) {} - -private: /** @brief This constructor is used when running checks */ - CheckMemoryLeakInFunction(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger), CheckMemoryLeak(tokenizer, errorLogger, settings) {} - - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + CheckMemoryLeakInFunctionImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckMemoryLeakImpl(tokenizer, settings, errorLogger) {} /** * Checking for a memory leak caused by improper realloc usage. */ void checkReallocUsage(); - - /** Report all possible errors (for the --errorlist) */ - void getErrorMessages(ErrorLogger *e, const Settings *settings) const override; - - /** - * Get name of class (--doc) - * @return name of class - */ - static std::string myName() { - return "Memory leaks (function variables)"; - } - - /** - * Get class information (--doc) - * @return Wiki formatted information about this class - */ - std::string classInfo() const override { - return "Is there any allocated memory when a function goes out of scope\n"; - } }; @@ -210,17 +261,10 @@ class CPPCHECKLIB CheckMemoryLeakInFunction : public Check, public CheckMemoryLe * @brief %Check class variables, variables that are allocated in the constructor should be deallocated in the destructor */ -class CPPCHECKLIB CheckMemoryLeakInClass : public Check, private CheckMemoryLeak { - friend class TestMemleakInClass; - +class CPPCHECKLIB CheckMemoryLeakInClassImpl : private CheckMemoryLeakImpl { public: - CheckMemoryLeakInClass() : Check(myName()), CheckMemoryLeak(nullptr, nullptr, nullptr) {} - -private: - CheckMemoryLeakInClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger), CheckMemoryLeak(tokenizer, errorLogger, settings) {} - - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + CheckMemoryLeakInClassImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckMemoryLeakImpl(tokenizer, settings, errorLogger) {} void check(); @@ -231,33 +275,17 @@ class CPPCHECKLIB CheckMemoryLeakInClass : public Check, private CheckMemoryLeak void publicAllocationError(const Token *tok, const std::string &varname); void unsafeClassError(const Token *tok, const std::string &classname, const std::string &varname); - - void getErrorMessages(ErrorLogger *e, const Settings *settings) const override; - - static std::string myName() { - return "Memory leaks (class variables)"; - } - - std::string classInfo() const override { - return "If the constructor allocate memory then the destructor must deallocate it.\n"; - } }; /** @brief detect simple memory leaks for struct members */ -class CPPCHECKLIB CheckMemoryLeakStructMember : public Check, private CheckMemoryLeak { - friend class TestMemleakStructMember; - +class CPPCHECKLIB CheckMemoryLeakStructMemberImpl : private CheckMemoryLeakImpl { public: - CheckMemoryLeakStructMember() : Check(myName()), CheckMemoryLeak(nullptr, nullptr, nullptr) {} - -private: - CheckMemoryLeakStructMember(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger), CheckMemoryLeak(tokenizer, errorLogger, settings) {} - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + CheckMemoryLeakStructMemberImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckMemoryLeakImpl(tokenizer, settings, errorLogger) {} void check(); @@ -265,33 +293,16 @@ class CPPCHECKLIB CheckMemoryLeakStructMember : public Check, private CheckMemor bool isMalloc(const Variable *variable) const; void checkStructVariable(const Variable* variable) const; - - void getErrorMessages(ErrorLogger* /*errorLogger*/, const Settings* /*settings*/) const override; - - static std::string myName() { - return "Memory leaks (struct members)"; - } - - std::string classInfo() const override { - return "Don't forget to deallocate struct members\n"; - } }; /** @brief detect simple memory leaks (address not taken) */ -class CPPCHECKLIB CheckMemoryLeakNoVar : public Check, private CheckMemoryLeak { - friend class TestMemleakNoVar; - +class CPPCHECKLIB CheckMemoryLeakNoVarImpl : private CheckMemoryLeakImpl { public: - CheckMemoryLeakNoVar() : Check(myName()), CheckMemoryLeak(nullptr, nullptr, nullptr) {} - -private: - CheckMemoryLeakNoVar(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger), CheckMemoryLeak(tokenizer, errorLogger, settings) {} - - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + CheckMemoryLeakNoVarImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckMemoryLeakImpl(tokenizer, settings, errorLogger) {} void check(); @@ -317,16 +328,6 @@ class CPPCHECKLIB CheckMemoryLeakNoVar : public Check, private CheckMemoryLeak { void functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall); void returnValueNotUsedError(const Token* tok, const std::string &alloc); void unsafeArgAllocError(const Token *tok, const std::string &funcName, const std::string &ptrType, const std::string &objType); - - void getErrorMessages(ErrorLogger *e, const Settings *settings) const override; - - static std::string myName() { - return "Memory leaks (address not taken)"; - } - - std::string classInfo() const override { - return "Not taking the address to allocated memory\n"; - } }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp index beb9d5d77a3..5c2e64e9a6c 100644 --- a/lib/checknullpointer.cpp +++ b/lib/checknullpointer.cpp @@ -47,26 +47,21 @@ 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) +static bool checkNullpointerFunctionCallPlausibility(const Function* func, size_t arg) { return !func || (func->argCount() >= arg && func->getArgumentVar(arg - 1) && func->getArgumentVar(arg - 1)->isPointer()); } -std::list CheckNullPointer::parseFunctionCall(const Token &tok, const Library &library, bool checkNullArg) +std::list CheckNullPointerImpl::parseFunctionCall(const Token &tok, const Library &library, bool checkNullArg) { if (Token::Match(&tok, "%name% ( )") || !tok.tokAt(2)) return {}; const std::vector args = getArguments(&tok); std::list var; - for (int argnr = 1; argnr <= args.size(); ++argnr) { + for (size_t argnr = 1; argnr <= args.size(); ++argnr) { const Token *param = args[argnr - 1]; if ((!checkNullArg || library.isnullargbad(&tok, argnr)) && checkNullpointerFunctionCallPlausibility(tok.function(), argnr)) var.push_back(param); @@ -133,21 +128,12 @@ namespace { }; } -/** - * Is there a pointer dereference? Everything that should result in - * a nullpointer dereference error message will result in a true - * return value. If it's unknown if the pointer is dereferenced false - * is returned. - * @param tok token for the pointer - * @param unknown it is not known if there is a pointer dereference (could be reported as a debug message) - * @return true => there is a dereference - */ -bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown) const +bool CheckNullPointerImpl::isPointerDeRef(const Token *tok, bool &unknown) const { - return isPointerDeRef(tok, unknown, *mSettings); + return isPointerDeRef(tok, unknown, mSettings.library); } -bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Settings &settings, bool checkNullArg) +bool CheckNullPointerImpl::isPointerDeRef(const Token *tok, bool &unknown, const Library &library, bool checkNullArg) { unknown = false; @@ -160,7 +146,7 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Set ftok = ftok->previous(); } if (ftok && ftok->previous()) { - const std::list varlist = parseFunctionCall(*ftok->previous(), settings.library, checkNullArg); + const std::list varlist = CheckNullPointerImpl::parseFunctionCall(*ftok->previous(), library, checkNullArg); if (std::find(varlist.cbegin(), varlist.cend(), tok) != varlist.cend()) { return true; } @@ -175,7 +161,7 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Set return false; const bool addressOf = parent->astParent() && parent->astParent()->str() == "&"; if (parent->str() == "." && astIsRHS(tok)) - return isPointerDeRef(parent, unknown, settings); + return isPointerDeRef(parent, unknown, library); const bool firstOperand = parent->astOperand1() == tok; parent = astParentSkipParens(tok); if (!parent) @@ -278,9 +264,9 @@ static bool isNullablePointer(const Token* tok) return false; } -void CheckNullPointer::nullPointerByDeRefAndCheck() +void CheckNullPointerImpl::nullPointerByDeRefAndCheck() { - const bool printInconclusive = (mSettings->certainty.isEnabled(Certainty::inconclusive)); + const bool printInconclusive = (mSettings.certainty.isEnabled(Certainty::inconclusive)); const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Scope * scope : symbolDatabase->functionScopes) { @@ -306,13 +292,13 @@ void CheckNullPointer::nullPointerByDeRefAndCheck() return true; }; const Token* const start = (scope->function && scope->function->isConstructor()) ? scope->function->token : scope->bodyStart; // Check initialization list - std::vector tokens = findTokensSkipDeadAndUnevaluatedCode(mSettings->library, start, scope->bodyEnd, pred); + std::vector tokens = findTokensSkipDeadAndUnevaluatedCode(mSettings.library, start, scope->bodyEnd, pred); for (const Token *tok : tokens) { const ValueFlow::Value *value = tok->getValue(0); // Pointer dereference. bool unknown = false; - if (!isPointerDeRef(tok, unknown)) { + if (!CheckNullPointerImpl::isPointerDeRef(tok, unknown, mSettings.library)) { if (unknown) nullPointerError(tok, tok->expressionString(), value, true); continue; @@ -323,7 +309,7 @@ void CheckNullPointer::nullPointerByDeRefAndCheck() } } -void CheckNullPointer::nullPointer() +void CheckNullPointerImpl::nullPointer() { logChecker("CheckNullPointer::nullPointer"); nullPointerByDeRefAndCheck(); @@ -337,7 +323,7 @@ namespace { } /** Dereferencing null constant (simplified token list) */ -void CheckNullPointer::nullConstantDereference() +void CheckNullPointerImpl::nullConstantDereference() { logChecker("CheckNullPointer::nullConstantDereference"); @@ -371,7 +357,7 @@ void CheckNullPointer::nullConstantDereference() if (var && !var->isPointer() && !var->isArray() && var->isStlStringType()) nullPointerError(tok); } else { // function call - const std::list var = parseFunctionCall(*tok, mSettings->library); + const std::list var = parseFunctionCall(*tok, mSettings.library); // is one of the var items a NULL pointer? for (const Token *vartok : var) { @@ -384,13 +370,13 @@ void CheckNullPointer::nullConstantDereference() else if (Token::Match(tok->previous(), "::|. %name% (")) { const std::vector &args = getArguments(tok); - for (int argnr = 0; argnr < args.size(); ++argnr) { + for (size_t argnr = 0; argnr < args.size(); ++argnr) { const Token *argtok = args[argnr]; if (!argtok->hasKnownIntValue()) continue; if (argtok->getKnownIntValue() != 0) continue; - if (mSettings->library.isnullargbad(tok, argnr+1)) + if (mSettings.library.isnullargbad(tok, argnr+1)) nullPointerError(argtok); } } @@ -430,14 +416,14 @@ void CheckNullPointer::nullConstantDereference() } } -void CheckNullPointer::nullPointerError(const Token *tok) +void CheckNullPointerImpl::nullPointerError(const Token *tok) { ValueFlow::Value v(0); v.setKnown(); nullPointerError(tok, "", &v, false); } -void CheckNullPointer::nullPointerError(const Token *tok, const std::string &varname, const ValueFlow::Value *value, bool inconclusive) +void CheckNullPointerImpl::nullPointerError(const Token *tok, const std::string &varname, const ValueFlow::Value *value, bool inconclusive) { const std::string errmsgcond("$symbol:" + varname + '\n' + ValueFlow::eitherTheConditionIsRedundant(value ? value->condition : nullptr) + " or there is possible null pointer dereference: $symbol."); const std::string errmsgdefarg("$symbol:" + varname + "\nPossible null pointer dereference if the default parameter value is used: $symbol"); @@ -458,7 +444,7 @@ void CheckNullPointer::nullPointerError(const Token *tok, const std::string &var return; } - if (!mSettings->isEnabled(value, inconclusive) && !mSettings->isPremiumEnabled("nullPointer")) + if (!mSettings.isEnabled(value, inconclusive) && !mSettings.isPremiumEnabled("nullPointer")) return; ErrorPath errorPath = getErrorPath(tok, value, "Null pointer dereference"); @@ -491,7 +477,7 @@ void CheckNullPointer::nullPointerError(const Token *tok, const std::string &var } } -void CheckNullPointer::arithmetic() +void CheckNullPointerImpl::arithmetic() { logChecker("CheckNullPointer::arithmetic"); const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -517,9 +503,9 @@ void CheckNullPointer::arithmetic() const ValueFlow::Value* value = pointerOperand->getValue(0); if (!value) continue; - if (!mSettings->certainty.isEnabled(Certainty::inconclusive) && value->isInconclusive()) + if (!mSettings.certainty.isEnabled(Certainty::inconclusive) && value->isInconclusive()) continue; - if (value->condition && !mSettings->severity.isEnabled(Severity::warning)) + if (value->condition && !mSettings.severity.isEnabled(Severity::warning)) continue; if (value->condition) redundantConditionWarning(tok, value, value->condition, value->isInconclusive()); @@ -538,7 +524,7 @@ static std::string arithmeticTypeString(const Token *tok) return "arithmetic"; } -void CheckNullPointer::pointerArithmeticError(const Token* tok, const ValueFlow::Value *value, bool inconclusive) +void CheckNullPointerImpl::pointerArithmeticError(const Token* tok, const ValueFlow::Value *value, bool inconclusive) { // cppcheck-suppress shadowFunction - TODO: fix this std::string arithmetic = arithmeticTypeString(tok); @@ -568,7 +554,7 @@ void CheckNullPointer::pointerArithmeticError(const Token* tok, const ValueFlow: inconclusive ? Certainty::inconclusive : Certainty::normal); } -void CheckNullPointer::redundantConditionWarning(const Token* tok, const ValueFlow::Value *value, const Token *condition, bool inconclusive) +void CheckNullPointerImpl::redundantConditionWarning(const Token* tok, const ValueFlow::Value *value, const Token *condition, bool inconclusive) { // cppcheck-suppress shadowFunction - TODO: fix this std::string arithmetic = arithmeticTypeString(tok); @@ -592,7 +578,7 @@ static bool isUnsafeUsage(const Settings &settings, const Token *vartok, CTU::Fi { (void)value; bool unknown = false; - return CheckNullPointer::isPointerDeRef(vartok, unknown, settings); + return CheckNullPointerImpl::isPointerDeRef(vartok, unknown, settings.library); } // a Clang-built executable will crash when using the anonymous MyFileInfo later on - so put it in a unique namespace for now @@ -618,9 +604,11 @@ namespace }; } -Check::FileInfo *CheckNullPointer::getFileInfo(const Tokenizer &tokenizer, const Settings &settings, const std::string& /*currentConfig*/) const +const Check::FileInfo *CheckNullPointer::getFileInfo(const Tokenizer &tokenizer, const Settings &settings, const std::string& currentConfig) const { - const std::list &unsafeUsage = CTU::getUnsafeUsage(tokenizer, settings, isUnsafeUsage); + (void)currentConfig; + + const std::list &unsafeUsage = CTU::getUnsafeUsage(tokenizer, settings, ::isUnsafeUsage); if (unsafeUsage.empty()) return nullptr; @@ -629,24 +617,24 @@ Check::FileInfo *CheckNullPointer::getFileInfo(const Tokenizer &tokenizer, const return fileInfo; } -Check::FileInfo * CheckNullPointer::loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const +const Check::FileInfo * CheckNullPointer::loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement, const std::string& file0) const { const std::list &unsafeUsage = CTU::loadUnsafeUsageListFromXml(xmlElement); if (unsafeUsage.empty()) return nullptr; - auto *fileInfo = new MyFileInfo; + auto *fileInfo = new MyFileInfo(file0); fileInfo->unsafeUsage = unsafeUsage; return fileInfo; } -bool CheckNullPointer::analyseWholeProgram(const CTU::FileInfo &ctu, const std::list &fileInfo, const Settings& settings, ErrorLogger &errorLogger) +bool CheckNullPointer::analyseWholeProgram(const CTU::FileInfo &ctu, const std::list &fileInfo, const Settings& settings, ErrorLogger &errorLogger) { (void)settings; - CheckNullPointer dummy(nullptr, &settings, &errorLogger); + CheckNullPointerImpl dummy(nullptr, settings, errorLogger); dummy. - logChecker("CheckNullPointer::analyseWholeProgram"); // unusedfunctions + logChecker("CheckNullPointer::analyseWholeProgram"); if (fileInfo.empty()) return false; @@ -704,17 +692,17 @@ bool CheckNullPointer::analyseWholeProgram(const CTU::FileInfo &ctu, const std:: return foundErrors; } -void CheckNullPointer::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckNullPointer::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { - CheckNullPointer checkNullPointer(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckNullPointerImpl checkNullPointer(&tokenizer, tokenizer.getSettings(), errorLogger); checkNullPointer.nullPointer(); checkNullPointer.arithmetic(); checkNullPointer.nullConstantDereference(); } -void CheckNullPointer::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const +void CheckNullPointer::getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const { - CheckNullPointer c(nullptr, settings, errorLogger); + CheckNullPointerImpl c(nullptr, settings, errorLogger); c.nullPointerError(nullptr, "pointer", nullptr, false); c.pointerArithmeticError(nullptr, nullptr, false); // TODO: nullPointerArithmeticOutOfMemory diff --git a/lib/checknullpointer.h b/lib/checknullpointer.h index c02feae303e..ed6a617d81a 100644 --- a/lib/checknullpointer.h +++ b/lib/checknullpointer.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,6 +23,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include @@ -47,11 +48,38 @@ namespace ValueFlow /** @brief check for null pointer dereferencing */ class CPPCHECKLIB CheckNullPointer : public Check { - friend class TestNullPointer; - public: /** @brief This constructor is used when registering the CheckNullPointer */ - CheckNullPointer() : Check(myName()) {} + CheckNullPointer() : Check("Null pointer") {} + +private: + /** @brief Run checks against the normal token list */ + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + + /** @brief Parse current TU and extract file info */ + const Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings &settings, const std::string& currentConfig) const override; + + const Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement, const std::string& file0) const override; + + /** @brief Analyse all file infos for all TU */ + bool analyseWholeProgram(const CTU::FileInfo &ctu, const std::list &fileInfo, const Settings& settings, ErrorLogger &errorLogger) override; + + /** Get error messages. Used by --errorlist */ + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; + + /** class info in WIKI format. Used by --doc */ + std::string classInfo() const override { + return "Null pointers\n" + "- null pointer dereferencing\n" + "- undefined null pointer arithmetic\n"; + } +}; + +class CPPCHECKLIB CheckNullPointerImpl : public CheckImpl { +public: + /** @brief This constructor is used when running checks. */ + CheckNullPointerImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} /** * Is there a pointer dereference? Everything that should result in @@ -64,9 +92,8 @@ class CPPCHECKLIB CheckNullPointer : public Check { */ bool isPointerDeRef(const Token *tok, bool &unknown) const; - static bool isPointerDeRef(const Token *tok, bool &unknown, const Settings &settings, bool checkNullArg = true); + static bool isPointerDeRef(const Token *tok, bool &unknown, const Library &library, bool checkNullArg = true); -private: /** * @brief parse a function call and extract information about variable usage * @param tok first token @@ -76,13 +103,6 @@ class CPPCHECKLIB CheckNullPointer : public Check { */ 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) - : Check(myName(), tokenizer, settings, errorLogger) {} - - /** @brief Run checks against the normal token list */ - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; - /** @brief possible null pointer dereference */ void nullPointer(); @@ -92,29 +112,6 @@ class CPPCHECKLIB CheckNullPointer : public Check { void nullPointerError(const Token *tok); void nullPointerError(const Token *tok, const std::string &varname, const ValueFlow::Value* value, bool inconclusive); - /** @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 * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override; - - /** @brief Analyse all file infos for all TU */ - bool analyseWholeProgram(const CTU::FileInfo &ctu, const std::list &fileInfo, const Settings& settings, ErrorLogger &errorLogger) override; - - /** Get error messages. Used by --errorlist */ - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - /** Name of check */ - static std::string myName() { - return "Null pointer"; - } - - /** class info in WIKI format. Used by --doc */ - std::string classInfo() const override { - return "Null pointers\n" - "- null pointer dereferencing\n" - "- undefined null pointer arithmetic\n"; - } - /** * @brief Does one part of the check for nullPointer(). * Dereferencing a pointer and then checking if it's NULL.. diff --git a/lib/checkother.cpp b/lib/checkother.cpp index fb75d80fca7..d8f2f6ff6f4 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -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 @@ -85,9 +80,9 @@ static const CWE CWE783(783U); // Operator Precedence Logic Error // - http://www.cplusplus.com/reference/cstdio/getchar/ // - http://www.cplusplus.com/reference/cstdio/ungetc/ ... //---------------------------------------------------------------------------------- -void CheckOther::checkCastIntToCharAndBack() +void CheckOtherImpl::checkCastIntToCharAndBack() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckOther::checkCastIntToCharAndBack"); // warning @@ -135,7 +130,7 @@ void CheckOther::checkCastIntToCharAndBack() } } -void CheckOther::checkCastIntToCharAndBackError(const Token *tok, const std::string &strFunctionName) +void CheckOtherImpl::checkCastIntToCharAndBackError(const Token *tok, const std::string &strFunctionName) { reportError( tok, @@ -155,9 +150,9 @@ void CheckOther::checkCastIntToCharAndBackError(const Token *tok, const std::str //--------------------------------------------------------------------------- // Clarify calculation precedence for ternary operators. //--------------------------------------------------------------------------- -void CheckOther::clarifyCalculation() +void CheckOtherImpl::clarifyCalculation() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("clarifyCalculation")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("clarifyCalculation")) return; logChecker("CheckOther::clarifyCalculation"); // style @@ -204,7 +199,7 @@ void CheckOther::clarifyCalculation() } } -void CheckOther::clarifyCalculationError(const Token *tok, const std::string &op) +void CheckOtherImpl::clarifyCalculationError(const Token *tok, const std::string &op) { // suspicious calculation const std::string calc("'a" + op + "b?c:d'"); @@ -226,9 +221,9 @@ void CheckOther::clarifyCalculationError(const Token *tok, const std::string &op //--------------------------------------------------------------------------- // Clarify (meaningless) statements like *foo++; with parentheses. //--------------------------------------------------------------------------- -void CheckOther::clarifyStatement() +void CheckOtherImpl::clarifyStatement() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckOther::clarifyStatement"); // warning @@ -252,7 +247,7 @@ void CheckOther::clarifyStatement() } } -void CheckOther::clarifyStatementError(const Token *tok) +void CheckOtherImpl::clarifyStatementError(const Token *tok) { reportError(tok, Severity::warning, "clarifyStatement", "In expression like '*A++' the result of '*' is unused. Did you intend to write '(*A)++;'?\n" "A statement like '*A++;' might not do what you intended. Postfix 'operator++' is executed before 'operator*'. " @@ -262,9 +257,9 @@ void CheckOther::clarifyStatementError(const Token *tok) //--------------------------------------------------------------------------- // Check for suspicious occurrences of 'if(); {}'. //--------------------------------------------------------------------------- -void CheckOther::checkSuspiciousSemicolon() +void CheckOtherImpl::checkSuspiciousSemicolon() { - if (!mSettings->certainty.isEnabled(Certainty::inconclusive) || !mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.certainty.isEnabled(Certainty::inconclusive) || !mSettings.severity.isEnabled(Severity::warning)) return; const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -286,7 +281,7 @@ void CheckOther::checkSuspiciousSemicolon() } } -void CheckOther::suspiciousSemicolonError(const Token* tok) +void CheckOtherImpl::suspiciousSemicolonError(const Token* tok) { reportError(tok, Severity::warning, "suspiciousSemicolon", "Suspicious use of ; at the end of '" + (tok ? tok->str() : std::string()) + "' statement.", CWE398, Certainty::normal); @@ -334,13 +329,13 @@ static bool isDangerousTypeConversion(const Token* const tok) //--------------------------------------------------------------------------- // For C++ code, warn if C-style casts are used on pointer types //--------------------------------------------------------------------------- -void CheckOther::warningOldStylePointerCast() +void CheckOtherImpl::warningOldStylePointerCast() { // Only valid on C++ code if (!mTokenizer->isCPP()) return; - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("cstyleCast")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("cstyleCast")) return; logChecker("CheckOther::warningOldStylePointerCast"); // style,c++ @@ -399,7 +394,7 @@ void CheckOther::warningOldStylePointerCast() } } -void CheckOther::cstyleCastError(const Token *tok, bool isPtr) +void CheckOtherImpl::cstyleCastError(const Token *tok, bool isPtr) { const std::string type = isPtr ? "pointer" : "reference"; reportError(tok, Severity::style, "cstyleCast", @@ -410,12 +405,12 @@ void CheckOther::cstyleCastError(const Token *tok, bool isPtr) "which kind of cast is expected.", CWE398, Certainty::normal); } -void CheckOther::warningDangerousTypeCast() +void CheckOtherImpl::warningDangerousTypeCast() { // Only valid on C++ code if (!mTokenizer->isCPP()) return; - if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("dangerousTypeCast")) + if (!mSettings.severity.isEnabled(Severity::warning) && !mSettings.isPremiumEnabled("dangerousTypeCast")) return; logChecker("CheckOther::warningDangerousTypeCast"); // warning,c++ @@ -438,7 +433,7 @@ void CheckOther::warningDangerousTypeCast() } } -void CheckOther::dangerousTypeCastError(const Token *tok, bool isPtr) +void CheckOtherImpl::dangerousTypeCastError(const Token *tok, bool isPtr) { //const std::string type = isPtr ? "pointer" : "reference"; (void)isPtr; @@ -447,9 +442,9 @@ void CheckOther::dangerousTypeCastError(const Token *tok, bool isPtr) CWE398, Certainty::normal); } -void CheckOther::warningIntToPointerCast() +void CheckOtherImpl::warningIntToPointerCast() { - if (!mSettings->severity.isEnabled(Severity::portability) && !mSettings->isPremiumEnabled("cstyleCast")) + if (!mSettings.severity.isEnabled(Severity::portability) && !mSettings.isPremiumEnabled("cstyleCast")) return; logChecker("CheckOther::warningIntToPointerCast"); // portability @@ -469,6 +464,8 @@ void CheckOther::warningIntToPointerCast() format = "decimal"; else if (MathLib::isOct(from->str())) format = "octal"; + else if (MathLib::isBin(from->str())) + format = "binary"; else continue; intToPointerCastError(tok, format); @@ -476,16 +473,16 @@ void CheckOther::warningIntToPointerCast() } } -void CheckOther::intToPointerCastError(const Token *tok, const std::string& format) +void CheckOtherImpl::intToPointerCastError(const Token *tok, const std::string& format) { reportError(tok, Severity::portability, "intToPointerCast", "Casting non-zero " + format + " integer literal to pointer.", CWE398, Certainty::normal); } -void CheckOther::suspiciousFloatingPointCast() +void CheckOtherImpl::suspiciousFloatingPointCast() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("suspiciousFloatingPointCast")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("suspiciousFloatingPointCast")) return; logChecker("CheckOther::suspiciousFloatingPointCast"); // style @@ -533,7 +530,7 @@ void CheckOther::suspiciousFloatingPointCast() } } -void CheckOther::suspiciousFloatingPointCastError(const Token* tok) +void CheckOtherImpl::suspiciousFloatingPointCastError(const Token* tok) { reportError(tok, Severity::style, "suspiciousFloatingPointCast", "Floating-point cast causes loss of precision.\n" @@ -544,14 +541,14 @@ void CheckOther::suspiciousFloatingPointCastError(const Token* tok) // float* f; double* d = (double*)f; <-- Pointer cast to a type with an incompatible binary data representation //--------------------------------------------------------------------------- -void CheckOther::invalidPointerCast() +void CheckOtherImpl::invalidPointerCast() { - if (!mSettings->severity.isEnabled(Severity::portability)) + if (!mSettings.severity.isEnabled(Severity::portability)) return; logChecker("CheckOther::invalidPointerCast"); // portability - const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive); + const bool printInconclusive = mSettings.certainty.isEnabled(Certainty::inconclusive); const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Scope * scope : symbolDatabase->functionScopes) { for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) { @@ -584,7 +581,7 @@ void CheckOther::invalidPointerCast() } -void CheckOther::invalidPointerCastError(const Token* tok, const std::string& from, const std::string& to, bool inconclusive, bool toIsInt) +void CheckOtherImpl::invalidPointerCastError(const Token* tok, const std::string& from, const std::string& to, bool inconclusive, bool toIsInt) { if (toIsInt) { // If we cast something to int*, this can be useful to play with its binary data representation reportError(tok, Severity::portability, "invalidPointerCast", "Casting from " + from + " to " + to + " is not portable due to different binary data representations on different platforms.", CWE704, inconclusive ? Certainty::inconclusive : Certainty::normal); @@ -597,11 +594,11 @@ void CheckOther::invalidPointerCastError(const Token* tok, const std::string& fr // Detect redundant assignments: x = 0; x = 4; //--------------------------------------------------------------------------- -void CheckOther::checkRedundantAssignment() +void CheckOtherImpl::checkRedundantAssignment() { - if (!mSettings->severity.isEnabled(Severity::style) && - !mSettings->isPremiumEnabled("redundantAssignment") && - !mSettings->isPremiumEnabled("redundantAssignInSwitch")) + if (!mSettings.severity.isEnabled(Severity::style) && + !mSettings.isPremiumEnabled("redundantAssignment") && + !mSettings.isPremiumEnabled("redundantAssignInSwitch")) return; logChecker("CheckOther::checkRedundantAssignment"); // style @@ -671,10 +668,10 @@ void CheckOther::checkRedundantAssignment() if (tok->astOperand1()->valueType()->type == ValueType::SMART_POINTER) break; } - if (inconclusive && !mSettings->certainty.isEnabled(Certainty::inconclusive)) + if (inconclusive && !mSettings.certainty.isEnabled(Certainty::inconclusive)) continue; - FwdAnalysis fwdAnalysis(*mSettings); + FwdAnalysis fwdAnalysis(mSettings); if (fwdAnalysis.hasOperand(tok->astOperand2(), tok->astOperand1())) continue; @@ -734,7 +731,7 @@ void CheckOther::checkRedundantAssignment() } } -void CheckOther::redundantCopyError(const Token *tok1, const Token* tok2, const std::string& var) +void CheckOtherImpl::redundantCopyError(const Token *tok1, const Token* tok2, const std::string& var) { const std::list callstack = { tok1, tok2 }; reportError(callstack, Severity::performance, "redundantCopy", @@ -742,7 +739,7 @@ void CheckOther::redundantCopyError(const Token *tok1, const Token* tok2, const "Buffer '$symbol' is being written before its old content has been used.", CWE563, Certainty::normal); } -void CheckOther::redundantAssignmentError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive) +void CheckOtherImpl::redundantAssignmentError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive) { ErrorPath errorPath = { ErrorPathItem(tok1, var + " is assigned"), ErrorPathItem(tok2, var + " is overwritten") }; if (inconclusive) @@ -756,7 +753,7 @@ void CheckOther::redundantAssignmentError(const Token *tok1, const Token* tok2, "Variable '$symbol' is reassigned a value before the old one has been used.", CWE563, Certainty::normal); } -void CheckOther::redundantInitializationError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive) +void CheckOtherImpl::redundantInitializationError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive) { ErrorPath errorPath = { ErrorPathItem(tok1, var + " is initialized"), ErrorPathItem(tok2, var + " is overwritten") }; reportError(std::move(errorPath), Severity::style, "redundantInitialization", @@ -765,7 +762,7 @@ void CheckOther::redundantInitializationError(const Token *tok1, const Token* to inconclusive ? Certainty::inconclusive : Certainty::normal); } -void CheckOther::redundantAssignmentInSwitchError(const Token *tok1, const Token* tok2, const std::string &var) +void CheckOtherImpl::redundantAssignmentInSwitchError(const Token *tok1, const Token* tok2, const std::string &var) { ErrorPath errorPath = { ErrorPathItem(tok1, "$symbol is assigned"), ErrorPathItem(tok2, "$symbol is overwritten") }; reportError(std::move(errorPath), Severity::style, "redundantAssignInSwitch", @@ -773,7 +770,7 @@ void CheckOther::redundantAssignmentInSwitchError(const Token *tok1, const Token "Variable '$symbol' is reassigned a value before the old one has been used. 'break;' missing?", CWE563, Certainty::normal); } -void CheckOther::redundantAssignmentSameValueError(const Token *tok, const ValueFlow::Value* val, const std::string &var) +void CheckOtherImpl::redundantAssignmentSameValueError(const Token *tok, const ValueFlow::Value* val, const std::string &var) { auto errorPath = val->errorPath; errorPath.emplace_back(tok, ""); @@ -794,12 +791,12 @@ void CheckOther::redundantAssignmentSameValueError(const Token *tok, const Value //--------------------------------------------------------------------------- static inline bool isFunctionOrBreakPattern(const Token *tok) { - return Token::Match(tok, "%name% (") || Token::Match(tok, "break|continue|return|exit|goto|throw"); + return Token::Match(tok, "%name% (") || (tok->isKeyword() && Token::Match(tok, "break|continue|return|goto|throw")); } -void CheckOther::redundantBitwiseOperationInSwitchError() +void CheckOtherImpl::redundantBitwiseOperationInSwitchError() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckOther::redundantBitwiseOperationInSwitch"); // warning @@ -914,7 +911,7 @@ void CheckOther::redundantBitwiseOperationInSwitchError() } } -void CheckOther::redundantBitwiseOperationInSwitchError(const Token *tok, const std::string &varname) +void CheckOtherImpl::redundantBitwiseOperationInSwitchError(const Token *tok, const std::string &varname) { reportError(tok, Severity::style, "redundantBitwiseOperationInSwitch", @@ -926,9 +923,9 @@ void CheckOther::redundantBitwiseOperationInSwitchError(const Token *tok, const //--------------------------------------------------------------------------- // Check for statements like case A||B: in switch() //--------------------------------------------------------------------------- -void CheckOther::checkSuspiciousCaseInSwitch() +void CheckOtherImpl::checkSuspiciousCaseInSwitch() { - if (!mSettings->certainty.isEnabled(Certainty::inconclusive) || !mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.certainty.isEnabled(Certainty::inconclusive) || !mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckOther::checkSuspiciousCaseInSwitch"); // warning,inconclusive @@ -960,7 +957,7 @@ void CheckOther::checkSuspiciousCaseInSwitch() } } -void CheckOther::suspiciousCaseInSwitchError(const Token* tok, const std::string& operatorString) +void CheckOtherImpl::suspiciousCaseInSwitchError(const Token* tok, const std::string& operatorString) { reportError(tok, Severity::warning, "suspiciousCase", "Found suspicious case label in switch(). Operator '" + operatorString + "' probably doesn't work as intended.\n" @@ -1010,18 +1007,18 @@ static bool isVardeclInSwitch(const Token* tok) // Detect dead code, that follows such a statement. e.g.: // return(0); foo(); //--------------------------------------------------------------------------- -void CheckOther::checkUnreachableCode() +void CheckOtherImpl::checkUnreachableCode() { // misra-c-2012-2.1 // misra-c-2023-2.1 // misra-cpp-2008-0-1-1 // autosar - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("duplicateBreak") && !mSettings->isPremiumEnabled("unreachableCode")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("duplicateBreak") && !mSettings.isPremiumEnabled("unreachableCode")) return; logChecker("CheckOther::checkUnreachableCode"); // style - const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive); + const bool printInconclusive = mSettings.certainty.isEnabled(Certainty::inconclusive); const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Scope * scope : symbolDatabase->functionScopes) { if (scope->hasInlineOrLambdaFunction(nullptr, /*onlyInline*/ true)) @@ -1048,7 +1045,7 @@ void CheckOther::checkUnreachableCode() } else if (Token::Match(tok, "goto %any% ;")) { secondBreak = tok->tokAt(3); labelName = tok->next(); - } else if (Token::Match(tok, "%name% (") && mSettings->library.isnoreturn(tok) && !Token::Match(tok->next()->astParent(), "?|:")) { + } else if (Token::Match(tok, "%name% (") && mSettings.library.isnoreturn(tok) && !Token::Match(tok->next()->astParent(), "?|:")) { if ((!tok->function() || (tok->function()->token != tok && tok->function()->tokenDef != tok)) && tok->linkAt(1)->strAt(1) != "{") secondBreak = tok->linkAt(1)->tokAt(2); if (Token::simpleMatch(secondBreak, "return")) { @@ -1130,7 +1127,7 @@ void CheckOther::checkUnreachableCode() } } -void CheckOther::duplicateBreakError(const Token *tok, bool inconclusive) +void CheckOtherImpl::duplicateBreakError(const Token *tok, bool inconclusive) { reportError(tok, Severity::style, "duplicateBreak", "Consecutive return, break, continue, goto or throw statements are unnecessary.\n" @@ -1138,10 +1135,10 @@ void CheckOther::duplicateBreakError(const Token *tok, bool inconclusive) "The second statement can never be executed, and so should be removed.", CWE561, inconclusive ? Certainty::inconclusive : Certainty::normal); } -void CheckOther::unreachableCodeError(const Token *tok, const Token* noreturn, bool inconclusive) +void CheckOtherImpl::unreachableCodeError(const Token *tok, const Token* noreturn, bool inconclusive) { std::string msg = "Statements following "; - if (noreturn && (noreturn->function() || mSettings->library.isnoreturn(noreturn))) + if (noreturn && (noreturn->function() || mSettings.library.isnoreturn(noreturn))) msg += "noreturn function '" + noreturn->str() + "()'"; else if (noreturn && noreturn->isKeyword()) msg += "'" + noreturn->str() + "'"; @@ -1152,7 +1149,7 @@ void CheckOther::unreachableCodeError(const Token *tok, const Token* noreturn, b msg, CWE561, inconclusive ? Certainty::inconclusive : Certainty::normal); } -void CheckOther::redundantContinueError(const Token *tok) +void CheckOtherImpl::redundantContinueError(const Token *tok) { reportError(tok, Severity::style, "redundantContinue", "'continue' is redundant since it is the last statement in a loop.", CWE561, Certainty::normal); @@ -1188,19 +1185,19 @@ static bool isSimpleExpr(const Token* tok, const Variable* var, const Settings& //--------------------------------------------------------------------------- // Check scope of variables.. //--------------------------------------------------------------------------- -void CheckOther::checkVariableScope() +void CheckOtherImpl::checkVariableScope() { - if (mSettings->clang) + if (mSettings.clang) return; - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("variableScope")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("variableScope")) return; const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); // In C it is common practice to declare local variables at the // start of functions. - if (mSettings->daca && mTokenizer->isC()) + if (mSettings.daca && mTokenizer->isC()) return; logChecker("CheckOther::checkVariableScope"); // style,notclang @@ -1249,7 +1246,7 @@ void CheckOther::checkVariableScope() bool isConstructor = false; if (Token::Match(tok, "; %varid% =", var->declarationId())) { // bailout for assignment tok = tok->tokAt(2)->astOperand2(); - if (!isSimpleExpr(tok, var, *mSettings)) + if (!isSimpleExpr(tok, var, mSettings)) continue; } else if (Token::Match(tok, "{|(")) { // bailout for constructor @@ -1258,11 +1255,11 @@ void CheckOther::checkVariableScope() bool bail = false; while (argTok) { if (Token::simpleMatch(argTok, ",")) { - if (!isSimpleExpr(argTok->astOperand2(), var, *mSettings)) { + if (!isSimpleExpr(argTok->astOperand2(), var, mSettings)) { bail = true; break; } - } else if (argTok->str() != "." && !isSimpleExpr(argTok, var, *mSettings)) { + } else if (argTok->str() != "." && !isSimpleExpr(argTok, var, mSettings)) { bail = true; break; } @@ -1292,7 +1289,7 @@ void CheckOther::checkVariableScope() tok = tok->link(); // parse else if blocks.. - } else if (Token::simpleMatch(tok, "else { if (") && tok->next()->isSimplifiedScope() && Token::simpleMatch(tok->linkAt(3), ") {")) { + } else if (Token::simpleMatch(tok, "else { if (") && tok->next()->isInsertedBrace() && Token::simpleMatch(tok->linkAt(3), ") {")) { tok = tok->next(); } else if (tok->varId() == var->declarationId() || tok->str() == "goto") { reduce = false; @@ -1340,7 +1337,7 @@ static bool isOnlyUsedInCurrentScope(const Variable* var, const Token *tok, cons return !Token::findmatch(tok->scope()->bodyEnd, "%varid%", var->scope()->bodyEnd, var->declarationId()); } -bool CheckOther::checkInnerScope(const Token *tok, const Variable* var, bool& used) const +bool CheckOtherImpl::checkInnerScope(const Token *tok, const Variable* var, bool& used) const { const Scope* scope = tok->next()->scope(); bool loopVariable = scope->isLoopScope(); @@ -1418,7 +1415,7 @@ bool CheckOther::checkInnerScope(const Token *tok, const Variable* var, bool& us if (scope->type == ScopeType::eSwitch) return false; // Used in outer switch scope - unsafe or impossible to reduce scope - if (scope->bodyStart && scope->bodyStart->isSimplifiedScope()) + if (scope->bodyStart && scope->bodyStart->isSimplifiedIfInitStmt()) return false; // simplified if/for/switch init statement } if (var->isArrayOrPointer()) { @@ -1427,7 +1424,7 @@ bool CheckOther::checkInnerScope(const Token *tok, const Variable* var, bool& us if (ftok->next()->astParent()) { // return value used? if (ftok->function() && Function::returnsPointer(ftok->function())) return false; - const std::string ret = mSettings->library.returnValueType(ftok); // assume that var is returned + const std::string ret = mSettings.library.returnValueType(ftok); // assume that var is returned if (!ret.empty() && ret.back() == '*') return false; } @@ -1442,7 +1439,7 @@ bool CheckOther::checkInnerScope(const Token *tok, const Variable* var, bool& us } } } - const auto yield = astContainerYield(tok, mSettings->library); + const auto yield = astContainerYield(tok, mSettings.library); if (yield == Library::Container::Yield::BUFFER || yield == Library::Container::Yield::BUFFER_NT) return false; } @@ -1451,7 +1448,7 @@ bool CheckOther::checkInnerScope(const Token *tok, const Variable* var, bool& us return true; } -void CheckOther::variableScopeError(const Token *tok, const std::string &varname) +void CheckOtherImpl::variableScopeError(const Token *tok, const std::string &varname) { reportError(tok, Severity::style, @@ -1478,10 +1475,10 @@ void CheckOther::variableScopeError(const Token *tok, const std::string &varname //--------------------------------------------------------------------------- // Comma in return statement: return a+1, b++;. (experimental) //--------------------------------------------------------------------------- -void CheckOther::checkCommaSeparatedReturn() +void CheckOtherImpl::checkCommaSeparatedReturn() { // TODO: This is experimental for now. See #5076 - if ((true) || !mSettings->severity.isEnabled(Severity::style)) // NOLINT(readability-simplify-boolean-expr,readability-redundant-parentheses) + if ((true) || !mSettings.severity.isEnabled(Severity::style)) // NOLINT(readability-simplify-boolean-expr,readability-redundant-parentheses) return; // logChecker @@ -1505,7 +1502,7 @@ void CheckOther::checkCommaSeparatedReturn() } } -void CheckOther::commaSeparatedReturnError(const Token *tok) +void CheckOtherImpl::commaSeparatedReturnError(const Token *tok) { reportError(tok, Severity::style, @@ -1543,9 +1540,9 @@ static bool isLargeContainer(const Variable* var, const Settings& settings) return arraySize > maxByValueSize; } -void CheckOther::checkPassByReference() +void CheckOtherImpl::checkPassByReference() { - if (!mSettings->severity.isEnabled(Severity::performance) || mTokenizer->isC()) + if (!mSettings.severity.isEnabled(Severity::performance) || mTokenizer->isC()) return; logChecker("CheckOther::checkPassByReference"); // performance,c++ @@ -1571,21 +1568,21 @@ void CheckOther::checkPassByReference() bool inconclusive = false; const bool isContainer = var->valueType() && var->valueType()->type == ValueType::Type::CONTAINER && var->valueType()->container && !var->valueType()->container->view; - if (isContainer && !isLargeContainer(var, *mSettings)) + if (isContainer && !isLargeContainer(var, mSettings)) continue; if (!isContainer) { if (var->type() && !var->type()->isEnumType()) { // Check if type is a struct or class. // Ensure that it is a large object. if (!var->type()->classScope) inconclusive = true; - else if (!var->valueType() || var->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer) <= 2 * mSettings->platform.sizeof_pointer) + else if (!var->valueType() || var->valueType()->getSizeOf(mSettings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer) <= 2 * mSettings.platform.sizeof_pointer) continue; } else continue; } - if (inconclusive && !mSettings->certainty.isEnabled(Certainty::inconclusive)) + if (inconclusive && !mSettings.certainty.isEnabled(Certainty::inconclusive)) continue; if (var->isArray() && (!var->isStlType() || Token::simpleMatch(var->nameToken()->next(), "["))) @@ -1616,13 +1613,13 @@ void CheckOther::checkPassByReference() if (!isRangeBasedFor && (!var->scope() || var->scope()->function->isImplicitlyVirtual())) continue; - if (!isVariableChanged(var, *mSettings)) { + if (!isVariableChanged(var, mSettings)) { passedByValueError(var, inconclusive, isRangeBasedFor); } } } -void CheckOther::passedByValueError(const Variable* var, bool inconclusive, bool isRangeBasedFor) +void CheckOtherImpl::passedByValueError(const Variable* var, bool inconclusive, bool isRangeBasedFor) { std::string id = isRangeBasedFor ? "iterateByValue" : "passedByValue"; const std::string action = isRangeBasedFor ? "declared as": "passed by"; @@ -1687,9 +1684,9 @@ static bool isCastToVoid(const Variable* var) return false; } -void CheckOther::checkConstVariable() +void CheckOtherImpl::checkConstVariable() { - if ((!mSettings->severity.isEnabled(Severity::style) || mTokenizer->isC()) && !mSettings->isPremiumEnabled("constVariable")) + if ((!mSettings.severity.isEnabled(Severity::style) || mTokenizer->isC()) && !mSettings.isPremiumEnabled("constVariable")) return; logChecker("CheckOther::checkConstVariable"); // style,c++ @@ -1737,7 +1734,7 @@ void CheckOther::checkConstVariable() continue; if (isCastToVoid(var)) continue; - if (isVariableChanged(var, *mSettings)) + if (isVariableChanged(var, mSettings)) continue; const bool hasFunction = function != nullptr; if (!hasFunction) { @@ -1760,7 +1757,7 @@ void CheckOther::checkConstVariable() ValueFlow::Value ltVal = ValueFlow::getLifetimeObjValue(retTok); if (ltVal.isLifetimeValue() && ltVal.tokvalue->varId() == var->declarationId()) return true; - return ValueFlow::hasLifetimeToken(getParentLifetime(retTok), var->nameToken(), *mSettings); + return ValueFlow::hasLifetimeToken(getParentLifetime(retTok), var->nameToken(), mSettings); })) continue; } @@ -1796,7 +1793,7 @@ void CheckOther::checkConstVariable() continue; } else if (const Token* ftok = getTokenArgumentFunction(tok, argn)) { bool inconclusive{}; - if (var->valueType() && !isVariableChangedByFunctionCall(ftok, var->valueType()->pointer, var->declarationId(), *mSettings, &inconclusive) && !inconclusive) + if (var->valueType() && !isVariableChangedByFunctionCall(ftok, var->valueType()->pointer, var->declarationId(), mSettings.library, &inconclusive) && !inconclusive) continue; } usedInAssignment = true; @@ -1880,13 +1877,13 @@ static const Function* getEnclosingFunction(const Variable* var) return scope ? scope->function : nullptr; } -void CheckOther::checkConstPointer() +void CheckOtherImpl::checkConstPointer() { - if (!mSettings->severity.isEnabled(Severity::style) && - !mSettings->isPremiumEnabled("constParameter") && - !mSettings->isPremiumEnabled("constParameterPointer") && - !mSettings->isPremiumEnabled("constParameterReference") && - !mSettings->isPremiumEnabled("constVariablePointer")) + if (!mSettings.severity.isEnabled(Severity::style) && + !mSettings.isPremiumEnabled("constParameter") && + !mSettings.isPremiumEnabled("constParameterPointer") && + !mSettings.isPremiumEnabled("constParameterReference") && + !mSettings.isPremiumEnabled("constVariablePointer")) return; logChecker("CheckOther::checkConstPointer"); // style @@ -1941,18 +1938,23 @@ 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) continue; - if (parent->astOperand2()) { - if (parent->astOperand2()->function() && parent->astOperand2()->function()->isConst()) + const Token* funcParent = parent; + while (Token::simpleMatch(funcParent->astParent(), ".")) + funcParent = funcParent->astParent(); + if (funcParent->astOperand2()) { + if (funcParent->astOperand2()->function() && funcParent->astOperand2()->function()->isConst()) continue; - if (mSettings->library.isFunctionConst(parent->astOperand2())) + if (mSettings.library.isFunctionConst(funcParent->astOperand2())) continue; - if (parent->astOperand2()->varId()) { - if (gparent->str() == "?" && astIsLHS(parent)) + if (funcParent->astOperand2()->varId()) { + if (gparent->str() == "?" && astIsLHS(funcParent)) continue; } } @@ -1987,7 +1989,7 @@ void CheckOther::checkConstPointer() continue; else if (const Token* ftok = getTokenArgumentFunction(parent, argn)) { bool inconclusive{}; - if (!isVariableChangedByFunctionCall(ftok->next(), vt->pointer, var->declarationId(), *mSettings, &inconclusive) && !inconclusive) + if (!isVariableChangedByFunctionCall(ftok->next(), vt->pointer, var->declarationId(), mSettings.library, &inconclusive) && !inconclusive) continue; } } else { @@ -2012,12 +2014,12 @@ void CheckOther::checkConstPointer() const Variable* argVar = ftok->function()->getArgumentVar(argn); if (argVar && argVar->valueType() && argVar->valueType()->isConst(vt->pointer)) { bool inconclusive{}; - if (!isVariableChangedByFunctionCall(ftok, vt->pointer, var->declarationId(), *mSettings, &inconclusive) && !inconclusive) + if (!isVariableChangedByFunctionCall(ftok, vt->pointer, var->declarationId(), mSettings.library, &inconclusive) && !inconclusive) continue; } } } else { - const auto dir = mSettings->library.getArgDirection(ftok, argn + 1); + const auto dir = mSettings.library.getArgDirection(ftok, argn + 1); if (dir == Library::ArgumentChecks::Direction::DIR_IN) continue; } @@ -2031,8 +2033,11 @@ void CheckOther::checkConstPointer() nonConstPointers.emplace(var); } for (const Variable *p: pointers) { + bool foundAllBaseClasses = true; if (p->isArgument()) { - if (!p->scope() || !p->scope()->function || p->scope()->function->isImplicitlyVirtual(true) || p->scope()->function->hasVirtualSpecifier()) + if (!p->scope() || !p->scope()->function || p->scope()->function->hasVirtualSpecifier()) + continue; + if (p->scope()->function->isImplicitlyVirtual(true, &foundAllBaseClasses) && foundAllBaseClasses) continue; if (p->isMaybeUnused()) continue; @@ -2045,16 +2050,16 @@ void CheckOther::checkConstPointer() // const int indirect = p->isArray() ? p->dimensions().size() : 1; // if (isVariableChanged(start, p->scope()->bodyEnd, indirect, p->declarationId(), false, *mSettings)) // continue; - if (!isConstPointerVariable(p, *mSettings)) + if (!isConstPointerVariable(p, mSettings)) continue; if (p->typeStartToken() && p->typeStartToken()->isSimplifiedTypedef() && !(Token::simpleMatch(p->typeEndToken(), "*") && !p->typeEndToken()->isSimplifiedTypedef())) continue; - constVariableError(p, p->isArgument() ? p->scope()->function : nullptr); + constVariableError(p, p->isArgument() ? p->scope()->function : nullptr, foundAllBaseClasses); } } } -void CheckOther::constVariableError(const Variable *var, const Function *function) +void CheckOtherImpl::constVariableError(const Variable *var, const Function *function, bool foundAllBaseClasses) { if (!var) { reportError(nullptr, Severity::style, "constParameter", "Parameter 'x' can be declared with const"); @@ -2067,13 +2072,18 @@ void CheckOther::constVariableError(const Variable *var, const Function *functio return; } - const std::string vartype(var->isArgument() ? "Parameter" : "Variable"); + std::string vartype(var->isArgument() ? "Parameter" : "Variable"); const std::string& varname(var->name()); const std::string ptrRefArray = var->isArray() ? "const array" : (var->isPointer() ? "pointer to const" : "reference to const"); ErrorPath errorPath; std::string id = "const" + vartype; - std::string message = "$symbol:" + varname + "\n" + vartype + " '$symbol' can be declared as " + ptrRefArray; + std::string message = "$symbol:" + varname + "\n"; + if (!foundAllBaseClasses) { + message += "Either there is a missing override/final keyword, or the "; + vartype[0] = std::tolower(vartype[0]); + } + message += vartype + " '$symbol' can be declared as " + ptrRefArray; errorPath.emplace_back(var->nameToken(), message); if (var->isArgument() && function && function->functionPointerUsage) { errorPath.emplace_front(function->functionPointerUsage, "You might need to cast the function pointer here"); @@ -2092,10 +2102,10 @@ void CheckOther::constVariableError(const Variable *var, const Function *functio // Check usage of char variables.. //--------------------------------------------------------------------------- -void CheckOther::checkCharVariable() +void CheckOtherImpl::checkCharVariable() { - const bool warning = mSettings->severity.isEnabled(Severity::warning); - const bool portability = mSettings->severity.isEnabled(Severity::portability); + const bool warning = mSettings.severity.isEnabled(Severity::warning); + const bool portability = mSettings.severity.isEnabled(Severity::portability); if (!warning && !portability) return; @@ -2110,24 +2120,24 @@ void CheckOther::checkCharVariable() if (!tok->variable()->isArray() && !tok->variable()->isPointer()) continue; const Token *index = tok->next()->astOperand2(); - if (warning && tok->variable()->isArray() && astIsSignedChar(index) && index->getValueGE(0x80, *mSettings)) + if (warning && tok->variable()->isArray() && astIsSignedChar(index) && index->getValueGE(0x80, mSettings)) signedCharArrayIndexError(tok); - if (portability && astIsUnknownSignChar(index) && index->getValueGE(0x80, *mSettings)) + if (portability && astIsUnknownSignChar(index) && index->getValueGE(0x80, mSettings)) unknownSignCharArrayIndexError(tok); } else if (warning && Token::Match(tok, "[&|^]") && tok->isBinaryOp()) { bool warn = false; if (astIsSignedChar(tok->astOperand1())) { - const ValueFlow::Value *v1 = tok->astOperand1()->getValueLE(-1, *mSettings); + const ValueFlow::Value *v1 = tok->astOperand1()->getValueLE(-1, mSettings); const ValueFlow::Value *v2 = tok->astOperand2()->getMaxValue(false); if (!v1) - v1 = tok->astOperand1()->getValueGE(0x80, *mSettings); + v1 = tok->astOperand1()->getValueGE(0x80, mSettings); if (v1 && !(tok->str() == "&" && v2 && v2->isKnown() && v2->intvalue >= 0 && v2->intvalue < 0x100)) warn = true; } else if (astIsSignedChar(tok->astOperand2())) { - const ValueFlow::Value *v1 = tok->astOperand2()->getValueLE(-1, *mSettings); + const ValueFlow::Value *v1 = tok->astOperand2()->getValueLE(-1, mSettings); const ValueFlow::Value *v2 = tok->astOperand1()->getMaxValue(false); if (!v1) - v1 = tok->astOperand2()->getValueGE(0x80, *mSettings); + v1 = tok->astOperand2()->getValueGE(0x80, mSettings); if (v1 && !(tok->str() == "&" && v2 && v2->isKnown() && v2->intvalue >= 0 && v2->intvalue < 0x100)) warn = true; } @@ -2143,7 +2153,7 @@ void CheckOther::checkCharVariable() } } -void CheckOther::signedCharArrayIndexError(const Token *tok) +void CheckOtherImpl::signedCharArrayIndexError(const Token *tok) { reportError(tok, Severity::warning, @@ -2154,7 +2164,7 @@ void CheckOther::signedCharArrayIndexError(const Token *tok) "because of sign extension.", CWE128, Certainty::normal); } -void CheckOther::unknownSignCharArrayIndexError(const Token *tok) +void CheckOtherImpl::unknownSignCharArrayIndexError(const Token *tok) { reportError(tok, Severity::portability, @@ -2164,7 +2174,7 @@ void CheckOther::unknownSignCharArrayIndexError(const Token *tok) "treated depending on whether 'char' is signed or unsigned on target platform.", CWE758, Certainty::normal); } -void CheckOther::charBitOpError(const Token *tok) +void CheckOtherImpl::charBitOpError(const Token *tok) { reportError(tok, Severity::warning, @@ -2313,18 +2323,12 @@ static bool isConstStatement(const Token *tok, const Library& library, bool plat static bool isVoidStmt(const Token *tok) { - if (Token::simpleMatch(tok, "( void")) - return true; - if (isCPPCast(tok) && tok->astOperand1() && Token::Match(tok->astOperand1()->next(), "< void *| >")) + if (Token::simpleMatch(tok, "( void") && !(tok->astOperand1() && (tok->astOperand1()->isLiteral() || isNullOperand(tok->astOperand1())))) return true; - const Token *tok2 = tok; - while (tok2->astOperand1()) - tok2 = tok2->astOperand1(); - if (Token::simpleMatch(tok2->previous(), ")") && Token::simpleMatch(tok2->linkAt(-1), "( void")) + if (isCPPCast(tok) && tok->astOperand1() && Token::Match(tok->astOperand1()->next(), "< void *| >") && + !(tok->astOperand2() && (tok->astOperand2()->isLiteral() || isNullOperand(tok->astOperand2())))) return true; - if (Token::simpleMatch(tok2, "( void")) - return true; - return Token::Match(tok2->previous(), "delete|throw|return"); + return false; } static bool isConstTop(const Token *tok) @@ -2351,10 +2355,10 @@ static bool isConstTop(const Token *tok) return false; } -void CheckOther::checkIncompleteStatement() +void CheckOtherImpl::checkIncompleteStatement() { - if (!mSettings->severity.isEnabled(Severity::warning) && - !mSettings->isPremiumEnabled("constStatement")) + if (!mSettings.severity.isEnabled(Severity::warning) && + !mSettings.isPremiumEnabled("constStatement")) return; logChecker("CheckOther::checkIncompleteStatement"); // warning @@ -2398,27 +2402,23 @@ void CheckOther::checkIncompleteStatement() !(tok->str() == "," && tok->astParent() && tok->astParent()->isAssignmentOp())) continue; // Skip statement expressions - if (Token::simpleMatch(rtok, "; } )")) + if (Token::simpleMatch(rtok, "; } )") || Token::simpleMatch(tok->next(), "; } )")) continue; - if (!isConstStatement(tok, mSettings->library, false)) + if (!isConstStatement(tok, mSettings.library, false)) continue; if (isVoidStmt(tok)) continue; if (tok->isCpp() && tok->str() == "&" && !(tok->astOperand1() && tok->astOperand1()->valueType() && tok->astOperand1()->valueType()->isIntegral())) // Possible archive continue; - const bool inconclusive = tok->isConstOp() && !mSettings->isPremiumEnabled("constStatement"); - if (mSettings->certainty.isEnabled(Certainty::inconclusive) || !inconclusive) + const bool inconclusive = tok->isConstOp() && !mSettings.isPremiumEnabled("constStatement"); + if (mSettings.certainty.isEnabled(Certainty::inconclusive) || !inconclusive) constStatementError(tok, tok->isNumber() ? "numeric" : "string", inconclusive); } } -void CheckOther::constStatementError(const Token *tok, const std::string &type, bool inconclusive) +void CheckOtherImpl::constStatementError(const Token *tok, const std::string &type, bool inconclusive) { - const Token *valueTok = tok; - while (valueTok && valueTok->isCast()) - valueTok = valueTok->astOperand2() ? valueTok->astOperand2() : valueTok->astOperand1(); - std::string msg; if (Token::simpleMatch(tok, "==")) msg = "Found suspicious equality comparison. Did you intend to assign a value instead?"; @@ -2426,26 +2426,24 @@ void CheckOther::constStatementError(const Token *tok, const std::string &type, msg = "Found suspicious operator '" + tok->str() + "', result is not used."; else if (Token::Match(tok, "%var%")) msg = "Unused variable value '" + tok->str() + "'"; - else if (isConstant(valueTok)) { + else if (isConstant(tok)) { std::string typeStr("string"); - if (valueTok->isNumber()) + if (tok->isNumber()) typeStr = "numeric"; - else if (valueTok->isBoolean()) + else if (tok->isBoolean()) typeStr = "bool"; - else if (valueTok->tokType() == Token::eChar) + else if (tok->tokType() == Token::eChar) typeStr = "character"; - else if (isNullOperand(valueTok)) - typeStr = "NULL"; - else if (valueTok->isEnumerator()) + else if (isNullOperand(tok)) + typeStr = "null"; + else if (tok->isEnumerator()) typeStr = "enumerator"; msg = "Redundant code: Found a statement that begins with " + typeStr + " constant."; } else if (!tok) msg = "Redundant code: Found a statement that begins with " + type + " constant."; - else if (tok->isCast() && tok->tokType() == Token::Type::eExtendedOp) { - msg = "Redundant code: Found unused cast "; - msg += valueTok ? "of expression '" + valueTok->expressionString() + "'." : "expression."; - } + else if (tok->isCast() && tok->tokType() == Token::Type::eExtendedOp) + msg = "Redundant code: Found unused cast in expression '" + tok->expressionString() + "'."; else if (tok->str() == "?" && tok->tokType() == Token::Type::eExtendedOp) msg = "Redundant code: Found unused result of ternary operator."; else if (tok->str() == "." && tok->tokType() == Token::Type::eOther) @@ -2458,7 +2456,7 @@ void CheckOther::constStatementError(const Token *tok, const std::string &type, msg = "Redundant code: Found unused function."; else if (Token::Match(tok->previous(), "%name% (")) msg = "Redundant code: Found unused '" + tok->strAt(-1) + "' expression."; - else if (mSettings->debugwarnings) { + else if (mSettings.debugwarnings) { reportError(tok, Severity::debug, "debug", "constStatementError not handled."); return; } @@ -2468,7 +2466,7 @@ void CheckOther::constStatementError(const Token *tok, const std::string &type, //--------------------------------------------------------------------------- // Detect division by zero. //--------------------------------------------------------------------------- -void CheckOther::checkZeroDivision() +void CheckOtherImpl::checkZeroDivision() { logChecker("CheckOther::checkZeroDivision"); @@ -2484,12 +2482,12 @@ void CheckOther::checkZeroDivision() // Value flow.. const ValueFlow::Value *value = tok->astOperand2()->getValue(0LL); - if (value && mSettings->isEnabled(value, false)) + if (value && mSettings.isEnabled(value, false)) zerodivError(tok, value); } } -void CheckOther::zerodivError(const Token *tok, const ValueFlow::Value *value) +void CheckOtherImpl::zerodivError(const Token *tok, const ValueFlow::Value *value) { if (!tok && !value) { reportError(tok, Severity::error, "zerodiv", "Division by zero.", CWE369, Certainty::normal); @@ -2518,9 +2516,9 @@ void CheckOther::zerodivError(const Token *tok, const ValueFlow::Value *value) // double d = 1.0 / 0.0 + 100.0; //--------------------------------------------------------------------------- -void CheckOther::checkNanInArithmeticExpression() +void CheckOtherImpl::checkNanInArithmeticExpression() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("nanInArithmeticExpression")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("nanInArithmeticExpression")) return; logChecker("CheckOther::checkNanInArithmeticExpression"); // style for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) { @@ -2533,7 +2531,7 @@ void CheckOther::checkNanInArithmeticExpression() } } -void CheckOther::nanInArithmeticExpressionError(const Token *tok) +void CheckOtherImpl::nanInArithmeticExpressionError(const Token *tok) { reportError(tok, Severity::style, "nanInArithmeticExpression", "Using NaN/Inf in a computation.\n" @@ -2544,13 +2542,13 @@ void CheckOther::nanInArithmeticExpressionError(const Token *tok) //--------------------------------------------------------------------------- // Creating instance of classes which are destroyed immediately //--------------------------------------------------------------------------- -void CheckOther::checkMisusedScopedObject() +void CheckOtherImpl::checkMisusedScopedObject() { // Skip this check for .c files if (mTokenizer->isC()) return; - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedScopedObject")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("unusedScopedObject")) return; logChecker("CheckOther::checkMisusedScopedObject"); // style,c++ @@ -2577,10 +2575,10 @@ void CheckOther::checkMisusedScopedObject() }; auto isLibraryConstructor = [&](const Token* tok, const std::string& typeStr) -> bool { - const Library::TypeCheck typeCheck = mSettings->library.getTypeCheck("unusedvar", typeStr); + const Library::TypeCheck typeCheck = mSettings.library.getTypeCheck("unusedvar", typeStr); if (typeCheck == Library::TypeCheck::check || typeCheck == Library::TypeCheck::checkFiniteLifetime) return true; - return mSettings->library.detectContainerOrIterator(tok); + return mSettings.library.detectContainerOrIterator(tok); }; const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -2595,7 +2593,7 @@ void CheckOther::checkMisusedScopedObject() if (Token::simpleMatch(parTok, "<") && parTok->link()) parTok = parTok->link()->next(); if (const Token* arg = parTok->astOperand2()) { - if (!isConstStatement(arg, mSettings->library, false)) + if (!isConstStatement(arg, mSettings.library, false)) continue; if (parTok->str() == "(") { if (arg->varId() && !(arg->variable() && arg->variable()->nameToken() != arg)) @@ -2619,7 +2617,7 @@ void CheckOther::checkMisusedScopedObject() } } -void CheckOther::misusedScopeObjectError(const Token *tok, const std::string& varname, bool isAssignment) +void CheckOtherImpl::misusedScopeObjectError(const Token *tok, const std::string& varname, bool isAssignment) { std::string msg = "Instance of '$symbol' object is destroyed immediately"; msg += isAssignment ? ", assignment has no effect." : "."; @@ -2644,7 +2642,7 @@ static const Token * getSingleExpressionInBlock(const Token * tok) // check for duplicate code in if and else branches // if (a) { b = true; } else { b = true; } //----------------------------------------------------------------------------- -void CheckOther::checkDuplicateBranch() +void CheckOtherImpl::checkDuplicateBranch() { // This is inconclusive since in practice most warnings are noise: // * There can be unfixed low-priority todos. The code is fine as it @@ -2654,7 +2652,7 @@ void CheckOther::checkDuplicateBranch() // and their conditional code is a duplicate of the condition that // is always true just in case it would be false. See for instance // abiword. - if (!mSettings->severity.isEnabled(Severity::style) || !mSettings->certainty.isEnabled(Certainty::inconclusive)) + if (!mSettings.severity.isEnabled(Severity::style) || !mSettings.certainty.isEnabled(Certainty::inconclusive)) return; logChecker("CheckOther::checkDuplicateBranch"); // style,inconclusive @@ -2716,14 +2714,14 @@ void CheckOther::checkDuplicateBranch() if (branchTop1->str() != branchTop2->str()) continue; ErrorPath errorPath; - if (isSameExpression(false, branchTop1->astOperand1(), branchTop2->astOperand1(), *mSettings, true, true, &errorPath) && - isSameExpression(false, branchTop1->astOperand2(), branchTop2->astOperand2(), *mSettings, true, true, &errorPath)) + if (isSameExpression(false, branchTop1->astOperand1(), branchTop2->astOperand1(), mSettings, true, true, &errorPath) && + isSameExpression(false, branchTop1->astOperand2(), branchTop2->astOperand2(), mSettings, true, true, &errorPath)) duplicateBranchError(scope.classDef, scope.bodyEnd->next(), std::move(errorPath)); } } } -void CheckOther::duplicateBranchError(const Token *tok1, const Token *tok2, ErrorPath errors) +void CheckOtherImpl::duplicateBranchError(const Token *tok1, const Token *tok2, ErrorPath errors) { errors.emplace_back(tok2, ""); errors.emplace_back(tok1, ""); @@ -2740,21 +2738,21 @@ void CheckOther::duplicateBranchError(const Token *tok1, const Token *tok2, Erro // char* p = malloc(100); // free(p + 10); //----------------------------------------------------------------------------- -void CheckOther::checkInvalidFree() +void CheckOtherImpl::checkInvalidFree() { std::map inconclusive; std::map allocation; logChecker("CheckOther::checkInvalidFree"); - const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive); + const bool printInconclusive = mSettings.certainty.isEnabled(Certainty::inconclusive); const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Scope * scope : symbolDatabase->functionScopes) { for (const Token* tok = scope->bodyStart->next(); tok && tok != scope->bodyEnd; tok = tok->next()) { // Keep track of which variables were assigned addresses to newly-allocated memory if ((tok->isCpp() && Token::Match(tok, "%var% = new")) || - (Token::Match(tok, "%var% = %name% (") && mSettings->library.getAllocFuncInfo(tok->tokAt(2)))) { + (Token::Match(tok, "%var% = %name% (") && mSettings.library.getAllocFuncInfo(tok->tokAt(2)))) { allocation.emplace(tok->varId(), tok->strAt(2)); inconclusive.emplace(tok->varId(), false); } @@ -2782,7 +2780,7 @@ void CheckOther::checkInvalidFree() // If a variable that was previously assigned a newly-allocated memory location is // added or subtracted from when used to free the memory, report an error. - else if ((Token::Match(tok, "%name% ( %any% +|-") && mSettings->library.getDeallocFuncInfo(tok)) || + else if ((Token::Match(tok, "%name% ( %any% +|-") && mSettings.library.getDeallocFuncInfo(tok)) || Token::Match(tok, "delete [ ] ( %any% +|-") || Token::Match(tok, "delete %any% +|- %any%")) { @@ -2802,7 +2800,7 @@ void CheckOther::checkInvalidFree() // If the previously-allocated variable is passed in to another function // as a parameter, it might be modified, so we shouldn't report an error // if it is later used to free memory - else if (Token::Match(tok, "%name% (") && !mSettings->library.isFunctionConst(tok->str(), true)) { + else if (Token::Match(tok, "%name% (") && !mSettings.library.isFunctionConst(tok->str(), true)) { const Token* tok2 = Token::findmatch(tok->next(), "%var%", tok->linkAt(1)); while (tok2 != nullptr) { allocation.erase(tok->varId()); @@ -2814,7 +2812,7 @@ void CheckOther::checkInvalidFree() } } -void CheckOther::invalidFreeError(const Token *tok, const std::string &allocation, bool inconclusive) +void CheckOtherImpl::invalidFreeError(const Token *tok, const std::string &allocation, bool inconclusive) { std::string alloc = allocation; if (alloc != "new") @@ -2873,17 +2871,17 @@ isStaticAssert(const Settings &settings, const Token *tok) return false; } -void CheckOther::checkDuplicateExpression() +void CheckOtherImpl::checkDuplicateExpression() { { - const bool styleEnabled = mSettings->severity.isEnabled(Severity::style); - const bool premiumEnabled = mSettings->isPremiumEnabled("oppositeExpression") || - mSettings->isPremiumEnabled("duplicateExpression") || - mSettings->isPremiumEnabled("duplicateAssignExpression") || - mSettings->isPremiumEnabled("duplicateExpressionTernary") || - mSettings->isPremiumEnabled("duplicateValueTernary") || - mSettings->isPremiumEnabled("selfAssignment") || - mSettings->isPremiumEnabled("knownConditionTrueFalse"); + const bool styleEnabled = mSettings.severity.isEnabled(Severity::style); + const bool premiumEnabled = mSettings.isPremiumEnabled("oppositeExpression") || + mSettings.isPremiumEnabled("duplicateExpression") || + mSettings.isPremiumEnabled("duplicateAssignExpression") || + mSettings.isPremiumEnabled("duplicateExpressionTernary") || + mSettings.isPremiumEnabled("duplicateValueTernary") || + mSettings.isPremiumEnabled("selfAssignment") || + mSettings.isPremiumEnabled("knownConditionTrueFalse"); if (!styleEnabled && !premiumEnabled) return; @@ -2921,8 +2919,8 @@ void CheckOther::checkDuplicateExpression() Token::Match(tok->astOperand2()->previous(), "%name% (") ) && tok->next()->tokType() != Token::eType && - isSameExpression(true, tok->next(), nextAssign->next(), *mSettings, true, false) && - isSameExpression(true, tok->astOperand2(), nextAssign->astOperand2(), *mSettings, true, false) && + isSameExpression(true, tok->next(), nextAssign->next(), mSettings, true, false) && + isSameExpression(true, tok->astOperand2(), nextAssign->astOperand2(), mSettings, true, false) && tok->astOperand2()->expressionString() == nextAssign->astOperand2()->expressionString()) { bool differentDomain = false; const Scope * varScope = var1->scope() ? var1->scope() : scope; @@ -2940,7 +2938,7 @@ void CheckOther::checkDuplicateExpression() !isSameExpression(true, tok->astOperand2(), assignTok->astOperand1(), - *mSettings, + mSettings, true, true)) continue; @@ -2949,7 +2947,7 @@ void CheckOther::checkDuplicateExpression() !isSameExpression(true, tok->astOperand2(), assignTok->astOperand2(), - *mSettings, + mSettings, true, true)) continue; @@ -2958,7 +2956,7 @@ void CheckOther::checkDuplicateExpression() } if (!differentDomain && !isUniqueExpression(tok->astOperand2())) duplicateAssignExpressionError(var1, var2, false); - else if (mSettings->certainty.isEnabled(Certainty::inconclusive)) { + else if (mSettings.certainty.isEnabled(Certainty::inconclusive)) { diag(assignTok); duplicateAssignExpressionError(var1, var2, true); } @@ -2984,14 +2982,14 @@ void CheckOther::checkDuplicateExpression() if (isSameExpression(true, tok->astOperand1(), tok->astOperand2(), - *mSettings, + mSettings, true, followVar, &errorPath)) { if (isWithoutSideEffects(tok->astOperand1())) { const Token* loopTok = isInLoopCondition(tok); if (!loopTok || - !findExpressionChanged(tok, tok, loopTok->link()->linkAt(1), *mSettings)) { + !findExpressionChanged(tok, tok, loopTok->link()->linkAt(1), mSettings)) { const bool isEnum = tok->scope()->type == ScopeType::eEnum; const bool assignment = !isEnum && tok->str() == "="; if (assignment) @@ -3003,7 +3001,7 @@ void CheckOther::checkDuplicateExpression() parent = parent->astParent(); } if (parent && parent->previous() && - (isStaticAssert(*mSettings, parent->previous()) || + (isStaticAssert(mSettings, parent->previous()) || Token::simpleMatch(parent->previous(), "assert"))) { continue; } @@ -3016,7 +3014,7 @@ void CheckOther::checkDuplicateExpression() isSameExpression(false, tok->astOperand1(), tok->astOperand2()->astOperand1(), - *mSettings, + mSettings, true, false)) { if (isWithoutSideEffects(tok->astOperand1())) { @@ -3024,7 +3022,7 @@ void CheckOther::checkDuplicateExpression() } } else if (isOppositeExpression(tok->astOperand1(), tok->astOperand2(), - *mSettings, + mSettings, false, true, &errorPath) && @@ -3036,15 +3034,15 @@ void CheckOther::checkDuplicateExpression() isSameExpression(true, tok->astOperand2(), tok->astOperand1()->astOperand2(), - *mSettings, + mSettings, true, followVar, &errorPath) && isWithoutSideEffects(tok->astOperand2())) duplicateExpressionError(tok->astOperand2(), tok->astOperand1()->astOperand2(), tok, std::move(errorPath)); - else if (tok->astOperand2() && isConstExpression(tok->astOperand1(), mSettings->library)) { + else if (tok->astOperand2() && isConstExpression(tok->astOperand1(), mSettings.library)) { auto checkDuplicate = [&](const Token* exp1, const Token* exp2, const Token* ast1) { - if (isSameExpression(true, exp1, exp2, *mSettings, true, true, &errorPath) && + if (isSameExpression(true, exp1, exp2, mSettings, true, true, &errorPath) && isWithoutSideEffects(exp1) && isWithoutSideEffects(ast1->astOperand2())) duplicateExpressionError(exp1, exp2, tok, errorPath, /*hasMultipleExpr*/ true); @@ -3059,19 +3057,19 @@ void CheckOther::checkDuplicateExpression() } } } else if (tok->astOperand1() && tok->astOperand2() && tok->str() == ":" && tok->astParent() && tok->astParent()->str() == "?") { - if (isSameExpression(true, tok->astOperand1(), tok->astOperand2(), *mSettings, false, true, &errorPath)) + if (isSameExpression(true, tok->astOperand1(), tok->astOperand2(), mSettings, false, true, &errorPath)) duplicateExpressionTernaryError(tok, std::move(errorPath)); else if (!tok->astOperand1()->values().empty() && !tok->astOperand2()->values().empty() && isEqualKnownValue(tok->astOperand1(), tok->astOperand2()) && - !isVariableChanged(tok->astParent(), /*indirect*/ 0, *mSettings) && - isConstStatement(tok->astOperand1(), mSettings->library, true) && isConstStatement(tok->astOperand2(), mSettings->library, true)) + !isVariableChanged(tok->astParent(), /*indirect*/ 0, mSettings) && + isConstStatement(tok->astOperand1(), mSettings.library, true) && isConstStatement(tok->astOperand2(), mSettings.library, true)) duplicateValueTernaryError(tok); } } } } -void CheckOther::oppositeExpressionError(const Token *opTok, ErrorPath errors) +void CheckOtherImpl::oppositeExpressionError(const Token *opTok, ErrorPath errors) { errors.emplace_back(opTok, ""); @@ -3083,7 +3081,7 @@ void CheckOther::oppositeExpressionError(const Token *opTok, ErrorPath errors) "determine if it is correct.", CWE398, Certainty::normal); } -void CheckOther::duplicateExpressionError(const Token *tok1, const Token *tok2, const Token *opTok, ErrorPath errors, bool hasMultipleExpr) +void CheckOtherImpl::duplicateExpressionError(const Token *tok1, const Token *tok2, const Token *opTok, ErrorPath errors, bool hasMultipleExpr) { errors.emplace_back(opTok, ""); @@ -3111,7 +3109,7 @@ void CheckOther::duplicateExpressionError(const Token *tok1, const Token *tok2, "determine if it is correct.", CWE398, Certainty::normal); } -void CheckOther::duplicateAssignExpressionError(const Token *tok1, const Token *tok2, bool inconclusive) +void CheckOtherImpl::duplicateAssignExpressionError(const Token *tok1, const Token *tok2, bool inconclusive) { const std::list toks = { tok2, tok1 }; @@ -3125,7 +3123,7 @@ void CheckOther::duplicateAssignExpressionError(const Token *tok1, const Token * "determine if it is correct.", CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal); } -void CheckOther::duplicateExpressionTernaryError(const Token *tok, ErrorPath errors) +void CheckOtherImpl::duplicateExpressionTernaryError(const Token *tok, ErrorPath errors) { errors.emplace_back(tok, ""); reportError(std::move(errors), Severity::style, "duplicateExpressionTernary", "Same expression in both branches of ternary operator.\n" @@ -3133,14 +3131,14 @@ void CheckOther::duplicateExpressionTernaryError(const Token *tok, ErrorPath err "the same code is executed regardless of the condition.", CWE398, Certainty::normal); } -void CheckOther::duplicateValueTernaryError(const Token *tok) +void CheckOtherImpl::duplicateValueTernaryError(const Token *tok) { reportError(tok, Severity::style, "duplicateValueTernary", "Same value in both branches of ternary operator.\n" "Finding the same value in both branches of ternary operator is suspicious as " "the same code is executed regardless of the condition.", CWE398, Certainty::normal); } -void CheckOther::selfAssignmentError(const Token *tok, const std::string &varname) +void CheckOtherImpl::selfAssignmentError(const Token *tok, const std::string &varname) { reportError(tok, Severity::style, "selfAssignment", @@ -3157,9 +3155,9 @@ void CheckOther::selfAssignmentError(const Token *tok, const std::string &varnam // Reference: // - http://www.cplusplus.com/reference/cmath/ //----------------------------------------------------------------------------- -void CheckOther::checkComparisonFunctionIsAlwaysTrueOrFalse() +void CheckOtherImpl::checkComparisonFunctionIsAlwaysTrueOrFalse() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckOther::checkComparisonFunctionIsAlwaysTrueOrFalse"); // warning @@ -3187,7 +3185,7 @@ void CheckOther::checkComparisonFunctionIsAlwaysTrueOrFalse() } } } -void CheckOther::checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* tok, const std::string &functionName, const std::string &varName, const bool result) +void CheckOtherImpl::checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* tok, const std::string &functionName, const std::string &varName, const bool result) { const std::string strResult = bool_to_string(result); const CWE cweResult = result ? CWE571 : CWE570; @@ -3202,9 +3200,9 @@ void CheckOther::checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* to //--------------------------------------------------------------------------- // Check testing sign of unsigned variables and pointers. //--------------------------------------------------------------------------- -void CheckOther::checkSignOfUnsignedVariable() +void CheckOtherImpl::checkSignOfUnsignedVariable() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unsignedLessThanZero")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("unsignedLessThanZero")) return; logChecker("CheckOther::checkSignOfUnsignedVariable"); // style @@ -3233,7 +3231,7 @@ void CheckOther::checkSignOfUnsignedVariable() } } -bool CheckOther::comparisonNonZeroExpressionLessThanZero(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr, bool suppress) +bool CheckOtherImpl::comparisonNonZeroExpressionLessThanZero(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr, bool suppress) { if (!tok->isComparisonOp() || !tok->astOperand1() || !tok->astOperand2()) return false; @@ -3259,7 +3257,7 @@ bool CheckOther::comparisonNonZeroExpressionLessThanZero(const Token *tok, const return vt && (vt->pointer || vt->sign == ValueType::UNSIGNED); } -bool CheckOther::testIfNonZeroExpressionIsPositive(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr) +bool CheckOtherImpl::testIfNonZeroExpressionIsPositive(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr) { if (!tok->isComparisonOp() || !tok->astOperand1() || !tok->astOperand2()) return false; @@ -3281,7 +3279,7 @@ bool CheckOther::testIfNonZeroExpressionIsPositive(const Token *tok, const Value return vt && (vt->pointer || vt->sign == ValueType::UNSIGNED); } -void CheckOther::unsignedLessThanZeroError(const Token *tok, const ValueFlow::Value * v, const std::string &varname) +void CheckOtherImpl::unsignedLessThanZeroError(const Token *tok, const ValueFlow::Value * v, const std::string &varname) { reportError(getErrorPath(tok, v, "Unsigned less than zero"), Severity::style, "unsignedLessThanZero", "$symbol:" + varname + "\n" @@ -3290,20 +3288,20 @@ void CheckOther::unsignedLessThanZeroError(const Token *tok, const ValueFlow::Va "is either pointless or an error to check if it is.", CWE570, Certainty::normal); } -void CheckOther::pointerLessThanZeroError(const Token *tok, const ValueFlow::Value *v) +void CheckOtherImpl::pointerLessThanZeroError(const Token *tok, const ValueFlow::Value *v) { reportError(getErrorPath(tok, v, "Pointer less than zero"), Severity::style, "pointerLessThanZero", "A pointer can not be negative so it is either pointless or an error to check if it is.", CWE570, Certainty::normal); } -void CheckOther::unsignedPositiveError(const Token *tok, const ValueFlow::Value * v, const std::string &varname) +void CheckOtherImpl::unsignedPositiveError(const Token *tok, const ValueFlow::Value * v, const std::string &varname) { reportError(getErrorPath(tok, v, "Unsigned positive"), Severity::style, "unsignedPositive", "$symbol:" + varname + "\n" "Unsigned expression '$symbol' can't be negative so it is unnecessary to test it.", CWE570, Certainty::normal); } -void CheckOther::pointerPositiveError(const Token *tok, const ValueFlow::Value * v) +void CheckOtherImpl::pointerPositiveError(const Token *tok, const ValueFlow::Value * v) { reportError(getErrorPath(tok, v, "Pointer positive"), Severity::style, "pointerPositive", "A pointer can not be negative so it is either pointless or an error to check if it is not.", CWE570, Certainty::normal); @@ -3314,7 +3312,7 @@ static bool constructorTakesReference(const Scope * const classScope) { return std::any_of(classScope->functionList.begin(), classScope->functionList.end(), [&](const Function& constructor) { if (constructor.isConstructor()) { - for (int argnr = 0U; argnr < constructor.argCount(); argnr++) { + for (size_t argnr = 0U; argnr < constructor.argCount(); argnr++) { const Variable * const argVar = constructor.getArgumentVar(argnr); if (argVar && argVar->isReference()) { return true; @@ -3386,9 +3384,9 @@ static bool checkVariableAssignment(const Token* tok, const ValueType* vtLhs, co return scope && scope->function && (!scope->functionOf || scope->function->isConst() || scope->function->isStatic()); } -void CheckOther::checkRedundantCopy() +void CheckOtherImpl::checkRedundantCopy() { - if (!mSettings->severity.isEnabled(Severity::performance) || mTokenizer->isC() || !mSettings->certainty.isEnabled(Certainty::inconclusive)) + if (!mSettings.severity.isEnabled(Severity::performance) || mTokenizer->isC() || !mSettings.certainty.isEnabled(Certainty::inconclusive)) return; logChecker("CheckOther::checkRedundantCopy"); // c++,performance,inconclusive @@ -3398,7 +3396,7 @@ void CheckOther::checkRedundantCopy() for (const Variable* var : symbolDatabase->variableList()) { if (!var || var->isReference() || var->isPointer() || (!var->type() && !var->isStlType() && !(var->valueType() && var->valueType()->container)) || // bailout if var is of standard type, if it is a pointer or non-const - (!var->isConst() && isVariableChanged(var, *mSettings))) + (!var->isConst() && isVariableChanged(var, mSettings))) continue; const Token* startTok = var->nameToken(); @@ -3418,13 +3416,13 @@ void CheckOther::checkRedundantCopy() const Token* tok = startTok->next()->astOperand2(); if (!tok) continue; - if (!checkFunctionReturnsRef(tok, *mSettings) && !checkVariableAssignment(tok, var->valueType(), *mSettings)) + if (!checkFunctionReturnsRef(tok, mSettings) && !checkVariableAssignment(tok, var->valueType(), mSettings)) continue; redundantCopyError(startTok, startTok->str()); } } -void CheckOther::redundantCopyError(const Token *tok,const std::string& varname) +void CheckOtherImpl::redundantCopyError(const Token *tok,const std::string& varname) { reportError(tok, Severity::performance, "redundantCopyLocalConst", "$symbol:" + varname + "\n" @@ -3444,9 +3442,9 @@ static bool isNegative(const Token *tok, const Settings &settings) return tok->valueType() && tok->valueType()->sign == ValueType::SIGNED && tok->getValueLE(-1LL, settings); } -void CheckOther::checkNegativeBitwiseShift() +void CheckOtherImpl::checkNegativeBitwiseShift() { - const bool portability = mSettings->severity.isEnabled(Severity::portability); + const bool portability = mSettings.severity.isEnabled(Severity::portability); logChecker("CheckOther::checkNegativeBitwiseShift"); @@ -3478,15 +3476,15 @@ void CheckOther::checkNegativeBitwiseShift() continue; // Get negative rhs value. preferably a value which doesn't have 'condition'. - if (portability && isNegative(tok->astOperand1(), *mSettings)) + if (portability && isNegative(tok->astOperand1(), mSettings)) negativeBitwiseShiftError(tok, 1); - else if (isNegative(tok->astOperand2(), *mSettings)) + else if (isNegative(tok->astOperand2(), mSettings)) negativeBitwiseShiftError(tok, 2); } } -void CheckOther::negativeBitwiseShiftError(const Token *tok, int op) +void CheckOtherImpl::negativeBitwiseShiftError(const Token *tok, int op) { if (op == 1) // LHS - this is used by intention in various software, if it @@ -3500,12 +3498,12 @@ void CheckOther::negativeBitwiseShiftError(const Token *tok, int op) //--------------------------------------------------------------------------- // Check for incompletely filled buffers. //--------------------------------------------------------------------------- -void CheckOther::checkIncompleteArrayFill() +void CheckOtherImpl::checkIncompleteArrayFill() { - if (!mSettings->certainty.isEnabled(Certainty::inconclusive)) + if (!mSettings.certainty.isEnabled(Certainty::inconclusive)) return; - const bool printWarning = mSettings->severity.isEnabled(Severity::warning); - const bool printPortability = mSettings->severity.isEnabled(Severity::portability); + const bool printWarning = mSettings.severity.isEnabled(Severity::warning); + const bool printPortability = mSettings.severity.isEnabled(Severity::portability); if (!printPortability && !printWarning) return; @@ -3535,9 +3533,9 @@ void CheckOther::checkIncompleteArrayFill() continue; int size = mTokenizer->sizeOfType(var->typeStartToken()); if (size == 0 && var->valueType()->pointer) - size = mSettings->platform.sizeof_pointer; + size = mSettings.platform.sizeof_pointer; else if (size == 0 && var->valueType()) - size = var->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer); + size = var->valueType()->getSizeOf(mSettings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer); const Token* tok3 = tok->next()->astOperand2()->astOperand1()->astOperand1(); if ((size != 1 && size != 100 && size != 0) || var->isPointer()) { if (printWarning) @@ -3549,7 +3547,7 @@ void CheckOther::checkIncompleteArrayFill() } } -void CheckOther::incompleteArrayFillError(const Token* tok, const std::string& buffer, const std::string& function, bool boolean) +void CheckOtherImpl::incompleteArrayFillError(const Token* tok, const std::string& buffer, const std::string& function, bool boolean) { if (boolean) reportError(tok, Severity::portability, "incompleteArrayFill", @@ -3569,9 +3567,9 @@ void CheckOther::incompleteArrayFillError(const Token* tok, const std::string& b // Detect NULL being passed to variadic function. //--------------------------------------------------------------------------- -void CheckOther::checkVarFuncNullUB() +void CheckOtherImpl::checkVarFuncNullUB() { - if (!mSettings->severity.isEnabled(Severity::portability)) + if (!mSettings.severity.isEnabled(Severity::portability)) return; logChecker("CheckOther::checkVarFuncNullUB"); // portability @@ -3607,7 +3605,7 @@ void CheckOther::checkVarFuncNullUB() } } -void CheckOther::varFuncNullUBError(const Token *tok) +void CheckOtherImpl::varFuncNullUBError(const Token *tok) { reportError(tok, Severity::portability, @@ -3654,9 +3652,9 @@ void CheckOther::varFuncNullUBError(const Token *tok) "}", CWE475, Certainty::normal); } -void CheckOther::checkRedundantPointerOp() +void CheckOtherImpl::checkRedundantPointerOp() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("redundantPointerOp")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("redundantPointerOp")) return; logChecker("CheckOther::checkRedundantPointerOp"); // style @@ -3693,16 +3691,16 @@ void CheckOther::checkRedundantPointerOp() } } -void CheckOther::redundantPointerOpError(const Token* tok, const std::string &varname, bool inconclusive, bool addressOfDeref) +void CheckOtherImpl::redundantPointerOpError(const Token* tok, const std::string &varname, bool inconclusive, bool addressOfDeref) { std::string msg = "$symbol:" + varname + "\nRedundant pointer operation on '$symbol' - it's already a "; msg += addressOfDeref ? "pointer." : "variable."; reportError(tok, Severity::style, "redundantPointerOp", msg, CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal); } -void CheckOther::checkInterlockedDecrement() +void CheckOtherImpl::checkInterlockedDecrement() { - if (!mSettings->platform.isWindows()) { + if (!mSettings.platform.isWindows()) { return; } @@ -3740,15 +3738,15 @@ void CheckOther::checkInterlockedDecrement() } } -void CheckOther::raceAfterInterlockedDecrementError(const Token* tok) +void CheckOtherImpl::raceAfterInterlockedDecrementError(const Token* tok) { reportError(tok, Severity::error, "raceAfterInterlockedDecrement", "Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead.", CWE362, Certainty::normal); } -void CheckOther::checkUnusedLabel() +void CheckOtherImpl::checkUnusedLabel() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("unusedLabel")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.severity.isEnabled(Severity::warning) && !mSettings.isPremiumEnabled("unusedLabel")) return; logChecker("CheckOther::checkUnusedLabel"); // style,warning @@ -3769,9 +3767,9 @@ void CheckOther::checkUnusedLabel() } } -void CheckOther::unusedLabelError(const Token* tok, bool inSwitch, bool hasIfdef) +void CheckOtherImpl::unusedLabelError(const Token* tok, bool inSwitch, bool hasIfdef) { - if (tok && !mSettings->severity.isEnabled(inSwitch ? Severity::warning : Severity::style) && !mSettings->isPremiumEnabled("unusedLabel")) + if (tok && !mSettings.severity.isEnabled(inSwitch ? Severity::warning : Severity::style) && !mSettings.isPremiumEnabled("unusedLabel")) return; std::string id = "unusedLabel"; @@ -3863,7 +3861,7 @@ static bool checkEvaluationOrderCpp17(const Token * tok, const Token * tok2, con return foundUndefined || foundUnspecified; } -void CheckOther::checkEvaluationOrder() +void CheckOtherImpl::checkEvaluationOrder() { logChecker("CheckOther::checkEvaluationOrder"); const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -3903,14 +3901,14 @@ void CheckOther::checkEvaluationOrder() break; bool foundError{false}, foundUnspecified{false}, bSelfAssignmentError{false}; - if (mTokenizer->isCPP() && mSettings->standards.cpp >= Standards::CPP11) { - if (mSettings->standards.cpp >= Standards::CPP17) - foundError = checkEvaluationOrderCpp17(tok, tok2, parent, *mSettings, foundUnspecified); + if (mTokenizer->isCPP() && mSettings.standards.cpp >= Standards::CPP11) { + if (mSettings.standards.cpp >= Standards::CPP17) + foundError = checkEvaluationOrderCpp17(tok, tok2, parent, mSettings, foundUnspecified); else - foundError = checkEvaluationOrderCpp11(tok, tok2, parent, *mSettings); + foundError = checkEvaluationOrderCpp11(tok, tok2, parent, mSettings); } else - foundError = checkEvaluationOrderC(tok, tok2, parent, *mSettings, bSelfAssignmentError); + foundError = checkEvaluationOrderC(tok, tok2, parent, mSettings, bSelfAssignmentError); if (foundError) { unknownEvaluationOrder(parent, foundUnspecified); @@ -3925,7 +3923,7 @@ void CheckOther::checkEvaluationOrder() } } -void CheckOther::unknownEvaluationOrder(const Token* tok, bool isUnspecifiedBehavior) +void CheckOtherImpl::unknownEvaluationOrder(const Token* tok, bool isUnspecifiedBehavior) { isUnspecifiedBehavior ? reportError(tok, Severity::portability, "unknownEvaluationOrder", @@ -3934,14 +3932,14 @@ void CheckOther::unknownEvaluationOrder(const Token* tok, bool isUnspecifiedBeha "Expression '" + (tok ? tok->expressionString() : std::string("x = x++;")) + "' depends on order of evaluation of side effects", CWE768, Certainty::normal); } -void CheckOther::checkAccessOfMovedVariable() +void CheckOtherImpl::checkAccessOfMovedVariable() { - if (!mTokenizer->isCPP() || mSettings->standards.cpp < Standards::CPP11) + if (!mTokenizer->isCPP() || mSettings.standards.cpp < Standards::CPP11) return; - if (!mSettings->isPremiumEnabled("accessMoved") && !mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.isPremiumEnabled("accessMoved") && !mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckOther::checkAccessOfMovedVariable"); // c++11,warning - const bool reportInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive); + const bool reportInconclusive = mSettings.certainty.isEnabled(Certainty::inconclusive); const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Scope * scope : symbolDatabase->functionScopes) { const Token * scopeStart = scope->bodyStart; @@ -3967,11 +3965,11 @@ void CheckOther::checkAccessOfMovedVariable() else inconclusive = true; } else { - const ExprUsage usage = getExprUsage(tok, 0, *mSettings); + const ExprUsage usage = getExprUsage(tok, 0, mSettings); if (usage == ExprUsage::Used) accessOfMoved = true; if (usage == ExprUsage::PassedByReference) - accessOfMoved = !isVariableChangedByFunctionCall(tok, 0, *mSettings, &inconclusive); + accessOfMoved = !isVariableChangedByFunctionCall(tok, 0, mSettings.library, &inconclusive); else if (usage == ExprUsage::Inconclusive) inconclusive = true; } @@ -3981,7 +3979,7 @@ void CheckOther::checkAccessOfMovedVariable() } } -void CheckOther::accessMovedError(const Token *tok, const std::string &varname, const ValueFlow::Value *value, bool inconclusive) +void CheckOtherImpl::accessMovedError(const Token *tok, const std::string &varname, const ValueFlow::Value *value, bool inconclusive) { if (!tok) { reportError(tok, Severity::warning, "accessMoved", "Access of moved variable 'v'.", CWE672, Certainty::normal); @@ -4010,13 +4008,13 @@ void CheckOther::accessMovedError(const Token *tok, const std::string &varname, -void CheckOther::checkFuncArgNamesDifferent() +void CheckOtherImpl::checkFuncArgNamesDifferent() { - const bool style = mSettings->severity.isEnabled(Severity::style); - const bool inconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive); - const bool warning = mSettings->severity.isEnabled(Severity::warning); + const bool style = mSettings.severity.isEnabled(Severity::style); + const bool inconclusive = mSettings.certainty.isEnabled(Certainty::inconclusive); + const bool warning = mSettings.severity.isEnabled(Severity::warning); - if (!(warning || (style && inconclusive)) && !mSettings->isPremiumEnabled("funcArgNamesDifferent")) + if (!(warning || (style && inconclusive)) && !mSettings.isPremiumEnabled("funcArgNamesDifferent")) return; logChecker("CheckOther::checkFuncArgNamesDifferent"); // style,warning,inconclusive @@ -4037,14 +4035,14 @@ void CheckOther::checkFuncArgNamesDifferent() std::vector declarations(function->argCount()); std::vector definitions(function->argCount()); const Token * decl = function->argDef->next(); - for (int j = 0; j < function->argCount(); ++j) { + for (size_t j = 0; j < function->argCount(); ++j) { // get the definition const Variable * variable = function->getArgumentVar(j); if (variable) { definitions[j] = variable->nameToken(); } // get the declaration (search for first token with varId) - while (decl && !Token::Match(decl, ",|)|;")) { + while (decl && !Token::Match(decl, "[,;]")) { // skip everything after the assignment because // it could also have a varId or be the first // token with a varId if there is no name token @@ -4053,7 +4051,7 @@ void CheckOther::checkFuncArgNamesDifferent() break; } // skip over templates and arrays - if (decl->link() && decl->str() != "(") + if (decl->link() && precedes(decl, decl->link()) && !Token::Match(decl, "( [*&]")) decl = decl->link(); else if (decl->varId()) declarations[j] = decl; @@ -4065,11 +4063,11 @@ void CheckOther::checkFuncArgNamesDifferent() // check for different argument order if (warning) { bool order_different = false; - for (int j = 0; j < function->argCount(); ++j) { + for (size_t j = 0; j < function->argCount(); ++j) { if (!declarations[j] || !definitions[j] || declarations[j]->str() == definitions[j]->str()) continue; - for (int k = 0; k < function->argCount(); ++k) { + for (size_t k = 0; k < function->argCount(); ++k) { if (j != k && definitions[k] && declarations[j]->str() == definitions[k]->str()) { order_different = true; break; @@ -4083,7 +4081,7 @@ void CheckOther::checkFuncArgNamesDifferent() } // check for different argument names if (style && inconclusive) { - for (int j = 0; j < function->argCount(); ++j) { + for (size_t j = 0; j < function->argCount(); ++j) { const bool warn = (declarations[j] != nullptr) != (definitions[j] != nullptr) || (declarations[j] && definitions[j] && declarations[j]->str() != definitions[j]->str()); if (warn) @@ -4093,8 +4091,8 @@ void CheckOther::checkFuncArgNamesDifferent() } } -void CheckOther::funcArgNamesDifferent(const std::string & functionName, nonneg int index, - const Token* declaration, const Token* definition) +void CheckOtherImpl::funcArgNamesDifferent(const std::string & functionName, size_t index, + const Token* declaration, const Token* definition) { std::list tokens = { declaration,definition }; const std::string id = (declaration != nullptr) == (definition != nullptr) ? "funcArgNamesDifferent" : "funcArgNamesDifferentUnnamed"; @@ -4105,10 +4103,10 @@ void CheckOther::funcArgNamesDifferent(const std::string & functionName, nonneg (definition ? definition->str() : "") + "'.", CWE628, Certainty::inconclusive); } -void CheckOther::funcArgOrderDifferent(const std::string & functionName, - const Token* declaration, const Token* definition, - const std::vector & declarations, - const std::vector & definitions) +void CheckOtherImpl::funcArgOrderDifferent(const std::string & functionName, + const Token* declaration, const Token* definition, + const std::vector & declarations, + const std::vector & definitions) { std::list tokens = { !declarations.empty() ? declarations[0] ? declarations[0] : declaration : nullptr, @@ -4143,7 +4141,8 @@ static const Token *findShadowed(const Scope *scope, const Variable& var, int li return v.nameToken(); } auto it = std::find_if(scope->functionList.cbegin(), scope->functionList.cend(), [&](const Function& f) { - return f.type == FunctionType::eFunction && f.name() == var.name() && precedes(f.tokenDef, var.nameToken()); + return f.type == FunctionType::eFunction && f.name() == var.name() + && (scope->isClassOrStructOrUnion() || precedes(f.tokenDef, var.nameToken())); }); if (it != scope->functionList.end()) return it->tokenDef; @@ -4156,9 +4155,9 @@ static const Token *findShadowed(const Scope *scope, const Variable& var, int li return shadowed; } -void CheckOther::checkShadowVariables() +void CheckOtherImpl::checkShadowVariables() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("shadowVariable")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("shadowVariable")) return; logChecker("CheckOther::checkShadowVariables"); // style const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -4197,6 +4196,9 @@ void CheckOther::checkShadowVariables() (functionScope->function->isStatic() || functionScope->function->isFriend()) && shadowed->variable() && !shadowed->variable()->isLocal()) return; + if (functionScope->functionOf && functionScope->functionOf->isClassOrStructOrUnion() && functionScope->function && + functionScope->function->isStatic() && shadowed->function() && !shadowed->function()->isStatic()) + return; if (var.scope() && var.scope()->function && var.scope()->function->isConstructor()) { if (shadowed->variable() && shadowed->variable()->isMember()) return; @@ -4216,8 +4218,8 @@ void CheckOther::checkShadowVariables() } } -void CheckOther::shadowError(const Token *shadows, const std::string &shadowsType, - const Token *shadowed, const std::string &shadowedType) +void CheckOtherImpl::shadowError(const Token *shadows, const std::string &shadowsType, + const Token *shadowed, const std::string &shadowedType) { ErrorPath errorPath; errorPath.emplace_back(shadowed, "Shadowed " + shadowedType); @@ -4257,9 +4259,9 @@ static bool isVariableExprHidden(const Token* tok) return false; } -void CheckOther::checkKnownArgument() +void CheckOtherImpl::checkKnownArgument() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("knownArgument")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("knownArgument")) return; logChecker("CheckOther::checkKnownArgument"); // style const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -4294,7 +4296,7 @@ void CheckOther::checkKnownArgument() continue; if (tok->isComparisonOp() && isSameExpression( - true, tok->astOperand1(), tok->astOperand2(), *mSettings, true, true)) + true, tok->astOperand1(), tok->astOperand2(), mSettings, true, true)) continue; // ensure that there is a integer variable in expression with unknown value const Token* vartok = nullptr; @@ -4326,7 +4328,7 @@ void CheckOther::checkKnownArgument() } } -void CheckOther::knownArgumentError(const Token *tok, const Token *ftok, const ValueFlow::Value *value, const std::string &varexpr, bool isVariableExpressionHidden) +void CheckOtherImpl::knownArgumentError(const Token *tok, const Token *ftok, const ValueFlow::Value *value, const std::string &varexpr, bool isVariableExpressionHidden) { if (!tok) { reportError(tok, Severity::style, "knownArgument", "Argument 'x-x' to function 'func' is always 0. It does not matter what value 'x' has."); @@ -4358,9 +4360,9 @@ void CheckOther::knownArgumentError(const Token *tok, const Token *ftok, const V reportError(std::move(errorPath), Severity::style, id, errmsg, CWE570, Certainty::normal); } -void CheckOther::checkKnownPointerToBool() +void CheckOtherImpl::checkKnownPointerToBool() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("knownPointerToBool")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("knownPointerToBool")) return; logChecker("CheckOther::checkKnownPointerToBool"); // style const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -4380,7 +4382,7 @@ void CheckOther::checkKnownPointerToBool() return parent->isExpandedMacro(); })) continue; - if (!isUsedAsBool(tok, *mSettings)) + if (!isUsedAsBool(tok, mSettings)) continue; const ValueFlow::Value& value = tok->values().front(); knownPointerToBoolError(tok, &value); @@ -4388,7 +4390,7 @@ void CheckOther::checkKnownPointerToBool() } } -void CheckOther::knownPointerToBoolError(const Token* tok, const ValueFlow::Value* value) +void CheckOtherImpl::knownPointerToBoolError(const Token* tok, const ValueFlow::Value* value) { if (!tok) { reportError(tok, Severity::style, "knownPointerToBool", "Pointer expression 'p' converted to bool is always true."); @@ -4401,7 +4403,7 @@ void CheckOther::knownPointerToBoolError(const Token* tok, const ValueFlow::Valu reportError(std::move(errorPath), Severity::style, "knownPointerToBool", errmsg, CWE570, Certainty::normal); } -void CheckOther::checkComparePointers() +void CheckOtherImpl::checkComparePointers() { logChecker("CheckOther::checkComparePointers"); const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -4431,10 +4433,10 @@ void CheckOther::checkComparePointers() continue; if (var1->isRValueReference() || var2->isRValueReference()) continue; - if (const Token* parent2 = getParentLifetime(v2.tokvalue, mSettings->library)) + if (const Token* parent2 = getParentLifetime(v2.tokvalue, mSettings.library)) if (var1 == parent2->variable()) continue; - if (const Token* parent1 = getParentLifetime(v1.tokvalue, mSettings->library)) + if (const Token* parent1 = getParentLifetime(v1.tokvalue, mSettings.library)) if (var2 == parent1->variable()) continue; comparePointersError(tok, &v1, &v2); @@ -4442,7 +4444,7 @@ void CheckOther::checkComparePointers() } } -void CheckOther::comparePointersError(const Token *tok, const ValueFlow::Value *v1, const ValueFlow::Value *v2) +void CheckOtherImpl::comparePointersError(const Token *tok, const ValueFlow::Value *v1, const ValueFlow::Value *v2) { ErrorPath errorPath; std::string verb = "Comparing"; @@ -4462,9 +4464,9 @@ void CheckOther::comparePointersError(const Token *tok, const ValueFlow::Value * std::move(errorPath), Severity::error, id, verb + " pointers that point to different objects", CWE758, Certainty::normal); } -void CheckOther::checkModuloOfOne() +void CheckOtherImpl::checkModuloOfOne() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("moduloofone")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("moduloofone")) return; logChecker("CheckOther::checkModuloOfOne"); // style @@ -4484,7 +4486,7 @@ void CheckOther::checkModuloOfOne() } } -void CheckOther::checkModuloOfOneError(const Token *tok) +void CheckOtherImpl::checkModuloOfOneError(const Token *tok) { reportError(tok, Severity::style, "moduloofone", "Modulo of one is always equal to zero"); } @@ -4572,9 +4574,9 @@ static bool isZeroInitializer(const Token *tok) } -void CheckOther::checkUnionZeroInit() +void CheckOtherImpl::checkUnionZeroInit() { - if (!mSettings->severity.isEnabled(Severity::portability)) + if (!mSettings.severity.isEnabled(Severity::portability)) return; logChecker("CheckOther::checkUnionZeroInit"); // portability @@ -4582,8 +4584,9 @@ void CheckOther::checkUnionZeroInit() const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); std::unordered_map unionsByScopeId; - const std::vector unions = parseUnions(*symbolDatabase, *mSettings); + const std::vector unions = parseUnions(*symbolDatabase, mSettings); for (const Union &u : unions) { + // cppcheck-suppress useStlAlgorithm - std::transform is cumbersome unionsByScopeId.emplace(u.scope, u); } @@ -4610,8 +4613,8 @@ void CheckOther::checkUnionZeroInit() } } -void CheckOther::unionZeroInitError(const Token *tok, - const UnionMember& largestMember) +void CheckOtherImpl::unionZeroInitError(const Token *tok, + const UnionMember& largestMember) { reportError(tok, Severity::portability, "UnionZeroInit", (tok != nullptr ? "$symbol:" + tok->str() + "\n" : "") + @@ -4682,7 +4685,7 @@ static bool getBufAndOffset(const Token *expr, const Token *&buf, MathLib::bigin return true; } -void CheckOther::checkOverlappingWrite() +void CheckOtherImpl::checkOverlappingWrite() { logChecker("CheckOther::checkOverlappingWrite"); const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -4721,7 +4724,7 @@ void CheckOther::checkOverlappingWrite() if (errorToken) overlappingWriteUnion(tok); } else if (Token::Match(tok, "%name% (")) { - const Library::NonOverlappingData *nonOverlappingData = mSettings->library.getNonOverlappingData(tok); + const Library::NonOverlappingData *nonOverlappingData = mSettings.library.getNonOverlappingData(tok); if (!nonOverlappingData) continue; const std::vector args = getArguments(tok); @@ -4746,7 +4749,7 @@ void CheckOther::checkOverlappingWrite() constexpr bool macro = true; constexpr bool pure = true; constexpr bool follow = true; - if (!isSameExpression(macro, ptr1, ptr2, *mSettings, pure, follow, &errorPath)) + if (!isSameExpression(macro, ptr1, ptr2, mSettings, pure, follow, &errorPath)) continue; overlappingWriteFunction(tok, tok->str()); } @@ -4758,9 +4761,9 @@ void CheckOther::checkOverlappingWrite() MathLib::bigint sizeValue = args[sizeArg-1]->getKnownIntValue(); const Token *buf1, *buf2; MathLib::bigint offset1, offset2; - if (!getBufAndOffset(ptr1, buf1, &offset1, *mSettings, isCountArg ? &sizeValue : nullptr)) + if (!getBufAndOffset(ptr1, buf1, &offset1, mSettings, isCountArg ? &sizeValue : nullptr)) continue; - if (!getBufAndOffset(ptr2, buf2, &offset2, *mSettings)) + if (!getBufAndOffset(ptr2, buf2, &offset2, mSettings)) continue; if (offset1 < offset2 && offset1 + sizeValue <= offset2) @@ -4772,7 +4775,7 @@ void CheckOther::checkOverlappingWrite() constexpr bool macro = true; constexpr bool pure = true; constexpr bool follow = true; - if (!isSameExpression(macro, buf1, buf2, *mSettings, pure, follow, &errorPath)) + if (!isSameExpression(macro, buf1, buf2, mSettings, pure, follow, &errorPath)) continue; overlappingWriteFunction(tok, tok->str()); } @@ -4780,19 +4783,19 @@ void CheckOther::checkOverlappingWrite() } } -void CheckOther::overlappingWriteUnion(const Token *tok) +void CheckOtherImpl::overlappingWriteUnion(const Token *tok) { reportError(tok, Severity::error, "overlappingWriteUnion", "Overlapping read/write of union is undefined behavior"); } -void CheckOther::overlappingWriteFunction(const Token *tok, const std::string& funcname) +void CheckOtherImpl::overlappingWriteFunction(const Token *tok, const std::string& funcname) { reportError(tok, Severity::error, "overlappingWriteFunction", "Overlapping read/write in " + funcname + "() is undefined behavior"); } -void CheckOther::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckOther::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { - CheckOther checkOther(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckOtherImpl checkOther(&tokenizer, tokenizer.getSettings(), errorLogger); // Checks checkOther.warningOldStylePointerCast(); @@ -4842,9 +4845,9 @@ void CheckOther::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) checkOther.checkUnionZeroInit(); } -void CheckOther::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const +void CheckOther::getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const { - CheckOther c(nullptr, settings, errorLogger); + CheckOtherImpl c(nullptr, settings, errorLogger); // error c.zerodivError(nullptr, nullptr); diff --git a/lib/checkother.h b/lib/checkother.h index f779141f499..caf9f4a9e57 100644 --- a/lib/checkother.h +++ b/lib/checkother.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,6 +23,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include "errortypes.h" @@ -49,28 +50,87 @@ struct UnionMember; /** @brief Various small checks */ class CPPCHECKLIB CheckOther : public Check { - friend class TestCharVar; - friend class TestIncompleteStatement; - friend class TestOther; - public: /** @brief This constructor is used when registering the CheckClass */ - CheckOther() : Check(myName()) {} + CheckOther() : Check("Other") {} - /** Is expression a comparison that checks if a nonzero (unsigned/pointer) expression is less than zero? */ - static bool comparisonNonZeroExpressionLessThanZero(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr, bool suppress = false); +private: + /** @brief Run checks against the normal token list */ + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; - /** Is expression a comparison that checks if a nonzero (unsigned/pointer) expression is positive? */ - static bool testIfNonZeroExpressionIsPositive(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr); + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; -private: + std::string classInfo() const override { + return "Other checks\n" + + // error + "- division with zero\n" + "- scoped object destroyed immediately after construction\n" + "- assignment in an assert statement\n" + "- free() or delete of an invalid memory location\n" + "- bitwise operation with negative right operand\n" + "- cast the return values of getc(),fgetc() and getchar() to character and compare it to EOF\n" + "- race condition with non-interlocked access after InterlockedDecrement() call\n" + "- expression 'x = x++;' depends on order of evaluation of side effects\n" + "- overlapping write of union\n" + + // warning + "- either division by zero or useless condition\n" + "- access of moved or forwarded variable.\n" + + // performance + "- redundant data copying for const variable\n" + "- subsequent assignment or copying to a variable or buffer\n" + "- passing parameter by value\n" + + // portability + "- Passing NULL pointer to function with variable number of arguments leads to UB.\n" + + // style + "- C-style pointer cast in C++ code\n" + "- casting between incompatible pointer types\n" + "- [Incomplete statement](IncompleteStatement)\n" + "- [check how signed char variables are used](CharVar)\n" + "- variable scope can be limited\n" + "- unusual pointer arithmetic. For example: \"abc\" + 'd'\n" + "- redundant assignment, increment, or bitwise operation in a switch statement\n" + "- redundant strcpy in a switch statement\n" + "- Suspicious case labels in switch()\n" + "- assignment of a variable to itself\n" + "- Comparison of values leading always to true or false\n" + "- Clarify calculation with parentheses\n" + "- suspicious comparison of '\\0' with a char\\* variable\n" + "- duplicate break statement\n" + "- unreachable code\n" + "- testing if unsigned variable is negative/positive\n" + "- Suspicious use of ; at the end of 'if/for/while' statement.\n" + "- Array filled incompletely using memset/memcpy/memmove.\n" + "- NaN (not a number) value used in arithmetic expression.\n" + "- comma in return statement (the comma can easily be misread as a semicolon).\n" + "- prefer erfc, expm1 or log1p to avoid loss of precision.\n" + "- identical code in both branches of if/else or ternary operator.\n" + "- redundant pointer operation on pointer like &\\*some_ptr.\n" + "- find unused 'goto' labels.\n" + "- function declaration and definition argument names different.\n" + "- function declaration and definition argument order different.\n" + "- shadow variable.\n" + "- variable can be declared const.\n" + "- calculating modulo of one.\n" + "- known function argument, suspicious calculation.\n"; + } +}; + +class CPPCHECKLIB CheckOtherImpl : public CheckImpl { +public: /** @brief This constructor is used when running checks. */ - CheckOther(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} + CheckOtherImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} + /** Is expression a comparison that checks if a nonzero (unsigned/pointer) expression is less than zero? */ + static bool comparisonNonZeroExpressionLessThanZero(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr, bool suppress = false); - /** @brief Run checks against the normal token list */ - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + /** Is expression a comparison that checks if a nonzero (unsigned/pointer) expression is positive? */ + static bool testIfNonZeroExpressionIsPositive(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr); /** @brief Clarify calculation for ".. a * b ? .." */ void clarifyCalculation(); @@ -215,7 +275,7 @@ class CPPCHECKLIB CheckOther : public Check { void suspiciousFloatingPointCastError(const Token *tok); void invalidPointerCastError(const Token* tok, const std::string& from, const std::string& to, bool inconclusive, bool toIsInt); void passedByValueError(const Variable* var, bool inconclusive, bool isRangeBasedFor = false); - void constVariableError(const Variable *var, const Function *function); + void constVariableError(const Variable *var, const Function *function, bool foundAllBaseClasses = true); void constStatementError(const Token *tok, const std::string &type, bool inconclusive); void signedCharArrayIndexError(const Token *tok); void unknownSignCharArrayIndexError(const Token *tok); @@ -256,7 +316,7 @@ class CPPCHECKLIB CheckOther : public Check { void unusedLabelError(const Token* tok, bool inSwitch, bool hasIfdef); void unknownEvaluationOrder(const Token* tok, bool isUnspecifiedBehavior = false); 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 funcArgNamesDifferent(const std::string & functionName, size_t 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 *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); @@ -265,74 +325,6 @@ class CPPCHECKLIB CheckOther : public Check { void checkModuloOfOneError(const Token *tok); void unionZeroInitError(const Token *tok, const UnionMember& largestMember); - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - static std::string myName() { - return "Other"; - } - - std::string classInfo() const override { - return "Other checks\n" - - // error - "- division with zero\n" - "- scoped object destroyed immediately after construction\n" - "- assignment in an assert statement\n" - "- free() or delete of an invalid memory location\n" - "- bitwise operation with negative right operand\n" - "- cast the return values of getc(),fgetc() and getchar() to character and compare it to EOF\n" - "- race condition with non-interlocked access after InterlockedDecrement() call\n" - "- expression 'x = x++;' depends on order of evaluation of side effects\n" - "- overlapping write of union\n" - - // warning - "- either division by zero or useless condition\n" - "- access of moved or forwarded variable.\n" - "- potentially dangerous C style type cast of pointer/reference to object.\n" - - // performance - "- redundant data copying for const variable\n" - "- subsequent assignment or copying to a variable or buffer\n" - "- passing parameter by value\n" - - // portability - "- Passing NULL pointer to function with variable number of arguments leads to UB.\n" - "- Casting non-zero integer literal in decimal or octal format to pointer.\n" - "- Incorrect zero initialization of unions can lead to access of uninitialized memory.\n" - - // style - "- C-style pointer cast in C++ code\n" - "- casting between incompatible pointer types\n" - "- [Incomplete statement](IncompleteStatement)\n" - "- [check how signed char variables are used](CharVar)\n" - "- variable scope can be limited\n" - "- unusual pointer arithmetic. For example: \"abc\" + 'd'\n" - "- redundant assignment, increment, or bitwise operation in a switch statement\n" - "- redundant strcpy in a switch statement\n" - "- Suspicious case labels in switch()\n" - "- assignment of a variable to itself\n" - "- Comparison of values leading always to true or false\n" - "- Clarify calculation with parentheses\n" - "- suspicious comparison of '\\0' with a char\\* variable\n" - "- duplicate break statement\n" - "- unreachable code\n" - "- testing if unsigned variable is negative/positive\n" - "- Suspicious use of ; at the end of 'if/for/while' statement.\n" - "- Array filled incompletely using memset/memcpy/memmove.\n" - "- NaN (not a number) value used in arithmetic expression.\n" - "- comma in return statement (the comma can easily be misread as a semicolon).\n" - "- prefer erfc, expm1 or log1p to avoid loss of precision.\n" - "- identical code in both branches of if/else or ternary operator.\n" - "- redundant pointer operation on pointer like &\\*some_ptr.\n" - "- find unused 'goto' labels.\n" - "- function declaration and definition argument names different.\n" - "- function declaration and definition argument order different.\n" - "- shadow variable.\n" - "- variable can be declared const.\n" - "- calculating modulo of one.\n" - "- known function argument, suspicious calculation.\n"; - } - bool diag(const Token* tok) { return !mRedundantAssignmentDiag.emplace(tok).second; } diff --git a/lib/checkpostfixoperator.cpp b/lib/checkpostfixoperator.cpp index c6c9ccba77b..f15fa293c49 100644 --- a/lib/checkpostfixoperator.cpp +++ b/lib/checkpostfixoperator.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,19 +34,12 @@ //--------------------------------------------------------------------------- -// 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 - -void CheckPostfixOperator::postfixOperator() +void CheckPostfixOperatorImpl::postfixOperator() { - if (!mSettings->severity.isEnabled(Severity::performance)) + if (!mSettings.severity.isEnabled(Severity::performance)) return; logChecker("CheckPostfixOperator::postfixOperator"); // performance @@ -90,7 +83,7 @@ void CheckPostfixOperator::postfixOperator() //--------------------------------------------------------------------------- -void CheckPostfixOperator::postfixOperatorError(const Token *tok) +void CheckPostfixOperatorImpl::postfixOperatorError(const Token *tok) { reportError(tok, Severity::performance, "postfixOperator", "Prefer prefix ++/-- operators for non-primitive types.\n" @@ -101,17 +94,17 @@ void CheckPostfixOperator::postfixOperatorError(const Token *tok) "adds a little extra code.", CWE398, Certainty::normal); } -void CheckPostfixOperator::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckPostfixOperator::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { if (tokenizer.isC()) return; - CheckPostfixOperator checkPostfixOperator(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckPostfixOperatorImpl checkPostfixOperator(&tokenizer, tokenizer.getSettings(), errorLogger); checkPostfixOperator.postfixOperator(); } -void CheckPostfixOperator::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const +void CheckPostfixOperator::getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const { - CheckPostfixOperator c(nullptr, settings, errorLogger); + CheckPostfixOperatorImpl c(nullptr, settings, errorLogger); c.postfixOperatorError(nullptr); } diff --git a/lib/checkpostfixoperator.h b/lib/checkpostfixoperator.h index c9f58a7e143..5898cefcc3c 100644 --- a/lib/checkpostfixoperator.h +++ b/lib/checkpostfixoperator.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,6 +23,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include @@ -40,34 +41,30 @@ class Tokenizer; */ class CPPCHECKLIB CheckPostfixOperator : public Check { - friend class TestPostfixOperator; - public: /** This constructor is used when registering the CheckPostfixOperator */ - CheckPostfixOperator() : Check(myName()) {} + CheckPostfixOperator() : Check("Using postfix operators") {} private: - /** This constructor is used when running checks. */ - CheckPostfixOperator(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; + std::string classInfo() const override { + return "Warn if using postfix operators ++ or -- rather than prefix operator\n"; + } +}; - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; +class CPPCHECKLIB CheckPostfixOperatorImpl : public CheckImpl { +public: + /** This constructor is used when running checks. */ + CheckPostfixOperatorImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} /** Check postfix operators */ void postfixOperator(); /** Report Error */ void postfixOperatorError(const Token *tok); - - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - static std::string myName() { - return "Using postfix operators"; - } - - std::string classInfo() const override { - return "Warn if using postfix operators ++ or -- rather than prefix operator\n"; - } }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checks.cpp b/lib/checks.cpp new file mode 100644 index 00000000000..ef4b9fef3da --- /dev/null +++ b/lib/checks.cpp @@ -0,0 +1,125 @@ +/* + * 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" + +#include + +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..9c053b81405 --- /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 f7c0d44d399..2d9012078a6 100644 --- a/lib/checksizeof.cpp +++ b/lib/checksizeof.cpp @@ -34,19 +34,14 @@ //--------------------------------------------------------------------------- -// 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 //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- -void CheckSizeof::checkSizeofForNumericParameter() +void CheckSizeofImpl::checkSizeofForNumericParameter() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckSizeof::checkSizeofForNumericParameter"); // warning @@ -62,7 +57,7 @@ void CheckSizeof::checkSizeofForNumericParameter() } } -void CheckSizeof::sizeofForNumericParameterError(const Token *tok) +void CheckSizeofImpl::sizeofForNumericParameterError(const Token *tok) { reportError(tok, Severity::warning, "sizeofwithnumericparameter", "Suspicious usage of 'sizeof' with a numeric constant as parameter.\n" @@ -74,9 +69,9 @@ void CheckSizeof::sizeofForNumericParameterError(const Token *tok) //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- -void CheckSizeof::checkSizeofForArrayParameter() +void CheckSizeofImpl::checkSizeofForArrayParameter() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckSizeof::checkSizeofForArrayParameter"); // warning @@ -92,14 +87,14 @@ void CheckSizeof::checkSizeofForArrayParameter() } const Variable *var = varTok->variable(); - if (var && var->isArray() && var->isArgument() && !var->isReference()) + if (var && var->isArray() && var->isArgument() && !var->isReference() && !(var->isStlType() && var->getTypeName() == "std::array")) sizeofForArrayParameterError(tok); } } } } -void CheckSizeof::sizeofForArrayParameterError(const Token *tok) +void CheckSizeofImpl::sizeofForArrayParameterError(const Token *tok) { reportError(tok, Severity::warning, "sizeofwithsilentarraypointer", "Using 'sizeof' on array given as function argument " @@ -115,9 +110,9 @@ void CheckSizeof::sizeofForArrayParameterError(const Token *tok) ); } -void CheckSizeof::checkSizeofForPointerSize() +void CheckSizeofImpl::checkSizeofForPointerSize() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckSizeof::checkSizeofForPointerSize"); // warning @@ -134,7 +129,7 @@ void CheckSizeof::checkSizeofForPointerSize() // Once leaving those tests, it is mandatory to have: // - variable matching the used pointer // - tokVar pointing on the argument where sizeof may be used - if (Token::Match(tok->tokAt(2), "%name% (") && mSettings->library.getAllocFuncInfo(tok->tokAt(2))) { + if (Token::Match(tok->tokAt(2), "%name% (") && mSettings.library.getAllocFuncInfo(tok->tokAt(2))) { if (Token::Match(tok, "%var% =")) variable = tok; else if (tok->strAt(1) == ")" && Token::Match(tok->linkAt(1)->tokAt(-2), "%var% =")) @@ -238,7 +233,8 @@ void CheckSizeof::checkSizeofForPointerSize() // Now check for the sizeof usage: Does the level of pointer indirection match? const Token * const tokLink = tokSize->linkAt(1); if (tokLink && tokLink->strAt(-1) == "*") { - if (variable && variable->valueType() && variable->valueType()->pointer == 1 && variable->valueType()->type != ValueType::VOID) + if (variable && variable->valueType() && variable->valueType()->pointer == 1 && variable->valueType()->type != ValueType::VOID && + variable->valueType()->isTypeEqual(tokSize->next()->astOperand2()->valueType())) sizeofForPointerError(variable, variable->str()); else if (variable2 && variable2->valueType() && variable2->valueType()->pointer == 1 && variable2->valueType()->type != ValueType::VOID) sizeofForPointerError(variable2, variable2->str()); @@ -267,7 +263,7 @@ void CheckSizeof::checkSizeofForPointerSize() } } -void CheckSizeof::sizeofForPointerError(const Token *tok, const std::string &varname) +void CheckSizeofImpl::sizeofForPointerError(const Token *tok, const std::string &varname) { reportError(tok, Severity::warning, "pointerSize", "Size of pointer '" + varname + "' used instead of size of its data.\n" @@ -276,7 +272,7 @@ void CheckSizeof::sizeofForPointerError(const Token *tok, const std::string &var "write 'sizeof(*" + varname + ")'.", CWE467, Certainty::normal); } -void CheckSizeof::divideBySizeofError(const Token *tok, const std::string &memfunc) +void CheckSizeofImpl::divideBySizeofError(const Token *tok, const std::string &memfunc) { reportError(tok, Severity::warning, "sizeofDivisionMemfunc", "Division by result of sizeof(). " + memfunc + "() expects a size in bytes, did you intend to multiply instead?", CWE682, Certainty::normal); @@ -284,9 +280,9 @@ void CheckSizeof::divideBySizeofError(const Token *tok, const std::string &memfu //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -void CheckSizeof::sizeofsizeof() +void CheckSizeofImpl::sizeofsizeof() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckSizeof::sizeofsizeof"); // warning @@ -299,7 +295,7 @@ void CheckSizeof::sizeofsizeof() } } -void CheckSizeof::sizeofsizeofError(const Token *tok) +void CheckSizeofImpl::sizeofsizeofError(const Token *tok) { reportError(tok, Severity::warning, "sizeofsizeof", "Calling 'sizeof' on 'sizeof'.\n" @@ -310,14 +306,14 @@ void CheckSizeof::sizeofsizeofError(const Token *tok) //----------------------------------------------------------------------------- -void CheckSizeof::sizeofCalculation() +void CheckSizeofImpl::sizeofCalculation() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckSizeof::sizeofCalculation"); // warning - const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive); + const bool printInconclusive = mSettings.certainty.isEnabled(Certainty::inconclusive); for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) { if (!Token::simpleMatch(tok, "sizeof (")) @@ -348,7 +344,7 @@ void CheckSizeof::sizeofCalculation() } } -void CheckSizeof::sizeofCalculationError(const Token *tok, bool inconclusive) +void CheckSizeofImpl::sizeofCalculationError(const Token *tok, bool inconclusive) { reportError(tok, Severity::warning, "sizeofCalculation", "Found calculation inside sizeof().", CWE682, inconclusive ? Certainty::inconclusive : Certainty::normal); @@ -356,9 +352,9 @@ void CheckSizeof::sizeofCalculationError(const Token *tok, bool inconclusive) //----------------------------------------------------------------------------- -void CheckSizeof::sizeofFunction() +void CheckSizeofImpl::sizeofFunction() { - if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("sizeofFunctionCall")) + if (!mSettings.severity.isEnabled(Severity::warning) && !mSettings.isPremiumEnabled("sizeofFunctionCall")) return; logChecker("CheckSizeof::sizeofFunction"); // warning @@ -390,7 +386,7 @@ void CheckSizeof::sizeofFunction() } } -void CheckSizeof::sizeofFunctionError(const Token *tok) +void CheckSizeofImpl::sizeofFunctionError(const Token *tok) { reportError(tok, Severity::warning, "sizeofFunctionCall", "Found function call inside sizeof().", CWE682, Certainty::normal); @@ -399,9 +395,9 @@ void CheckSizeof::sizeofFunctionError(const Token *tok) //----------------------------------------------------------------------------- // Check for code like sizeof()*sizeof() or sizeof(ptr)/value //----------------------------------------------------------------------------- -void CheckSizeof::suspiciousSizeofCalculation() +void CheckSizeofImpl::suspiciousSizeofCalculation() { - if (!mSettings->severity.isEnabled(Severity::warning) || !mSettings->certainty.isEnabled(Certainty::inconclusive)) + if (!mSettings.severity.isEnabled(Severity::warning) || !mSettings.certainty.isEnabled(Certainty::inconclusive)) return; logChecker("CheckSizeof::suspiciousSizeofCalculation"); // warning,inconclusive @@ -429,13 +425,13 @@ void CheckSizeof::suspiciousSizeofCalculation() } } -void CheckSizeof::multiplySizeofError(const Token *tok) +void CheckSizeofImpl::multiplySizeofError(const Token *tok) { reportError(tok, Severity::warning, "multiplySizeof", "Multiplying sizeof() with sizeof() indicates a logic error.", CWE682, Certainty::inconclusive); } -void CheckSizeof::divideSizeofError(const Token *tok) +void CheckSizeofImpl::divideSizeofError(const Token *tok) { reportError(tok, Severity::warning, "divideSizeof", "Division of result of sizeof() on pointer type.\n" @@ -443,9 +439,9 @@ void CheckSizeof::divideSizeofError(const Token *tok) "not the size of the memory area it points to.", CWE682, Certainty::inconclusive); } -void CheckSizeof::sizeofVoid() +void CheckSizeofImpl::sizeofVoid() { - if (!mSettings->severity.isEnabled(Severity::portability)) + if (!mSettings.severity.isEnabled(Severity::portability)) return; logChecker("CheckSizeof::sizeofVoid"); // portability @@ -481,30 +477,30 @@ void CheckSizeof::sizeofVoid() } } -void CheckSizeof::sizeofVoidError(const Token *tok) +void CheckSizeofImpl::sizeofVoidError(const Token *tok) { const std::string message = "Behaviour of 'sizeof(void)' is not covered by the ISO C standard."; const std::string verbose = message + " A value for 'sizeof(void)' is defined only as part of a GNU C extension, which defines 'sizeof(void)' to be 1."; reportError(tok, Severity::portability, "sizeofVoid", message + "\n" + verbose, CWE682, Certainty::normal); } -void CheckSizeof::sizeofDereferencedVoidPointerError(const Token *tok, const std::string &varname) +void CheckSizeofImpl::sizeofDereferencedVoidPointerError(const Token *tok, const std::string &varname) { const std::string message = "'*" + varname + "' is of type 'void', the behaviour of 'sizeof(void)' is not covered by the ISO C standard."; const std::string verbose = message + " A value for 'sizeof(void)' is defined only as part of a GNU C extension, which defines 'sizeof(void)' to be 1."; reportError(tok, Severity::portability, "sizeofDereferencedVoidPointer", message + "\n" + verbose, CWE682, Certainty::normal); } -void CheckSizeof::arithOperationsOnVoidPointerError(const Token* tok, const std::string &varname, const std::string &vartype) +void CheckSizeofImpl::arithOperationsOnVoidPointerError(const Token* tok, const std::string &varname, const std::string &vartype) { const std::string message = "'$symbol' is of type '" + vartype + "'. When using void pointers in calculations, the behaviour is undefined."; const std::string verbose = message + " Arithmetic operations on 'void *' is a GNU C extension, which defines the 'sizeof(void)' to be 1."; reportError(tok, Severity::portability, "arithOperationsOnVoidPointer", "$symbol:" + varname + '\n' + message + '\n' + verbose, CWE467, Certainty::normal); } -void CheckSizeof::runChecks(const Tokenizer& tokenizer, ErrorLogger* errorLogger) +void CheckSizeof::runChecks(const Tokenizer& tokenizer, ErrorLogger& errorLogger) { - CheckSizeof checkSizeof(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckSizeofImpl checkSizeof(&tokenizer, tokenizer.getSettings(), errorLogger); // Checks checkSizeof.sizeofsizeof(); @@ -517,9 +513,9 @@ void CheckSizeof::runChecks(const Tokenizer& tokenizer, ErrorLogger* errorLogger checkSizeof.sizeofVoid(); } -void CheckSizeof::getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const +void CheckSizeof::getErrorMessages(ErrorLogger& errorLogger, const Settings& settings) const { - CheckSizeof c(nullptr, settings, errorLogger); + CheckSizeofImpl c(nullptr, settings, errorLogger); c.sizeofForArrayParameterError(nullptr); c.sizeofForPointerError(nullptr, "varname"); c.divideBySizeofError(nullptr, "memset"); diff --git a/lib/checksizeof.h b/lib/checksizeof.h index 4c10ca88dac..7540fe6785d 100644 --- a/lib/checksizeof.h +++ b/lib/checksizeof.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,6 +23,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include @@ -41,15 +42,32 @@ class Tokenizer; class CPPCHECKLIB CheckSizeof : public Check { public: /** @brief This constructor is used when registering the CheckClass */ - CheckSizeof() : Check(myName()) {} + CheckSizeof() : Check("Sizeof") {} private: - /** @brief This constructor is used when running checks. */ - CheckSizeof(const Tokenizer* tokenizer, const Settings* settings, ErrorLogger* errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} - /** @brief Run checks against the normal token list */ - void runChecks(const Tokenizer& tokenizer, ErrorLogger* errorLogger) override; + void runChecks(const Tokenizer& tokenizer, ErrorLogger& errorLogger) override; + + void getErrorMessages(ErrorLogger& errorLogger, const Settings& settings) const override; + + std::string classInfo() const override { + return "sizeof() usage checks\n" + "- sizeof for array given as function argument\n" + "- sizeof for numeric given as function argument\n" + "- using sizeof(pointer) instead of the size of pointed data\n" + "- look for 'sizeof sizeof ..'\n" + "- look for calculations inside sizeof()\n" + "- look for function calls inside sizeof()\n" + "- look for suspicious calculations with sizeof()\n" + "- using 'sizeof(void)' which is undefined\n"; + } +}; + +class CPPCHECKLIB CheckSizeofImpl : public CheckImpl { +public: + /** @brief This constructor is used when running checks. */ + CheckSizeofImpl(const Tokenizer* tokenizer, const Settings& settings, ErrorLogger& errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} /** @brief %Check for 'sizeof sizeof ..' */ void sizeofsizeof(); @@ -88,24 +106,6 @@ class CPPCHECKLIB CheckSizeof : public Check { void sizeofVoidError(const Token *tok); void sizeofDereferencedVoidPointerError(const Token *tok, const std::string &varname); void arithOperationsOnVoidPointerError(const Token* tok, const std::string &varname, const std::string &vartype); - - void getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const override; - - static std::string myName() { - return "Sizeof"; - } - - std::string classInfo() const override { - return "sizeof() usage checks\n" - "- sizeof for array given as function argument\n" - "- sizeof for numeric given as function argument\n" - "- using sizeof(pointer) instead of the size of pointed data\n" - "- look for 'sizeof sizeof ..'\n" - "- look for calculations inside sizeof()\n" - "- look for function calls inside sizeof()\n" - "- look for suspicious calculations with sizeof()\n" - "- using 'sizeof(void)' which is undefined\n"; - } }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index faa6f25911d..500adc08b01 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.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,6 +35,7 @@ #include "checknullpointer.h" #include +#include #include #include #include @@ -46,11 +47,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 @@ -132,7 +128,17 @@ static const Token* getContainerFromSize(const Library::Container* container, co return nullptr; } -void CheckStl::outOfBounds() +// A value that out of bounds analysis can use: not impossible, and inconclusive only when enabled +static bool isUsableValue(const ValueFlow::Value& value, const Settings& settings) +{ + if (value.isImpossible()) + return false; + if (value.isInconclusive() && !settings.certainty.isEnabled(Certainty::inconclusive)) + return false; + return true; +} + +void CheckStlImpl::outOfBounds() { logChecker("CheckStl::outOfBounds"); @@ -153,11 +159,9 @@ void CheckStl::outOfBounds() for (const ValueFlow::Value &value : tok->values()) { if (!value.isContainerSizeValue()) continue; - if (value.isImpossible()) - continue; - if (value.isInconclusive() && !mSettings->certainty.isEnabled(Certainty::inconclusive)) + if (!isUsableValue(value, mSettings)) continue; - if (!value.errorSeverity() && !mSettings->severity.isEnabled(Severity::warning)) + if (!value.errorSeverity() && !mSettings.severity.isEnabled(Severity::warning)) continue; if (value.intvalue == 0 && (indexTok || (containerYieldsElement(container, parent) && !containerAppendsElement(container, parent)) || @@ -170,7 +174,7 @@ void CheckStl::outOfBounds() } if (indexTok) { std::vector indexValues = - ValueFlow::isOutOfBounds(value, indexTok, mSettings->severity.isEnabled(Severity::warning)); + ValueFlow::isOutOfBounds(value, indexTok, mSettings.severity.isEnabled(Severity::warning)); if (!indexValues.empty()) { outOfBoundsError( accessTok, tok->expressionString(), &value, indexTok->expressionString(), &indexValues.front()); @@ -180,7 +184,7 @@ void CheckStl::outOfBounds() } if (indexTok && !indexTok->hasKnownIntValue()) { const ValueFlow::Value* value = - ValueFlow::findValue(indexTok->values(), *mSettings, [&](const ValueFlow::Value& v) { + ValueFlow::findValue(indexTok->values(), mSettings, [&](const ValueFlow::Value& v) { if (!v.isSymbolicValue()) return false; if (v.isImpossible()) @@ -220,7 +224,7 @@ static std::string indexValueString(const ValueFlow::Value& indexValue, const st return indexString; } -void CheckStl::outOfBoundsError(const Token *tok, const std::string &containerName, const ValueFlow::Value *containerSize, const std::string &index, const ValueFlow::Value *indexValue) +void CheckStlImpl::outOfBoundsError(const Token *tok, const std::string &containerName, const ValueFlow::Value *containerSize, const std::string &index, const ValueFlow::Value *indexValue) { // Do not warn if both the container size and index value are possible if (containerSize && indexValue && containerSize->isPossible() && indexValue->isPossible()) @@ -279,18 +283,18 @@ void CheckStl::outOfBoundsError(const Token *tok, const std::string &containerNa (containerSize && containerSize->isInconclusive()) || (indexValue && indexValue->isInconclusive()) ? Certainty::inconclusive : Certainty::normal); } -bool CheckStl::isContainerSize(const Token *containerToken, const Token *expr) const +bool CheckStlImpl::isContainerSize(const Token *containerToken, const Token *expr) const { if (!Token::simpleMatch(expr, "( )")) return false; if (!Token::Match(expr->astOperand1(), ". %name% (")) return false; - if (!isSameExpression(false, containerToken, expr->astOperand1()->astOperand1(), *mSettings, false, false)) + if (!isSameExpression(false, containerToken, expr->astOperand1()->astOperand1(), mSettings, false, false)) return false; return containerToken->valueType()->container->getYield(expr->strAt(-1)) == Library::Container::Yield::SIZE; } -bool CheckStl::isContainerSizeGE(const Token * containerToken, const Token *expr) const +bool CheckStlImpl::isContainerSizeGE(const Token * containerToken, const Token *expr) const { if (!expr) return false; @@ -314,12 +318,12 @@ bool CheckStl::isContainerSizeGE(const Token * containerToken, const Token *expr op = expr->astOperand1(); else return false; - return op && op->getValueGE(0, *mSettings); + return op && op->getValueGE(0, mSettings); } return false; } -void CheckStl::outOfBoundsIndexExpression() +void CheckStlImpl::outOfBoundsIndexExpression() { logChecker("CheckStl::outOfBoundsIndexExpression"); for (const Scope *function : mTokenizer->getSymbolDatabase()->functionScopes) { @@ -339,7 +343,7 @@ void CheckStl::outOfBoundsIndexExpression() } } -void CheckStl::outOfBoundsIndexExpressionError(const Token *tok, const Token *index) +void CheckStlImpl::outOfBoundsIndexExpressionError(const Token *tok, const Token *index) { const std::string varname = tok ? tok->str() : std::string("var"); const std::string i = index ? index->expressionString() : (varname + ".size()"); @@ -357,12 +361,12 @@ void CheckStl::outOfBoundsIndexExpressionError(const Token *tok, const Token *in // Error message for bad iterator usage.. -void CheckStl::invalidIteratorError(const Token *tok, const std::string &iteratorName) +void CheckStlImpl::invalidIteratorError(const Token *tok, const std::string &iteratorName) { reportError(tok, Severity::error, "invalidIterator1", "$symbol:"+iteratorName+"\nInvalid iterator: $symbol", CWE664, Certainty::normal); } -void CheckStl::iteratorsError(const Token* tok, const std::string& containerName1, const std::string& containerName2) +void CheckStlImpl::iteratorsError(const Token* tok, const std::string& containerName1, const std::string& containerName2) { reportError(tok, Severity::error, "iterators1", "$symbol:" + containerName1 + "\n" @@ -370,7 +374,7 @@ void CheckStl::iteratorsError(const Token* tok, const std::string& containerName "Same iterator is used with different containers '" + containerName1 + "' and '" + containerName2 + "'.", CWE664, Certainty::normal); } -void CheckStl::iteratorsError(const Token* tok, const Token* containerTok, const std::string& containerName) +void CheckStlImpl::iteratorsError(const Token* tok, const Token* containerTok, const std::string& containerName) { std::list callstack = { tok, containerTok }; reportError(callstack, @@ -384,7 +388,7 @@ void CheckStl::iteratorsError(const Token* tok, const Token* containerTok, const } // Error message used when dereferencing an iterator that has been erased.. -void CheckStl::dereferenceErasedError(const Token *erased, const Token* deref, const std::string &itername, bool inconclusive) +void CheckStlImpl::dereferenceErasedError(const Token *erased, const Token* deref, const std::string &itername, bool inconclusive) { if (erased) { std::list callstack = { deref, erased }; @@ -454,7 +458,7 @@ static bool isVector(const Token* tok) return Token::simpleMatch(decltok, "std :: vector"); } -void CheckStl::iterators() +void CheckStlImpl::iterators() { logChecker("CheckStl::iterators"); @@ -475,7 +479,7 @@ void CheckStl::iterators() bool inconclusiveType=false; if (!isIterator(var, inconclusiveType)) continue; - if (inconclusiveType && !mSettings->certainty.isEnabled(Certainty::inconclusive)) + if (inconclusiveType && !mSettings.certainty.isEnabled(Certainty::inconclusive)) continue; const int iteratorId = var->declarationId(); @@ -554,7 +558,7 @@ void CheckStl::iterators() } // Not different containers if a reference is used.. - if (containerToken && containerToken->variable() && containerToken->variable()->isReference()) { + if (containerToken->variable() && containerToken->variable()->isReference()) { const Token *nameToken = containerToken->variable()->nameToken(); if (Token::Match(nameToken, "%name% =")) { const Token *name1 = nameToken->tokAt(2); @@ -639,21 +643,23 @@ void CheckStl::iterators() } } -void CheckStl::mismatchingContainerIteratorError(const Token* containerTok, const Token* iterTok, const Token* containerTok2) +void CheckStlImpl::mismatchingContainerIteratorError(const Token* containerTok, const Token* iterTok, const Token* containerTok2) { const std::string container(containerTok ? containerTok->expressionString() : std::string("v1")); + const std::string containerTemp(isTemporary(containerTok, &mSettings.library) ? " temporary " : " "); const std::string container2(containerTok2 ? containerTok2->expressionString() : std::string("v2")); + const std::string containerTemp2(isTemporary(containerTok2, &mSettings.library) ? " temporary " : " "); const std::string iter(iterTok ? iterTok->expressionString() : std::string("it")); reportError(containerTok, Severity::error, "mismatchingContainerIterator", - "Iterator '" + iter + "' referring to container '" + container2 + "' is used with container '" + container + "'.", + "Iterator '" + iter + "' referring to" + containerTemp2 + "container '" + container2 + "' is used with" + containerTemp + "container '" + container + "'.", CWE664, Certainty::normal); } // Error message for bad iterator usage.. -void CheckStl::mismatchingContainersError(const Token* tok1, const Token* tok2) +void CheckStlImpl::mismatchingContainersError(const Token* tok1, const Token* tok2) { const std::string expr1(tok1 ? tok1->expressionString() : std::string("v1")); const std::string expr2(tok2 ? tok2->expressionString() : std::string("v2")); @@ -665,7 +671,7 @@ void CheckStl::mismatchingContainersError(const Token* tok1, const Token* tok2) Certainty::normal); } -void CheckStl::mismatchingContainerExpressionError(const Token *tok1, const Token *tok2) +void CheckStlImpl::mismatchingContainerExpressionError(const Token *tok1, const Token *tok2) { const std::string expr1(tok1 ? tok1->expressionString() : std::string("v1")); const std::string expr2(tok2 ? tok2->expressionString() : std::string("v2")); @@ -674,7 +680,7 @@ void CheckStl::mismatchingContainerExpressionError(const Token *tok1, const Toke expr1 + "' and '" + expr2 + "' are used together.", CWE664, Certainty::normal); } -void CheckStl::sameIteratorExpressionError(const Token *tok) +void CheckStlImpl::sameIteratorExpressionError(const Token *tok) { reportError(tok, Severity::style, "sameIteratorExpression", "Same iterators expression are used for algorithm.", CWE664, Certainty::normal); } @@ -759,7 +765,7 @@ static ValueFlow::Value getLifetimeIteratorValue(const Token* tok, MathLib::bigi return ValueFlow::Value{}; } -bool CheckStl::checkIteratorPair(const Token* tok1, const Token* tok2) +bool CheckStlImpl::checkIteratorPair(const Token* tok1, const Token* tok2) { if (!tok1) return false; @@ -777,7 +783,7 @@ bool CheckStl::checkIteratorPair(const Token* tok1, const Token* tok2) (!astIsContainer(val1.tokvalue) || !astIsContainer(val2.tokvalue))) return false; } - if (isSameIteratorContainerExpression(val1.tokvalue, val2.tokvalue, *mSettings, val1.lifetimeKind)) + if (isSameIteratorContainerExpression(val1.tokvalue, val2.tokvalue, mSettings, val1.lifetimeKind)) return false; if (val1.tokvalue->expressionString() == val2.tokvalue->expressionString()) iteratorsError(tok1, val1.tokvalue, val1.tokvalue->expressionString()); @@ -797,7 +803,7 @@ bool CheckStl::checkIteratorPair(const Token* tok1, const Token* tok2) const Token* iter2 = getIteratorExpression(tok2); if (!iter2) return false; - if (!isSameIteratorContainerExpression(iter1, iter2, *mSettings)) { + if (!isSameIteratorContainerExpression(iter1, iter2, mSettings)) { mismatchingContainerExpressionError(iter1, iter2); return true; } @@ -811,7 +817,7 @@ namespace { }; } -void CheckStl::mismatchingContainers() +void CheckStlImpl::mismatchingContainers() { logChecker("CheckStl::misMatchingContainers"); @@ -833,8 +839,8 @@ void CheckStl::mismatchingContainers() // Group args together by container std::map> containers; - for (int argnr = 1; argnr <= args.size(); ++argnr) { - const Library::ArgumentChecks::IteratorInfo *i = mSettings->library.getArgIteratorInfo(ftok, argnr); + for (size_t argnr = 1; argnr <= args.size(); ++argnr) { + const Library::ArgumentChecks::IteratorInfo *i = mSettings.library.getArgIteratorInfo(ftok, argnr); if (!i) continue; const Token * const argTok = args[argnr - 1]; @@ -851,7 +857,7 @@ void CheckStl::mismatchingContainers() if (iter1.tok == iter2.tok) continue; if (iter1.info->first && iter2.info->last && - isSameExpression(false, iter1.tok, iter2.tok, *mSettings, false, false)) + isSameExpression(false, iter1.tok, iter2.tok, mSettings, false, false)) sameIteratorExpressionError(iter1.tok); if (checkIteratorPair(iter1.tok, iter2.tok)) return; @@ -871,7 +877,7 @@ void CheckStl::mismatchingContainers() } } -void CheckStl::mismatchingContainerIterator() +void CheckStlImpl::mismatchingContainerIterator() { logChecker("CheckStl::misMatchingContainerIterator"); @@ -889,7 +895,7 @@ void CheckStl::mismatchingContainerIterator() const std::vector args = getArguments(ftok); const Library::Container * c = tok->valueType()->container; - const Library::Container::Action action = c->getAction(tok->strAt(2)); + const Library::Container::Action action = c->getAction(ftok->str()); const Token* iterTok = nullptr; if (action == Library::Container::Action::INSERT && args.size() == 2) { // Skip if iterator pair @@ -915,7 +921,7 @@ void CheckStl::mismatchingContainerIterator() continue; if (iterTok->str() == "*" && iterTok->astOperand1()->valueType() && iterTok->astOperand1()->valueType()->type == ValueType::ITERATOR) continue; - if (isSameIteratorContainerExpression(tok, val.tokvalue, *mSettings)) + if (isSameIteratorContainerExpression(tok, val.tokvalue, mSettings)) continue; mismatchingContainerIteratorError(tok, iterTok, val.tokvalue); } @@ -1123,7 +1129,7 @@ static const Token* endOfExpression(const Token* tok) return endToken; } -void CheckStl::invalidContainer() +void CheckStlImpl::invalidContainer() { logChecker("CheckStl::invalidContainer"); const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -1148,7 +1154,7 @@ void CheckStl::invalidContainer() const Scope* s = tok2->scope(); if (!s) continue; - if (isReturnScope(s->bodyEnd, mSettings->library)) + if (isReturnScope(s->bodyEnd, mSettings.library)) continue; invalidContainerLoopError(r.ftok, tok, r.errorPath); bail = true; @@ -1193,14 +1199,13 @@ 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; } ErrorPath ep; bool addressOf = false; - const Variable* var = ValueFlow::getLifetimeVariable(info.tok, ep, *mSettings, &addressOf); + const Variable* var = ValueFlow::getLifetimeVariable(info.tok, ep, mSettings, &addressOf); // Check the reference is created before the change if (var && var->declarationId() == r.tok->varId() && !addressOf) { // An argument always reaches @@ -1237,7 +1242,7 @@ void CheckStl::invalidContainer() } } -void CheckStl::invalidContainerLoopError(const Token* tok, const Token* loopTok, ErrorPath errorPath) +void CheckStlImpl::invalidContainerLoopError(const Token* tok, const Token* loopTok, ErrorPath errorPath) { const std::string method = tok ? tok->str() : "erase"; errorPath.emplace_back(loopTok, "Iterating container here."); @@ -1252,7 +1257,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 ValueFlow::Value *val, ErrorPath errorPath) +void CheckStlImpl::invalidContainerError(const Token *tok, const ValueFlow::Value *val, ErrorPath errorPath) { const bool inconclusive = val ? val->isInconclusive() : false; if (val) @@ -1262,7 +1267,7 @@ void CheckStl::invalidContainerError(const Token *tok, const ValueFlow::Value *v reportError(std::move(errorPath), Severity::error, "invalidContainer", msg + " that may be invalid.", CWE664, inconclusive ? Certainty::inconclusive : Certainty::normal); } -void CheckStl::invalidContainerReferenceError(const Token* tok, const Token* contTok, ErrorPath errorPath) +void CheckStlImpl::invalidContainerReferenceError(const Token* tok, const Token* contTok, ErrorPath errorPath) { std::string name = contTok ? contTok->expressionString() : "x"; std::string msg = "Reference to " + name; @@ -1270,7 +1275,7 @@ void CheckStl::invalidContainerReferenceError(const Token* tok, const Token* con reportError(std::move(errorPath), Severity::error, "invalidContainerReference", msg + " that may be invalid.", CWE664, Certainty::normal); } -void CheckStl::stlOutOfBounds() +void CheckStlImpl::stlOutOfBounds() { logChecker("CheckStl::stlOutOfBounds"); @@ -1356,7 +1361,7 @@ void CheckStl::stlOutOfBounds() } } -void CheckStl::stlOutOfBoundsError(const Token *tok, const std::string &num, const std::string &var, bool at) +void CheckStlImpl::stlOutOfBoundsError(const Token *tok, const std::string &num, const std::string &var, bool at) { if (at) reportError(tok, Severity::error, "stlOutOfBounds", "$symbol:" + var + "\nWhen " + num + "==$symbol.size(), $symbol.at(" + num + ") is out of bounds.", CWE788, Certainty::normal); @@ -1364,7 +1369,7 @@ void CheckStl::stlOutOfBoundsError(const Token *tok, const std::string &num, con reportError(tok, Severity::error, "stlOutOfBounds", "$symbol:" + var + "\nWhen " + num + "==$symbol.size(), $symbol[" + num + "] is out of bounds.", CWE788, Certainty::normal); } -void CheckStl::negativeIndex() +void CheckStlImpl::negativeIndex() { logChecker("CheckStl::negativeIndex"); @@ -1377,10 +1382,10 @@ void CheckStl::negativeIndex() const Variable * const var = tok->variable(); if (!var || tok == var->nameToken()) continue; - const Library::Container * const container = mSettings->library.detectContainer(var->typeStartToken()); + const Library::Container * const container = mSettings.library.detectContainer(var->typeStartToken()); if (!container || !container->arrayLike_indexOp) continue; - const ValueFlow::Value *index = tok->next()->astOperand2()->getValueLE(-1, *mSettings); + const ValueFlow::Value *index = tok->next()->astOperand2()->getValueLE(-1, mSettings); if (!index) continue; negativeIndexError(tok, *index); @@ -1388,7 +1393,7 @@ void CheckStl::negativeIndex() } } -void CheckStl::negativeIndexError(const Token *tok, const ValueFlow::Value &index) +void CheckStlImpl::negativeIndexError(const Token *tok, const ValueFlow::Value &index) { ErrorPath errorPath = getErrorPath(tok, &index, "Negative array index"); std::ostringstream errmsg; @@ -1402,7 +1407,7 @@ void CheckStl::negativeIndexError(const Token *tok, const ValueFlow::Value &inde reportError(std::move(errorPath), severity, "negativeContainerIndex", errmsg.str(), CWE786, certainty); } -void CheckStl::erase() +void CheckStlImpl::erase() { logChecker("CheckStl::erase"); @@ -1423,7 +1428,7 @@ void CheckStl::erase() } } -void CheckStl::eraseCheckLoopVar(const Scope &scope, const Variable *var) +void CheckStlImpl::eraseCheckLoopVar(const Scope &scope, const Variable *var) { bool inconclusiveType=false; if (!isIterator(var, inconclusiveType)) @@ -1439,7 +1444,7 @@ void CheckStl::eraseCheckLoopVar(const Scope &scope, const Variable *var) if (Token::Match(tok->astParent(), "=|return")) continue; // Iterator is invalid.. - int indentlevel = 0U; + int indentlevel = 0; const Token *tok2 = tok->link(); for (; tok2 != scope.bodyEnd; tok2 = tok2->next()) { if (tok2->str() == "{") { @@ -1447,7 +1452,7 @@ void CheckStl::eraseCheckLoopVar(const Scope &scope, const Variable *var) continue; } if (tok2->str() == "}") { - if (indentlevel > 0U) + if (indentlevel > 0) --indentlevel; else if (Token::simpleMatch(tok2, "} else {")) tok2 = tok2->linkAt(2); @@ -1467,7 +1472,7 @@ void CheckStl::eraseCheckLoopVar(const Scope &scope, const Variable *var) } } -void CheckStl::stlBoundaries() +void CheckStlImpl::stlBoundaries() { logChecker("CheckStl::stlBoundaries"); @@ -1476,7 +1481,7 @@ void CheckStl::stlBoundaries() if (!var || !var->scope() || !var->scope()->isExecutable()) continue; - const Library::Container* container = mSettings->library.detectIterator(var->typeStartToken()); + const Library::Container* container = mSettings.library.detectIterator(var->typeStartToken()); if (!container || container->opLessAllowed) continue; @@ -1492,7 +1497,7 @@ void CheckStl::stlBoundaries() } // Error message for bad boundary usage.. -void CheckStl::stlBoundariesError(const Token *tok) +void CheckStlImpl::stlBoundariesError(const Token *tok) { reportError(tok, Severity::error, "stlBoundaries", "Dangerous comparison using operator< on iterator.\n" @@ -1521,10 +1526,10 @@ static bool if_findCompare(const Token * const tokBack, bool stdStringLike) return false; } -void CheckStl::if_find() +void CheckStlImpl::if_find() { - const bool printWarning = mSettings->severity.isEnabled(Severity::warning); - const bool printPerformance = mSettings->severity.isEnabled(Severity::performance); + const bool printWarning = mSettings.severity.isEnabled(Severity::warning); + const bool printPerformance = mSettings.severity.isEnabled(Severity::performance); if (!printWarning && !printPerformance) return; @@ -1548,7 +1553,7 @@ void CheckStl::if_find() tok = tok->linkAt(1); else if (tok->variable() && Token::Match(tok, "%var% . %name% (")) { - container = mSettings->library.detectContainer(tok->variable()->typeStartToken()); + container = mSettings.library.detectContainer(tok->variable()->typeStartToken()); funcTok = tok->tokAt(2); } @@ -1562,16 +1567,16 @@ void CheckStl::if_find() funcTok = tok2->astParent()->next(); if (tok->variable()->isArrayOrPointer()) - container = mSettings->library.detectContainer(tok->variable()->typeStartToken()); + container = mSettings.library.detectContainer(tok->variable()->typeStartToken()); else { // Container of container - find the inner container - container = mSettings->library.detectContainer(tok->variable()->typeStartToken()); // outer container + container = mSettings.library.detectContainer(tok->variable()->typeStartToken()); // outer container tok2 = Token::findsimplematch(tok->variable()->typeStartToken(), "<", tok->variable()->typeEndToken()); if (container && container->type_templateArgNo >= 0 && tok2) { tok2 = tok2->next(); for (int j = 0; j < container->type_templateArgNo; j++) tok2 = tok2->nextTemplateArgument(); - container = mSettings->library.detectContainer(tok2); // inner container + container = mSettings.library.detectContainer(tok2); // inner container } else container = nullptr; } @@ -1598,9 +1603,9 @@ void CheckStl::if_find() } -void CheckStl::if_findError(const Token *tok, bool str) +void CheckStlImpl::if_findError(const Token *tok, bool str) { - if (str && mSettings->standards.cpp >= Standards::CPP20) + if (str && mSettings.standards.cpp >= Standards::CPP20) reportError(tok, Severity::performance, "stlIfStrFind", "Inefficient usage of string::find() in condition; string::starts_with() could be faster.\n" "Either inefficient or wrong usage of string::find(). string::starts_with() will be faster if " @@ -1689,9 +1694,9 @@ static const Token *findInsertValue(const Token *tok, const Token *containerTok, return nullptr; } -void CheckStl::checkFindInsert() +void CheckStlImpl::checkFindInsert() { - if (!mSettings->severity.isEnabled(Severity::performance)) + if (!mSettings.severity.isEnabled(Severity::performance)) return; logChecker("CheckStl::checkFindInsert"); // performance @@ -1712,20 +1717,20 @@ void CheckStl::checkFindInsert() if (!containerTok) continue; // In < C++17 we only warn for small simple types - if (mSettings->standards.cpp < Standards::CPP17 && !(keyTok && keyTok->valueType() && (keyTok->valueType()->isIntegral() || keyTok->valueType()->pointer > 0))) + if (mSettings.standards.cpp < Standards::CPP17 && !(keyTok && keyTok->valueType() && (keyTok->valueType()->isIntegral() || keyTok->valueType()->pointer > 0))) continue; const Token *thenTok = tok->linkAt(1)->next(); - const Token *valueTok = findInsertValue(thenTok, containerTok, keyTok, *mSettings); + const Token *valueTok = findInsertValue(thenTok, containerTok, keyTok, mSettings); if (!valueTok) continue; if (Token::simpleMatch(thenTok->link(), "} else {")) { const Token *valueTok2 = - findInsertValue(thenTok->link()->tokAt(2), containerTok, keyTok, *mSettings); + findInsertValue(thenTok->link()->tokAt(2), containerTok, keyTok, mSettings); if (!valueTok2) continue; - if (isSameExpression(true, valueTok, valueTok2, *mSettings, true, true)) { + if (isSameExpression(true, valueTok, valueTok2, mSettings, true, true)) { checkFindInsertError(valueTok); } } else { @@ -1735,14 +1740,14 @@ void CheckStl::checkFindInsert() } } -void CheckStl::checkFindInsertError(const Token *tok) +void CheckStlImpl::checkFindInsertError(const Token *tok) { std::string replaceExpr; if (tok && Token::simpleMatch(tok->astParent(), "=") && tok == tok->astParent()->astOperand2() && Token::simpleMatch(tok->astParent()->astOperand1(), "[")) { - if (mSettings->standards.cpp < Standards::CPP11) + if (mSettings.standards.cpp < Standards::CPP11) // We will recommend using emplace/try_emplace instead return; - const std::string f = (mSettings->standards.cpp < Standards::CPP17) ? "emplace" : "try_emplace"; + const std::string f = (mSettings.standards.cpp < Standards::CPP17) ? "emplace" : "try_emplace"; replaceExpr = " Instead of '" + tok->astParent()->expressionString() + "' consider using '" + tok->astParent()->astOperand1()->astOperand1()->expressionString() + "." + f + "(" + @@ -1767,12 +1772,12 @@ static bool isCpp03ContainerSizeSlow(const Token *tok) return var && var->isStlType("list"); } -void CheckStl::size() +void CheckStlImpl::size() { - if (!mSettings->severity.isEnabled(Severity::performance)) + if (!mSettings.severity.isEnabled(Severity::performance)) return; - if (mSettings->standards.cpp >= Standards::CPP11) + if (mSettings.standards.cpp >= Standards::CPP11) return; logChecker("CheckStl::size"); // performance,c++03 @@ -1816,7 +1821,7 @@ void CheckStl::size() } } -void CheckStl::sizeError(const Token *tok) +void CheckStlImpl::sizeError(const Token *tok) { const std::string varname = tok ? tok->str() : std::string("list"); reportError(tok, Severity::performance, "stlSize", @@ -1828,9 +1833,9 @@ void CheckStl::sizeError(const Token *tok) "guaranteed to take constant time.", CWE398, Certainty::normal); } -void CheckStl::redundantCondition() +void CheckStlImpl::redundantCondition() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("redundantIfRemove")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("redundantIfRemove")) return; logChecker("CheckStl::redundantCondition"); // style @@ -1861,7 +1866,7 @@ void CheckStl::redundantCondition() } } -void CheckStl::redundantIfRemoveError(const Token *tok) +void CheckStlImpl::redundantIfRemoveError(const Token *tok) { reportError(tok, Severity::style, "redundantIfRemove", "Redundant checking of STL container element existence before removing it.\n" @@ -1869,9 +1874,9 @@ void CheckStl::redundantIfRemoveError(const Token *tok) "It is safe to call the remove method on a non-existing element.", CWE398, Certainty::normal); } -void CheckStl::missingComparison() +void CheckStlImpl::missingComparison() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckStl::missingComparison"); // warning @@ -1933,7 +1938,7 @@ void CheckStl::missingComparison() } } -void CheckStl::missingComparisonError(const Token *incrementToken1, const Token *incrementToken2) +void CheckStlImpl::missingComparisonError(const Token *incrementToken1, const Token *incrementToken2) { std::list callstack = { incrementToken1,incrementToken2 }; @@ -2029,10 +2034,10 @@ namespace { }; } -void CheckStl::string_c_str() +void CheckStlImpl::string_c_str() { - const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive); - const bool printPerformance = mSettings->severity.isEnabled(Severity::performance); + const bool printInconclusive = mSettings.certainty.isEnabled(Certainty::inconclusive); + const bool printPerformance = mSettings.severity.isEnabled(Severity::performance); const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -2225,25 +2230,25 @@ void CheckStl::string_c_str() } } -void CheckStl::string_c_strThrowError(const Token* tok) +void CheckStlImpl::string_c_strThrowError(const Token* tok) { reportError(tok, Severity::error, "stlcstrthrow", "Dangerous usage of c_str(). The value returned by c_str() is invalid after throwing exception.\n" "Dangerous usage of c_str(). The string is destroyed after the c_str() call so the thrown pointer is invalid."); } -void CheckStl::string_c_strError(const Token* tok) +void CheckStlImpl::string_c_strError(const Token* tok) { reportError(tok, Severity::error, "stlcstr", "Dangerous usage of c_str(). The value returned by c_str() is invalid after this call.\n" "Dangerous usage of c_str(). The c_str() return value is only valid until its string is deleted.", CWE664, Certainty::normal); } -void CheckStl::string_c_strReturn(const Token* tok) +void CheckStlImpl::string_c_strReturn(const Token* tok) { reportError(tok, Severity::performance, "stlcstrReturn", "Returning the result of c_str() in a function that returns std::string is slow and redundant.\n" "The conversion from const char* as returned by c_str() to std::string creates an unnecessary string copy. Solve that by directly returning the string.", CWE704, Certainty::normal); } -void CheckStl::string_c_strParam(const Token* tok, nonneg int number, const std::string& argtype) +void CheckStlImpl::string_c_strParam(const Token* tok, nonneg int number, const std::string& argtype) { std::ostringstream oss; oss << "Passing the result of c_str() to a function that takes " << argtype << " as argument no. " << number << " is slow and redundant.\n" @@ -2251,28 +2256,28 @@ void CheckStl::string_c_strParam(const Token* tok, nonneg int number, const std: reportError(tok, Severity::performance, "stlcstrParam", oss.str(), CWE704, Certainty::normal); } -void CheckStl::string_c_strConstructor(const Token* tok, const std::string& argtype) +void CheckStlImpl::string_c_strConstructor(const Token* tok, const std::string& argtype) { std::string msg = "Constructing a " + argtype + " from the result of c_str() is slow and redundant.\n" "Constructing a " + argtype + " from const char* requires a call to strlen(). Solve that by directly passing the string."; reportError(tok, Severity::performance, "stlcstrConstructor", msg, CWE704, Certainty::normal); } -void CheckStl::string_c_strAssignment(const Token* tok, const std::string& argtype) +void CheckStlImpl::string_c_strAssignment(const Token* tok, const std::string& argtype) { std::string msg = "Assigning the result of c_str() to a " + argtype + " is slow and redundant.\n" "Assigning a const char* to a " + argtype + " requires a call to strlen(). Solve that by directly assigning the string."; reportError(tok, Severity::performance, "stlcstrAssignment", msg, CWE704, Certainty::normal); } -void CheckStl::string_c_strConcat(const Token* tok) +void CheckStlImpl::string_c_strConcat(const Token* tok) { std::string msg = "Concatenating the result of c_str() and a std::string is slow and redundant.\n" "Concatenating a const char* with a std::string requires a call to strlen(). Solve that by directly concatenating the strings."; reportError(tok, Severity::performance, "stlcstrConcat", msg, CWE704, Certainty::normal); } -void CheckStl::string_c_strStream(const Token* tok) +void CheckStlImpl::string_c_strStream(const Token* tok) { std::string msg = "Passing the result of c_str() to a stream is slow and redundant.\n" "Passing a const char* to a stream requires a call to strlen(). Solve that by directly passing the string."; @@ -2293,10 +2298,10 @@ namespace { } -void CheckStl::uselessCalls() +void CheckStlImpl::uselessCalls() { - const bool printPerformance = mSettings->severity.isEnabled(Severity::performance); - const bool printWarning = mSettings->severity.isEnabled(Severity::warning); + const bool printPerformance = mSettings.severity.isEnabled(Severity::performance); + const bool printWarning = mSettings.severity.isEnabled(Severity::warning); if (!printPerformance && !printWarning) return; @@ -2333,7 +2338,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()) @@ -2354,7 +2359,7 @@ void CheckStl::uselessCalls() } -void CheckStl::uselessCallsReturnValueError(const Token *tok, const std::string &varname, const std::string &function) +void CheckStlImpl::uselessCallsReturnValueError(const Token *tok, const std::string &varname, const std::string &function) { std::ostringstream errmsg; errmsg << "$symbol:" << varname << '\n'; @@ -2367,7 +2372,7 @@ void CheckStl::uselessCallsReturnValueError(const Token *tok, const std::string reportError(tok, Severity::warning, "uselessCallsCompare", errmsg.str(), CWE628, Certainty::normal); } -void CheckStl::uselessCallsSwapError(const Token *tok, const std::string &varname) +void CheckStlImpl::uselessCallsSwapError(const Token *tok, const std::string &varname) { reportError(tok, Severity::performance, "uselessCallsSwap", "$symbol:" + varname + "\n" @@ -2377,7 +2382,7 @@ void CheckStl::uselessCallsSwapError(const Token *tok, const std::string &varnam "code is inefficient. Is the object or the parameter wrong here?", CWE628, Certainty::normal); } -void CheckStl::uselessCallsSubstrError(const Token *tok, SubstrErrorType type) +void CheckStlImpl::uselessCallsSubstrError(const Token *tok, SubstrErrorType type) { std::string msg = "Ineffective call of function 'substr' because "; switch (type) { @@ -2397,19 +2402,19 @@ void CheckStl::uselessCallsSubstrError(const Token *tok, SubstrErrorType type) reportError(tok, Severity::performance, "uselessCallsSubstr", msg, CWE398, Certainty::normal); } -void CheckStl::uselessCallsConstructorError(const Token *tok) +void CheckStlImpl::uselessCallsConstructorError(const Token *tok) { const std::string container = tok ? tok->str() : ""; const std::string msg = "Inefficient constructor call: container '" + container + "' is assigned a partial copy of itself. Use erase() or resize() instead."; reportError(tok, Severity::performance, "uselessCallsConstructor", msg, CWE398, Certainty::normal); } -void CheckStl::uselessCallsEmptyError(const Token *tok) +void CheckStlImpl::uselessCallsEmptyError(const Token *tok) { reportError(tok, Severity::warning, "uselessCallsEmpty", "Ineffective call of function 'empty()'. Did you intend to call 'clear()' instead?", CWE398, Certainty::normal); } -void CheckStl::uselessCallsRemoveError(const Token *tok, const std::string& function) +void CheckStlImpl::uselessCallsRemoveError(const Token *tok, const std::string& function) { reportError(tok, Severity::warning, "uselessCallsRemove", "$symbol:" + function + "\n" @@ -2420,9 +2425,9 @@ void CheckStl::uselessCallsRemoveError(const Token *tok, const std::string& func // Check for iterators being dereferenced before being checked for validity. // E.g. if (*i && i != str.end()) { } -void CheckStl::checkDereferenceInvalidIterator() +void CheckStlImpl::checkDereferenceInvalidIterator() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckStl::checkDereferenceInvalidIterator"); // warning @@ -2484,10 +2489,8 @@ void CheckStl::checkDereferenceInvalidIterator() } -void CheckStl::checkDereferenceInvalidIterator2() +void CheckStlImpl::checkDereferenceInvalidIterator2() { - const bool printInconclusive = (mSettings->certainty.isEnabled(Certainty::inconclusive)); - logChecker("CheckStl::checkDereferenceInvalidIterator2"); for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) { @@ -2500,20 +2503,16 @@ void CheckStl::checkDereferenceInvalidIterator2() continue; std::vector contValues; - std::copy_if(tok->values().cbegin(), tok->values().cend(), std::back_inserter(contValues), [&](const ValueFlow::Value& value) { - if (value.isImpossible()) - return false; - if (!printInconclusive && value.isInconclusive()) - return false; - return value.isContainerSizeValue(); + std::copy_if(tok->values().cbegin(), + tok->values().cend(), + std::back_inserter(contValues), + [&](const ValueFlow::Value& value) { + return isUsableValue(value, mSettings) && value.isContainerSizeValue(); }); - // Can iterator point to END or before START? for (const ValueFlow::Value& value:tok->values()) { - if (value.isImpossible()) - continue; - if (!printInconclusive && value.isInconclusive()) + if (!isUsableValue(value, mSettings)) continue; if (!value.isIteratorValue()) continue; @@ -2556,7 +2555,7 @@ void CheckStl::checkDereferenceInvalidIterator2() emptyAdvance = tok->astParent(); } } - if (!CheckNullPointer::isPointerDeRef(tok, unknown, *mSettings) && !isInvalidIterator && !emptyAdvance) { + if (!CheckNullPointerImpl::isPointerDeRef(tok, unknown, mSettings.library) && !isInvalidIterator && !emptyAdvance) { if (!unknown) continue; inconclusive = true; @@ -2580,7 +2579,7 @@ void CheckStl::checkDereferenceInvalidIterator2() } } -void CheckStl::dereferenceInvalidIteratorError(const Token* tok, const ValueFlow::Value *value, bool inconclusive) +void CheckStlImpl::dereferenceInvalidIteratorError(const Token* tok, const ValueFlow::Value *value, bool inconclusive) { const std::string& varname = tok ? tok->expressionString() : "var"; const std::string errmsgcond("$symbol:" + varname + '\n' + ValueFlow::eitherTheConditionIsRedundant(value ? value->condition : nullptr) + " or there is possible dereference of an invalid iterator: $symbol."); @@ -2589,7 +2588,7 @@ void CheckStl::dereferenceInvalidIteratorError(const Token* tok, const ValueFlow reportError(tok, Severity::warning, "derefInvalidIteratorRedundantCheck", errmsgcond, CWE825, Certainty::normal); return; } - if (!mSettings->isEnabled(value, inconclusive)) + if (!mSettings.isEnabled(value, inconclusive)) return; ErrorPath errorPath = getErrorPath(tok, value, "Dereference of an invalid iterator"); @@ -2609,7 +2608,7 @@ void CheckStl::dereferenceInvalidIteratorError(const Token* tok, const ValueFlow } } -void CheckStl::dereferenceInvalidIteratorError(const Token* deref, const std::string &iterName) +void CheckStlImpl::dereferenceInvalidIteratorError(const Token* deref, const std::string &iterName) { reportError(deref, Severity::warning, "derefInvalidIterator", @@ -2618,7 +2617,7 @@ void CheckStl::dereferenceInvalidIteratorError(const Token* deref, const std::st "Possible dereference of an invalid iterator: $symbol. Make sure to check that the iterator is valid before dereferencing it - not after.", CWE825, Certainty::normal); } -void CheckStl::useStlAlgorithmError(const Token *tok, const std::string &algoName) +void CheckStlImpl::useStlAlgorithmError(const Token *tok, const std::string &algoName) { reportError(tok, Severity::style, "useStlAlgorithm", "Consider using " + algoName + " algorithm instead of a raw loop.", CWE398, Certainty::normal); @@ -2873,26 +2872,25 @@ static bool isTernaryAssignment(const Token* assignTok, nonneg int loopVarId, no namespace { struct LoopAnalyzer { - const Token* bodyTok = nullptr; - const Token* loopVar = nullptr; - const Settings* settings = nullptr; - std::set varsChanged; - - explicit LoopAnalyzer(const Token* tok, const Settings* psettings) - : bodyTok(tok->linkAt(1)->next()), settings(psettings) + private: + const Token* mBodyTok; + const Token* mLoopVar{}; + const Settings& mSettings; + std::set mVarsChanged; + + public: + explicit LoopAnalyzer(const Token* tok, const Settings& settings) + : mBodyTok(tok->linkAt(1)->next()), mSettings(settings) { const Token* splitTok = tok->next()->astOperand2(); if (Token::simpleMatch(splitTok, ":") && splitTok->previous()->varId() != 0) { - loopVar = splitTok->previous(); + mLoopVar = splitTok->previous(); } if (valid()) { findChangedVariables(); } } - bool isLoopVarChanged() const { - return varsChanged.count(loopVar->varId()) > 0; - } - + private: bool isModified(const Token* tok) const { if (tok->variable() && tok->variable()->isConst()) @@ -2900,11 +2898,11 @@ namespace { int n = 1 + (astIsPointer(tok) ? 1 : 0); for (int i = 0; i < n; i++) { bool inconclusive = false; - if (isVariableChangedByFunctionCall(tok, i, *settings, &inconclusive)) + if (isVariableChangedByFunctionCall(tok, i, mSettings.library, &inconclusive)) return true; if (inconclusive) return true; - if (isVariableChanged(tok, i, *settings)) + if (isVariableChanged(tok, i, mSettings)) return true; } return false; @@ -2913,7 +2911,7 @@ namespace { template void findTokens(Predicate pred, F f) const { - for (const Token* tok = bodyTok; precedes(tok, bodyTok->link()); tok = tok->next()) { + for (const Token* tok = mBodyTok; precedes(tok, mBodyTok->link()); tok = tok->next()) { if (pred(tok)) f(tok); } @@ -2922,7 +2920,7 @@ namespace { template const Token* findToken(Predicate pred) const { - for (const Token* tok = bodyTok; precedes(tok, bodyTok->link()); tok = tok->next()) { + for (const Token* tok = mBodyTok; precedes(tok, mBodyTok->link()); tok = tok->next()) { if (pred(tok)) return tok; } @@ -2937,58 +2935,56 @@ namespace { } bool valid() const { - return bodyTok && loopVar; + return mBodyTok && mLoopVar; } + public: std::string findAlgo() const { if (!valid()) return ""; - bool loopVarChanged = isLoopVarChanged(); - if (!loopVarChanged && varsChanged.empty()) { - if (hasGotoOrBreak()) - return ""; - bool alwaysTrue = true; - bool alwaysFalse = true; - auto hasReturn = [](const Token* tok) { - return Token::simpleMatch(tok, "return"); - }; - findTokens(hasReturn, [&](const Token* tok) { - const Token* returnTok = tok->astOperand1(); - if (!returnTok || !returnTok->hasKnownIntValue() || !astIsBool(returnTok)) { - alwaysTrue = false; - alwaysFalse = false; - return; - } - (returnTok->getKnownIntValue() ? alwaysTrue : alwaysFalse) &= true; - (returnTok->getKnownIntValue() ? alwaysFalse : alwaysTrue) &= false; - }); - if (alwaysTrue == alwaysFalse) - return ""; - if (alwaysTrue) - return "std::any_of"; - return "std::all_of or std::none_of"; - } - return ""; + if (!mVarsChanged.empty()) + return ""; + if (hasGotoOrBreak()) + return ""; + bool alwaysTrue = true; + bool alwaysFalse = true; + const auto hasReturn = [](const Token* tok) { + return Token::simpleMatch(tok, "return"); + }; + findTokens(hasReturn, [&](const Token* tok) { + const Token* returnTok = tok->astOperand1(); + if (!returnTok || !returnTok->hasKnownIntValue() || !astIsBool(returnTok)) { + alwaysTrue = false; + alwaysFalse = false; + return; + } + (returnTok->getKnownIntValue() ? alwaysTrue : alwaysFalse) &= true; + (returnTok->getKnownIntValue() ? alwaysFalse : alwaysTrue) &= false; + }); + if (alwaysTrue == alwaysFalse) + return ""; + if (alwaysTrue) + return "std::any_of"; + return "std::all_of or std::none_of"; } - + private: bool isLocalVar(const Variable* var) const { if (!var) return false; if (var->isPointer() || var->isReference()) return false; - if (var->declarationId() == loopVar->varId()) + if (var->declarationId() == mLoopVar->varId()) return false; const Scope* scope = var->scope(); - return scope && scope->isNestedIn(bodyTok->scope()); + return scope && scope->isNestedIn(mBodyTok->scope()); } - private: void findChangedVariables() { std::set vars; - for (const Token* tok = bodyTok; precedes(tok, bodyTok->link()); tok = tok->next()) { + for (const Token* tok = mBodyTok; precedes(tok, mBodyTok->link()); tok = tok->next()) { if (tok->varId() == 0) continue; if (vars.count(tok->varId()) > 0) @@ -2999,16 +2995,16 @@ namespace { } if (!isModified(tok)) continue; - varsChanged.insert(tok->varId()); + mVarsChanged.insert(tok->varId()); vars.insert(tok->varId()); } } }; } // namespace -void CheckStl::useStlAlgorithm() +void CheckStlImpl::useStlAlgorithm() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("useStlAlgorithm")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("useStlAlgorithm")) return; logChecker("CheckStl::useStlAlgorithm"); // style @@ -3024,7 +3020,7 @@ void CheckStl::useStlAlgorithm() if (!Token::simpleMatch(tok, "{") || !Token::simpleMatch(tok->previous(), ")")) return false; const Token* condTok = tok->linkAt(-1)->astOperand2(); - if (isConstExpression(condTok, mSettings->library)) { + if (isConstExpression(condTok, mSettings.library)) { if (condTok->str() == "<") type = ConditionOpType::MIN; else if (condTok->str() == ">") @@ -3088,7 +3084,7 @@ void CheckStl::useStlAlgorithm() // Check for single assignment bool useLoopVarInAssign{}, hasBreak{}; - const Token *assignTok = singleAssignInScope(bodyTok, loopVar->varId(), useLoopVarInAssign, hasBreak, loopType, *mSettings); + const Token *assignTok = singleAssignInScope(bodyTok, loopVar->varId(), useLoopVarInAssign, hasBreak, loopType, mSettings); if (assignTok) { if (!checkAssignee(assignTok->astOperand1())) continue; @@ -3120,21 +3116,20 @@ void CheckStl::useStlAlgorithm() } // Check for container calls bool useLoopVarInMemCall; - const Token *memberAccessTok = singleMemberCallInScope(bodyTok, loopVar->varId(), useLoopVarInMemCall, *mSettings); + const Token *memberAccessTok = singleMemberCallInScope(bodyTok, loopVar->varId(), useLoopVarInMemCall, mSettings); if (memberAccessTok && loopType == LoopType::RANGE) { - const Token *memberCallTok = memberAccessTok->astOperand2(); const int contVarId = memberAccessTok->astOperand1()->varId(); if (contVarId == loopVar->varId()) continue; - if (memberCallTok->str() == "push_back" || - memberCallTok->str() == "push_front" || - memberCallTok->str() == "emplace_back") { + using Action = Library::Container::Action; + const auto action = astContainerAction(memberAccessTok->astOperand1(), mSettings.library); + if (contains({Action::PUSH, Action::INSERT}, action)) { std::string algo; if (useLoopVarInMemCall) algo = "std::copy"; else algo = "std::transform"; - useStlAlgorithmError(memberCallTok, algo); + useStlAlgorithmError(memberAccessTok->astOperand2(), algo); } continue; } @@ -3153,10 +3148,10 @@ void CheckStl::useStlAlgorithm() } // Check for conditionals - const Token *condBodyTok = singleConditionalInScope(bodyTok, loopVar->varId(), loopType, *mSettings); + const Token *condBodyTok = singleConditionalInScope(bodyTok, loopVar->varId(), loopType, mSettings); if (condBodyTok) { // Check for single assign - assignTok = singleAssignInScope(condBodyTok, loopVar->varId(), useLoopVarInAssign, hasBreak, loopType, *mSettings); + assignTok = singleAssignInScope(condBodyTok, loopVar->varId(), useLoopVarInAssign, hasBreak, loopType, mSettings); if (assignTok) { if (!checkAssignee(assignTok->astOperand1())) continue; @@ -3197,7 +3192,7 @@ void CheckStl::useStlAlgorithm() } // Check for container call - memberAccessTok = singleMemberCallInScope(condBodyTok, loopVar->varId(), useLoopVarInMemCall, *mSettings); + memberAccessTok = singleMemberCallInScope(condBodyTok, loopVar->varId(), useLoopVarInMemCall, mSettings); if (memberAccessTok) { const Token *memberCallTok = memberAccessTok->astOperand2(); const int contVarId = memberAccessTok->astOperand1()->varId(); @@ -3242,7 +3237,7 @@ void CheckStl::useStlAlgorithm() } } -void CheckStl::knownEmptyContainerError(const Token *tok, const std::string& algo) +void CheckStlImpl::knownEmptyContainerError(const Token *tok, const std::string& algo) { const std::string var = tok ? tok->expressionString() : std::string("var"); @@ -3273,9 +3268,9 @@ static bool isKnownEmptyContainer(const Token* tok) }); } -void CheckStl::knownEmptyContainer() +void CheckStlImpl::knownEmptyContainer() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("knownEmptyContainer")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("knownEmptyContainer")) return; logChecker("CheckStl::knownEmptyContainer"); // style for (const Scope *function : mTokenizer->getSymbolDatabase()->functionScopes) { @@ -3300,8 +3295,8 @@ void CheckStl::knownEmptyContainer() if (args.empty()) continue; - for (int argnr = 1; argnr <= args.size(); ++argnr) { - const Library::ArgumentChecks::IteratorInfo *i = mSettings->library.getArgIteratorInfo(tok, argnr); + for (size_t argnr = 1; argnr <= args.size(); ++argnr) { + const Library::ArgumentChecks::IteratorInfo *i = mSettings.library.getArgIteratorInfo(tok, argnr); if (!i) continue; const Token * const argTok = args[argnr - 1]; @@ -3316,7 +3311,7 @@ void CheckStl::knownEmptyContainer() } } -void CheckStl::eraseIteratorOutOfBoundsError(const Token *ftok, const Token* itertok, const ValueFlow::Value* val) +void CheckStlImpl::eraseIteratorOutOfBoundsError(const Token *ftok, const Token* itertok, const ValueFlow::Value* val) { if (!ftok || !itertok || !val) { reportError(ftok, Severity::error, "eraseIteratorOutOfBounds", @@ -3361,7 +3356,7 @@ static const ValueFlow::Value* getOOBIterValue(const Token* tok, const ValueFlow return it != tok->values().end() ? &*it : nullptr; } -void CheckStl::eraseIteratorOutOfBounds() +void CheckStlImpl::eraseIteratorOutOfBounds() { logChecker("CheckStl::eraseIteratorOutOfBounds"); for (const Scope *function : mTokenizer->getSymbolDatabase()->functionScopes) { @@ -3387,6 +3382,378 @@ void CheckStl::eraseIteratorOutOfBounds() } } +namespace { +// An iterator position described by the ValueFlow values attached to the iterator expression + struct IteratorPosition { + const ValueFlow::Value* value = nullptr; // ITERATOR_START or ITERATOR_END value + const ValueFlow::Value* sizeValue = nullptr; // container size value with the same path, if available + bool fromEnd() const { + return value->isIteratorEndValue(); + } + explicit operator bool() const { + return value != nullptr; + } + }; + +// A number of elements together with the ValueFlow values it was derived from + struct ElementCount { + MathLib::bigint count = 0; + std::vector values; + explicit operator bool() const { + return !values.empty(); + } + }; + +// The best candidate proving an out of bounds access, preferring proofs without possible values + struct BestCandidate { + ElementCount best; + bool certain = false; + void consider(const ElementCount& candidate) + { + const bool candidateCertain = + std::none_of(candidate.values.cbegin(), candidate.values.cend(), std::mem_fn(&ValueFlow::Value::isPossible)); + if (best && (certain || !candidateCertain)) + return; + best = candidate; + certain = candidateCertain; + } + }; +} // namespace + +// Get the first ValueFlow value of a token matching the predicate, preferring known values +template +static const ValueFlow::Value* selectPreferredValue(const Token* tok, const Predicate& pred) +{ + const ValueFlow::Value* result = nullptr; + for (const ValueFlow::Value& value : tok->values()) { + if (!pred(value)) + continue; + if (result && !(value.isKnown() && !result->isKnown())) + continue; + result = &value; + } + return result; +} + +// Get the iterator value of an iterator expression together with the container size value that +// ValueFlow has added to the iterator +static IteratorPosition getIteratorPosition(const Token* tok, const Settings& settings) +{ + IteratorPosition position; + if (!tok) + return position; + position.value = selectPreferredValue(tok, [&](const ValueFlow::Value& value) { + return isUsableValue(value, settings) && value.isIteratorValue(); + }); + if (!position.value) + return position; + position.sizeValue = selectPreferredValue(tok, [&](const ValueFlow::Value& value) { + return isUsableValue(value, settings) && value.isContainerSizeValue() && value.path == position.value->path; + }); + return position; +} + +// Compute the distance last-first between two iterators into the same container +static ElementCount getIteratorDistance(const IteratorPosition& first, const IteratorPosition& last) +{ + ElementCount distance; + if (first.value->path != last.value->path) + return distance; + // bounded values could make the distance an overestimate + if (first.value->bound != ValueFlow::Value::Bound::Point || last.value->bound != ValueFlow::Value::Bound::Point) + return distance; + if (first.fromEnd() == last.fromEnd()) { // the container size cancels out + distance.count = last.value->intvalue - first.value->intvalue; + distance.values = {first.value, last.value}; + return distance; + } + const IteratorPosition& endPosition = first.fromEnd() ? first : last; + if (!endPosition.sizeValue || endPosition.sizeValue->bound != ValueFlow::Value::Bound::Point) + return distance; + const MathLib::bigint endIndex = endPosition.sizeValue->intvalue + endPosition.value->intvalue; + distance.count = last.fromEnd() ? endIndex - first.value->intvalue : last.value->intvalue - endIndex; + distance.values = {first.value, last.value, endPosition.sizeValue}; + return distance; +} + +// Compute the number of elements available in the container behind the iterator position +static ElementCount getAvailableSpace(const IteratorPosition& position) +{ + ElementCount available; + // the position could be smaller, which would make more elements available + if (position.value->bound == ValueFlow::Value::Bound::Upper) + return available; + if (position.fromEnd()) { // the container size cancels out + available.count = -position.value->intvalue; + available.values = {position.value}; + return available; + } + // the container size could be larger, which would make more elements available + if (!position.sizeValue || position.sizeValue->bound == ValueFlow::Value::Bound::Lower) + return available; + available.count = position.sizeValue->intvalue - position.value->intvalue; + available.values = {position.value, position.sizeValue}; + return available; +} + +// Find iterator values and paired container sizes of the iterator that prove accessing +// elements to be out of bounds, preferring a proof that does not rely on possible values +static ElementCount findInsufficientSpace(const Token* tok, + MathLib::bigint accessed, + MathLib::bigint sourcePath, + const Settings& settings) +{ + BestCandidate insufficient; + if (!tok) + return insufficient.best; + const auto consider = [&](const ElementCount& candidate) { + if (!candidate) + return; + if (candidate.count < 0 || accessed <= candidate.count) + return; // the space is sufficient + insufficient.consider(candidate); + }; + for (const ValueFlow::Value& value : tok->values()) { + if (!isUsableValue(value, settings) || !value.isIteratorValue()) + continue; + if (value.path != 0 && sourcePath != 0 && value.path != sourcePath) + continue; + IteratorPosition position; + position.value = &value; + if (position.fromEnd()) { // the available space does not depend on the container size + consider(getAvailableSpace(position)); + continue; + } + for (const ValueFlow::Value& sizeValue : tok->values()) { + if (!isUsableValue(sizeValue, settings) || !sizeValue.isContainerSizeValue() || sizeValue.path != value.path) + continue; + position.sizeValue = &sizeValue; + consider(getAvailableSpace(position)); + } + } + return insufficient.best; +} + +// Find iterator values and paired container sizes of the source range that prove more than +// elements to be accessed, preferring a proof that does not rely on possible values +static ElementCount findExcessiveDistance(const Token* firstTok, + const Token* lastTok, + MathLib::bigint available, + MathLib::bigint destPath, + const Settings& settings) +{ + BestCandidate excessive; + const auto consider = [&](const ElementCount& candidate) { + if (!candidate) + return; + if (candidate.count <= available) + return; // the access is within bounds + excessive.consider(candidate); + }; + for (const ValueFlow::Value& firstValue : firstTok->values()) { + if (!isUsableValue(firstValue, settings) || !firstValue.isIteratorValue()) + continue; + if (firstValue.path != 0 && destPath != 0 && firstValue.path != destPath) + continue; + for (const ValueFlow::Value& lastValue : lastTok->values()) { + if (!isUsableValue(lastValue, settings) || !lastValue.isIteratorValue()) + continue; + IteratorPosition first, last; + first.value = &firstValue; + last.value = &lastValue; + if (first.fromEnd() == last.fromEnd()) { // the distance does not depend on the container size + consider(getIteratorDistance(first, last)); + continue; + } + IteratorPosition& endPosition = first.fromEnd() ? first : last; + const Token* const endTok = first.fromEnd() ? firstTok : lastTok; + for (const ValueFlow::Value& sizeValue : endTok->values()) { + if (!isUsableValue(sizeValue, settings) || !sizeValue.isContainerSizeValue() || + sizeValue.path != endPosition.value->path) + continue; + endPosition.sizeValue = &sizeValue; + consider(getIteratorDistance(first, last)); + } + } + } + return excessive.best; +} + +// Find count values of a count-based algorithm that prove more than elements to be accessed +static ElementCount findExcessiveCount(const Token* tok, + MathLib::bigint available, + MathLib::bigint destPath, + const Settings& settings) +{ + BestCandidate excessive; + if (!tok) + return excessive.best; + for (const ValueFlow::Value& value : tok->values()) { + if (!isUsableValue(value, settings) || !value.isIntValue()) + continue; + // a count with an upper bound could be smaller, which would make fewer elements accessed + if (value.bound == ValueFlow::Value::Bound::Upper) + continue; + if (value.path != 0 && destPath != 0 && value.path != destPath) + continue; + if (value.intvalue <= available) + continue; // the access is within bounds + ElementCount candidate; + candidate.count = value.intvalue; + candidate.values.push_back(&value); + excessive.consider(candidate); + } + return excessive.best; +} + +// Do not warn when the proof relies on possible values on both sides +static bool bothSidesPossible(const ElementCount& accessed, const ElementCount& available) +{ + const auto isPossible = std::mem_fn(&ValueFlow::Value::isPossible); + return std::any_of(accessed.values.cbegin(), accessed.values.cend(), isPossible) && + std::any_of(available.values.cbegin(), available.values.cend(), isPossible); +} + +// Get the number of accessed elements of a count-based algorithm such as std::fill_n +static const ValueFlow::Value* getCountValue(const Token* tok, const Settings& settings) +{ + if (!tok) + return nullptr; + return selectPreferredValue(tok, [&](const ValueFlow::Value& value) { + // a count with an upper bound could be smaller, which would make fewer elements accessed + return isUsableValue(value, settings) && value.isIntValue() && value.bound != ValueFlow::Value::Bound::Upper; + }); +} + +void CheckStlImpl::algorithmOutOfBounds() +{ + logChecker("CheckStl::algorithmOutOfBounds"); + for (const Scope* function : mTokenizer->getSymbolDatabase()->functionScopes) { + for (const Token* tok = function->bodyStart; tok != function->bodyEnd; tok = tok->next()) { + if (!Token::Match(tok, "std :: %name% (")) + continue; + const Token* const nameTok = tok->tokAt(2); + // algorithms accessing the range denoted by the third argument exactly last1-first1 times.. + const bool exact = Token::Match( + nameTok, + "copy|move|swap_ranges|transform|replace_copy|replace_copy_if|reverse_copy|equal|mismatch|is_permutation|partial_sum|adjacent_difference|inner_product ("); + // ..or at most last1-first1 times, depending on the values in the input range.. + const bool atMost = !exact && Token::Match(nameTok, "copy_if|remove_copy|remove_copy_if|unique_copy ("); + // ..or accessing their iterator arguments as many times as the count argument says + const bool countBased = !exact && !atMost && Token::Match(nameTok, "copy_n|fill_n|generate_n ("); + if (!exact && !atMost && !countBased) + continue; + if (atMost && !mSettings.certainty.isEnabled(Certainty::inconclusive)) + continue; + const std::vector args = getArguments(nameTok); + if (args.size() < 3) + continue; + ElementCount accessed; // source access count using the preferred values + std::vector iterArgs; + if (countBased) { + if (const ValueFlow::Value* countValue = getCountValue(args[1], mSettings)) { + accessed.count = countValue->intvalue; + accessed.values.push_back(countValue); + } + iterArgs.push_back(args[0]); + if (Token::simpleMatch(nameTok, "copy_n")) + iterArgs.push_back(args[2]); // copy_n also writes through the third argument + } else { + // two-range overloads taking a last2 iterator do not access the second range out of bounds + if (Token::Match(nameTok, "equal|mismatch|is_permutation") && args.size() >= 4 && astIsIterator(args[3])) + continue; + // both iterators must refer to the same container + const ValueFlow::Value firstLifetime = getLifetimeIteratorValue(args[0]); + const ValueFlow::Value lastLifetime = getLifetimeIteratorValue(args[1]); + if (!firstLifetime.tokvalue || !lastLifetime.tokvalue) + continue; + if (!isSameIteratorContainerExpression(firstLifetime.tokvalue, + lastLifetime.tokvalue, + mSettings, + firstLifetime.lifetimeKind)) + continue; + const IteratorPosition first = getIteratorPosition(args[0], mSettings); + const IteratorPosition last = getIteratorPosition(args[1], mSettings); + if (first && last) + accessed = getIteratorDistance(first, last); + iterArgs.push_back(args[2]); + if (Token::simpleMatch(nameTok, "transform") && args.size() == 5) + iterArgs.push_back(args[3]); // binary transform also writes through the fourth argument + } + if (accessed.count <= 0) + accessed = ElementCount(); // there is no preferred source access count + for (const Token* const iterArg : iterArgs) { + // check the preferred source access count against all destination values.. + ElementCount sourceCount = accessed; + ElementCount available; + if (sourceCount) + available = + findInsufficientSpace(iterArg, sourceCount.count, sourceCount.values.front()->path, mSettings); + if (!available || bothSidesPossible(sourceCount, available)) { + // ..or all source access counts against the preferred destination values + const IteratorPosition dest = getIteratorPosition(iterArg, mSettings); + if (!dest) + continue; + available = getAvailableSpace(dest); + if (!available || available.count < 0) + continue; + sourceCount = + countBased + ? findExcessiveCount(args[1], available.count, dest.value->path, mSettings) + : findExcessiveDistance(args[0], args[1], available.count, dest.value->path, mSettings); + if (!sourceCount || bothSidesPossible(sourceCount, available)) + continue; + } + const ValueFlow::Value* conditionValue = nullptr; + bool inconclusiveValues = false; + std::vector usedValues = sourceCount.values; + usedValues.insert(usedValues.end(), available.values.cbegin(), available.values.cend()); + for (const ValueFlow::Value* value : usedValues) { + if (!conditionValue && value->condition) + conditionValue = value; + inconclusiveValues |= value->isInconclusive(); + } + if (conditionValue && !mSettings.severity.isEnabled(Severity::warning)) + continue; + const ValueFlow::Value* pathValue = conditionValue ? conditionValue : available.values.back(); + algorithmOutOfBoundsError(iterArg, + "std::" + nameTok->str(), + sourceCount.count, + available.count, + pathValue, + atMost, + atMost || inconclusiveValues); + } + } + } +} + +void CheckStlImpl::algorithmOutOfBoundsError(const Token* tok, + const std::string& algoName, + MathLib::bigint accessed, + MathLib::bigint available, + const ValueFlow::Value* value, + bool mayAccessFewer, + bool inconclusive) +{ + const Token* const condition = value ? value->condition : nullptr; + const std::string iterExpr = tok ? tok->expressionString() : "it"; + const std::string accessedStr = MathLib::toString(accessed) + (accessed == 1 ? " element" : " elements"); + const std::string availableStr = MathLib::toString(available) + (available == 1 ? " element is" : " elements are"); + const std::string body = "algorithm '" + algoName + "' " + (mayAccessFewer ? "may access up to " : "accesses ") + + accessedStr + " through the iterator '" + iterExpr + "' but only " + availableStr + + " available."; + const std::string msg = + condition ? (ValueFlow::eitherTheConditionIsRedundant(condition) + " or the " + body) : ("The " + body); + ErrorPath errorPath = getErrorPath(tok, value, "Access out of bounds"); + reportError(std::move(errorPath), + (condition || mayAccessFewer) ? Severity::warning : Severity::error, + "algorithmOutOfBounds", + msg, + CWE788, + inconclusive ? Certainty::inconclusive : Certainty::normal); +} + static bool isMutex(const Variable* var) { const Token* tok = Token::typeDecl(var->nameToken()).first; @@ -3408,23 +3775,23 @@ static bool isLocalMutex(const Variable* var, const Scope* scope) return !var->isReference() && !var->isRValueReference() && !var->isStatic() && var->scope() == scope; } -void CheckStl::globalLockGuardError(const Token* tok) +void CheckStlImpl::globalLockGuardError(const Token* tok) { reportError(tok, Severity::warning, "globalLockGuard", "Lock guard is defined globally. Lock guards are intended to be local. A global lock guard could lead to a deadlock since it won't unlock until the end of the program.", CWE833, Certainty::normal); } -void CheckStl::localMutexError(const Token* tok) +void CheckStlImpl::localMutexError(const Token* tok) { reportError(tok, Severity::warning, "localMutex", "The lock is ineffective because the mutex is locked at the same scope as the mutex itself.", CWE667, Certainty::normal); } -void CheckStl::checkMutexes() +void CheckStlImpl::checkMutexes() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckStl::checkMutexes"); // warning for (const Scope *function : mTokenizer->getSymbolDatabase()->functionScopes) { @@ -3459,13 +3826,13 @@ void CheckStl::checkMutexes() } } -void CheckStl::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckStl::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { if (!tokenizer.isCPP()) { return; } - CheckStl checkStl(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckStlImpl checkStl(&tokenizer, tokenizer.getSettings(), errorLogger); checkStl.erase(); checkStl.if_find(); checkStl.checkFindInsert(); @@ -3486,6 +3853,7 @@ void CheckStl::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) checkStl.mismatchingContainerIterator(); checkStl.knownEmptyContainer(); checkStl.eraseIteratorOutOfBounds(); + checkStl.algorithmOutOfBounds(); checkStl.stlBoundaries(); checkStl.checkDereferenceInvalidIterator(); @@ -3496,9 +3864,9 @@ void CheckStl::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) checkStl.size(); } -void CheckStl::getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const +void CheckStl::getErrorMessages(ErrorLogger& errorLogger, const Settings& settings) const { - CheckStl c(nullptr, settings, errorLogger); + CheckStlImpl c(nullptr, settings, errorLogger); c.outOfBoundsError(nullptr, "container", nullptr, "x", nullptr); c.invalidIteratorError(nullptr, "iterator"); c.iteratorsError(nullptr, "container1", "container2"); @@ -3530,13 +3898,14 @@ void CheckStl::getErrorMessages(ErrorLogger* errorLogger, const Settings* settin c.redundantIfRemoveError(nullptr); c.uselessCallsReturnValueError(nullptr, "str", "find"); c.uselessCallsSwapError(nullptr, "str"); - c.uselessCallsSubstrError(nullptr, SubstrErrorType::COPY); + c.uselessCallsSubstrError(nullptr, CheckStlImpl::SubstrErrorType::COPY); c.uselessCallsConstructorError(nullptr); c.uselessCallsEmptyError(nullptr); c.uselessCallsRemoveError(nullptr, "remove"); c.dereferenceInvalidIteratorError(nullptr, "i"); // TODO: derefInvalidIteratorRedundantCheck c.eraseIteratorOutOfBoundsError(nullptr, nullptr); + c.algorithmOutOfBoundsError(nullptr, "std::copy", 10, 6, nullptr, false, false); c.useStlAlgorithmError(nullptr, ""); c.knownEmptyContainerError(nullptr, ""); c.globalLockGuardError(nullptr); diff --git a/lib/checkstl.h b/lib/checkstl.h index 03a634f1ed1..0f9a70a7a15 100644 --- a/lib/checkstl.h +++ b/lib/checkstl.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,8 +23,10 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include "errortypes.h" +#include "mathlib.h" #include #include @@ -48,15 +50,43 @@ namespace ValueFlow class CPPCHECKLIB CheckStl : public Check { public: /** This constructor is used when registering the CheckClass */ - CheckStl() : Check(myName()) {} + CheckStl() : Check("STL usage") {} private: - /** This constructor is used when running checks. */ - CheckStl(const Tokenizer* tokenizer, const Settings* settings, ErrorLogger* errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} - /** run checks, the token list is not simplified */ - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + + void getErrorMessages(ErrorLogger& errorLogger, const Settings& settings) const override; + + std::string classInfo() const override { + return "Check for invalid usage of STL:\n" + "- out of bounds errors\n" + "- misuse of iterators when iterating through a container\n" + "- mismatching containers in calls\n" + "- same iterators in calls\n" + "- dereferencing an erased iterator\n" + "- for vectors: using iterator/pointer after push_back has been used\n" + "- optimisation: use empty() instead of size() to guarantee fast code\n" + "- suspicious condition when using find\n" + "- unnecessary searching in associative containers\n" + "- redundant condition\n" + "- common mistakes when using string::c_str()\n" + "- useless calls of string and STL functions\n" + "- dereferencing an invalid iterator\n" + "- erasing an iterator that is out of bounds\n" + "- out of bounds access of an iterator passed to an STL algorithm\n" + "- reading from empty STL container\n" + "- iterating over an empty STL container\n" + "- consider using an STL algorithm instead of raw loop\n" + "- incorrect locking with mutex\n"; + } +}; + +class CPPCHECKLIB CheckStlImpl : public CheckImpl { +public: + /** This constructor is used when running checks. */ + CheckStlImpl(const Tokenizer* tokenizer, const Settings& settings, ErrorLogger& errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} /** Accessing container out of bounds using ValueFlow */ void outOfBounds(); @@ -155,6 +185,12 @@ class CPPCHECKLIB CheckStl : public Check { void eraseIteratorOutOfBounds(); + /** + * Check that the iterator given to an STL algorithm is not accessed + * out of bounds: std::equal(in.begin(), in.end(), out.begin()) + */ + void algorithmOutOfBounds(); + void checkMutexes(); bool isContainerSize(const Token *containerToken, const Token *expr) const; @@ -207,36 +243,16 @@ class CPPCHECKLIB CheckStl : public Check { void eraseIteratorOutOfBoundsError(const Token* ftok, const Token* itertok, const ValueFlow::Value* val = nullptr); + void algorithmOutOfBoundsError(const Token* tok, + const std::string& algoName, + MathLib::bigint accessed, + MathLib::bigint available, + const ValueFlow::Value* value, + bool mayAccessFewer, + bool inconclusive); + void globalLockGuardError(const Token *tok); void localMutexError(const Token *tok); - - void getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const override; - - static std::string myName() { - return "STL usage"; - } - - std::string classInfo() const override { - return "Check for invalid usage of STL:\n" - "- out of bounds errors\n" - "- misuse of iterators when iterating through a container\n" - "- mismatching containers in calls\n" - "- same iterators in calls\n" - "- dereferencing an erased iterator\n" - "- for vectors: using iterator/pointer after push_back has been used\n" - "- optimisation: use empty() instead of size() to guarantee fast code\n" - "- suspicious condition when using find\n" - "- unnecessary searching in associative containers\n" - "- redundant condition\n" - "- common mistakes when using string::c_str()\n" - "- useless calls of string and STL functions\n" - "- dereferencing an invalid iterator\n" - "- erasing an iterator that is out of bounds\n" - "- reading from empty STL container\n" - "- iterating over an empty STL container\n" - "- consider using an STL algorithm instead of raw loop\n" - "- incorrect locking with mutex\n"; - } }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checkstring.cpp b/lib/checkstring.cpp index 64b575df72d..1d391895c3e 100644 --- a/lib/checkstring.cpp +++ b/lib/checkstring.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 @@ //--------------------------------------------------------------------------- -// 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 @@ -52,7 +47,7 @@ static const CWE CWE758(758U); // Reliance on Undefined, Unspecified, or Imple //--------------------------------------------------------------------------- // Writing string literal is UB //--------------------------------------------------------------------------- -void CheckString::stringLiteralWrite() +void CheckStringImpl::stringLiteralWrite() { logChecker("CheckString::stringLiteralWrite"); const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -60,7 +55,7 @@ void CheckString::stringLiteralWrite() for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) { if (!tok->variable() || !tok->variable()->isPointer()) continue; - const Token *str = tok->getValueTokenMinStrSize(*mSettings); + const Token *str = tok->getValueTokenMinStrSize(mSettings); if (!str) continue; if (Token::Match(tok, "%var% [") && Token::simpleMatch(tok->linkAt(1), "] =")) @@ -71,7 +66,7 @@ void CheckString::stringLiteralWrite() } } -void CheckString::stringLiteralWriteError(const Token *tok, const Token *strValue) +void CheckStringImpl::stringLiteralWriteError(const Token *tok, const Token *strValue) { std::list callstack{ tok }; if (strValue) @@ -94,9 +89,9 @@ void CheckString::stringLiteralWriteError(const Token *tok, const Token *strValu // Check for string comparison involving two static strings. // if(strcmp("00FF00","00FF00")==0) // <- statement is always true //--------------------------------------------------------------------------- -void CheckString::checkAlwaysTrueOrFalseStringCompare() +void CheckStringImpl::checkAlwaysTrueOrFalseStringCompare() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckString::checkAlwaysTrueOrFalseStringCompare"); // warning @@ -138,7 +133,7 @@ void CheckString::checkAlwaysTrueOrFalseStringCompare() } } -void CheckString::alwaysTrueFalseStringCompareError(const Token *tok, const std::string& str1, const std::string& str2) +void CheckStringImpl::alwaysTrueFalseStringCompareError(const Token *tok, const std::string& str1, const std::string& str2) { constexpr std::size_t stringLen = 10; const std::string string1 = (str1.size() < stringLen) ? str1 : (str1.substr(0, stringLen-2) + ".."); @@ -150,7 +145,7 @@ void CheckString::alwaysTrueFalseStringCompareError(const Token *tok, const std: "Therefore the comparison is unnecessary and looks suspicious.", (str1==str2)?CWE571:CWE570, Certainty::normal); } -void CheckString::alwaysTrueStringVariableCompareError(const Token *tok, const std::string& str1, const std::string& str2) +void CheckStringImpl::alwaysTrueStringVariableCompareError(const Token *tok, const std::string& str1, const std::string& str2) { reportError(tok, Severity::warning, "stringCompare", "Comparison of identical string variables.\n" @@ -163,9 +158,9 @@ void CheckString::alwaysTrueStringVariableCompareError(const Token *tok, const s // Detect "str == '\0'" where "*str == '\0'" is correct. // Comparing char* with each other instead of using strcmp() //----------------------------------------------------------------------------- -void CheckString::checkSuspiciousStringCompare() +void CheckStringImpl::checkSuspiciousStringCompare() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckString::checkSuspiciousStringCompare"); // warning @@ -202,14 +197,14 @@ void CheckString::checkSuspiciousStringCompare() } } -void CheckString::suspiciousStringCompareError(const Token* tok, const std::string& var, bool isLong) +void CheckStringImpl::suspiciousStringCompareError(const Token* tok, const std::string& var, bool isLong) { const std::string cmpFunc = isLong ? "wcscmp" : "strcmp"; reportError(tok, Severity::warning, "literalWithCharPtrCompare", "$symbol:" + var + "\nString literal compared with variable '$symbol'. Did you intend to use " + cmpFunc + "() instead?", CWE595, Certainty::normal); } -void CheckString::suspiciousStringCompareError_char(const Token* tok, const std::string& var) +void CheckStringImpl::suspiciousStringCompareError_char(const Token* tok, const std::string& var) { reportError(tok, Severity::warning, "charLiteralWithCharPtrCompare", "$symbol:" + var + "\nChar literal compared with pointer '$symbol'. Did you intend to dereference it?", CWE595, Certainty::normal); @@ -225,7 +220,7 @@ static bool isChar(const Variable* var) return (var && !var->isPointer() && !var->isArray() && (var->typeStartToken()->str() == "char" || var->typeStartToken()->str() == "wchar_t")); } -void CheckString::strPlusChar() +void CheckStringImpl::strPlusChar() { logChecker("CheckString::strPlusChar"); const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase(); @@ -241,7 +236,7 @@ void CheckString::strPlusChar() } } -void CheckString::strPlusCharError(const Token *tok) +void CheckStringImpl::strPlusCharError(const Token *tok) { std::string charType = "char"; if (tok && tok->astOperand2() && tok->astOperand2()->variable()) @@ -277,9 +272,9 @@ static bool isMacroUsage(const Token* tok) // Implicit casts of string literals to bool // Comparing string literal with strlen() with wrong length //--------------------------------------------------------------------------- -void CheckString::checkIncorrectStringCompare() +void CheckStringImpl::checkIncorrectStringCompare() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckString::checkIncorrectStringCompare"); // warning @@ -319,19 +314,19 @@ void CheckString::checkIncorrectStringCompare() } } else if (Token::Match(tok, "%str%|%char%") && !Token::Match(tok->next(), "%name%") && - isUsedAsBool(tok, *mSettings) && + isUsedAsBool(tok, mSettings) && !isMacroUsage(tok)) incorrectStringBooleanError(tok, tok->str()); } } } -void CheckString::incorrectStringCompareError(const Token *tok, const std::string& func, const std::string &string) +void CheckStringImpl::incorrectStringCompareError(const Token *tok, const std::string& func, const std::string &string) { reportError(tok, Severity::warning, "incorrectStringCompare", "$symbol:" + func + "\nString literal " + string + " doesn't match length argument for $symbol().", CWE570, Certainty::normal); } -void CheckString::incorrectStringBooleanError(const Token *tok, const std::string& string) +void CheckStringImpl::incorrectStringBooleanError(const Token *tok, const std::string& string) { const bool charLiteral = isCharLiteral(string); const std::string literalType = charLiteral ? "char" : "string"; @@ -346,9 +341,9 @@ void CheckString::incorrectStringBooleanError(const Token *tok, const std::strin // always true: strcmp(str,"a")==0 || strcmp(str,"b") // TODO: Library configuration for string comparison functions //--------------------------------------------------------------------------- -void CheckString::overlappingStrcmp() +void CheckStringImpl::overlappingStrcmp() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckString::overlappingStrcmp"); // warning @@ -400,7 +395,7 @@ void CheckString::overlappingStrcmp() if (args1[1]->isLiteral() && args2[1]->isLiteral() && args1[1]->str() != args2[1]->str() && - isSameExpression(true, args1[0], args2[0], *mSettings, true, false)) + isSameExpression(true, args1[0], args2[0], mSettings, true, false)) overlappingStrcmpError(eq0, ne0); } } @@ -408,7 +403,7 @@ void CheckString::overlappingStrcmp() } } -void CheckString::overlappingStrcmpError(const Token *eq0, const Token *ne0) +void CheckStringImpl::overlappingStrcmpError(const Token *eq0, const Token *ne0) { std::string eq0Expr(eq0 ? eq0->expressionString() : std::string("strcmp(x,\"abc\")")); if (eq0 && eq0->astParent()->str() == "!") @@ -425,7 +420,7 @@ void CheckString::overlappingStrcmpError(const Token *eq0, const Token *ne0) // Overlapping source and destination passed to sprintf(). // TODO: Library configuration for overlapping arguments //--------------------------------------------------------------------------- -void CheckString::sprintfOverlappingData() +void CheckStringImpl::sprintfOverlappingData() { logChecker("CheckString::sprintfOverlappingData"); @@ -451,7 +446,7 @@ void CheckString::sprintfOverlappingData() const bool same = isSameExpression(false, dest, arg, - *mSettings, + mSettings, true, false); if (same) { @@ -462,7 +457,7 @@ void CheckString::sprintfOverlappingData() } } -void CheckString::sprintfOverlappingDataError(const Token *funcTok, const Token *tok, const std::string &varname) +void CheckStringImpl::sprintfOverlappingDataError(const Token *funcTok, const Token *tok, const std::string &varname) { const std::string func = funcTok ? funcTok->str() : "s[n]printf"; @@ -476,9 +471,9 @@ void CheckString::sprintfOverlappingDataError(const Token *funcTok, const Token "to sprintf() or snprintf(), the results are undefined.\"", CWE628, Certainty::normal); } -void CheckString::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckString::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { - CheckString checkString(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckStringImpl checkString(&tokenizer, tokenizer.getSettings(), errorLogger); // Checks checkString.strPlusChar(); @@ -490,9 +485,9 @@ void CheckString::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger checkString.checkAlwaysTrueOrFalseStringCompare(); } -void CheckString::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const +void CheckString::getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const { - CheckString c(nullptr, settings, errorLogger); + CheckStringImpl c(nullptr, settings, errorLogger); c.stringLiteralWriteError(nullptr, nullptr); c.sprintfOverlappingDataError(nullptr, nullptr, "varname"); c.strPlusCharError(nullptr); diff --git a/lib/checkstring.h b/lib/checkstring.h index 76002f8ed3d..1614e4dc7d3 100644 --- a/lib/checkstring.h +++ b/lib/checkstring.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,6 +23,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include @@ -41,15 +42,31 @@ class Tokenizer; class CPPCHECKLIB CheckString : public Check { public: /** @brief This constructor is used when registering the CheckClass */ - CheckString() : Check(myName()) {} + CheckString() : Check("String") {} private: - /** @brief This constructor is used when running checks. */ - CheckString(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} - /** @brief Run checks against the normal token list */ - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; + + std::string classInfo() const override { + return "Detect misusage of C-style strings:\n" + "- overlapping buffers passed to sprintf as source and destination\n" + "- incorrect length arguments for 'substr' and 'strncmp'\n" + "- suspicious condition (runtime comparison of string literals)\n" + "- suspicious condition (string/char literals as boolean)\n" + "- suspicious comparison of a string literal with a char\\* variable\n" + "- suspicious comparison of '\\0' with a char\\* variable\n" + "- overlapping strcmp() expression\n"; + } +}; + +class CPPCHECKLIB CheckStringImpl : public CheckImpl { +public: + /** @brief This constructor is used when running checks. */ + CheckStringImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} /** @brief undefined behaviour, writing string literal */ void stringLiteralWrite(); @@ -82,23 +99,6 @@ class CPPCHECKLIB CheckString : public Check { void suspiciousStringCompareError(const Token* tok, const std::string& var, bool isLong); void suspiciousStringCompareError_char(const Token* tok, const std::string& var); void overlappingStrcmpError(const Token* eq0, const Token *ne0); - - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - static std::string myName() { - return "String"; - } - - std::string classInfo() const override { - return "Detect misusage of C-style strings:\n" - "- overlapping buffers passed to sprintf as source and destination\n" - "- incorrect length arguments for 'substr' and 'strncmp'\n" - "- suspicious condition (runtime comparison of string literals)\n" - "- suspicious condition (string/char literals as boolean)\n" - "- suspicious comparison of a string literal with a char\\* variable\n" - "- suspicious comparison of '\\0' with a char\\* variable\n" - "- overlapping strcmp() expression\n"; - } }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checktype.cpp b/lib/checktype.cpp index 3f42bf075ef..447a8924360 100644 --- a/lib/checktype.cpp +++ b/lib/checktype.cpp @@ -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 //--------------------------------------------------------------------------- @@ -61,10 +56,10 @@ static const CWE CWE758(758U); // Reliance on Undefined, Unspecified, or Imple static const CWE CWE190(190U); // Integer Overflow or Wraparound -void CheckType::checkTooBigBitwiseShift() +void CheckTypeImpl::checkTooBigBitwiseShift() { // unknown sizeof(int) => can't run this checker - if (mSettings->platform.type == Platform::Type::Unspecified) + if (mSettings.platform.type == Platform::Type::Unspecified) return; logChecker("CheckType::checkTooBigBitwiseShift"); // platform @@ -95,27 +90,27 @@ void CheckType::checkTooBigBitwiseShift() (lhstype->type == ValueType::Type::WCHAR_T) || (lhstype->type == ValueType::Type::BOOL) || (lhstype->type == ValueType::Type::INT)) - lhsbits = mSettings->platform.int_bit; + lhsbits = mSettings.platform.int_bit; else if (lhstype->type == ValueType::Type::LONG) - lhsbits = mSettings->platform.long_bit; + lhsbits = mSettings.platform.long_bit; else if (lhstype->type == ValueType::Type::LONGLONG) - lhsbits = mSettings->platform.long_long_bit; + lhsbits = mSettings.platform.long_long_bit; else continue; // Get biggest rhs value. preferably a value which doesn't have 'condition'. - const ValueFlow::Value * value = tok->astOperand2()->getValueGE(lhsbits, *mSettings); - if (value && mSettings->isEnabled(value, false)) + const ValueFlow::Value * value = tok->astOperand2()->getValueGE(lhsbits, mSettings); + if (value && mSettings.isEnabled(value, false)) tooBigBitwiseShiftError(tok, lhsbits, *value); else if (lhstype->sign == ValueType::Sign::SIGNED) { - value = tok->astOperand2()->getValueGE(lhsbits-1, *mSettings); - if (value && mSettings->isEnabled(value, false)) + value = tok->astOperand2()->getValueGE(lhsbits-1, mSettings); + if (value && mSettings.isEnabled(value, false)) tooBigSignedBitwiseShiftError(tok, lhsbits, *value); } } } -void CheckType::tooBigBitwiseShiftError(const Token *tok, int lhsbits, const ValueFlow::Value &rhsbits) +void CheckTypeImpl::tooBigBitwiseShiftError(const Token *tok, int lhsbits, const ValueFlow::Value &rhsbits) { constexpr char id[] = "shiftTooManyBits"; @@ -134,11 +129,11 @@ void CheckType::tooBigBitwiseShiftError(const Token *tok, int lhsbits, const Val reportError(std::move(errorPath), rhsbits.errorSeverity() ? Severity::error : Severity::warning, id, errmsg.str(), CWE758, rhsbits.isInconclusive() ? Certainty::inconclusive : Certainty::normal); } -void CheckType::tooBigSignedBitwiseShiftError(const Token *tok, int lhsbits, const ValueFlow::Value &rhsbits) +void CheckTypeImpl::tooBigSignedBitwiseShiftError(const Token *tok, int lhsbits, const ValueFlow::Value &rhsbits) { constexpr char id[] = "shiftTooManyBitsSigned"; - const bool cpp14 = ((tok && tok->isCpp()) || (mTokenizer && mTokenizer->isCPP())) && (mSettings->standards.cpp >= Standards::CPP14); + const bool cpp14 = ((tok && tok->isCpp()) || (mTokenizer && mTokenizer->isCPP())) && (mSettings.standards.cpp >= Standards::CPP14); std::string behaviour = "undefined"; if (cpp14) @@ -153,7 +148,7 @@ void CheckType::tooBigSignedBitwiseShiftError(const Token *tok, int lhsbits, con if (cpp14) severity = Severity::portability; - if ((severity == Severity::portability) && !mSettings->severity.isEnabled(Severity::portability)) + if ((severity == Severity::portability) && !mSettings.severity.isEnabled(Severity::portability)) return; ErrorPath errorPath = getErrorPath(tok, &rhsbits, "Shift"); @@ -169,10 +164,10 @@ void CheckType::tooBigSignedBitwiseShiftError(const Token *tok, int lhsbits, con // Checking for integer overflow //--------------------------------------------------------------------------- -void CheckType::checkIntegerOverflow() +void CheckTypeImpl::checkIntegerOverflow() { // unknown sizeof(int) => can't run this checker - if (mSettings->platform.type == Platform::Type::Unspecified || mSettings->platform.int_bit >= MathLib::bigint_bits) + if (mSettings.platform.type == Platform::Type::Unspecified || mSettings.platform.int_bit >= MathLib::bigint_bits) return; logChecker("CheckType::checkIntegerOverflow"); // platform @@ -188,11 +183,11 @@ void CheckType::checkIntegerOverflow() unsigned int bits; if (vt->type == ValueType::Type::INT) - bits = mSettings->platform.int_bit; + bits = mSettings.platform.int_bit; else if (vt->type == ValueType::Type::LONG) - bits = mSettings->platform.long_bit; + bits = mSettings.platform.long_bit; else if (vt->type == ValueType::Type::LONGLONG) - bits = mSettings->platform.long_long_bit; + bits = mSettings.platform.long_long_bit; else continue; @@ -204,12 +199,12 @@ void CheckType::checkIntegerOverflow() // is there a overflow result value bool isOverflow = true; - const ValueFlow::Value *value = tok->getValueGE(maxvalue + 1, *mSettings); + const ValueFlow::Value *value = tok->getValueGE(maxvalue + 1, mSettings); if (!value) { - value = tok->getValueLE(-maxvalue - 2, *mSettings); + value = tok->getValueLE(-maxvalue - 2, mSettings); isOverflow = false; } - if (!value || !mSettings->isEnabled(value,false)) + if (!value || !mSettings.isEnabled(value,false)) continue; // For left shift, it's common practice to shift into the sign bit @@ -220,7 +215,16 @@ void CheckType::checkIntegerOverflow() } } -void CheckType::integerOverflowError(const Token *tok, const ValueFlow::Value &value, bool isOverflow) +static std::string getMessageId(const ValueFlow::Value &value, const char id[]) +{ + if (value.condition != nullptr) + return id + std::string("Cond"); + if (value.safe) + return std::string("safe") + static_cast(std::toupper(id[0])) + (id + 1); + return id; +} + +void CheckTypeImpl::integerOverflowError(const Token *tok, const ValueFlow::Value &value, bool isOverflow) { const std::string expr(tok ? tok->expressionString() : ""); const std::string type = isOverflow ? "overflow" : "underflow"; @@ -247,9 +251,9 @@ void CheckType::integerOverflowError(const Token *tok, const ValueFlow::Value &v // Checking for sign conversion when operand can be negative //--------------------------------------------------------------------------- -void CheckType::checkSignConversion() +void CheckTypeImpl::checkSignConversion() { - if (!mSettings->severity.isEnabled(Severity::warning)) + if (!mSettings.severity.isEnabled(Severity::warning)) return; logChecker("CheckType::checkSignConversion"); // warning @@ -268,7 +272,7 @@ void CheckType::checkSignConversion() if (!tok1) continue; const ValueFlow::Value* negativeValue = - ValueFlow::findValue(tok1->values(), *mSettings, [&](const ValueFlow::Value& v) { + ValueFlow::findValue(tok1->values(), mSettings, [&](const ValueFlow::Value& v) { return !v.isImpossible() && v.isIntValue() && (v.intvalue <= -1 || v.wideintvalue <= -1); }); if (!negativeValue) @@ -279,7 +283,7 @@ void CheckType::checkSignConversion() } } -void CheckType::signConversionError(const Token *tok, const ValueFlow::Value *negativeValue, const bool constvalue) +void CheckTypeImpl::signConversionError(const Token *tok, const ValueFlow::Value *negativeValue, const bool constvalue) { const std::string expr(tok ? tok->expressionString() : "var"); @@ -297,7 +301,7 @@ void CheckType::signConversionError(const Token *tok, const ValueFlow::Value *ne ErrorPath errorPath = getErrorPath(tok,negativeValue,"Negative value is converted to an unsigned value"); reportError(std::move(errorPath), Severity::warning, - Check::getMessageId(*negativeValue, "signConversion").c_str(), + getMessageId(*negativeValue, "signConversion").c_str(), msg.str(), CWE195, negativeValue->isInconclusive() ? Certainty::inconclusive : Certainty::normal); @@ -332,9 +336,9 @@ static bool checkTypeCombination(ValueType src, ValueType tgt, const Settings& s }); } -void CheckType::checkLongCast() +void CheckTypeImpl::checkLongCast() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("truncLongCastAssignment")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("truncLongCastAssignment")) return; logChecker("CheckType::checkLongCast"); // style @@ -345,7 +349,7 @@ void CheckType::checkLongCast() continue; if (const ValueFlow::Value* v = tok->astOperand2()->getKnownValue(ValueFlow::Value::ValueType::INT)) { - if (mSettings->platform.isIntValue(v->intvalue)) + if (mSettings.platform.isIntValue(v->intvalue)) continue; } @@ -354,7 +358,7 @@ void CheckType::checkLongCast() if (!lhstype || !rhstype) continue; - if (!checkTypeCombination(*rhstype, *lhstype, *mSettings)) + if (!checkTypeCombination(*rhstype, *lhstype, mSettings)) continue; // assign int result to long/longlong const nonpointer? @@ -381,12 +385,12 @@ void CheckType::checkLongCast() if (tok->str() == "return") { if (Token::Match(tok->astOperand1(), "<<|*")) { const ValueType *type = tok->astOperand1()->valueType(); - if (type && checkTypeCombination(*type, *retVt, *mSettings) && + if (type && checkTypeCombination(*type, *retVt, mSettings) && type->pointer == 0U && type->originalTypeName.empty()) { if (!tok->astOperand1()->hasKnownIntValue()) { ret = tok; - } else if (!mSettings->platform.isIntValue(tok->astOperand1()->getKnownIntValue())) + } else if (!mSettings.platform.isIntValue(tok->astOperand1()->getKnownIntValue())) ret = tok; } } @@ -410,7 +414,7 @@ static void makeBaseTypeString(std::string& typeStr) typeStr.erase(typeStr.begin(), typeStr.begin() + pos + 6 + 1); } -void CheckType::longCastAssignError(const Token *tok, const ValueType* src, const ValueType* tgt) +void CheckTypeImpl::longCastAssignError(const Token *tok, const ValueType* src, const ValueType* tgt) { std::string srcStr = src ? src->str() : "int"; makeBaseTypeString(srcStr); @@ -423,7 +427,7 @@ void CheckType::longCastAssignError(const Token *tok, const ValueType* src, cons srcStr + " result is assigned to " + tgtStr + " variable. If the variable is " + tgtStr + " to avoid loss of information, then there is loss of information. To avoid loss of information you must cast a calculation operand to " + tgtStr + ", for example 'l = a * b;' => 'l = (" + tgtStr + ")a * b;'.", CWE197, Certainty::normal); } -void CheckType::longCastReturnError(const Token *tok, const ValueType* src, const ValueType* tgt) +void CheckTypeImpl::longCastReturnError(const Token *tok, const ValueType* src, const ValueType* tgt) { std::string srcStr = src ? src->str() : "int"; makeBaseTypeString(srcStr); @@ -440,7 +444,7 @@ void CheckType::longCastReturnError(const Token *tok, const ValueType* src, cons // Checking for float to integer overflow //--------------------------------------------------------------------------- -void CheckType::checkFloatToIntegerOverflow() +void CheckTypeImpl::checkFloatToIntegerOverflow() { logChecker("CheckType::checkFloatToIntegerOverflow"); @@ -472,7 +476,7 @@ void CheckType::checkFloatToIntegerOverflow() while (scope && scope->type != ScopeType::eLambda && scope->type != ScopeType::eFunction) scope = scope->nestedIn; if (scope && scope->type == ScopeType::eFunction && scope->function && scope->function->retDef) { - const ValueType &valueType = ValueType::parseDecl(scope->function->retDef, *mSettings); + const ValueType &valueType = ValueType::parseDecl(scope->function->retDef, mSettings); vtfloat = tok->astOperand1()->valueType(); checkFloatToIntegerOverflow(tok, &valueType, vtfloat, tok->astOperand1()->values()); } @@ -480,7 +484,7 @@ void CheckType::checkFloatToIntegerOverflow() } } -void CheckType::checkFloatToIntegerOverflow(const Token *tok, const ValueType *vtint, const ValueType *vtfloat, const std::list &floatValues) +void CheckTypeImpl::checkFloatToIntegerOverflow(const Token *tok, const ValueType *vtint, const ValueType *vtfloat, const std::list &floatValues) { // Conversion of float to integer? if (!vtint || !vtint->isIntegral()) @@ -491,24 +495,24 @@ void CheckType::checkFloatToIntegerOverflow(const Token *tok, const ValueType *v for (const ValueFlow::Value &f : floatValues) { if (f.valueType != ValueFlow::Value::ValueType::FLOAT) continue; - if (!mSettings->isEnabled(&f, false)) + if (!mSettings.isEnabled(&f, false)) continue; - if (f.floatValue >= std::exp2(mSettings->platform.long_long_bit)) + if (f.floatValue >= std::exp2(mSettings.platform.long_long_bit)) floatToIntegerOverflowError(tok, f); - else if ((-f.floatValue) > std::exp2(mSettings->platform.long_long_bit - 1)) + else if ((-f.floatValue) > std::exp2(mSettings.platform.long_long_bit - 1)) floatToIntegerOverflowError(tok, f); - else if (mSettings->platform.type != Platform::Type::Unspecified) { + else if (mSettings.platform.type != Platform::Type::Unspecified) { int bits = 0; if (vtint->type == ValueType::Type::CHAR) - bits = mSettings->platform.char_bit; + bits = mSettings.platform.char_bit; else if (vtint->type == ValueType::Type::SHORT) - bits = mSettings->platform.short_bit; + bits = mSettings.platform.short_bit; else if (vtint->type == ValueType::Type::INT) - bits = mSettings->platform.int_bit; + bits = mSettings.platform.int_bit; else if (vtint->type == ValueType::Type::LONG) - bits = mSettings->platform.long_bit; + bits = mSettings.platform.long_bit; else if (vtint->type == ValueType::Type::LONGLONG) - bits = mSettings->platform.long_long_bit; + bits = mSettings.platform.long_long_bit; else continue; if (bits < MathLib::bigint_bits && f.floatValue >= (1ULL << bits)) @@ -517,7 +521,7 @@ void CheckType::checkFloatToIntegerOverflow(const Token *tok, const ValueType *v } } -void CheckType::floatToIntegerOverflowError(const Token *tok, const ValueFlow::Value &value) +void CheckTypeImpl::floatToIntegerOverflowError(const Token *tok, const ValueFlow::Value &value) { std::ostringstream errmsg; errmsg << "Undefined behaviour: float (" << value.floatValue << ") to integer conversion overflow."; @@ -527,10 +531,10 @@ void CheckType::floatToIntegerOverflowError(const Token *tok, const ValueFlow::V errmsg.str(), CWE190, value.isInconclusive() ? Certainty::inconclusive : Certainty::normal); } -void CheckType::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckType::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { // These are not "simplified" because casts can't be ignored - CheckType checkType(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckTypeImpl checkType(&tokenizer, tokenizer.getSettings(), errorLogger); checkType.checkTooBigBitwiseShift(); checkType.checkIntegerOverflow(); checkType.checkSignConversion(); @@ -538,9 +542,9 @@ void CheckType::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) checkType.checkFloatToIntegerOverflow(); } -void CheckType::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const +void CheckType::getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const { - CheckType c(nullptr, settings, errorLogger); + CheckTypeImpl c(nullptr, settings, errorLogger); c.tooBigBitwiseShiftError(nullptr, 32, ValueFlow::Value(64)); c.tooBigSignedBitwiseShiftError(nullptr, 31, ValueFlow::Value(31)); c.integerOverflowError(nullptr, ValueFlow::Value(1LL<<32)); diff --git a/lib/checktype.h b/lib/checktype.h index d90e11f6fd1..83eedda5583 100644 --- a/lib/checktype.h +++ b/lib/checktype.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,6 +23,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include @@ -47,15 +48,30 @@ namespace ValueFlow class CPPCHECKLIB CheckType : public Check { public: /** @brief This constructor is used when registering the CheckClass */ - CheckType() : Check(myName()) {} + CheckType() : Check("Type") {} private: - /** @brief This constructor is used when running checks. */ - CheckType(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} - /** @brief Run checks against the normal token list */ - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; + + std::string classInfo() const override { + return "Type checks\n" + "- bitwise shift by too many bits (only enabled when --platform is used)\n" + "- signed integer overflow (only enabled when --platform is used)\n" + "- dangerous sign conversion, when signed value can be negative\n" + "- possible loss of information when assigning int result to long variable\n" + "- possible loss of information when returning int result as long return value\n" + "- float conversion overflow\n"; + } +}; + +class CPPCHECKLIB CheckTypeImpl : public CheckImpl { +public: + /** @brief This constructor is used when running checks. */ + CheckTypeImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} /** @brief %Check for bitwise shift with too big right operand */ void checkTooBigBitwiseShift(); @@ -81,22 +97,6 @@ class CPPCHECKLIB CheckType : public Check { void longCastAssignError(const Token *tok, const ValueType* src = nullptr, const ValueType* tgt = nullptr); void longCastReturnError(const Token *tok, const ValueType* src = nullptr, const ValueType* tgt = nullptr); void floatToIntegerOverflowError(const Token *tok, const ValueFlow::Value &value); - - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - static std::string myName() { - return "Type"; - } - - std::string classInfo() const override { - return "Type checks\n" - "- bitwise shift by too many bits (only enabled when --platform is used)\n" - "- signed integer overflow (only enabled when --platform is used)\n" - "- dangerous sign conversion, when signed value can be negative\n" - "- possible loss of information when assigning int result to long variable\n" - "- possible loss of information when returning int result as long return value\n" - "- float conversion overflow\n"; - } }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index a7a4d8b1bf3..d05ea3fbd28 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -21,6 +21,7 @@ #include "checkuninitvar.h" #include "astutils.h" +#include "checkimpl.h" #include "ctu.h" #include "errorlogger.h" #include "library.h" @@ -50,11 +51,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 @@ -102,7 +98,7 @@ static std::map getVariableValues(const Token* tok) { return ret; } -bool CheckUninitVar::diag(const Token* tok) +bool CheckUninitVarImpl::diag(const Token* tok) { if (!tok) return true; @@ -111,7 +107,7 @@ bool CheckUninitVar::diag(const Token* tok) return !mUninitDiags.insert(tok).second; } -void CheckUninitVar::check() +void CheckUninitVarImpl::check() { logChecker("CheckUninitVar::check"); @@ -131,7 +127,7 @@ void CheckUninitVar::check() } } -void CheckUninitVar::checkScope(const Scope* scope, const std::set &arrayTypeDefs) +void CheckUninitVarImpl::checkScope(const Scope* scope, const std::set &arrayTypeDefs) { for (const Variable &var : scope->varlist) { if ((mTokenizer->isCPP() && var.type() && !var.isPointer() && var.type()->needInitialization != Type::NeedInitialization::True) || @@ -216,10 +212,10 @@ void CheckUninitVar::checkScope(const Scope* scope, const std::set for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) { if (!Token::Match(tok, "[;{}] %varid% =", arg.declarationId())) continue; - const Token *allocFuncCallToken = findAllocFuncCallToken(tok->tokAt(2)->astOperand2(), mSettings->library); + const Token *allocFuncCallToken = findAllocFuncCallToken(tok->tokAt(2)->astOperand2(), mSettings.library); if (!allocFuncCallToken) continue; - const Library::AllocFunc *allocFunc = mSettings->library.getAllocFuncInfo(allocFuncCallToken); + const Library::AllocFunc *allocFunc = mSettings.library.getAllocFuncInfo(allocFuncCallToken); if (!allocFunc || allocFunc->initData) continue; @@ -236,7 +232,7 @@ void CheckUninitVar::checkScope(const Scope* scope, const std::set } } -void CheckUninitVar::checkStruct(const Token *tok, const Variable &structvar) +void CheckUninitVarImpl::checkStruct(const Token *tok, const Variable &structvar) { const Token *typeToken = structvar.typeStartToken(); while (Token::Match(typeToken, "%name% ::")) @@ -397,10 +393,10 @@ static bool isVariableUsed(const Token *tok, const Variable& var) return !parent2 || parent2->isConstOp() || (parent2->str() == "=" && parent2->astOperand2() == parent); } -bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var, bool * const possibleInit, bool * const noreturn, Alloc* const alloc, const std::string &membervar, std::map& variableValue) +bool CheckUninitVarImpl::checkScopeForVariable(const Token *tok, const Variable& var, bool * const possibleInit, bool * const noreturn, Alloc* const alloc, const std::string &membervar, std::map& variableValue) { const bool suppressErrors(possibleInit && *possibleInit); // Assume that this is a variable declaration, rather than a fundef - const bool printDebug = mSettings->debugwarnings; + const bool printDebug = mSettings.debugwarnings; if (possibleInit) *possibleInit = false; @@ -767,7 +763,7 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var while (rhs && rhs->isCast()) rhs = rhs->astOperand2() ? rhs->astOperand2() : rhs->astOperand1(); if (rhs && Token::Match(rhs->previous(), "%name% (")) { - const Library::AllocFunc *allocFunc = mSettings->library.getAllocFuncInfo(rhs->astOperand1()); + const Library::AllocFunc *allocFunc = mSettings.library.getAllocFuncInfo(rhs->astOperand1()); if (allocFunc && !allocFunc->initData) { *alloc = NO_CTOR_CALL; continue; @@ -857,7 +853,7 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var return false; } -const Token* CheckUninitVar::checkExpr(const Token* tok, const Variable& var, const Alloc alloc, bool known, bool* bailout) const +const Token* CheckUninitVarImpl::checkExpr(const Token* tok, const Variable& var, const Alloc alloc, bool known, bool* bailout) const { if (!tok) return nullptr; @@ -886,7 +882,7 @@ const Token* CheckUninitVar::checkExpr(const Token* tok, const Variable& var, co return nullptr; } -bool CheckUninitVar::checkIfForWhileHead(const Token *startparentheses, const Variable& var, bool suppressErrors, bool isuninit, Alloc alloc, const std::string &membervar) +bool CheckUninitVarImpl::checkIfForWhileHead(const Token *startparentheses, const Variable& var, bool suppressErrors, bool isuninit, Alloc alloc, const std::string &membervar) { const Token * const endpar = startparentheses->link(); if (Token::Match(startparentheses, "( ! %name% %oror%") && startparentheses->tokAt(2)->getValue(0)) @@ -923,7 +919,7 @@ bool CheckUninitVar::checkIfForWhileHead(const Token *startparentheses, const Va } /** recursively check loop, return error token */ -const Token* CheckUninitVar::checkLoopBodyRecursive(const Token *start, const Variable& var, const Alloc alloc, const std::string &membervar, bool &bailout, bool &alwaysReturns) const +const Token* CheckUninitVarImpl::checkLoopBodyRecursive(const Token *start, const Variable& var, const Alloc alloc, const std::string &membervar, bool &bailout, bool &alwaysReturns) const { assert(start->str() == "{"); @@ -1091,7 +1087,7 @@ const Token* CheckUninitVar::checkLoopBodyRecursive(const Token *start, const Va return errorToken; } -bool CheckUninitVar::checkLoopBody(const Token *tok, const Variable& var, const Alloc alloc, const std::string &membervar, const bool suppressErrors) +bool CheckUninitVarImpl::checkLoopBody(const Token *tok, const Variable& var, const Alloc alloc, const std::string &membervar, const bool suppressErrors) { bool bailout = false; bool alwaysReturns = false; @@ -1108,7 +1104,7 @@ bool CheckUninitVar::checkLoopBody(const Token *tok, const Variable& var, const return bailout || alwaysReturns; } -void CheckUninitVar::checkRhs(const Token *tok, const Variable &var, Alloc alloc, nonneg int number_of_if, const std::string &membervar) +void CheckUninitVarImpl::checkRhs(const Token *tok, const Variable &var, Alloc alloc, nonneg int number_of_if, const std::string &membervar) { bool rhs = false; int indent = 0; @@ -1155,7 +1151,7 @@ static bool astIsRhs(const Token *tok) return tok && tok->astParent() && tok == tok->astParent()->astOperand2(); } -const Token* CheckUninitVar::isVariableUsage(const Token *vartok, const Library& library, bool pointer, Alloc alloc, int indirect) +const Token* CheckUninitVarImpl::isVariableUsage(const Token *vartok, const Library& library, bool pointer, Alloc alloc, int indirect) { const bool cpp = vartok->isCpp(); const Token *valueExpr = vartok; // non-dereferenced , no address of value as variable @@ -1357,9 +1353,9 @@ const Token* CheckUninitVar::isVariableUsage(const Token *vartok, const Library& return derefValue ? derefValue : valueExpr; } -const Token* CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, Alloc alloc, int indirect) const +const Token* CheckUninitVarImpl::isVariableUsage(const Token *vartok, bool pointer, Alloc alloc, int indirect) const { - return isVariableUsage(vartok, mSettings->library, pointer, alloc, indirect); + return isVariableUsage(vartok, mSettings.library, pointer, alloc, indirect); } /*** @@ -1368,7 +1364,7 @@ const Token* CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, * is passed "by reference" then it is not necessarily "used". * @return -1 => unknown 0 => not used 1 => used */ -int CheckUninitVar::isFunctionParUsage(const Token *vartok, const Library& library, bool pointer, Alloc alloc, int indirect) +int CheckUninitVarImpl::isFunctionParUsage(const Token *vartok, const Library& library, bool pointer, Alloc alloc, int indirect) { bool unknown = false; const Token *parent = getAstParentSkipPossibleCastAndAddressOf(vartok, &unknown); @@ -1438,12 +1434,12 @@ int CheckUninitVar::isFunctionParUsage(const Token *vartok, const Library& libra return -1; } -int CheckUninitVar::isFunctionParUsage(const Token *vartok, bool pointer, Alloc alloc, int indirect) const +int CheckUninitVarImpl::isFunctionParUsage(const Token *vartok, bool pointer, Alloc alloc, int indirect) const { - return CheckUninitVar::isFunctionParUsage(vartok, mSettings->library, pointer, alloc, indirect); + return isFunctionParUsage(vartok, mSettings.library, pointer, alloc, indirect); } -bool CheckUninitVar::isMemberVariableAssignment(const Token *tok, const std::string &membervar) const +bool CheckUninitVarImpl::isMemberVariableAssignment(const Token *tok, const std::string &membervar) const { if (Token::Match(tok, "%name% . %name%") && tok->strAt(2) == membervar) { if (Token::Match(tok->tokAt(3), "[=.[]")) @@ -1487,9 +1483,9 @@ bool CheckUninitVar::isMemberVariableAssignment(const Token *tok, const std::str // check how function handle uninitialized data arguments.. const Function *function = ftok->function(); - if (!function && mSettings) { + if (!function) { // Function definition not seen, check if direction is specified in the library configuration - const Library::ArgumentChecks::Direction argDirection = mSettings->library.getArgDirection(ftok, 1 + argumentNumber); + const Library::ArgumentChecks::Direction argDirection = mSettings.library.getArgDirection(ftok, 1 + argumentNumber); if (argDirection == Library::ArgumentChecks::Direction::DIR_IN) return false; if (argDirection == Library::ArgumentChecks::Direction::DIR_OUT) @@ -1512,7 +1508,7 @@ bool CheckUninitVar::isMemberVariableAssignment(const Token *tok, const std::str return false; } -bool CheckUninitVar::isMemberVariableUsage(const Token *tok, bool isPointer, Alloc alloc, const std::string &membervar) const +bool CheckUninitVarImpl::isMemberVariableUsage(const Token *tok, bool isPointer, Alloc alloc, const std::string &membervar) const { if (Token::Match(tok->previous(), "[(,] %name% . %name% [,)]") && tok->strAt(2) == membervar) { @@ -1554,12 +1550,12 @@ bool CheckUninitVar::isMemberVariableUsage(const Token *tok, bool isPointer, All return false; } -void CheckUninitVar::uninitdataError(const Token *tok, const std::string &varname) +void CheckUninitVarImpl::uninitdataError(const Token *tok, const std::string &varname) { reportError(tok, Severity::error, "uninitdata", "$symbol:" + varname + "\nMemory is allocated but not initialized: $symbol", CWE_USE_OF_UNINITIALIZED_VARIABLE, Certainty::normal); } -void CheckUninitVar::uninitvarError(const Token *tok, const std::string &varname, ErrorPath errorPath) +void CheckUninitVarImpl::uninitvarError(const Token *tok, const std::string &varname, ErrorPath errorPath) { if (diag(tok)) return; @@ -1572,9 +1568,9 @@ void CheckUninitVar::uninitvarError(const Token *tok, const std::string &varname Certainty::normal); } -void CheckUninitVar::uninitvarError(const Token* tok, const ValueFlow::Value& v) +void CheckUninitVarImpl::uninitvarError(const Token* tok, const ValueFlow::Value& v) { - if (!mSettings->isEnabled(&v)) + if (!mSettings.isEnabled(&v)) return; if (diag(tok)) return; @@ -1609,7 +1605,7 @@ void CheckUninitVar::uninitvarError(const Token* tok, const ValueFlow::Value& v) certainty); } -void CheckUninitVar::uninitStructMemberError(const Token *tok, const std::string &membername) +void CheckUninitVarImpl::uninitStructMemberError(const Token *tok, const std::string &membername) { reportError(tok, Severity::error, @@ -1617,7 +1613,7 @@ void CheckUninitVar::uninitStructMemberError(const Token *tok, const std::string "$symbol:" + membername + "\nUninitialized struct member: $symbol", CWE_USE_OF_UNINITIALIZED_VARIABLE, Certainty::normal); } -void CheckUninitVar::valueFlowUninit() +void CheckUninitVarImpl::valueFlowUninit() { logChecker("CheckUninitVar::valueFlowUninit"); @@ -1664,28 +1660,28 @@ void CheckUninitVar::valueFlowUninit() if (isarray && tok->variable()->isMember()) continue; // Todo: this is a bailout if (isarray && tok->variable()->isStlType() && Token::simpleMatch(tok->astParent(), ".")) { - const auto yield = astContainerYield(tok, mSettings->library); + const auto yield = astContainerYield(tok, mSettings.library); if (yield != Library::Container::Yield::AT_INDEX && yield != Library::Container::Yield::ITEM) continue; } - const bool deref = CheckNullPointer::isPointerDeRef(tok, unknown, *mSettings); + const bool deref = CheckNullPointerImpl::isPointerDeRef(tok, unknown, mSettings.library); uninitderef = deref && v->indirect == 0; const bool isleaf = isLeafDot(tok) || uninitderef; if (!isleaf && Token::Match(tok->astParent(), ". %name%") && (tok->astParent()->next()->variable() || tok->astParent()->next()->isEnumerator())) continue; } - const ExprUsage usage = getExprUsage(tok, v->indirect, *mSettings); + const ExprUsage usage = getExprUsage(tok, v->indirect, mSettings); if (usage == ExprUsage::NotUsed || usage == ExprUsage::Inconclusive) continue; if (!v->subexpressions.empty() && usage == ExprUsage::PassedByReference) continue; if (usage != ExprUsage::Used) { if (!(Token::Match(tok->astParent(), ". %name% (|[") && uninitderef) && - isVariableChanged(tok, v->indirect, *mSettings)) + isVariableChanged(tok, v->indirect, mSettings)) continue; bool inconclusive = false; - if (isVariableChangedByFunctionCall(tok, v->indirect, *mSettings, &inconclusive) || inconclusive) + if (isVariableChangedByFunctionCall(tok, v->indirect, mSettings.library, &inconclusive) || inconclusive) continue; } uninitvarError(tok, *v); @@ -1701,7 +1697,7 @@ void CheckUninitVar::valueFlowUninit() static bool isVariableUsage(const Settings &settings, const Token *vartok, MathLib::bigint *value) { (void)value; - return CheckUninitVar::isVariableUsage(vartok, settings.library, true, CheckUninitVar::Alloc::ARRAY); + return !!CheckUninitVarImpl::isVariableUsage(vartok, settings.library, true, CheckUninitVarImpl::Alloc::ARRAY); } // a Clang-built executable will crash when using the anonymous MyFileInfo later on - so put it in a unique namespace for now @@ -1731,7 +1727,7 @@ static bool isVariableUsage(const Settings &settings, const Token *argtok, CTU:: return isVariableUsage(settings, argtok, &value->value); } -Check::FileInfo *CheckUninitVar::getFileInfo(const Tokenizer &tokenizer, const Settings &settings, const std::string& /*currentConfig*/) const +const Check::FileInfo *CheckUninitVar::getFileInfo(const Tokenizer &tokenizer, const Settings &settings, const std::string& /*currentConfig*/) const { const std::list &unsafeUsage = CTU::getUnsafeUsage(tokenizer, settings, ::isVariableUsage); if (unsafeUsage.empty()) @@ -1742,22 +1738,22 @@ Check::FileInfo *CheckUninitVar::getFileInfo(const Tokenizer &tokenizer, const S return fileInfo; } -Check::FileInfo * CheckUninitVar::loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const +const Check::FileInfo * CheckUninitVar::loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement, const std::string& file0) const { const std::list &unsafeUsage = CTU::loadUnsafeUsageListFromXml(xmlElement); if (unsafeUsage.empty()) return nullptr; - auto *fileInfo = new MyFileInfo; + auto *fileInfo = new MyFileInfo(file0); fileInfo->unsafeUsage = unsafeUsage; return fileInfo; } -bool CheckUninitVar::analyseWholeProgram(const CTU::FileInfo &ctu, const std::list &fileInfo, const Settings& settings, ErrorLogger &errorLogger) +bool CheckUninitVar::analyseWholeProgram(const CTU::FileInfo &ctu, const std::list &fileInfo, const Settings& settings, ErrorLogger &errorLogger) { (void)settings; - CheckUninitVar dummy(nullptr, &settings, &errorLogger); + CheckUninitVarImpl dummy(nullptr, settings, errorLogger); dummy. logChecker("CheckUninitVar::analyseWholeProgram"); @@ -1801,16 +1797,16 @@ bool CheckUninitVar::analyseWholeProgram(const CTU::FileInfo &ctu, const std::li return foundErrors; } -void CheckUninitVar::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckUninitVar::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { - CheckUninitVar checkUninitVar(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckUninitVarImpl checkUninitVar(&tokenizer, tokenizer.getSettings(), errorLogger); checkUninitVar.valueFlowUninit(); checkUninitVar.check(); } -void CheckUninitVar::getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const +void CheckUninitVar::getErrorMessages(ErrorLogger& errorLogger, const Settings& settings) const { - CheckUninitVar c(nullptr, settings, errorLogger); + CheckUninitVarImpl c(nullptr, settings, errorLogger); ValueFlow::Value v{}; diff --git a/lib/checkuninitvar.h b/lib/checkuninitvar.h index b79e9c22be0..a9156adfe36 100644 --- a/lib/checkuninitvar.h +++ b/lib/checkuninitvar.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,6 +23,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include "mathlib.h" #include "errortypes.h" @@ -57,24 +58,38 @@ struct VariableValue { /** @brief Checking for uninitialized variables */ class CPPCHECKLIB CheckUninitVar : public Check { - friend class TestUninitVar; - public: /** @brief This constructor is used when registering the CheckUninitVar */ - CheckUninitVar() : Check(myName()) {} + CheckUninitVar() : Check("Uninitialized variables") {} - enum Alloc : std::uint8_t { NO_ALLOC, NO_CTOR_CALL, CTOR_CALL, ARRAY }; +private: + /** @brief Run checks against the normal token list */ + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; - static const Token *isVariableUsage(const Token *vartok, const Library &library, bool pointer, Alloc alloc, int indirect = 0); - const Token *isVariableUsage(const Token *vartok, bool pointer, Alloc alloc, int indirect = 0) const; + /** @brief Parse current TU and extract file info */ + const Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings &settings, const std::string& /*currentConfig*/) const override; -private: + const Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement, const std::string& file0) const override; + + /** @brief Analyse all file infos for all TU */ + bool analyseWholeProgram(const CTU::FileInfo &ctu, const std::list &fileInfo, const Settings& settings, ErrorLogger &errorLogger) override; + + void getErrorMessages(ErrorLogger& errorLogger, const Settings& settings) const override; + + std::string classInfo() const override { + return "Uninitialized variables\n" + "- using uninitialized local variables\n" + "- using allocated data before it has been initialized\n"; + } +}; + +class CPPCHECKLIB CheckUninitVarImpl : public CheckImpl { +public: /** @brief This constructor is used when running checks. */ - CheckUninitVar(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} + CheckUninitVarImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} - /** @brief Run checks against the normal token list */ - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + enum Alloc : std::uint8_t { NO_ALLOC, NO_CTOR_CALL, CTOR_CALL, ARRAY }; bool diag(const Token* tok); /** Check for uninitialized variables */ @@ -92,17 +107,12 @@ class CPPCHECKLIB CheckUninitVar : public Check { bool isMemberVariableAssignment(const Token *tok, const std::string &membervar) const; bool isMemberVariableUsage(const Token *tok, bool isPointer, Alloc alloc, const std::string &membervar) const; + static const Token *isVariableUsage(const Token *vartok, const Library &library, bool pointer, Alloc alloc, int indirect = 0); + const Token *isVariableUsage(const Token *vartok, bool pointer, Alloc alloc, int indirect = 0) const; + /** ValueFlow-based checking for uninitialized variables */ void valueFlowUninit(); - /** @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 * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override; - - /** @brief Analyse all file infos for all TU */ - bool analyseWholeProgram(const CTU::FileInfo &ctu, const std::list &fileInfo, const Settings& settings, ErrorLogger &errorLogger) override; - void uninitvarError(const Token* tok, const ValueFlow::Value& v); void uninitdataError(const Token *tok, const std::string &varname); void uninitvarError(const Token *tok, const std::string &varname, ErrorPath errorPath); @@ -118,18 +128,6 @@ class CPPCHECKLIB CheckUninitVar : public Check { void uninitStructMemberError(const Token *tok, const std::string &membername); std::set mUninitDiags; - - void getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const override; - - static std::string myName() { - return "Uninitialized variables"; - } - - std::string classInfo() const override { - return "Uninitialized variables\n" - "- using uninitialized local variables\n" - "- using allocated data before it has been initialized\n"; - } }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checkunusedfunctions.cpp b/lib/checkunusedfunctions.cpp index 5965de1aada..4177a13a013 100644 --- a/lib/checkunusedfunctions.cpp +++ b/lib/checkunusedfunctions.cpp @@ -65,11 +65,11 @@ static bool isRecursiveCall(const Token* ftok) return ftok->function() && ftok->function() == Scope::nestedInFunction(ftok->scope()); } -void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Settings &settings) +void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Library &library) { const char * const FileName = tokenizer.list.getFiles().front().c_str(); - const bool doMarkup = settings.library.markupFile(FileName); + const bool doMarkup = library.markupFile(FileName); // Function declarations.. if (!doMarkup) { @@ -139,8 +139,8 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Setting lambdaEndToken = findLambdaEndToken(tok); // parsing of library code to find called functions - if (settings.library.isexecutableblock(FileName, tok->str())) { - const Token * markupVarToken = tok->tokAt(settings.library.blockstartoffset(FileName)); + if (library.isexecutableblock(FileName, tok->str())) { + const Token * markupVarToken = tok->tokAt(library.blockstartoffset(FileName)); // not found if (!markupVarToken) continue; @@ -148,12 +148,12 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Setting bool start = true; // find all function calls in library code (starts with '(', not if or while etc) while ((scope || start) && markupVarToken) { - if (markupVarToken->str() == settings.library.blockstart(FileName)) { + if (markupVarToken->str() == library.blockstart(FileName)) { scope++; start = false; - } else if (markupVarToken->str() == settings.library.blockend(FileName)) + } else if (markupVarToken->str() == library.blockend(FileName)) scope--; - else if (!settings.library.iskeyword(FileName, markupVarToken->str())) { + else if (!library.iskeyword(FileName, markupVarToken->str())) { mFunctionCalls.insert(markupVarToken->str()); if (mFunctions.find(markupVarToken->str()) != mFunctions.end()) mFunctions[markupVarToken->str()].usedOtherFile = true; @@ -171,10 +171,10 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Setting } if (!doMarkup // only check source files - && settings.library.isexporter(tok->str()) && tok->next() != nullptr) { + && library.isexporter(tok->str()) && tok->next() != nullptr) { const Token * propToken = tok->next(); while (propToken && propToken->str() != ")") { - if (settings.library.isexportedprefix(tok->str(), propToken->str())) { + if (library.isexportedprefix(tok->str(), propToken->str())) { const Token* nextPropToken = propToken->next(); const std::string& value = nextPropToken->str(); if (mFunctions.find(value) != mFunctions.end()) { @@ -182,7 +182,7 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Setting } mFunctionCalls.insert(value); } - if (settings.library.isexportedsuffix(tok->str(), propToken->str())) { + if (library.isexportedsuffix(tok->str(), propToken->str())) { const Token* prevPropToken = propToken->previous(); const std::string& value = prevPropToken->str(); if (value != ")" && mFunctions.find(value) != mFunctions.end()) { @@ -194,7 +194,7 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Setting } } - if (doMarkup && settings.library.isimporter(FileName, tok->str()) && tok->next()) { + if (doMarkup && library.isimporter(FileName, tok->str()) && tok->next()) { const Token * propToken = tok->next(); if (propToken->next()) { propToken = propToken->next(); @@ -210,8 +210,8 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Setting } } - if (settings.library.isreflection(tok->str())) { - const int argIndex = settings.library.reflectionArgument(tok->str()); + if (library.isreflection(tok->str())) { + const int argIndex = library.reflectionArgument(tok->str()); if (argIndex >= 0) { const Token * funcToken = tok->next(); int index = 0; @@ -366,7 +366,7 @@ void CheckUnusedFunctions::staticFunctionError(ErrorLogger& errorLogger, errorLogger.reportErr(errmsg); \ } while (false) -bool CheckUnusedFunctions::check(const Settings& settings, ErrorLogger& errorLogger) const +bool CheckUnusedFunctions::check(const Library& library, ErrorLogger& errorLogger) const { logChecker("CheckUnusedFunctions::check"); // unusedFunction @@ -379,7 +379,7 @@ bool CheckUnusedFunctions::check(const Settings& settings, ErrorLogger& errorLog const FunctionUsage &func = it->second; if (func.usedOtherFile || func.filename.empty()) continue; - if (settings.library.isentrypoint(it->first)) + if (library.isentrypoint(it->first)) continue; if (!func.usedSameFile) { if (isOperatorFunction(it->first)) diff --git a/lib/checkunusedfunctions.h b/lib/checkunusedfunctions.h index 20e1788cf64..1b560cfb7cb 100644 --- a/lib/checkunusedfunctions.h +++ b/lib/checkunusedfunctions.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 @@ -33,6 +33,7 @@ class ErrorLogger; class Function; class Settings; class Tokenizer; +class Library; /** @brief Check for functions never called */ /// @{ @@ -44,7 +45,7 @@ class CPPCHECKLIB CheckUnusedFunctions { // Parse current tokens and determine.. // * Check what functions are used // * What functions are declared - void parseTokens(const Tokenizer &tokenizer, const Settings &settings); + void parseTokens(const Tokenizer &tokenizer, const Library &library); std::string analyzerInfo(const Tokenizer &tokenizer) const; @@ -56,7 +57,7 @@ class CPPCHECKLIB CheckUnusedFunctions { } // Return true if an error is reported. - bool check(const Settings& settings, ErrorLogger& errorLogger) const; + bool check(const Library& library, ErrorLogger& errorLogger) const; void updateFunctionData(const CheckUnusedFunctions& checkUnusedFunctions); diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index 6dd98de078e..fe85260fc8d 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -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 @@ -254,7 +249,7 @@ void Variables::clearAliases(nonneg int varid) void Variables::eraseAliases(nonneg int varid) { - VariableUsage *usage = find(varid); + const VariableUsage *usage = find(varid); if (usage) { for (auto aliases = usage->_aliases.cbegin(); aliases != usage->_aliases.cend(); ++aliases) @@ -334,7 +329,7 @@ void Variables::write(nonneg int varid, const Token* tok) void Variables::writeAliases(nonneg int varid, const Token* tok) { - VariableUsage *usage = find(varid); + const VariableUsage *usage = find(varid); if (usage) { for (auto aliases = usage->_aliases.cbegin(); aliases != usage->_aliases.cend(); ++aliases) { @@ -704,7 +699,7 @@ static void useFunctionArgs(const Token *tok, Variables& variables) //--------------------------------------------------------------------------- // Usage of function variables //--------------------------------------------------------------------------- -void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const scope, Variables& variables) const +void CheckUnusedVarImpl::checkFunctionVariableUsage_iterateScopes(const Scope* const scope, Variables& variables) const { // Find declarations if the scope is executable.. if (scope->isExecutable()) { @@ -731,8 +726,8 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const i->typeEndToken()->isStandardType() || i->isStlType() || mTokenizer->getSymbolDatabase()->isRecordTypeWithoutSideEffects(i->type()) || - mSettings->library.detectContainer(i->typeStartToken()) || - mSettings->library.getTypeCheck("unusedvar", i->typeStartToken()->str()) == Library::TypeCheck::check) + mSettings.library.detectContainer(i->typeStartToken()) || + mSettings.library.getTypeCheck("unusedvar", i->typeStartToken()->str()) == Library::TypeCheck::check) type = Variables::standard; if (type == Variables::none || isPartOfClassStructUnion(i->typeStartToken())) @@ -857,7 +852,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const } } // Freeing memory (not considered "using" the pointer if it was also allocated in this function) - if ((Token::Match(tok, "%name% ( %var% )") && mSettings->library.getDeallocFuncInfo(tok)) || + if ((Token::Match(tok, "%name% ( %var% )") && mSettings.library.getDeallocFuncInfo(tok)) || (tok->isCpp() && (Token::Match(tok, "delete %var% ;") || Token::Match(tok, "delete [ ] %var% ;")))) { nonneg int varid = 0; if (tok->str() != "delete") { @@ -963,10 +958,10 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const // Consider allocating memory separately because allocating/freeing alone does not constitute using the variable else if (var && var->mType == Variables::pointer && Token::Match(start, "%name% =") && - findAllocFuncCallToken(start->next()->astOperand2(), mSettings->library)) { + findAllocFuncCallToken(start->next()->astOperand2(), mSettings.library)) { - const Token *allocFuncCallToken = findAllocFuncCallToken(start->next()->astOperand2(), mSettings->library); - const Library::AllocFunc *allocFunc = mSettings->library.getAllocFuncInfo(allocFuncCallToken); + const Token *allocFuncCallToken = findAllocFuncCallToken(start->next()->astOperand2(), mSettings.library); + const Library::AllocFunc *allocFunc = mSettings.library.getAllocFuncInfo(allocFuncCallToken); bool allocateMemory = !allocFunc || Library::ismemory(allocFunc->groupId); @@ -1048,7 +1043,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const // Consider allocating memory separately because allocating/freeing alone does not constitute using the variable if (var->mType == Variables::pointer && ((tok->isCpp() && Token::simpleMatch(skipBrackets(tok->next()), "= new")) || - (Token::Match(skipBrackets(tok->next()), "= %name% (") && mSettings->library.getAllocFuncInfo(tok->tokAt(2))))) { + (Token::Match(skipBrackets(tok->next()), "= %name% (") && mSettings.library.getAllocFuncInfo(tok->tokAt(2))))) { variables.allocateMemory(varid, tok); } else if (var->mType == Variables::pointer || var->mType == Variables::reference) { variables.read(varid, tok); @@ -1160,10 +1155,6 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const variables.read(tok2->varId(), tok); } } - } else if (tok->variable() && tok->variable()->isClass() && tok->variable()->type() && - (tok->variable()->type()->needInitialization == Type::NeedInitialization::False) && - tok->strAt(1) == ";") { - variables.write(tok->varId(), tok); } } } @@ -1178,9 +1169,9 @@ static bool isReturnedByRef(const Variable* var, const Function* func) }); } -void CheckUnusedVar::checkFunctionVariableUsage() +void CheckUnusedVarImpl::checkFunctionVariableUsage() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->checkLibrary && !mSettings->isPremiumEnabled("unusedVariable")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.checkLibrary && !mSettings.isPremiumEnabled("unusedVariable")) return; logChecker("CheckUnusedVar::checkFunctionVariableUsage"); // style @@ -1189,7 +1180,7 @@ void CheckUnusedVar::checkFunctionVariableUsage() const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); auto reportLibraryCfgError = [this](const Token* tok, const std::string& typeName) { - if (mSettings->checkLibrary) { + if (mSettings.checkLibrary) { reportError(tok, Severity::information, "checkLibraryCheckType", @@ -1336,7 +1327,7 @@ void CheckUnusedVar::checkFunctionVariableUsage() std::string typeName = op1Var->getTypeName(); if (startsWith(typeName, "::")) typeName.erase(typeName.begin(), typeName.begin() + 2); - switch (mSettings->library.getTypeCheck("unusedvar", typeName)) { + switch (mSettings.library.getTypeCheck("unusedvar", typeName)) { case Library::TypeCheck::def: bailoutTypeName = std::move(typeName); break; @@ -1375,7 +1366,7 @@ void CheckUnusedVar::checkFunctionVariableUsage() continue; } - FwdAnalysis fwdAnalysis(*mSettings); + FwdAnalysis fwdAnalysis(mSettings); const Token* scopeEnd = ValueFlow::getEndOfExprScope(expr, scope, /*smallest*/ false); if (fwdAnalysis.unusedValue(expr, start, scopeEnd)) { if (!bailoutTypeName.empty()) { @@ -1383,7 +1374,7 @@ void CheckUnusedVar::checkFunctionVariableUsage() reportLibraryCfgError(tok, bailoutTypeName); continue; } - if (isTrivialInit && findExpressionChanged(expr, start, scopeEnd, *mSettings)) + if (isTrivialInit && findExpressionChanged(expr, start, scopeEnd, mSettings)) continue; // warn @@ -1465,7 +1456,7 @@ void CheckUnusedVar::checkFunctionVariableUsage() if (mTokenizer->isCPP() && var->isClass() && (!var->valueType() || var->valueType()->type == ValueType::Type::UNKNOWN_TYPE)) { const std::string typeName = var->getTypeName(); - switch (mSettings->library.getTypeCheck("unusedvar", typeName)) { + switch (mSettings.library.getTypeCheck("unusedvar", typeName)) { case Library::TypeCheck::def: reportLibraryCfgError(vnt, typeName); break; @@ -1484,25 +1475,25 @@ void CheckUnusedVar::checkFunctionVariableUsage() } } -void CheckUnusedVar::unusedVariableError(const Token *tok, const std::string &varname) +void CheckUnusedVarImpl::unusedVariableError(const Token *tok, const std::string &varname) { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedVariable")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("unusedVariable")) return; reportError(tok, Severity::style, "unusedVariable", "$symbol:" + varname + "\nUnused variable: $symbol", CWE563, Certainty::normal); } -void CheckUnusedVar::allocatedButUnusedVariableError(const Token *tok, const std::string &varname) +void CheckUnusedVarImpl::allocatedButUnusedVariableError(const Token *tok, const std::string &varname) { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedVariable")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("unusedVariable")) return; reportError(tok, Severity::style, "unusedAllocatedMemory", "$symbol:" + varname + "\nVariable '$symbol' is allocated memory that is never used.", CWE563, Certainty::normal); } -void CheckUnusedVar::unreadVariableError(const Token *tok, const std::string &varname, bool modified) +void CheckUnusedVarImpl::unreadVariableError(const Token *tok, const std::string &varname, bool modified) { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedVariable")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("unusedVariable")) return; if (modified) @@ -1511,9 +1502,9 @@ void CheckUnusedVar::unreadVariableError(const Token *tok, const std::string &va reportError(tok, Severity::style, "unreadVariable", "$symbol:" + varname + "\nVariable '$symbol' is assigned a value that is never used.", CWE563, Certainty::normal); } -void CheckUnusedVar::unassignedVariableError(const Token *tok, const std::string &varname) +void CheckUnusedVarImpl::unassignedVariableError(const Token *tok, const std::string &varname) { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedVariable")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("unusedVariable")) return; reportError(tok, Severity::style, "unassignedVariable", "$symbol:" + varname + "\nVariable '$symbol' is not assigned a value.", CWE665, Certainty::normal); @@ -1522,9 +1513,9 @@ void CheckUnusedVar::unassignedVariableError(const Token *tok, const std::string //--------------------------------------------------------------------------- // Check that all struct members are used //--------------------------------------------------------------------------- -void CheckUnusedVar::checkStructMemberUsage() +void CheckUnusedVarImpl::checkStructMemberUsage() { - if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedStructMember") && !mSettings->isPremiumEnabled("unusedVariable")) + if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("unusedStructMember") && !mSettings.isPremiumEnabled("unusedVariable")) return; logChecker("CheckUnusedVar::checkStructMemberUsage"); // style @@ -1646,7 +1637,8 @@ void CheckUnusedVar::checkStructMemberUsage() for (const Variable &var : scope.varlist) { // only warn for variables without side effects - if (!var.typeStartToken()->isStandardType() && !var.isPointer() && !astIsContainer(var.nameToken()) && !mTokenizer->getSymbolDatabase()->isRecordTypeWithoutSideEffects(var.type())) + if (!(var.valueType() && var.valueType()->type >= ValueType::VOID) && !var.isPointer() && !astIsContainer(var.nameToken()) && + !astIsSmartPointer(var.nameToken()) && !mTokenizer->getSymbolDatabase()->isRecordTypeWithoutSideEffects(var.type())) continue; if (isInherited && !var.isPrivate()) continue; @@ -1703,12 +1695,12 @@ void CheckUnusedVar::checkStructMemberUsage() } } -void CheckUnusedVar::unusedStructMemberError(const Token* tok, const std::string& structname, const std::string& varname, const std::string& prefix) +void CheckUnusedVarImpl::unusedStructMemberError(const Token* tok, const std::string& structname, const std::string& varname, const std::string& prefix) { reportError(tok, Severity::style, "unusedStructMember", "$symbol:" + structname + "::" + varname + '\n' + prefix + " member '$symbol' is never used.", CWE563, Certainty::normal); } -bool CheckUnusedVar::isEmptyType(const Type* type) +bool CheckUnusedVarImpl::isEmptyType(const Type* type) { // a type that has no variables and no constructor @@ -1729,21 +1721,22 @@ bool CheckUnusedVar::isEmptyType(const Type* type) return (emptyType = false); } -void CheckUnusedVar::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckUnusedVar::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { - CheckUnusedVar checkUnusedVar(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckUnusedVarImpl checkUnusedVar(&tokenizer, tokenizer.getSettings(), errorLogger); // Coding style checks checkUnusedVar.checkStructMemberUsage(); checkUnusedVar.checkFunctionVariableUsage(); } -void CheckUnusedVar::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const +void CheckUnusedVar::getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const { - CheckUnusedVar c(nullptr, settings, errorLogger); + CheckUnusedVarImpl c(nullptr, settings, errorLogger); c.unusedVariableError(nullptr, "varname"); c.allocatedButUnusedVariableError(nullptr, "varname"); c.unreadVariableError(nullptr, "varname", false); c.unassignedVariableError(nullptr, "varname"); c.unusedStructMemberError(nullptr, "structname", "variable"); } + diff --git a/lib/checkunusedvar.h b/lib/checkunusedvar.h index 5ab79514cf9..2239b4a60d8 100644 --- a/lib/checkunusedvar.h +++ b/lib/checkunusedvar.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 @@ -22,6 +22,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include @@ -42,19 +43,33 @@ class Tokenizer; /** @brief Various small checks */ class CPPCHECKLIB CheckUnusedVar : public Check { - friend class TestUnusedVar; - public: /** @brief This constructor is used when registering the CheckClass */ - CheckUnusedVar() : Check(myName()) {} + CheckUnusedVar() : Check("UnusedVar") {} private: - /** @brief This constructor is used when running checks. */ - CheckUnusedVar(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} - /** @brief Run checks against the normal token list */ - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; + + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; + + std::string classInfo() const override { + return "UnusedVar checks\n" + + // style + "- unused variable\n" + "- allocated but unused variable\n" + "- unread variable\n" + "- unassigned variable\n" + "- unused struct member\n"; + } +}; + +class CPPCHECKLIB CheckUnusedVarImpl : public CheckImpl { +public: + /** @brief This constructor is used when running checks. */ + CheckUnusedVarImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} /** @brief %Check for unused function variables */ void checkFunctionVariableUsage_iterateScopes(const Scope* scope, Variables& variables) const; @@ -72,25 +87,7 @@ class CPPCHECKLIB CheckUnusedVar : public Check { void unreadVariableError(const Token *tok, const std::string &varname, bool modified); void unassignedVariableError(const Token *tok, const std::string &varname); - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - static std::string myName() { - return "UnusedVar"; - } - - std::string classInfo() const override { - return "UnusedVar checks\n" - - // style - "- unused variable\n" - "- allocated but unused variable\n" - "- unread variable\n" - "- unassigned variable\n" - "- unused struct member\n"; - } - std::map mIsEmptyTypeMap; - }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/checkvaarg.cpp b/lib/checkvaarg.cpp index 8151957a7d7..ae8b1626ba6 100644 --- a/lib/checkvaarg.cpp +++ b/lib/checkvaarg.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,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() //--------------------------------------------------------------------------- @@ -47,11 +39,11 @@ static const CWE CWE664(664U); // Improper Control of a Resource Through its L static const CWE CWE688(688U); // Function Call With Incorrect Variable or Reference as Argument static const CWE CWE758(758U); // Reliance on Undefined, Unspecified, or Implementation-Defined Behavior -void CheckVaarg::va_start_argument() +void CheckVaargImpl::va_start_argument() { const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase(); const std::size_t functions = symbolDatabase->functionScopes.size(); - const bool printWarnings = mSettings->severity.isEnabled(Severity::warning); + const bool printWarnings = mSettings.severity.isEnabled(Severity::warning); logChecker("CheckVaarg::va_start_argument"); @@ -81,13 +73,13 @@ void CheckVaarg::va_start_argument() } } -void CheckVaarg::wrongParameterTo_va_start_error(const Token *tok, const std::string& paramIsName, const std::string& paramShouldName) +void CheckVaargImpl::wrongParameterTo_va_start_error(const Token *tok, const std::string& paramIsName, const std::string& paramShouldName) { reportError(tok, Severity::warning, "va_start_wrongParameter", "'" + paramIsName + "' given to va_start() is not last named argument of the function. Did you intend to pass '" + paramShouldName + "'?", CWE688, Certainty::normal); } -void CheckVaarg::referenceAs_va_start_error(const Token *tok, const std::string& paramName) +void CheckVaargImpl::referenceAs_va_start_error(const Token *tok, const std::string& paramName) { reportError(tok, Severity::error, "va_start_referencePassed", "Using reference '" + paramName + "' as parameter for va_start() results in undefined behaviour.", CWE758, Certainty::normal); @@ -98,9 +90,9 @@ void CheckVaarg::referenceAs_va_start_error(const Token *tok, const std::string& // Detect va_list usage after va_end() //--------------------------------------------------------------------------- -void CheckVaarg::va_list_usage() +void CheckVaargImpl::va_list_usage() { - if (mSettings->clang) + if (mSettings.clang) return; logChecker("CheckVaarg::va_list_usage"); // notclang @@ -163,34 +155,34 @@ void CheckVaarg::va_list_usage() } } -void CheckVaarg::va_end_missingError(const Token *tok, const std::string& varname) +void CheckVaargImpl::va_end_missingError(const Token *tok, const std::string& varname) { reportError(tok, Severity::error, "va_end_missing", "va_list '" + varname + "' was opened but not closed by va_end().", CWE664, Certainty::normal); } -void CheckVaarg::va_list_usedBeforeStartedError(const Token *tok, const std::string& varname) +void CheckVaargImpl::va_list_usedBeforeStartedError(const Token *tok, const std::string& varname) { reportError(tok, Severity::error, "va_list_usedBeforeStarted", "va_list '" + varname + "' used before va_start() was called.", CWE664, Certainty::normal); } -void CheckVaarg::va_start_subsequentCallsError(const Token *tok, const std::string& varname) +void CheckVaargImpl::va_start_subsequentCallsError(const Token *tok, const std::string& varname) { reportError(tok, Severity::error, "va_start_subsequentCalls", "va_start() or va_copy() called subsequently on '" + varname + "' without va_end() in between.", CWE664, Certainty::normal); } -void CheckVaarg::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) +void CheckVaarg::runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) { - CheckVaarg check(&tokenizer, &tokenizer.getSettings(), errorLogger); + CheckVaargImpl check(&tokenizer, tokenizer.getSettings(), errorLogger); check.va_start_argument(); check.va_list_usage(); } -void CheckVaarg::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const +void CheckVaarg::getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const { - CheckVaarg c(nullptr, settings, errorLogger); + CheckVaargImpl c(nullptr, settings, errorLogger); c.wrongParameterTo_va_start_error(nullptr, "arg1", "arg2"); c.referenceAs_va_start_error(nullptr, "arg1"); c.va_end_missingError(nullptr, "vl"); diff --git a/lib/checkvaarg.h b/lib/checkvaarg.h index 7af5d98d66f..eea3f345bcc 100644 --- a/lib/checkvaarg.h +++ b/lib/checkvaarg.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,6 +23,7 @@ //--------------------------------------------------------------------------- #include "check.h" +#include "checkimpl.h" #include "config.h" #include @@ -41,13 +42,28 @@ class Tokenizer; class CPPCHECKLIB CheckVaarg : public Check { public: - CheckVaarg() : Check(myName()) {} + CheckVaarg() : Check("Vaarg") {} + + void runChecks(const Tokenizer &tokenizer, ErrorLogger& errorLogger) override; private: - CheckVaarg(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} + void getErrorMessages(ErrorLogger& errorLogger, const Settings &settings) const override; + + std::string classInfo() const override { + return "Check for misusage of variable argument lists:\n" + "- Wrong parameter passed to va_start()\n" + "- Reference passed to va_start()\n" + "- Missing va_end()\n" + "- Using va_list before it is opened\n" + "- Subsequent calls to va_start/va_copy()\n"; + } +}; - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; +class CPPCHECKLIB CheckVaargImpl : public CheckImpl +{ +public: + CheckVaargImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) + : CheckImpl(tokenizer, settings, errorLogger) {} void va_start_argument(); void va_list_usage(); @@ -57,21 +73,6 @@ class CPPCHECKLIB CheckVaarg : public Check { void va_end_missingError(const Token *tok, const std::string& varname); void va_list_usedBeforeStartedError(const Token *tok, const std::string& varname); void va_start_subsequentCallsError(const Token *tok, const std::string& varname); - - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - static std::string myName() { - return "Vaarg"; - } - - std::string classInfo() const override { - return "Check for misusage of variable argument lists:\n" - "- Wrong parameter passed to va_start()\n" - "- Reference passed to va_start()\n" - "- Missing va_end()\n" - "- Using va_list before it is opened\n" - "- Subsequent calls to va_start/va_copy()\n"; - } }; /// @} diff --git a/lib/clangimport.cpp b/lib/clangimport.cpp index c96a678347a..98c0e700d83 100644 --- a/lib/clangimport.cpp +++ b/lib/clangimport.cpp @@ -140,7 +140,7 @@ static std::vector splitString(const std::string &line) pos2 = line.find('\"', pos1+1); else if (line[pos1] == '\'') { pos2 = line.find('\'', pos1+1); - if (pos2 < static_cast(line.size()) - 3 && line.compare(pos2, 3, "\':\'", 0, 3) == 0) + if (pos2 < line.size() - 3 && line.compare(pos2, 3, "\':\'", 0, 3) == 0) pos2 = line.find('\'', pos2 + 3); } else { pos2 = pos1; @@ -303,7 +303,7 @@ namespace clangimport { } // "}" tokens that are not end-of-scope - std::set mNotScope; + std::set mNotScope; std::map scopeAccessControl; private: @@ -357,7 +357,7 @@ namespace clangimport { /** * @throws InternalError thrown if index is out of bounds */ - AstNodePtr getChild(int c) { + AstNodePtr getChild(size_t c) { if (c >= children.size()) { std::ostringstream err; err << "ClangImport: AstNodePtr::getChild(" << c << ") out of bounds. children.size=" << children.size() << " " << nodeType; @@ -509,7 +509,7 @@ void clangimport::AstNode::dumpAst(int num, int indent) const for (const auto& tok: mExtTokens) std::cout << " " << tok; std::cout << std::endl; - for (int c = 0; c < children.size(); ++c) { + for (size_t c = 0; c < children.size(); ++c) { if (children[c]) children[c]->dumpAst(c, indent + 2); else @@ -1432,7 +1432,7 @@ void clangimport::AstNode::createTokensFunctionDecl(TokenList &tokenList) function->nestedIn = nestedIn; function->argDef = par1; // Function arguments - for (int i = 0; i < children.size(); ++i) { + for (size_t i = 0; i < children.size(); ++i) { AstNodePtr child = children[i]; if (child->nodeType != ParmVarDecl) continue; @@ -1657,7 +1657,7 @@ void clangimport::parseClangAstDump(Tokenizer &tokenizer, std::istream &f) continue; } - const int level = (pos1 - 1) / 2; + const size_t level = (pos1 - 1) / 2; if (level == 0 || level > tree.size()) continue; diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 3ef1e7c83e3..26d98c0c7b4 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -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" @@ -46,6 +47,7 @@ #ifdef HAVE_RULES #include "regex.h" +#include "rule.h" #endif #include @@ -59,6 +61,7 @@ #include // IWYU pragma: keep #include #include +#include #include #include #include @@ -98,9 +101,9 @@ class CppCheck::CppCheckLogger : public ErrorLogger closePlist(); } - void setRemarkComments(std::vector remarkComments) + void addRemarkComments(const std::vector &remarkComments) { - mRemarkComments = std::move(remarkComments); + mRemarkComments.insert(mRemarkComments.end(), remarkComments.begin(), remarkComments.end()); } void setLocationMacros(const Token* startTok, const std::vector& files) @@ -122,17 +125,25 @@ class CppCheck::CppCheckLogger : public ErrorLogger mErrorList.clear(); } - void openPlist(const std::string& filename, const std::vector& files) + void openPlist(const std::string& filename) { mPlistFile.open(filename); - mPlistFile << ErrorLogger::plistHeader(version(), files); + mPlistFile << ErrorLogger::plistHeader(version()); + } + + void setPlistFilenames(std::vector files) + { + if (mPlistFile.is_open()) { + mPlistFilenames = std::move(files); + } } void closePlist() { if (mPlistFile.is_open()) { - mPlistFile << ErrorLogger::plistFooter(); + mPlistFile << ErrorLogger::plistFooter(mPlistFilenames); mPlistFile.close(); + mPlistFilenames.clear(); } } @@ -280,6 +291,7 @@ class CppCheck::CppCheckLogger : public ErrorLogger std::map> mLocationMacros; // What macros are used on a location? std::ofstream mPlistFile; + std::vector mPlistFilenames; unsigned int mExitCode{}; @@ -823,6 +835,7 @@ unsigned int CppCheck::check(const FileSettings &fs) else tempSettings.userDefines += fs.cppcheckDefines(); tempSettings.includePaths = fs.includePaths; + tempSettings.userIncludes.insert(tempSettings.userIncludes.end(), fs.forcedIncludes.cbegin(), fs.forcedIncludes.cend()); tempSettings.userUndefs.insert(fs.undefs.cbegin(), fs.undefs.cend()); if (fs.standard.find("++") != std::string::npos) tempSettings.standards.setCPP(fs.standard); @@ -895,7 +908,7 @@ unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string return checkInternal(file, cfgname, f); } -void CppCheck::checkPlistOutput(const FileWithDetails& file, const std::vector& files) +void CppCheck::checkPlistOutput(const FileWithDetails& file) { if (!mSettings.plistOutput.empty()) { const bool slashFound = file.spath().find('/') != std::string::npos; @@ -906,7 +919,7 @@ void CppCheck::checkPlistOutput(const FileWithDetails& file, const std::vector {}(file.spath()); filename = mSettings.plistOutput + noSuffixFilename + "_" + std::to_string(fileNameHash) + ".plist"; - mLogger->openPlist(filename, files); + mLogger->openPlist(filename); } } @@ -974,7 +987,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str tokenlist.createTokens(std::move(tokens)); // this is not a real source file - we just want to tokenize it. treat it as C anyways as the language needs to be determined. Tokenizer tokenizer(std::move(tokenlist), mErrorLogger); - mUnusedFunctionsCheck->parseTokens(tokenizer, mSettings); + mUnusedFunctionsCheck->parseTokens(tokenizer, mSettings.library); if (analyzerInformation) { mLogger->setAnalyzerInfo(nullptr); @@ -997,24 +1010,16 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str if (preprocessor.reportOutput(outputList, true)) return mLogger->exitcode(); - if (!preprocessor.loadFiles(files)) - return mLogger->exitcode(); - - checkPlistOutput(file, files); + checkPlistOutput(file); - std::string dumpProlog; + std::string dumpFooter; if (mSettings.dump || !mSettings.addons.empty()) { - dumpProlog += getDumpFileContentsRawTokens(files, tokens1); + dumpFooter += getDumpFileContentsRawTokensFooter(tokens1); } // Parse comments and then remove them - mLogger->setRemarkComments(preprocessor.getRemarkComments()); + mLogger->addRemarkComments(preprocessor.getRemarkComments()); preprocessor.inlineSuppressions(mSuppressions.nomsg); - if (mSettings.dump || !mSettings.addons.empty()) { - std::ostringstream oss; - mSuppressions.nomsg.dump(oss); - dumpProlog += oss.str(); - } preprocessor.removeComments(); if (!mSettings.buildDir.empty()) { @@ -1037,19 +1042,45 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str } // Get directives - std::list directives = preprocessor.createDirectives(); + std::list directives; + preprocessor.createDirectives(directives); preprocessor.simplifyPragmaAsm(); + std::set configurations; + std::set configDefines = { "__cplusplus" }; + + // Insert library defines + const auto getDefineName = [](const std::string &defineString) { + return defineString.substr(0, defineString.find_first_of("( ")); + }; + std::transform(mSettings.library.defines().begin(), + mSettings.library.defines().end(), + std::inserter(configDefines, configDefines.end()), + getDefineName); + + preprocessor.setLoadCallback([&](simplecpp::FileData &data) { + // Do preprocessing on included file + mLogger->addRemarkComments(preprocessor.getRemarkComments(data.tokens)); + preprocessor.inlineSuppressions(data.tokens, mSuppressions.nomsg); + Preprocessor::removeComments(data.tokens); + Preprocessor::createDirectives(data.tokens, directives); + Preprocessor::simplifyPragmaAsm(data.tokens); + // Discover new configurations from included file + if (configurations.size() < maxConfigs) + preprocessor.getConfigs(data.filename, data.tokens, configDefines, configurations); + }); + preprocessor.setPlatformInfo(); // Get configurations.. - std::set configurations; if (maxConfigs > 1) { Timer::run("Preprocessor::getConfigs", mTimerResults, [&]() { - configurations = preprocessor.getConfigs(); + configurations = { "" }; + preprocessor.getConfigs(configDefines, configurations); + preprocessor.loadFiles(files); }); } else { - configurations.insert(mSettings.userDefines); + configurations = { mSettings.userDefines }; } if (mSettings.checkConfiguration) { @@ -1086,7 +1117,6 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str createDumpFile(mSettings, file, fdump, dumpFile); if (fdump.is_open()) { fdump << getLibraryDumpData(); - fdump << dumpProlog; if (!mSettings.dump) filesDeleter.addFile(dumpFile); } @@ -1134,15 +1164,7 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str codeWithoutCfg = preprocessor.getcode(currentConfig, files, true); }); - if (startsWith(codeWithoutCfg,"#file")) - codeWithoutCfg.insert(0U, "//"); std::string::size_type pos = 0; - while ((pos = codeWithoutCfg.find("\n#file",pos)) != std::string::npos) - codeWithoutCfg.insert(pos+1U, "//"); - pos = 0; - while ((pos = codeWithoutCfg.find("\n#endfile",pos)) != std::string::npos) - codeWithoutCfg.insert(pos+1U, "//"); - pos = 0; while ((pos = codeWithoutCfg.find(Preprocessor::macroChar,pos)) != std::string::npos) codeWithoutCfg[pos] = ' '; mErrorLogger.reportOut(codeWithoutCfg, Color::Reset); @@ -1264,12 +1286,20 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str } // TODO: will not be closed if we encountered an exception - // dumped all configs, close root element now if (fdump.is_open()) { + // dump all filenames, raw tokens, suppressions + std::string dumpHeader = getDumpFileContentsRawTokensHeader(files); + fdump << getDumpFileContentsRawTokens(dumpHeader, dumpFooter); + mSuppressions.nomsg.dump(fdump); + // dumped all configs, close root element now fdump << "" << std::endl; fdump.close(); } + if (!mSettings.plistOutput.empty()) { + mLogger->setPlistFilenames(std::move(files)); + } + executeAddons(dumpFile, file); } catch (const TerminateException &) { // Analysis is terminated @@ -1338,8 +1368,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; @@ -1357,17 +1386,17 @@ void CppCheck::checkNormalTokens(const Tokenizer &tokenizer, AnalyzerInformation return; } - Timer::run(check->name() + "::runChecks", mTimerResults, [&]() { - check->runChecks(tokenizer, &mErrorLogger); + Timer::run(c->name() + "::runChecks", mTimerResults, [&]() { + c->runChecks(tokenizer, mErrorLogger); }); } } if (mSettings.checks.isEnabled(Checks::unusedFunction) && !mSettings.buildDir.empty()) { - unusedFunctionsChecker.parseTokens(tokenizer, mSettings); + unusedFunctionsChecker.parseTokens(tokenizer, mSettings.library); } if (mUnusedFunctionsCheck && mSettings.useSingleJob() && mSettings.buildDir.empty()) { - mUnusedFunctionsCheck->parseTokens(tokenizer, mSettings); + mUnusedFunctionsCheck->parseTokens(tokenizer, mSettings.library); } if (mSettings.clang) { @@ -1378,7 +1407,7 @@ void CppCheck::checkNormalTokens(const Tokenizer &tokenizer, AnalyzerInformation if (mSettings.useSingleJob() || analyzerInformation) { // Analyse the tokens.. { - CTU::FileInfo * const fi1 = CTU::getFileInfo(tokenizer); + const CTU::FileInfo * const fi1 = CTU::getFileInfo(tokenizer); if (analyzerInformation) analyzerInformation->setFileInfo("ctu", fi1->toString()); if (mSettings.useSingleJob()) @@ -1388,11 +1417,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 (const 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 @@ -1416,7 +1444,7 @@ void CppCheck::checkNormalTokens(const Tokenizer &tokenizer, AnalyzerInformation #ifdef HAVE_RULES bool CppCheck::hasRule(const std::string &tokenlist) const { - return std::any_of(mSettings.rules.cbegin(), mSettings.rules.cend(), [&](const Settings::Rule& rule) { + return std::any_of(mSettings.rules.cbegin(), mSettings.rules.cend(), [&](const Rule& rule) { return rule.tokenlist == tokenlist; }); } @@ -1434,7 +1462,7 @@ void CppCheck::executeRules(const std::string &tokenlist, const TokenList &list) str += tok->str(); } - for (const Settings::Rule &rule : mSettings.rules) { + for (const Rule &rule : mSettings.rules) { if (rule.tokenlist != tokenlist) continue; @@ -1714,8 +1742,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); @@ -1832,13 +1860,12 @@ 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) - errors |= mUnusedFunctionsCheck->check(mSettings, mErrorLogger); + errors |= mUnusedFunctionsCheck->check(mSettings.library, mErrorLogger); return errors && (mLogger->exitcode() > 0); } @@ -1849,14 +1876,14 @@ unsigned int CppCheck::analyseWholeProgram(const std::string &buildDir, const st CheckUnusedFunctions::analyseWholeProgram(mSettings, mErrorLogger, buildDir); if (mUnusedFunctionsCheck) - mUnusedFunctionsCheck->check(mSettings, mErrorLogger); + mUnusedFunctionsCheck->check(mSettings.library, mErrorLogger); if (Settings::unusedFunctionOnly()) return mLogger->exitcode(); executeAddonsWholeProgram(files, fileSettings, ctuInfo); - std::list fileInfoList; + std::list fileInfoList; CTU::FileInfo ctuFileInfo; const auto handler = [&fileInfoList, &ctuFileInfo](const char* checkattr, const tinyxml2::XMLElement* e, const AnalyzerInformation::Info& filesTxtInfo) { @@ -1864,10 +1891,9 @@ 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; + if (const Check::FileInfo* fi = check->loadFileInfoFromXml(e, filesTxtInfo.sourceFile)) { fileInfoList.push_back(fi); } } @@ -1881,12 +1907,11 @@ unsigned int CppCheck::analyseWholeProgram(const std::string &buildDir, const st } else { // Analyse the tokens - // cppcheck-suppress shadowFunction - TODO: fix this - for (Check *check : Check::instances()) - check->analyseWholeProgram(ctuFileInfo, fileInfoList, mSettings, mErrorLogger); + for (Check * const c : CheckInstances::get()) + c->analyseWholeProgram(ctuFileInfo, fileInfoList, mSettings, mErrorLogger); } - for (Check::FileInfo *fi : fileInfoList) + for (const Check::FileInfo *fi : fileInfoList) delete fi; return mLogger->exitcode(); @@ -1902,9 +1927,26 @@ bool CppCheck::isPremiumCodingStandardId(const std::string& id) const { return false; } -std::string CppCheck::getDumpFileContentsRawTokens(const std::vector& files, const simplecpp::TokenList& tokens1) const { +std::string CppCheck::getDumpFileContentsRawTokens(const std::vector& files, const simplecpp::TokenList& tokens1) const +{ + std::string header = getDumpFileContentsRawTokensHeader(files); + std::string footer = getDumpFileContentsRawTokensFooter(tokens1); + return getDumpFileContentsRawTokens(header, footer); +} + +std::string CppCheck::getDumpFileContentsRawTokens(const std::string& header, const std::string& footer) +{ std::string dumpProlog; dumpProlog += " \n"; + dumpProlog += header; + dumpProlog += footer; + dumpProlog += " \n"; + return dumpProlog; +} + +std::string CppCheck::getDumpFileContentsRawTokensHeader(const std::vector& files) const +{ + std::string dumpProlog; for (unsigned int i = 0; i < files.size(); ++i) { dumpProlog += " \n"; } + return dumpProlog; +} + +std::string CppCheck::getDumpFileContentsRawTokensFooter(const simplecpp::TokenList& tokens1) +{ + std::string dumpProlog; for (const simplecpp::Token *tok = tokens1.cfront(); tok; tok = tok->next) { dumpProlog += " location.line); dumpProlog += "\" "; - dumpProlog +="column=\""; + dumpProlog += "column=\""; dumpProlog += std::to_string(tok->location.col); dumpProlog += "\" "; @@ -1933,6 +1981,5 @@ std::string CppCheck::getDumpFileContentsRawTokens(const std::vector #include +#ifdef HAVE_RULES class TokenList; +#endif struct FileSettings; class CheckUnusedFunctions; class Tokenizer; @@ -151,6 +153,9 @@ class CPPCHECKLIB CppCheck { * @brief Get dumpfile contents, this is only public for testing purposes */ std::string getDumpFileContentsRawTokens(const std::vector& files, const simplecpp::TokenList& tokens1) const; + static std::string getDumpFileContentsRawTokens(const std::string& header, const std::string& footer); + std::string getDumpFileContentsRawTokensHeader(const std::vector& files) const; + static std::string getDumpFileContentsRawTokensFooter(const simplecpp::TokenList& tokens1); std::string getLibraryDumpData() const; @@ -181,7 +186,7 @@ class CPPCHECKLIB CppCheck { */ unsigned int checkFile(const FileWithDetails& file, const std::string &cfgname); - void checkPlistOutput(const FileWithDetails& file, const std::vector& files); + void checkPlistOutput(const FileWithDetails& file); /** * @brief Check a file using buffer @@ -248,7 +253,7 @@ class CPPCHECKLIB CppCheck { bool mUseGlobalSuppressions; /** File info used for whole program analysis */ - std::list mFileInfo; + std::list mFileInfo; /** Callback for executing a shell command (exe, args, output) */ ExecuteCmdFn mExecuteCommand; diff --git a/lib/cppcheck.vcxproj b/lib/cppcheck.vcxproj index b0e52a814fe..553392c53c2 100644 --- a/lib/cppcheck.vcxproj +++ b/lib/cppcheck.vcxproj @@ -32,12 +32,6 @@ - - Create - Create - Create - Create - @@ -50,6 +44,12 @@ + + Create + Create + Create + Create + @@ -57,6 +57,7 @@ + @@ -123,6 +124,7 @@ + @@ -130,6 +132,7 @@ + @@ -165,6 +168,7 @@ + diff --git a/lib/ctu.cpp b/lib/ctu.cpp index 938bb2a4dcc..feef065d3ac 100644 --- a/lib/ctu.cpp +++ b/lib/ctu.cpp @@ -280,11 +280,11 @@ std::list CTU::loadUnsafeUsageListFromXml(const tiny return ret; } -static int isCallFunction(const Scope *scope, int argnr, const Token *&tok) +static size_t isCallFunction(const Scope *scope, size_t argnr, const Token *&tok) { const Variable * const argvar = scope->function->getArgumentVar(argnr); if (!argvar->isPointer()) - return -1; + return 0; for (const Token *tok2 = scope->bodyStart; tok2 != scope->bodyEnd; tok2 = tok2->next()) { if (tok2->variable() != argvar) continue; @@ -306,11 +306,11 @@ static int isCallFunction(const Scope *scope, int argnr, const Token *&tok) tok = prev->previous(); return argnr2; } - return -1; + return 0; } -CTU::FileInfo *CTU::getFileInfo(const Tokenizer &tokenizer) +const CTU::FileInfo *CTU::getFileInfo(const Tokenizer &tokenizer) { const SymbolDatabase * const symbolDatabase = tokenizer.getSymbolDatabase(); @@ -330,7 +330,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer &tokenizer) if (!tokFunction) continue; const std::vector args(getArguments(tok->previous())); - for (int argnr = 0; argnr < args.size(); ++argnr) { + for (size_t argnr = 0; argnr < args.size(); ++argnr) { const Token *argtok = args[argnr]; if (!argtok) continue; @@ -427,9 +427,9 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer &tokenizer) } // Nested function calls - for (int argnr = 0; argnr < scopeFunction->argCount(); ++argnr) { + for (size_t argnr = 0; argnr < scopeFunction->argCount(); ++argnr) { const Token *tok; - const int argnr2 = isCallFunction(&scope, argnr, tok); + const size_t argnr2 = isCallFunction(&scope, argnr, tok); if (argnr2 > 0) { FileInfo::NestedCall nestedCall(tokenizer, scopeFunction, tok); nestedCall.myArgNr = argnr + 1; @@ -442,7 +442,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer &tokenizer) return fileInfo; } -static std::vector> getUnsafeFunction(const Settings &settings, const Scope *scope, int argnr, bool (*isUnsafeUsage)(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *value)) +static std::vector> getUnsafeFunction(const Settings &settings, const Scope *scope, size_t argnr, bool (*isUnsafeUsage)(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *value)) { std::vector> ret; const Variable * const argvar = scope->function->getArgumentVar(argnr); @@ -487,7 +487,7 @@ std::list CTU::getUnsafeUsage(const Tokenizer &token const Function *const function = scope.function; // "Unsafe" functions unconditionally reads data before it is written.. - for (int argnr = 0; argnr < function->argCount(); ++argnr) { + for (size_t argnr = 0; argnr < function->argCount(); ++argnr) { for (const std::pair &v : getUnsafeFunction(settings, &scope, argnr, isUnsafeUsage)) { const Token *tok = v.first; const MathLib::bigint val = v.second.value; @@ -500,7 +500,7 @@ std::list CTU::getUnsafeUsage(const Tokenizer &token } static bool findPath(const std::string &callId, - nonneg int callArgNr, + size_t callArgNr, MathLib::bigint unsafeValue, CTU::FileInfo::InvalidValueType invalidValue, const std::map> &callsMap, diff --git a/lib/ctu.h b/lib/ctu.h index 4f5e0b0294c..76baff21b9f 100644 --- a/lib/ctu.h +++ b/lib/ctu.h @@ -52,6 +52,8 @@ namespace tinyxml2 { namespace CTU { class CPPCHECKLIB FileInfo : public Check::FileInfo { public: + FileInfo() : Check::FileInfo("") {} + enum class InvalidValueType : std::uint8_t { null, uninit, bufferOverflow }; std::string toString() const override; @@ -77,14 +79,14 @@ namespace CTU { struct UnsafeUsage { UnsafeUsage() = default; - UnsafeUsage(std::string myId, nonneg int myArgNr, std::string myArgumentName, Location location, MathLib::bigint value) + UnsafeUsage(std::string myId, size_t myArgNr, std::string myArgumentName, Location location, MathLib::bigint value) : myId(std::move(myId)) , myArgNr(myArgNr) , myArgumentName(std::move(myArgumentName)) , location(std::move(location)) , value(value) {} std::string myId; - nonneg int myArgNr{}; + size_t myArgNr{}; std::string myArgumentName; Location location; MathLib::bigint value{}; @@ -94,14 +96,14 @@ namespace CTU { class CallBase { public: CallBase() = default; - CallBase(std::string callId, int callArgNr, std::string callFunctionName, Location loc) + CallBase(std::string callId, size_t callArgNr, std::string callFunctionName, Location loc) : callId(std::move(callId)), callArgNr(callArgNr), callFunctionName(std::move(callFunctionName)), location(std::move(loc)) {} CallBase(const Tokenizer &tokenizer, const Token *callToken); virtual ~CallBase() = default; CallBase(const CallBase&) = default; std::string callId; - int callArgNr{}; + size_t callArgNr{}; std::string callFunctionName; Location location; protected: @@ -136,7 +138,7 @@ namespace CTU { bool loadFromXml(const tinyxml2::XMLElement *xmlElement); std::string myId; - nonneg int myArgNr{}; + size_t myArgNr{}; }; std::list functionCalls; @@ -160,7 +162,7 @@ namespace CTU { CPPCHECKLIB std::string getFunctionId(const Tokenizer &tokenizer, const Function *function); /** @brief Parse current TU and extract file info */ - CPPCHECKLIB RET_NONNULL FileInfo *getFileInfo(const Tokenizer &tokenizer); + CPPCHECKLIB RET_NONNULL const FileInfo *getFileInfo(const Tokenizer &tokenizer); CPPCHECKLIB std::list getUnsafeUsage(const Tokenizer &tokenizer, const Settings &settings, bool (*isUnsafeUsage)(const Settings &settings, const Token *argtok, FileInfo::Value *value)); diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index 3b05a7d5a8f..d58c5abcbba 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -821,7 +821,7 @@ std::string ErrorLogger::toxml(const std::string &str) return xml; } -std::string ErrorLogger::plistHeader(const std::string &version, const std::vector &files) +std::string ErrorLogger::plistHeader(const std::string &version) { std::ostringstream ostr; ostr << "\r\n" @@ -829,12 +829,7 @@ std::string ErrorLogger::plistHeader(const std::string &version, const std::vect << "\r\n" << "\r\n" << " clang_version\r\n" - << "cppcheck version " << version << "\r\n" - << " files\r\n" - << " \r\n"; - for (const std::string & file : files) - ostr << " " << ErrorLogger::toxml(file) << "\r\n"; - ostr << " \r\n" + << " cppcheck version " << version << "\r\n" << " diagnostics\r\n" << " \r\n"; return ostr.str(); diff --git a/lib/errorlogger.h b/lib/errorlogger.h index d739cb3fbf9..97cc3e7f82e 100644 --- a/lib/errorlogger.h +++ b/lib/errorlogger.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -88,7 +89,7 @@ class CPPCHECKLIB ErrorMessage { std::string stringify(bool addcolumn = false) const; unsigned int fileIndex; - int line; // negative value means "no line" + int line; // negative value means "no line" - TODO: actually 0 means no line - lines from simplecpp are unsigned unsigned int column; const std::string& getinfo() const { @@ -271,12 +272,19 @@ class CPPCHECKLIB ErrorLogger { */ static std::string toxml(const std::string &str); - static std::string plistHeader(const std::string &version, const std::vector &files); + static std::string plistHeader(const std::string &version); static std::string plistData(const ErrorMessage &msg); - static const char *plistFooter() { - return " \r\n" - "\r\n" - ""; + static std::string plistFooter(const std::vector& files) { + std::ostringstream ostr; + ostr << " \r\n" + << " files\r\n" + << " \r\n"; + for (const std::string& file : files) + ostr << " " << ErrorLogger::toxml(file) << "\r\n"; + ostr << " \r\n" + << "\r\n" + << ""; + return ostr.str(); } static bool isCriticalErrorId(const std::string& id) { diff --git a/lib/filesettings.h b/lib/filesettings.h index 183e38708fd..0ef53db85c5 100644 --- a/lib/filesettings.h +++ b/lib/filesettings.h @@ -46,9 +46,9 @@ class FileWithDetails throw std::runtime_error("empty path specified"); } - void setPath(std::string path) + void setPath(std::string p) { - mPath = std::move(path); + mPath = std::move(p); mPathSimplified = Path::simplifyPath(mPath); mPathAbsolute.clear(); } @@ -76,9 +76,9 @@ class FileWithDetails return mSize; } - void setLang(Standards::Language lang) + void setLang(Standards::Language language) { - mLang = lang; + mLang = language; } Standards::Language lang() const @@ -148,6 +148,7 @@ struct CPPCHECKLIB FileSettings { } std::set undefs; std::list includePaths; + std::list forcedIncludes; // only used by clang mode std::list systemIncludePaths; std::string standard; diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index 5c97528372b..3e227873b26 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -59,6 +59,10 @@ namespace { Analyzer::Terminate terminate = Analyzer::Terminate::None; std::vector loopEnds; int branchCount = 0; + // Nested condition-fork depth on this lineage (copied by fork()); bounds the fan-out. + int forkDepth = 0; + // Total forks of the traversal (shared via the fork() copy); backstop past the depth bound. + std::shared_ptr forkBudget = std::make_shared(0); Progress Break(Analyzer::Terminate t = Analyzer::Terminate::None) { if ((!analyzeOnly || analyzeTerminate) && t != Analyzer::Terminate::None) @@ -73,7 +77,6 @@ namespace { bool check = false; bool escape = false; bool escapeUnknown = false; - bool active = false; bool isEscape() const { return escape || escapeUnknown; } @@ -89,6 +92,9 @@ namespace { bool isDead() const { return action.isModified() || action.isInconclusive() || isEscape(); } + bool hasGoto() const { + return endBlock ? ForwardTraversal::hasGoto(endBlock) : false; + } }; bool stopUpdates() { @@ -138,7 +144,7 @@ namespace { // If we are in a loop then jump to the end if (out) *out = loopEnds.back(); - } else if (Token::Match(tok, "return|throw")) { + } else if (isEscapeKeyword(tok, settings)) { traverseRecursive(tok->astOperand2(), f, traverseUnknown); traverseRecursive(tok->astOperand1(), f, traverseUnknown); return Break(Analyzer::Terminate::Escape); @@ -348,18 +354,6 @@ namespace { return Token::findmatch(endBlock->link(), "goto|break", endBlock); } - bool hasInnerReturnScope(const Token* start, const Token* end) const { - for (const Token* tok=start; tok != end; tok = tok->previous()) { - if (Token::simpleMatch(tok, "}")) { - const Token* ftok = nullptr; - const bool r = isReturnScope(tok, settings.library, &ftok); - if (r) - return true; - } - } - return false; - } - bool isEscapeScope(const Token* endBlock, bool& unknown) const { const Token* ftok = nullptr; const bool r = isReturnScope(endBlock, settings.library, &ftok); @@ -383,30 +377,60 @@ namespace { return a; } - bool checkBranch(Branch& branch) const { - Analyzer::Action a = analyzeScope(branch.endBlock); - branch.action = a; - std::vector ft1 = tryForkUpdateScope(branch.endBlock, a.isModified()); - const bool bail = hasGoto(branch.endBlock); - if (!a.isModified() && !bail) { - if (ft1.empty()) { - // Traverse into the branch to see if there is a conditional escape - if (!branch.escape && hasInnerReturnScope(branch.endBlock->previous(), branch.endBlock->link())) { - ForwardTraversal ft2 = fork(true); - ft2.updateScope(branch.endBlock); - if (ft2.terminate == Analyzer::Terminate::Escape) { - branch.escape = true; - branch.escapeUnknown = false; - } - } - } else { - if (ft1.front().terminate == Analyzer::Terminate::Escape) { - branch.escape = true; - branch.escapeUnknown = false; - } + Progress updateBranch(Branch& branch, int depth) + { + // Save and reset actions + Analyzer::Action prevActions = actions; + actions = Analyzer::Action::None; + Progress p = updateRange(branch.endBlock->link(), branch.endBlock, depth); + branch.action |= actions; + // Restore actions + actions |= prevActions; + + if (terminate == Analyzer::Terminate::Escape) { + branch.escape = true; + // The traversal followed an escaping path, but if the scope does not structurally + // always escape then another path (e.g. a modified fork) falls through, so the escape + // is only conditional - keep isModified() meaningful by not treating it as conclusive. + bool structuralUnknown = false; + const bool structuralEscape = isEscapeScope(branch.endBlock, structuralUnknown); + branch.escapeUnknown = !structuralEscape || structuralUnknown; + // The traversal stopped at the escape, so the rest of the scope was not walked; a + // fall-through path could still modify the value there - include the whole scope's + // actions so isModified() sees it. + if (branch.escapeUnknown) + branch.action |= analyzeScope(branch.endBlock); + } else { + // Detect an escape the traversal did not flag (e.g. an unknown noreturn call); + // escapeUnknown reports a possible (unknown) escape. + branch.escape = isEscapeScope(branch.endBlock, branch.escapeUnknown); + if (terminate != Analyzer::Terminate::None && terminate != Analyzer::Terminate::Modified) { + branch.action |= analyzeScope(branch.endBlock); } } - return bail; + + return p; + } + + // Update the branch that the evaluated condition takes + Progress updateTakenBranch(Branch& branch, const Token* skippedBlock, const Token* condTok, int depth) + { + // The condition is only "known" because of an earlier assumption, so the + // skipped block could still modify the value -> lower to possible + if (!condTok->hasKnownIntValue() && skippedBlock && analyzeScope(skippedBlock).isModified() && + !analyzer->lowerToPossible()) + return Break(Analyzer::Terminate::Bail); + if (!branch.endBlock) + return Progress::Continue; + updateScopeState(branch.endBlock); + if (updateBranch(branch, depth - 1) == Progress::Break) + return Progress::Break; + // The branch was entered because of the tracked value; if it might not + // return (it ends in a call to an unknown, possibly noreturn function) + // then the value might not flow past the branch. + if (!condTok->hasKnownIntValue() && !branch.escape && branch.escapeUnknown && !analyzer->lowerToInconclusive()) + return Break(Analyzer::Terminate::Bail); + return Progress::Continue; } bool reentersLoop(Token* endBlock, const Token* condTok, const Token* stepTok) const { @@ -529,14 +553,12 @@ namespace { forkContinue = false; } - if (allAnalysis.isModified() || !forkContinue) { - // TODO: Don't bail on missing condition - if (!condTok) - return Break(Analyzer::Terminate::Bail); - if (analyzer->isConditional() && stopUpdates()) - return Break(Analyzer::Terminate::Conditional); - analyzer->assume(condTok, false); - } + // TODO: Don't bail on missing condition + if (!condTok) + return Break(Analyzer::Terminate::Bail); + if (analyzer->isConditional() && stopUpdates()) + return Break(Analyzer::Terminate::Conditional); + analyzer->assume(condTok, false); if (forkContinue) { for (ForwardTraversal& ft : ftv) { if (!ft.actions.isIncremental()) @@ -562,16 +584,21 @@ namespace { return updateLoop(endToken, endBlock, condTok, initTok, stepTok, true); } - Progress updateScope(Token* endBlock, int depth = 20) + void updateScopeState(const Token* endBlock) { - if (!endBlock) - return Break(); assert(endBlock->link()); - Token* ctx = endBlock->link()->previous(); + const Token* ctx = endBlock->link()->previous(); if (Token::simpleMatch(ctx, ")")) ctx = ctx->link()->previous(); if (ctx) analyzer->updateState(ctx); + } + + Progress updateScope(Token* endBlock, int depth = 20) + { + if (!endBlock) + return Break(); + updateScopeState(endBlock); return updateRange(endBlock->link(), endBlock, depth); } @@ -646,11 +673,20 @@ namespace { const bool inElse = scope->type == ScopeType::eElse; const bool inDoWhile = scope->type == ScopeType::eDo; const bool inLoop = contains({ScopeType::eDo, ScopeType::eFor, ScopeType::eWhile}, scope->type); + const bool hasElse = Token::simpleMatch(tok, "} else {"); Token* condTok = getCondTokFromEnd(tok); if (!condTok) return Break(); + // When the 'else' branch escapes (e.g. returns), control can only continue + // here via the 'then' branch, so the value established there is still + // definite - keep it known instead of lowering to possible. + bool elseEscape = false; + if (!inLoop && !inElse && hasElse) { + bool unknownEscape = false; + elseEscape = isEscapeScope(tok->linkAt(2), unknownEscape); + } if (!condTok->hasKnownIntValue() || inLoop) { - if (!analyzer->lowerToPossible()) + if (!elseEscape && !analyzer->lowerToPossible()) return Break(Analyzer::Terminate::Bail); } else if (condTok->getKnownIntValue() == inElse) { return Break(); @@ -675,7 +711,7 @@ namespace { } analyzer->assume(condTok, !inElse, Analyzer::Assume::Quiet); assert(!inDoWhile || Token::simpleMatch(tok, "} while (")); - if (Token::simpleMatch(tok, "} else {") || inDoWhile) + if (hasElse || inDoWhile) tok = tok->linkAt(2); } else if (contains({ScopeType::eTry, ScopeType::eCatch}, scope->type)) { if (!analyzer->lowerToPossible()) @@ -731,71 +767,80 @@ namespace { if (!thenBranch.check && !elseBranch.check && stopOnCondition(condTok) && stopUpdates()) return Break(Analyzer::Terminate::Conditional); const bool hasElse = Token::simpleMatch(endBlock, "} else {"); - bool bail = false; - - // Traverse then block - thenBranch.escape = isEscapeScope(endBlock, thenBranch.escapeUnknown); + tok = hasElse ? endBlock->linkAt(2) : endBlock; if (thenBranch.check) { - thenBranch.active = true; - if (updateScope(endBlock, depth - 1) == Progress::Break) + if (updateTakenBranch(thenBranch, hasElse ? elseBranch.endBlock : nullptr, condTok, depth) == + Progress::Break) + return Break(); + } else if (elseBranch.check) { + if (updateTakenBranch(elseBranch, thenBranch.endBlock, condTok, depth) == Progress::Break) return Break(); - } else if (!elseBranch.check) { - thenBranch.active = true; - if (checkBranch(thenBranch)) - bail = true; - } - // Traverse else block - if (hasElse) { - elseBranch.escape = isEscapeScope(endBlock->linkAt(2), elseBranch.escapeUnknown); - if (elseBranch.check) { - elseBranch.active = true; - const Progress result = updateScope(endBlock->linkAt(2), depth - 1); - if (result == Progress::Break) - return Break(); - } else if (!thenBranch.check) { - elseBranch.active = true; - if (checkBranch(elseBranch)) - bail = true; - } - tok = endBlock->linkAt(2); } else { - tok = endBlock; - } - if (thenBranch.active) + const bool conditional = stopOnCondition(condTok); + // The value only flows into the then-branch when the condition can split + // it; for an opaque or correlated condition (e.g. 'if (f(x))') it does + // not, so fork in analyze-only mode: the branch's effect is still tracked + // but nothing is reported in it. + ForwardTraversal ft = fork(!analyzer->updateScope(thenBranch.endBlock, false)); + // The branch is traversed below, so don't record its boundary state here. + ft.analyzer->assume(condTok, true, Analyzer::Assume::Pending); + Progress pThen = ft.updateBranch(thenBranch, depth - 1); + // Merge the fork's actions so a modification in the then-branch bubbles up + // to the enclosing branch's isModified(). actions |= thenBranch.action; - if (elseBranch.active) - actions |= elseBranch.action; - if (bail) - return Break(Analyzer::Terminate::Bail); - if (thenBranch.isDead() && elseBranch.isDead()) { - if (thenBranch.isModified() && elseBranch.isModified()) - return Break(Analyzer::Terminate::Modified); - if (thenBranch.isConclusiveEscape() && elseBranch.isConclusiveEscape()) - return Break(Analyzer::Terminate::Escape); - return Break(Analyzer::Terminate::Bail); - } - // Conditional return - if (thenBranch.active && thenBranch.isEscape() && !hasElse) { - if (!thenBranch.isConclusiveEscape()) { - if (!analyzer->lowerToInconclusive()) - return Break(Analyzer::Terminate::Bail); - } else if (thenBranch.check) { - return Break(); - } else { - if (analyzer->isConditional() && stopUpdates()) - return Break(Analyzer::Terminate::Conditional); - analyzer->assume(condTok, false); + + // Commit the condition as false on the main path only when the then-branch + // is dead. The else block, if any, is traversed separately (Pending); with + // no else the false path continues past the closing brace, so record the + // assumed state there (None). + if (thenBranch.isDead()) + analyzer->assume(condTok, + false, + hasElse ? Analyzer::Assume::Pending : Analyzer::Assume::None); + // The else block is traversed on the main path. If it kills the value + // (modified) the main path stops, but the then-fork may still carry the + // value forward, so defer the break until after the fork continues. + Progress pElse = Progress::Continue; + if (hasElse) + pElse = updateBranch(elseBranch, depth - 1); + if (thenBranch.isDead() || elseBranch.isDead()) { + if (conditional && stopUpdates()) + pElse = Break(Analyzer::Terminate::Conditional); } - } - if (thenBranch.isInconclusive() || elseBranch.isInconclusive()) { - if (!analyzer->lowerToInconclusive()) - return Break(Analyzer::Terminate::Bail); - } else if (thenBranch.isModified() || elseBranch.isModified()) { - if (!hasElse && analyzer->isConditional() && stopUpdates()) - return Break(Analyzer::Terminate::Conditional); - if (!analyzer->lowerToPossible()) + if (thenBranch.isModified() || elseBranch.isModified()) { + if (!ft.analyzer->lowerToPossible()) + pThen = Progress::Break; + if (pElse != Progress::Break && !analyzer->lowerToPossible()) + pElse = Break(Analyzer::Terminate::Bail); + } + if (thenBranch.isInconclusive() || elseBranch.isInconclusive()) { + if (!ft.analyzer->lowerToInconclusive()) + pThen = Progress::Break; + if (pElse != Progress::Break && !analyzer->lowerToInconclusive()) + pElse = Break(Analyzer::Terminate::Bail); + } + if (thenBranch.hasGoto() || elseBranch.hasGoto()) { return Break(Analyzer::Terminate::Bail); - analyzer->assume(condTok, elseBranch.isModified()); + } + // Carry the then-fork forward, unless a limit is hit - then only the linear main + // path continues (no bail). forkDepth bounds nesting, forkBudget total. <0 = off. + assert(forkBudget != nullptr); + const int forkDepthLimit = settings.vfOptions.maxForwardConditionForkDepth; + const int forkBudgetLimit = settings.vfOptions.maxForwardConditionForks; + const bool depthOk = forkDepthLimit < 0 || forkDepth < forkDepthLimit; + const bool budgetOk = forkBudgetLimit < 0 || *forkBudget < forkBudgetLimit; + if (pThen != Progress::Break && !thenBranch.isEscape() && depthOk && budgetOk) { + ++(*forkBudget); + ++ft.forkDepth; + ft.updateRange(thenBranch.endBlock, end, depth - 1); + } + if (pElse == Progress::Break) { + // Only the else branch escaped; the then branch falls through, so + // the scope as a whole does not always escape. + if (terminate == Analyzer::Terminate::Escape && !thenBranch.isEscape()) + terminate = Analyzer::Terminate::None; + return Break(); + } } } } else if (Token::simpleMatch(tok, "try {")) { @@ -845,7 +890,7 @@ namespace { return Break(); } else if (Token* callTok = callExpr(tok)) { // TODO: Dont traverse tokens a second time - if (start != callTok && tok != callTok && updateRecursive(callTok->astOperand1()) == Progress::Break) + if (start != callTok && tok != callTok && (tok->str() != "." || tok != callTok->astOperand1()) && updateRecursive(callTok->astOperand1()) == Progress::Break) return Break(); // Since the call could be an unknown macro, traverse the tokens as a range instead of recursively if (!Token::simpleMatch(callTok, "( )") && diff --git a/lib/fwdanalysis.cpp b/lib/fwdanalysis.cpp index c45213a4be9..07ba7cc2e59 100644 --- a/lib/fwdanalysis.cpp +++ b/lib/fwdanalysis.cpp @@ -30,6 +30,7 @@ #include #include #include +#include static bool isUnchanged(const Token *startToken, const Token *endToken, const std::set &exprVarIds, bool local) { @@ -94,7 +95,7 @@ static bool hasVolatileCastOrVar(const Token *expr) return ret; } -FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set &exprVarIds, bool local, bool inInnerClass, int depth) +FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set &exprVarIds, bool local, bool inInnerClass, int depth) const { // Parse the given tokens if (++depth > 1000) @@ -155,10 +156,6 @@ FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token * } if (tok->str() == "}") { - // Known value => possible value - if (tok->scope() == expr->scope()) - mValueFlowKnown = false; - if (tok->scope()->isLoopScope()) { // check condition const Token *conditionStart = nullptr; @@ -195,65 +192,6 @@ FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token * if (Token::simpleMatch(tok, "asm (")) return Result(Result::Type::BAILOUT); - if (mWhat == What::ValueFlow && (Token::Match(tok, "while|for (") || Token::simpleMatch(tok, "do {"))) { - const Token *bodyStart = nullptr; - const Token *conditionStart = nullptr; - if (Token::simpleMatch(tok, "do {")) { - bodyStart = tok->next(); - if (Token::simpleMatch(bodyStart->link(), "} while (")) - conditionStart = bodyStart->link()->tokAt(2); - } else { - conditionStart = tok->next(); - if (Token::simpleMatch(conditionStart->link(), ") {")) - bodyStart = conditionStart->link()->next(); - } - - if (!bodyStart || !conditionStart) - return Result(Result::Type::BAILOUT); - - // Is expr changed in condition? - if (!isUnchanged(conditionStart, conditionStart->link(), exprVarIds, local)) - return Result(Result::Type::BAILOUT); - - // Is expr changed in loop body? - if (!isUnchanged(bodyStart, bodyStart->link(), exprVarIds, local)) - return Result(Result::Type::BAILOUT); - } - - if (mWhat == What::ValueFlow && Token::simpleMatch(tok, "if (") && Token::simpleMatch(tok->linkAt(1), ") {")) { - const Token *bodyStart = tok->linkAt(1)->next(); - const Token *conditionStart = tok->next(); - const Token *condTok = conditionStart->astOperand2(); - if (const ValueFlow::Value* v = condTok->getKnownValue(ValueFlow::Value::ValueType::INT)) { - const bool cond = !!v->intvalue; - if (cond) { - FwdAnalysis::Result result = checkRecursive(expr, bodyStart, bodyStart->link(), exprVarIds, local, true, depth); - if (result.type != Result::Type::NONE) - return result; - } else if (Token::simpleMatch(bodyStart->link(), "} else {")) { - bodyStart = bodyStart->link()->tokAt(2); - FwdAnalysis::Result result = checkRecursive(expr, bodyStart, bodyStart->link(), exprVarIds, local, true, depth); - if (result.type != Result::Type::NONE) - return result; - } - } - tok = bodyStart->link(); - if (isReturnScope(tok, mSettings.library)) - return Result(Result::Type::BAILOUT); - if (Token::simpleMatch(tok, "} else {")) - tok = tok->linkAt(2); - if (!tok) - return Result(Result::Type::BAILOUT); - - // Is expr changed in condition? - if (!isUnchanged(conditionStart, conditionStart->link(), exprVarIds, local)) - return Result(Result::Type::BAILOUT); - - // Is expr changed in condition body? - if (!isUnchanged(bodyStart, bodyStart->link(), exprVarIds, local)) - return Result(Result::Type::BAILOUT); - } - if (!local && Token::Match(tok, "%name% (") && !Token::simpleMatch(tok->linkAt(1), ") {")) { // TODO: this is a quick bailout return Result(Result::Type::BAILOUT); @@ -279,22 +217,15 @@ FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token * parent = parent->astParent(); if (parent->str() == "(" && !parent->isCast()) break; - if (isSameExpression(false, expr, parent, mSettings, true, false, nullptr)) { + if (isSameExpression(false, expr, parent, mSettings, true, false, nullptr)) same = true; - if (mWhat == What::ValueFlow) { - KnownAndToken v; - v.known = mValueFlowKnown; - v.token = parent; - mValueFlow.push_back(v); - } - } if (Token::Match(parent, ". %var%") && parent->next()->varId() && exprVarIds.find(parent->next()->varId()) == exprVarIds.end() && isSameExpression(false, expr->astOperand1(), parent->astOperand1(), mSettings, true, false, nullptr)) { other = true; break; } } - if (mWhat != What::ValueFlow && same && Token::simpleMatch(parent->astParent(), "[") && parent == parent->astParent()->astOperand2()) { + if (same && Token::simpleMatch(parent->astParent(), "[") && parent == parent->astParent()->astOperand2()) { return Result(Result::Type::READ); } if (other) @@ -358,7 +289,7 @@ FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token * ftok = ftok->astParent(); if (ftok && Token::Match(ftok->previous(), "%name% (")) { const std::vector args = getArguments(ftok); - int argnr = 0; + size_t argnr = 0; while (argnr < args.size() && args[argnr] != parent) argnr++; if (argnr < args.size()) { @@ -381,8 +312,6 @@ FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token * return result1; if (mWhat == What::UnusedValue && result1.type == Result::Type::WRITE && expr->variable() && expr->variable()->isReference()) return result1; - if (mWhat == What::ValueFlow && result1.type == Result::Type::WRITE) - mValueFlowKnown = false; if (mWhat == What::Reassign && result1.type == Result::Type::BREAK) { const Token *scopeEndToken = findNextTokenFromBreak(result1.token); if (scopeEndToken) { @@ -394,8 +323,6 @@ FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token * if (Token::simpleMatch(tok->linkAt(1), "} else {")) { const Token *elseStart = tok->linkAt(1)->tokAt(2); const Result &result2 = checkRecursive(expr, elseStart, elseStart->link(), exprVarIds, local, inInnerClass, depth); - if (mWhat == What::ValueFlow && result2.type == Result::Type::WRITE) - mValueFlowKnown = false; if (result2.type == Result::Type::READ || result2.type == Result::Type::BAILOUT) return result2; if (result1.type == Result::Type::WRITE && result2.type == Result::Type::WRITE) @@ -454,7 +381,7 @@ std::set FwdAnalysis::getExprVarIds(const Token* expr, bool* localOu return exprVarIds; } -FwdAnalysis::Result FwdAnalysis::check(const Token* expr, const Token* startToken, const Token* endToken) +FwdAnalysis::Result FwdAnalysis::check(const Token* expr, const Token* startToken, const Token* endToken) const { // all variable ids in expr. bool local = true; @@ -475,7 +402,7 @@ FwdAnalysis::Result FwdAnalysis::check(const Token* expr, const Token* startToke Result result = checkRecursive(expr, startToken, endToken, exprVarIds, local, false); // Break => continue checking in outer scope - while (mWhat!=What::ValueFlow && result.type == FwdAnalysis::Result::Type::BREAK) { + while (result.type == FwdAnalysis::Result::Type::BREAK) { const Token *scopeEndToken = findNextTokenFromBreak(result.token); if (!scopeEndToken) break; @@ -542,7 +469,7 @@ bool FwdAnalysis::possiblyAliased(const Token *expr, const Token *startToken) co if (Token::Match(tok, "%name% (") && !Token::Match(tok, "if|while|for")) { // Is argument passed by reference? const std::vector args = getArguments(tok); - for (int argnr = 0; argnr < args.size(); ++argnr) { + for (size_t argnr = 0; argnr < args.size(); ++argnr) { if (!Token::Match(args[argnr], "%name%|.|::")) continue; if (tok->function() && tok->function()->getArgumentVar(argnr) && !tok->function()->getArgumentVar(argnr)->isReference() && !tok->function()->isConst()) diff --git a/lib/fwdanalysis.h b/lib/fwdanalysis.h index 389ea195da2..34d0da24d4d 100644 --- a/lib/fwdanalysis.h +++ b/lib/fwdanalysis.h @@ -25,7 +25,6 @@ #include #include -#include class Token; class Settings; @@ -60,11 +59,6 @@ class FwdAnalysis { */ bool unusedValue(const Token *expr, const Token *startToken, const Token *endToken); - struct KnownAndToken { - bool known{}; - const Token* token{}; - }; - /** Is there some possible alias for given expression */ bool possiblyAliased(const Token *expr, const Token *startToken) const; @@ -80,13 +74,11 @@ class FwdAnalysis { const Token* token{}; }; - Result check(const Token *expr, const Token *startToken, const Token *endToken); - Result checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set &exprVarIds, bool local, bool inInnerClass, int depth=0); + Result check(const Token *expr, const Token *startToken, const Token *endToken) const; + Result checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set &exprVarIds, bool local, bool inInnerClass, int depth=0) const; const Settings &mSettings; - enum class What : std::uint8_t { Reassign, UnusedValue, ValueFlow } mWhat = What::Reassign; - std::vector mValueFlow; - bool mValueFlowKnown = true; + enum class What : std::uint8_t { Reassign, UnusedValue } mWhat = What::Reassign; }; #endif // fwdanalysisH diff --git a/lib/importproject.cpp b/lib/importproject.cpp index ac19db922ed..0e6ca353480 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -148,6 +149,11 @@ void ImportProject::parseArgs(FileSettings &fs, const std::vector & continue; } + if (!(optArg = getOptArg({ "-include", "/FI", "-FI" }, i)).empty()) { + fs.forcedIncludes.push_back(std::move(optArg)); + continue; + } + if (!(optArg = getOptArg({ "-D", "/D" }, i)).empty()) { defs += optArg + ";"; continue; @@ -523,27 +529,51 @@ bool ImportProject::importSlnx(const std::string& filename, const std::vectorName(), "Solution") != 0) { + errors.emplace_back("Invalid Visual Studio solution file format"); + return false; + } + std::map variables; variables["SolutionDir"] = Path::simplifyPath(Path::getPathFromFilename(filename)); bool found = false; std::vector sharedItemsProjects; + auto processProject = [&](const tinyxml2::XMLElement* projectNode) { + const char* pathAttribute = projectNode->Attribute("Path"); + if (pathAttribute == nullptr) + return true; + + std::string vcxproj(pathAttribute); + vcxproj = Path::toNativeSeparators(std::move(vcxproj)); + + if (Path::getFilenameExtensionInLowerCase(vcxproj) != ".vcxproj") + return true; // skip other project types + + 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; + return true; + }; + 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; + if (!processProject(node)) + return false; + } else if (std::strcmp(name, "Folder") == 0) { + for (const tinyxml2::XMLElement* childNode = node->FirstChildElement(); childNode; childNode = childNode->NextSiblingElement()) { + if (std::strcmp(childNode->Name(), "Project") == 0) { + if (!processProject(childNode)) + return false; } - found = true; } } } @@ -1698,8 +1728,10 @@ void ImportProject::setRelativePaths(const std::string &filename) const std::vector basePaths{Path::fromNativeSeparators(Path::getCurrentPath())}; for (auto &fs: fileSettings) { fs.file.setPath(Path::getRelativePath(fs.filename(), basePaths)); - for (auto &includePath: fs.includePaths) - includePath = Path::getRelativePath(includePath, basePaths); + for (auto &includePath: fs.includePaths) { + const std::string rel = Path::getRelativePath(includePath, basePaths); + includePath = rel.empty() ? "." : rel; + } } } diff --git a/lib/importproject.h b/lib/importproject.h index 608af552408..b8bbbed3fa3 100644 --- a/lib/importproject.h +++ b/lib/importproject.h @@ -110,6 +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); + void setRelativePaths(const std::string &filename); struct SharedItemsProject { bool successful = false; @@ -123,7 +124,6 @@ class CPPCHECKLIB WARN_UNUSED ImportProject { 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); diff --git a/lib/library.cpp b/lib/library.cpp index 7520944d8ad..2a198001d3c 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -1781,6 +1781,8 @@ bool Library::isFunctionConst(const Token *ftok) const const Yield yield = astContainerYield(ftok->astParent()->astOperand1(), *this); if (yield == Yield::EMPTY || yield == Yield::SIZE || yield == Yield::BUFFER_NT) return true; + if ((yield == Yield::START_ITERATOR || yield == Yield::END_ITERATOR) && ftok->str()[0] == 'c') + return true; } return false; } diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index 403662f4df2..c7c055899fd 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -266,7 +266,7 @@ MathLib::value MathLib::value::shiftLeft(const MathLib::value &v) const if (!isInt() || !v.isInt()) throw InternalError(nullptr, "Shift operand is not integer"); MathLib::value ret(*this); - if (v.mIntValue >= MathLib::bigint_bits) { + if (v.mIntValue < 0 || v.mIntValue >= MathLib::bigint_bits || ret.mIntValue < 0) { return ret; } ret.mIntValue <<= v.mIntValue; @@ -278,7 +278,7 @@ MathLib::value MathLib::value::shiftRight(const MathLib::value &v) const if (!isInt() || !v.isInt()) throw InternalError(nullptr, "Shift operand is not integer"); MathLib::value ret(*this); - if (v.mIntValue >= MathLib::bigint_bits) { + if (v.mIntValue < 0 || v.mIntValue >= MathLib::bigint_bits) { return ret; } ret.mIntValue >>= v.mIntValue; diff --git a/lib/mathlib.h b/lib/mathlib.h index 9b6b304501c..84338b5ce70 100644 --- a/lib/mathlib.h +++ b/lib/mathlib.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/path.cpp b/lib/path.cpp index caa45898f99..fc059cdea4e 100644 --- a/lib/path.cpp +++ b/lib/path.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,6 +51,8 @@ #endif #if defined(__APPLE__) #include +#elif defined(__HAIKU__) +#include #endif @@ -158,6 +160,17 @@ std::string Path::getCurrentExecutablePath(const char* fallback) #elif defined(__APPLE__) uint32_t size = sizeof(buf); success = (_NSGetExecutablePath(buf, &size) == 0); +#elif defined(__HAIKU__) + int32 cookie = 0; + image_info info; + while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) + { + if (info.type == B_APP_IMAGE) + { + break; + } + } + return std::string(info.name); #else const char* procPath = #ifdef __SVR4 // Solaris diff --git a/lib/path.h b/lib/path.h index 22bfcf667f3..863e74580f8 100644 --- a/lib/path.h +++ b/lib/path.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/preprocessor.cpp b/lib/preprocessor.cpp index 4246da39c83..3e0b33c7f10 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -336,67 +336,49 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett } } -void Preprocessor::inlineSuppressions(SuppressionList &suppressions) +void Preprocessor::inlineSuppressions(SuppressionList &suppressions) const +{ + inlineSuppressions(mTokens, suppressions); +} + +void Preprocessor::inlineSuppressions(const simplecpp::TokenList &tokens, SuppressionList &suppressions) const { if (!mSettings.inlineSuppressions) return; std::list err; - ::addInlineSuppressions(mTokens, mSettings, suppressions, err); - for (const auto &filedata : mFileCache) { - ::addInlineSuppressions(filedata->tokens, mSettings, suppressions, err); - } + ::addInlineSuppressions(tokens, mSettings, suppressions, err); for (const BadInlineSuppression &bad : err) { invalidSuppression(bad.location, bad.errmsg); } } -std::vector Preprocessor::getRemarkComments() const +void Preprocessor::createDirectives(std::list &directives) const { - std::vector ret; - addRemarkComments(mTokens, ret); - for (const auto &filedata : mFileCache) { - addRemarkComments(filedata->tokens, ret); - } - return ret; + createDirectives(mTokens, directives); } -std::list Preprocessor::createDirectives() const +void Preprocessor::createDirectives(const simplecpp::TokenList &tokens, std::list &directives) { - // directive list.. - std::list directives; - - std::vector list; - list.reserve(1U + mFileCache.size()); - list.push_back(&mTokens); - std::transform(mFileCache.cbegin(), mFileCache.cend(), std::back_inserter(list), - [](const std::unique_ptr &filedata) { - return &filedata->tokens; - }); - - for (const simplecpp::TokenList *tokenList : list) { - for (const simplecpp::Token *tok = tokenList->cfront(); tok; tok = tok->next) { - if ((tok->op != '#') || (tok->previous && tok->previous->location.line == tok->location.line)) - continue; - if (tok->next && tok->next->str() == "endfile") + for (const simplecpp::Token *tok = tokens.cfront(); tok; tok = tok->next) { + if ((tok->op != '#') || (tok->previous && tok->previous->location.line == tok->location.line)) + continue; + if (tok->next && tok->next->str() == "endfile") + continue; + Directive directive(tokens, tok->location, ""); + for (const simplecpp::Token *tok2 = tok; tok2 && tok2->location.line == directive.linenr; tok2 = tok2->next) { + if (tok2->comment) continue; - Directive directive(mTokens, tok->location, ""); - for (const simplecpp::Token *tok2 = tok; tok2 && tok2->location.line == directive.linenr; tok2 = tok2->next) { - if (tok2->comment) - continue; - if (!directive.str.empty() && (tok2->location.col > tok2->previous->location.col + tok2->previous->str().size())) - directive.str += ' '; - if (directive.str == "#" && tok2->str() == "file") - directive.str += "include"; - else - directive.str += tok2->str(); - - directive.strTokens.emplace_back(*tok2); - } - directives.push_back(std::move(directive)); + if (!directive.str.empty() && (tok2->location.col > tok2->previous->location.col + tok2->previous->str().size())) + directive.str += ' '; + if (directive.str == "#" && tok2->str() == "file") + directive.str += "include"; + else + directive.str += tok2->str(); + + directive.strTokens.emplace_back(*tok2); } + directives.push_back(std::move(directive)); } - - return directives; } static std::string readcondition(const simplecpp::Token *iftok, const std::set &defined, const std::set &undefined) @@ -769,36 +751,21 @@ static void getConfigs(const simplecpp::TokenList &tokens, std::set ret.insert(std::move(elseError)); } - -std::set Preprocessor::getConfigs() const +void Preprocessor::getConfigs(std::set &defined, std::set &configs) const { - std::set ret = { "" }; if (!mTokens.cfront()) - return ret; - - std::set defined = { "__cplusplus" }; - - // Insert library defines - for (const auto &define : mSettings.library.defines()) { - - const std::string::size_type paren = define.find("("); - const std::string::size_type space = define.find(" "); - std::string::size_type end = space; - - if (paren != std::string::npos && paren < space) - end = paren; - - defined.insert(define.substr(0, end)); - } + return; - ::getConfigs(mTokens, defined, mSettings.userDefines, mSettings.userUndefs, ret); + ::getConfigs(mTokens, defined, mSettings.userDefines, mSettings.userUndefs, configs); +} - for (const auto &filedata : mFileCache) { - if (!mSettings.configurationExcluded(filedata->filename)) - ::getConfigs(filedata->tokens, defined, mSettings.userDefines, mSettings.userUndefs, ret); - } +void Preprocessor::getConfigs(const std::string &filename, const simplecpp::TokenList &tokens, std::set &defined, std::set &configs) const +{ + if (!tokens.cfront()) + return; - return ret; + if (!mSettings.configurationExcluded(filename)) + ::getConfigs(tokens, defined, mSettings.userDefines, mSettings.userUndefs, configs); } static void splitcfg(const std::string &cfgStr, std::list &defines, const std::string &defaultValue) @@ -871,16 +838,18 @@ bool Preprocessor::loadFiles(std::vector &files) const simplecpp::DUI dui = createDUI(mSettings, "", mLang); simplecpp::OutputList outputList; - mFileCache = simplecpp::load(mTokens, files, dui, &outputList); + mFileCache = simplecpp::load(mTokens, files, dui, &outputList, std::move(mFileCache)); return !handleErrors(outputList); } void Preprocessor::removeComments() { - mTokens.removeComments(); - for (const auto &filedata : mFileCache) { - filedata->tokens.removeComments(); - } + removeComments(mTokens); +} + +void Preprocessor::removeComments(simplecpp::TokenList &tokens) +{ + tokens.removeComments(); } void Preprocessor::setPlatformInfo() @@ -1016,12 +985,12 @@ static std::string simplecppErrToId(simplecpp::Output::Type type) cppcheck::unreachable(); } -void Preprocessor::error(const simplecpp::Location& loc, const std::string &msg, simplecpp::Output::Type type) +void Preprocessor::error(const simplecpp::Location& loc, const std::string &msg, simplecpp::Output::Type type) const { error(loc, msg, simplecppErrToId(type)); } -void Preprocessor::error(const simplecpp::Location& loc, const std::string &msg, const std::string& id) +void Preprocessor::error(const simplecpp::Location& loc, const std::string &msg, const std::string& id) const { std::list locationList; if (!mTokens.file(loc).empty()) { @@ -1059,7 +1028,7 @@ void Preprocessor::missingInclude(const simplecpp::Location& loc, const std::str mErrorLogger.reportErr(errmsg); } -void Preprocessor::invalidSuppression(const simplecpp::Location& loc, const std::string &msg) +void Preprocessor::invalidSuppression(const simplecpp::Location& loc, const std::string &msg) const { error(loc, msg, "invalidSuppression"); } @@ -1143,13 +1112,10 @@ std::size_t Preprocessor::calculateHash(const std::string &toolinfo) const void Preprocessor::simplifyPragmaAsm() { - Preprocessor::simplifyPragmaAsmPrivate(mTokens); - for (const auto &filedata : mFileCache) { - Preprocessor::simplifyPragmaAsmPrivate(filedata->tokens); - } + simplifyPragmaAsm(mTokens); } -void Preprocessor::simplifyPragmaAsmPrivate(simplecpp::TokenList &tokenList) +void Preprocessor::simplifyPragmaAsm(simplecpp::TokenList &tokenList) { // assembler code.. for (simplecpp::Token *tok = tokenList.front(); tok; tok = tok->next) { @@ -1196,9 +1162,15 @@ void Preprocessor::simplifyPragmaAsmPrivate(simplecpp::TokenList &tokenList) } } +std::vector Preprocessor::getRemarkComments() const +{ + return getRemarkComments(mTokens); +} -void Preprocessor::addRemarkComments(const simplecpp::TokenList &tokens, std::vector &remarkComments) const +std::vector Preprocessor::getRemarkComments(const simplecpp::TokenList &tokens) const { + std::vector remarkComments; + for (const simplecpp::Token *tok = tokens.cfront(); tok; tok = tok->next) { if (!tok->comment) continue; @@ -1245,4 +1217,6 @@ void Preprocessor::addRemarkComments(const simplecpp::TokenList &tokens, std::ve // Add the suppressions. remarkComments.emplace_back(relativeFilename, remarkedToken->location.line, remarkText); } + + return remarkComments; } diff --git a/lib/preprocessor.h b/lib/preprocessor.h index 9daabbf6ca8..3a5a8393a3e 100644 --- a/lib/preprocessor.h +++ b/lib/preprocessor.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 @@ -98,24 +98,36 @@ class CPPCHECKLIB RemarkComment { * configurations that exist in a source file. */ class CPPCHECKLIB WARN_UNUSED Preprocessor { + friend class TestPreprocessor; + public: /** character that is inserted in expanded macros */ static char macroChar; Preprocessor(simplecpp::TokenList& tokens, const Settings& settings, ErrorLogger &errorLogger, Standards::Language lang); - void inlineSuppressions(SuppressionList &suppressions); + void inlineSuppressions(SuppressionList &suppressions) const; + + void inlineSuppressions(const simplecpp::TokenList &tokens, SuppressionList &suppressions) const; + + void createDirectives(std::list &directives) const; - std::list createDirectives() const; + static void createDirectives(const simplecpp::TokenList &tokens, std::list &directives); - std::set getConfigs() const; + void getConfigs(std::set &defined, std::set &configs) const; + + void getConfigs(const std::string &filename, const simplecpp::TokenList &tokens, std::set &defined, std::set &configs) const; std::vector getRemarkComments() const; + std::vector getRemarkComments(const simplecpp::TokenList &tokens) const; + bool loadFiles(std::vector &files); void removeComments(); + static void removeComments(simplecpp::TokenList &tokens); + void setPlatformInfo(); simplecpp::TokenList preprocess(const std::string &cfgStr, std::vector &files, simplecpp::OutputList& outputList); @@ -132,6 +144,8 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { void simplifyPragmaAsm(); + static void simplifyPragmaAsm(simplecpp::TokenList &tokenList); + static void getErrorMessages(ErrorLogger &errorLogger, const Settings &settings); /** @@ -141,12 +155,15 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { const simplecpp::Output* reportOutput(const simplecpp::OutputList &outputList, bool showerror); - void error(const simplecpp::Location& loc, const std::string &msg, simplecpp::Output::Type type); + void error(const simplecpp::Location& loc, const std::string &msg, simplecpp::Output::Type type) const; const simplecpp::Output* handleErrors(const simplecpp::OutputList &outputList); + void setLoadCallback(simplecpp::FileDataCache::load_callback_type cb) { + mFileCache.set_load_callback(std::move(cb)); + } + private: - static void simplifyPragmaAsmPrivate(simplecpp::TokenList &tokenList); /** * Include file types. @@ -157,18 +174,14 @@ class CPPCHECKLIB WARN_UNUSED Preprocessor { }; 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; + void invalidSuppression(const simplecpp::Location& loc, const std::string &msg) const; + void error(const simplecpp::Location& loc, const std::string &msg, const std::string& id) const; simplecpp::TokenList& mTokens; const Settings& mSettings; ErrorLogger &mErrorLogger; - /** list of all directives met while preprocessing file */ - simplecpp::FileDataCache mFileCache; /** filename for cpp/c file - useful when reporting errors */ diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index 92952152ca5..9571e04ea00 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.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 @@ -262,26 +262,33 @@ ProgramMemory::Map::iterator ProgramMemory::find(nonneg int exprid) return mValues->find(ExprIdToken::create(exprid)); } -static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Settings& settings); +static ValueFlow::Value execute(const Token* expr, + ProgramMemory& pm, + const Settings& settings, + const ProgramMemory::Map& vars = {}); -static bool evaluateCondition(MathLib::bigint r, const Token* condition, ProgramMemory& pm, const Settings& settings) +static bool evaluateCondition(MathLib::bigint r, + const Token* condition, + ProgramMemory& pm, + const Settings& settings, + const ProgramMemory::Map& vars = {}) { if (!condition) return false; MathLib::bigint result = 0; bool error = false; - execute(condition, pm, &result, &error, settings); + execute(condition, pm, &result, &error, settings, vars); return !error && result == r; } -bool conditionIsFalse(const Token* condition, ProgramMemory pm, const Settings& settings) +bool conditionIsFalse(const Token* condition, ProgramMemory pm, const Settings& settings, const ProgramMemory::Map& vars) { - return evaluateCondition(0, condition, pm, settings); + return evaluateCondition(0, condition, pm, settings, vars); } -bool conditionIsTrue(const Token* condition, ProgramMemory pm, const Settings& settings) +bool conditionIsTrue(const Token* condition, ProgramMemory pm, const Settings& settings, const ProgramMemory::Map& vars) { - return evaluateCondition(1, condition, pm, settings); + return evaluateCondition(1, condition, pm, settings, vars); } static bool frontIs(const std::vector& v, bool i) @@ -337,7 +344,13 @@ static bool isBasicForLoop(const Token* tok) return true; } -static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Token* endTok, const Settings& settings, bool then) +// findChanged: optional cached findExpressionChanged (see ProgramMemoryState::FindChangedFn). +static void programMemoryParseCondition(ProgramMemory& pm, + const Token* tok, + const Token* endTok, + const Settings& settings, + bool then, + const ProgramMemoryState::FindChangedFn& findChanged = {}) { auto eval = [&](const Token* t) -> std::vector { if (!t) @@ -351,6 +364,10 @@ static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, con return {result}; return std::vector{}; }; + // Use the cached closure if given, else compute directly. + auto changed = [&](const Token* e, const Token* s, const Token* en) -> const Token* { + return findChanged ? findChanged(e, s, en) : findExpressionChanged(e, s, en, settings); + }; if (Token::Match(tok, "==|>=|<=|<|>|!=")) { ValueFlow::Value truevalue; ValueFlow::Value falsevalue; @@ -361,7 +378,7 @@ static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, con return; if (!truevalue.isIntValue()) return; - if (endTok && findExpressionChanged(vartok, tok->next(), endTok, settings)) + if (endTok && changed(vartok, tok->next(), endTok)) return; const bool impossible = (tok->str() == "==" && !then) || (tok->str() == "!=" && then); const ValueFlow::Value& v = then ? truevalue : falsevalue; @@ -370,26 +387,26 @@ static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, con if (containerTok) pm.setContainerSizeValue(containerTok, v.intvalue, !impossible); } else if (Token::simpleMatch(tok, "!")) { - programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, !then); + programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, !then, findChanged); } else if (then && Token::simpleMatch(tok, "&&")) { - programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then); - programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then); + programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then, findChanged); + programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then, findChanged); } else if (!then && Token::simpleMatch(tok, "||")) { - programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then); - programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then); + programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then, findChanged); + programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then, findChanged); } else if (Token::Match(tok, "&&|%oror%")) { std::vector lhs = eval(tok->astOperand1()); std::vector rhs = eval(tok->astOperand2()); if (lhs.empty() || rhs.empty()) { if (frontIs(lhs, !then)) - programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then); + programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then, findChanged); else if (frontIs(rhs, !then)) - programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then); + programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then, findChanged); else pm.setIntValue(tok, 0, then); } } else if (tok && tok->exprId() > 0) { - if (endTok && findExpressionChanged(tok, tok->next(), endTok, settings)) + if (endTok && changed(tok, tok->next(), endTok)) return; pm.setIntValue(tok, 0, then); const Token* containerTok = settings.library.getContainerFromYield(tok, Library::Container::Yield::EMPTY); @@ -398,14 +415,18 @@ static void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, con } } -static void fillProgramMemoryFromConditions(ProgramMemory& pm, const Scope* scope, const Token* endTok, const Settings& settings) +static void fillProgramMemoryFromConditions(ProgramMemory& pm, + const Scope* scope, + const Token* endTok, + const Settings& settings, + const ProgramMemoryState::FindChangedFn& findChanged) { if (!scope) return; if (!scope->isLocal()) return; assert(scope != scope->nestedIn); - fillProgramMemoryFromConditions(pm, scope->nestedIn, endTok, settings); + fillProgramMemoryFromConditions(pm, scope->nestedIn, endTok, settings, findChanged); if (scope->type == ScopeType::eIf || scope->type == ScopeType::eWhile || scope->type == ScopeType::eElse || scope->type == ScopeType::eFor) { const Token* condTok = getCondTokFromEnd(scope->bodyEnd); if (!condTok) @@ -414,13 +435,16 @@ static void fillProgramMemoryFromConditions(ProgramMemory& pm, const Scope* scop bool error = false; execute(condTok, pm, &result, &error, settings); if (error) - programMemoryParseCondition(pm, condTok, endTok, settings, scope->type != ScopeType::eElse); + programMemoryParseCondition(pm, condTok, endTok, settings, scope->type != ScopeType::eElse, findChanged); } } -static void fillProgramMemoryFromConditions(ProgramMemory& pm, const Token* tok, const Settings& settings) +static void fillProgramMemoryFromConditions(ProgramMemory& pm, + const Token* tok, + const Settings& settings, + const ProgramMemoryState::FindChangedFn& findChanged = {}) { - fillProgramMemoryFromConditions(pm, tok->scope(), tok, settings); + fillProgramMemoryFromConditions(pm, tok->scope(), tok, settings, findChanged); } static void fillProgramMemoryFromAssignments(ProgramMemory& pm, const Token* tok, const Settings& settings, const ProgramMemory& state, const ProgramMemory::Map& vars) @@ -429,22 +453,12 @@ static void fillProgramMemoryFromAssignments(ProgramMemory& pm, const Token* tok for (const Token *tok2 = tok; tok2; tok2 = tok2->previous()) { if ((Token::simpleMatch(tok2, "=") || Token::Match(tok2->previous(), "%var% (|{")) && tok2->astOperand1() && tok2->astOperand2()) { - bool setvar = false; const Token* vartok = tok2->astOperand1(); - for (const auto& p:vars) { - if (p.first.getExpressionId() != vartok->exprId()) - continue; - if (vartok == tok) - continue; - pm.setValue(vartok, p.second); - setvar = true; - } - if (!setvar) { - if (!pm.hasValue(vartok->exprId())) { - const Token* valuetok = tok2->astOperand2(); - ProgramMemory local = state; - pm.setValue(vartok, execute(valuetok, local, settings)); - } + if (!pm.hasValue(vartok->exprId())) { + const Token* valuetok = tok2->astOperand2(); + ProgramMemory local = state; + // Tracked values are substituted by execute() when the expression is evaluated. + pm.setValue(vartok, execute(valuetok, local, settings, vars)); } } else if (Token::simpleMatch(tok2, ")") && tok2->link() && Token::Match(tok2->link()->previous(), "assert|ASSERT ( !!)")) { @@ -516,7 +530,7 @@ static ProgramMemory getInitialProgramState(const Token* tok, return pm; } -ProgramMemoryState::ProgramMemoryState(const Settings& s) : settings(s) +ProgramMemoryState::ProgramMemoryState(const Settings& s) : settings(s), changedCache(std::make_shared()) {} void ProgramMemoryState::replace(ProgramMemory pm, const Token* origin) @@ -539,7 +553,7 @@ void ProgramMemoryState::addState(const Token* tok, const ProgramMemory::Map& va { ProgramMemory local = state; addVars(local, vars); - fillProgramMemoryFromConditions(local, tok, settings); + fillProgramMemoryFromConditions(local, tok, settings, getCachedFindExpressionChanged(/*skipDeadCode*/ false)); ProgramMemory pm; fillProgramMemoryFromAssignments(pm, tok, settings, local, vars); local.replace(std::move(pm)); @@ -547,44 +561,73 @@ void ProgramMemoryState::addState(const Token* tok, const ProgramMemory::Map& va replace(std::move(local), tok); } -void ProgramMemoryState::assume(const Token* tok, bool b, bool isEmpty) +void ProgramMemoryState::assume(const Token* tok, bool b, bool isEmpty, const Token* origin) { ProgramMemory pm = state; if (isEmpty) pm.setContainerSizeValue(tok, 0, b); else programMemoryParseCondition(pm, tok, nullptr, settings, b); - const Token* origin = tok; - const Token* top = tok->astTop(); - if (Token::Match(top->previous(), "for|while|if (") && !Token::simpleMatch(tok->astParent(), "?")) { - origin = top->link()->next(); - if (!b && origin->link()) { - origin = origin->link(); + if (!origin) { + origin = tok; + const Token* top = tok->astTop(); + if (Token::Match(top->previous(), "for|while|if (") && !Token::simpleMatch(tok->astParent(), "?")) { + origin = top->link()->next(); + if (!b && origin->link()) { + origin = origin->link(); + } } } replace(std::move(pm), origin); } -void ProgramMemoryState::removeModifiedVars(const Token* tok) +ProgramMemoryState::FindChangedFn ProgramMemoryState::getCachedFindExpressionChanged(bool skipDeadCode) const { - const ProgramMemory& pm = state; - auto eval = [&](const Token* cond) -> std::vector { - ProgramMemory pm2 = pm; - auto result = execute(cond, pm2, settings); - if (isTrue(result)) - return {1}; - if (isFalse(result)) - return {0}; - return {}; + // Structural findExpressionChanged() is pure, so memoize it in changedCache (never invalidated). + // skipDeadCode adds the dead-code walk; it evaluates guards against a fixed state snapshot (so every + // variable follows the same path) and memoizes those evals in evalCache for the closure's lifetime. + using EvalCache = std::map>; + const std::shared_ptr cache = changedCache; + const Settings* const sp = &settings; + ProgramMemory snapshot = state; + const std::shared_ptr evalCache = skipDeadCode ? std::make_shared() : nullptr; + return [cache, sp, snapshot, skipDeadCode, evalCache](const Token* expr, + const Token* start, + const Token* end) -> const Token* { + const auto key = std::make_tuple(expr, start, end); + const auto it = cache->find(key); + const Token* modified = (it != cache->end()) + ? it->second + : cache->emplace(key, findExpressionChanged(expr, start, end, *sp)).first->second; + if (!skipDeadCode || !modified) + return modified; + auto eval = [&](const Token* cond) -> std::vector { + const auto cit = evalCache->find(cond); + if (cit != evalCache->end()) + return cit->second; + ProgramMemory pm2 = snapshot; + const auto result = execute(cond, pm2, *sp); + std::vector r; + if (isTrue(result)) + r = {1}; + else if (isFalse(result)) + r = {0}; + return evalCache->emplace(cond, std::move(r)).first->second; + }; + return findExpressionChangedSkipDeadCode(expr, start, end, *sp, eval); }; +} + +void ProgramMemoryState::removeModifiedVars(const Token* tok) +{ + const auto findChanged = getCachedFindExpressionChanged(/*skipDeadCode*/ true); state.erase_if([&](const ExprIdToken& e) { const Token* start = origins[e.getExpressionId()]; const Token* expr = e.tok; - if (!expr || findExpressionChangedSkipDeadCode(expr, start, tok, settings, eval)) { + const bool changed = !expr || findChanged(expr, start, tok); + if (changed) origins.erase(e.getExpressionId()); - return true; - } - return false; + return changed; }); } @@ -1316,6 +1359,9 @@ namespace { struct Executor { ProgramMemory* pm; const Settings& settings; + // Values tracked by the forward/reverse analysis. A tracked value is the authoritative + // current value of its expression and takes precedence over the program memory. + const ProgramMemory::Map* vars = nullptr; int fdepth = 4; int depth = 10; @@ -1324,6 +1370,26 @@ namespace { assert(pm != nullptr); } + // Is the tracked value for this expression available? + const ValueFlow::Value* getTrackedValue(const Token* expr) const + { + if (!vars || expr->exprId() == 0) + return nullptr; + const auto it = vars->find(ExprIdToken::create(expr->exprId())); + return it == vars->end() ? nullptr : &it->second; + } + + // Does the expression read a tracked value? If so, any value cached for it may be stale + // (the tracked value may have changed since), so it must be re-evaluated, not served cached. + bool dependsOnTrackedValue(const Token* expr) const + { + if (!vars || vars->empty()) + return false; + return findAstNode(expr, [&](const Token* tok) { + return getTrackedValue(tok) != nullptr; + }) != nullptr; + } + static ValueFlow::Value unknown() { return ValueFlow::Value::unknown(); } @@ -1446,6 +1512,31 @@ namespace { return unknown(); } + // Get the size of the container. If the container itself is not tracked in the program + // memory then check if it is symbolically equal to a container whose size is tracked. + ValueFlow::Value executeContainerSize(const Token* containerTok) + { + ValueFlow::Value v = execute(containerTok); + if (v.isContainerSizeValue()) + return v; + for (const ValueFlow::Value& value : containerTok->values()) { + if (!value.isSymbolicValue()) + continue; + if (value.isImpossible()) + continue; + if (value.intvalue != 0) + continue; + if (!value.tokvalue) + continue; + if (value.tokvalue->exprId() == 0) + continue; + const ValueFlow::Value* sizeValue = pm->getValue(value.tokvalue->exprId()); + if (sizeValue && sizeValue->isContainerSizeValue()) + return *sizeValue; + } + return unknown(); + } + ValueFlow::Value executeImpl(const Token* expr) { const ValueFlow::Value* value = nullptr; @@ -1474,14 +1565,14 @@ namespace { const Token* containerTok = expr->tokAt(-2)->astOperand1(); const Library::Container::Yield yield = containerTok->valueType()->container->getYield(expr->strAt(-1)); if (yield == Library::Container::Yield::SIZE) { - ValueFlow::Value v = execute(containerTok); + ValueFlow::Value v = executeContainerSize(containerTok); if (!v.isContainerSizeValue()) return unknown(); v.valueType = ValueFlow::Value::ValueType::INT; return v; } if (yield == Library::Container::Yield::EMPTY) { - ValueFlow::Value v = execute(containerTok); + ValueFlow::Value v = executeContainerSize(containerTok); if (!v.isContainerSizeValue()) return unknown(); if (v.isImpossible() && v.intvalue == 0) @@ -1552,7 +1643,7 @@ namespace { return unknown(); const MathLib::bigint index = rhs.intvalue; if (index >= 0 && index < strValue.size()) - return ValueFlow::Value{strValue[static_cast(index)]}; + return ValueFlow::Value{strValue[index]}; if (index == strValue.size()) return ValueFlow::Value{}; } else if (Token::Match(expr, "%cop%") && expr->astOperand1() && expr->astOperand2()) { @@ -1622,7 +1713,15 @@ namespace { } return execute(expr->astOperand1()); } - if (expr->exprId() > 0 && pm->hasValue(expr->exprId())) { + // Return the tracked value and write it back when it differs, so later reads see the + // same value (as fillProgramMemoryFromAssignments used to do). + if (const ValueFlow::Value* tracked = getTrackedValue(expr)) { + const ValueFlow::Value* stored = pm->getValue(expr->exprId(), /*impossible*/ true); + if (!stored || *stored != *tracked) + pm->setValue(expr, *tracked); + return *tracked; + } + if (expr->exprId() > 0 && pm->hasValue(expr->exprId()) && !dependsOnTrackedValue(expr)) { ValueFlow::Value result = utils::as_const(*pm).at(expr->exprId()); if (result.isImpossible() && result.isIntValue() && result.intvalue == 0 && isUsedAsBool(expr, settings)) { result.intvalue = !result.intvalue; @@ -1815,9 +1914,13 @@ namespace { }; } // namespace -static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Settings& settings) +static ValueFlow::Value execute(const Token* expr, + ProgramMemory& pm, + const Settings& settings, + const ProgramMemory::Map& vars) { Executor ex{&pm, settings}; + ex.vars = &vars; return ex.execute(expr); } @@ -1907,9 +2010,10 @@ void execute(const Token* expr, ProgramMemory& programMemory, MathLib::bigint* result, bool* error, - const Settings& settings) + const Settings& settings, + const ProgramMemory::Map& vars) { - ValueFlow::Value v = execute(expr, programMemory, settings); + ValueFlow::Value v = execute(expr, programMemory, settings, vars); if (!v.isIntValue() || v.isImpossible()) { if (error) *error = true; diff --git a/lib/programmemory.h b/lib/programmemory.h index 21350d86d36..de81d0bc901 100644 --- a/lib/programmemory.h +++ b/lib/programmemory.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 @@ #include #include #include +#include #include #include #include @@ -161,9 +162,26 @@ struct CPPCHECKLIB ProgramMemory { }; struct ProgramMemoryState { + struct ChangedKeyHash { + std::size_t operator()(const std::tuple& t) const + { + const std::hash h; + std::size_t seed = h(std::get<0>(t)); + seed ^= h(std::get<1>(t)) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + seed ^= h(std::get<2>(t)) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } + }; + using ChangedCache = + std::unordered_map, const Token*, ChangedKeyHash>; + // The token modifying expr between start and end, or nullptr. + using FindChangedFn = std::function; + ProgramMemory state; std::map origins; const Settings& settings; + // Memoized findExpressionChanged() pre-filter; structural, so never invalidated. + std::shared_ptr changedCache; explicit ProgramMemoryState(const Settings& s); @@ -171,10 +189,13 @@ struct ProgramMemoryState { void addState(const Token* tok, const ProgramMemory::Map& vars); - void assume(const Token* tok, bool b, bool isEmpty = false); + void assume(const Token* tok, bool b, bool isEmpty = false, const Token* origin = nullptr); void removeModifiedVars(const Token* tok); + // A findExpressionChanged() closure memoized in changedCache + FindChangedFn getCachedFindExpressionChanged(bool skipDeadCode) const; + ProgramMemory get(const Token* tok, const Token* ctx, const ProgramMemory::Map& vars) const; }; @@ -184,21 +205,30 @@ void execute(const Token* expr, ProgramMemory& programMemory, MathLib::bigint* result, bool* error, - const Settings& settings); + const Settings& settings, + const ProgramMemory::Map& vars = {}); /** * Is condition always false when variable has given value? * \param condition top ast token in condition * \param pm program memory + * \param vars optional tracked values that take precedence over the program memory */ -bool conditionIsFalse(const Token* condition, ProgramMemory pm, const Settings& settings); +bool conditionIsFalse(const Token* condition, + ProgramMemory pm, + const Settings& settings, + const ProgramMemory::Map& vars = {}); /** * Is condition always true when variable has given value? * \param condition top ast token in condition * \param pm program memory + * \param vars optional tracked values that take precedence over the program memory */ -bool conditionIsTrue(const Token* condition, ProgramMemory pm, const Settings& settings); +bool conditionIsTrue(const Token* condition, + ProgramMemory pm, + const Settings& settings, + const ProgramMemory::Map& vars = {}); /** * Get program memory by looking backwards from given token. diff --git a/lib/regex.cpp b/lib/regex.cpp index 0c8b0c9f188..3a94b293ed5 100644 --- a/lib/regex.cpp +++ b/lib/regex.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 @@ -179,6 +179,10 @@ namespace { std::string compile(); std::string match(const std::string& str, const MatchFn& matchFn) const override; + Engine engine() const override { + return Engine::Pcre; + } + private: std::string mPattern; pcre* mRe{}; diff --git a/lib/regex.h b/lib/regex.h index afe92d92d40..c17fba41d4e 100644 --- a/lib/regex.h +++ b/lib/regex.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 @@ -44,6 +44,8 @@ class CPPCHECKLIB Regex Pcre = 1 }; + virtual Engine engine() const = 0; + static std::shared_ptr create(std::string pattern, Engine engine, std::string& err); }; diff --git a/lib/reverseanalyzer.cpp b/lib/reverseanalyzer.cpp index 4afd2556a24..0c3c966f2b2 100644 --- a/lib/reverseanalyzer.cpp +++ b/lib/reverseanalyzer.cpp @@ -204,7 +204,7 @@ namespace { void traverse(Token* start, const Token* end = nullptr) { if (start == end) return; - std::size_t i = start->index(); + nonneg int i = start->index(); for (Token* tok = start->previous(); succeeds(tok, end); tok = tok->previous()) { if (tok->index() >= i) throw InternalError(tok, "Cyclic reverse analysis."); @@ -340,9 +340,6 @@ namespace { valueFlowGenericForward(condTok, analyzer, tokenlist, errorLogger, settings); else if (condAction.isRead()) break; - // If the condition modifies the variable then bail - if (condAction.isModified()) - break; tok = jumpToStart(tok->link()); continue; } diff --git a/lib/rule.h b/lib/rule.h new file mode 100644 index 00000000000..dd5cf92effd --- /dev/null +++ b/lib/rule.h @@ -0,0 +1,43 @@ +/* -*- 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 ruleH +#define ruleH + +#ifdef HAVE_RULES + +#include "errortypes.h" + +#include +#include + +class Regex; + +/** Rule */ +struct Rule +{ + std::string tokenlist = "normal"; // use normal tokenlist + std::string pattern; + std::string id = "rule"; // default id + std::string summary; + Severity severity = Severity::style; // default severity + std::shared_ptr regex; +}; +#endif // HAVE_RULES + +#endif // ruleH diff --git a/lib/settings.cpp b/lib/settings.cpp index 080946e07bc..479346208e3 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -16,13 +16,19 @@ * along with this program. If not, see . */ +#include "addoninfo.h" #include "config.h" +#include "errortypes.h" #include "settings.h" #include "path.h" #include "summaries.h" #include "suppressions.h" #include "vfvalue.h" +#ifdef HAVE_RULES +#include "rule.h" +#endif + #include #include #include @@ -68,6 +74,14 @@ Settings::Settings() pid = getPid(); } +Settings::~Settings() = default; + +Settings::Settings(const Settings&) = default; +Settings & Settings::operator=(const Settings &) = default; + +Settings::Settings(Settings&&) CPPCHECK_NOEXCEPT = default; +Settings & Settings::operator=(Settings &&) CPPCHECK_NOEXCEPT = default; + std::string Settings::loadCppcheckCfg(Settings& settings, Suppressions& suppressions, bool debug) { static const std::string cfgFilename = "cppcheck.cfg"; @@ -321,6 +335,7 @@ void Settings::setCheckLevel(CheckLevel level) vfOptions.maxIfCount = 100; vfOptions.doConditionExpressionAnalysis = false; vfOptions.maxForwardBranches = 4; + vfOptions.maxForwardConditionForkDepth = 0; vfOptions.maxIterations = 1; } else if (level == CheckLevel::normal) { @@ -330,6 +345,7 @@ void Settings::setCheckLevel(CheckLevel level) vfOptions.maxIfCount = 100; vfOptions.doConditionExpressionAnalysis = false; vfOptions.maxForwardBranches = 4; + vfOptions.maxForwardConditionForkDepth = 1; } else if (level == CheckLevel::exhaustive) { // Checking can take a little while. ~ 10 times slower than normal analysis is OK. @@ -338,6 +354,8 @@ void Settings::setCheckLevel(CheckLevel level) vfOptions.maxSubFunctionArgs = 256; vfOptions.doConditionExpressionAnalysis = true; vfOptions.maxForwardBranches = -1; + vfOptions.maxForwardConditionForkDepth = 4; + vfOptions.maxForwardConditionForks = 256; } } diff --git a/lib/settings.h b/lib/settings.h index 6c12c509701..ce4a32e1690 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -21,9 +21,7 @@ #define settingsH //--------------------------------------------------------------------------- -#include "addoninfo.h" #include "config.h" -#include "errortypes.h" #include "library.h" #include "platform.h" #include "standards.h" @@ -40,22 +38,21 @@ #include #include -#include "regex.h" - #if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING) #include #endif #ifdef HAVE_RULES -#include - -class Regex; +struct Rule; #endif - struct Suppressions; +struct AddonInfo; namespace ValueFlow { class Value; } +enum class Severity : std::uint8_t; +enum class Certainty : std::uint8_t; +enum class Checks : std::uint8_t; /// @addtogroup Core /// @{ @@ -97,6 +94,16 @@ class SimpleEnableGroup { }; +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 9 +// Hack to workaround GCC bug. +// Details: https://trac.cppcheck.net/ticket/14850 +// seen on g++ before 10.x +#define CPPCHECK_NOEXCEPT +#else +#define CPPCHECK_NOEXCEPT noexcept +#endif + + /** * @brief This is just a container for general settings so that we don't need * to pass individual values to functions or constructors now or in the @@ -111,6 +118,13 @@ class CPPCHECKLIB WARN_UNUSED Settings { public: Settings(); + ~Settings(); + + Settings(const Settings&); + Settings& operator=(const Settings&); + + Settings(Settings&&) CPPCHECK_NOEXCEPT; + Settings& operator=(Settings&&) CPPCHECK_NOEXCEPT; static std::string loadCppcheckCfg(Settings& settings, Suppressions& suppressions, bool debug = false); @@ -368,17 +382,6 @@ class CPPCHECKLIB WARN_UNUSED Settings { int reportProgress{-1}; #ifdef HAVE_RULES - /** Rule */ - struct CPPCHECKLIB Rule { - std::string tokenlist = "normal"; // use normal tokenlist - std::string pattern; - 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; - }; - /** * @brief Extra rules */ @@ -509,6 +512,15 @@ class CPPCHECKLIB WARN_UNUSED Settings { /** @brief Maximum performed forward branches */ int maxForwardBranches = -1; + /** @brief Maximum depth of nested condition-fork continuations in the forward analyzer. + Bounds the exponential fan-out of carrying condition state forward at exhaustive level (where + maxForwardBranches is unlimited); past it the forward analysis continues on a single linear path + without skipping any branch. 0 disables forking (linear); a negative value means unlimited. */ + int maxForwardConditionForkDepth = 4; + + /** @brief Maximum total condition-fork continuations in one forward traversal. */ + int maxForwardConditionForks = 256; + /** @brief Maximum performed alignof recursion */ int maxAlignOfRecursion = 100; diff --git a/lib/suppressions.cpp b/lib/suppressions.cpp index 70b689e2cdb..fe483e347fe 100644 --- a/lib/suppressions.cpp +++ b/lib/suppressions.cpp @@ -31,6 +31,7 @@ #include #include // std::isdigit, std::isalnum, etc #include +#include #include // std::bind, std::placeholders #include #include diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index dda3e9b1e0b..d98c66770e1 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -138,8 +138,14 @@ const Token* SymbolDatabase::isEnumDefinition(const Token* tok) if (tok->str() == "{") return tok; tok = tok->next(); // skip ':' - while (Token::Match(tok, "%name%|::")) + bool hasType = false; + while (Token::Match(tok, "%name%|::")) { + if (tok->isName()) + hasType = true; tok = tok->next(); + } + if (!hasType) + throw InternalError(tok, "SymbolDatabase bailout; invalid enum", InternalError::SYNTAX); return Token::simpleMatch(tok, "{") ? tok : nullptr; } @@ -175,9 +181,9 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() // Store current access in each scope (depends on evaluation progress) std::map access; - std::map> forwardDecls; + std::map> forwardDecls; - const std::function findForwardDeclScope = [&](const Token *tok, Scope *startScope) { + const std::function findForwardDeclScope = [&](const Token *tok, const Scope *startScope) { if (tok->str() == "::") return findForwardDeclScope(tok->next(), &scopeList.front()); @@ -187,14 +193,14 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() }); if (it == startScope->nestedList.cend()) - return static_cast(nullptr); + return static_cast(nullptr); return findForwardDeclScope(tok->tokAt(2), *it); } auto it = forwardDecls.find(startScope); if (it == forwardDecls.cend()) - return static_cast(nullptr); + return static_cast(nullptr); return it->second.count(tok->str()) > 0 ? startScope : nullptr; }; @@ -1043,10 +1049,8 @@ void SymbolDatabase::createSymbolDatabaseNeedInitialization() scope.definedType->needInitialization = Type::NeedInitialization::True; else if (!unknown) scope.definedType->needInitialization = Type::NeedInitialization::False; - else { - if (scope.definedType->needInitialization == Type::NeedInitialization::Unknown) - unknowns++; - } + else + unknowns++; } } else if (scope.type == ScopeType::eUnion && scope.definedType->needInitialization == Type::NeedInitialization::Unknown) scope.definedType->needInitialization = Type::NeedInitialization::True; @@ -1246,6 +1250,7 @@ void SymbolDatabase::createSymbolDatabaseSetTypePointers() { std::unordered_set typenames; for (const Type &t : typeList) { + // cppcheck-suppress useStlAlgorithm - std::transform is cumbersome typenames.insert(t.name()); } @@ -1492,7 +1497,7 @@ void SymbolDatabase::createSymbolDatabaseEnums() void SymbolDatabase::createSymbolDatabaseIncompleteVars() { - for (Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) { + for (Token* tok = mTokenizer.list.front(); precedes(tok, mTokenizer.list.back()); tok = tok->next()) { const Scope * scope = tok->scope(); if (!scope) continue; @@ -2173,7 +2178,7 @@ namespace { { if (const Scope* scope = var->nameToken()->scope()) { auto it = std::find_if(scope->functionList.begin(), scope->functionList.end(), [&](const Function& function) { - for (nonneg int arg = 0; arg < function.argCount(); ++arg) { + for (size_t arg = 0; arg < function.argCount(); ++arg) { if (var == function.getArgumentVar(arg)) return true; } @@ -3402,6 +3407,20 @@ bool Function::returnsVoid(const Function* function, bool unknown) }); } +bool Function::isCoroutine(const Function* function, const Standards &standards, const Tokenizer &tokens) +{ + if (!tokens.isCPP() || standards.cpp < Standards::CPP20) + return false; + if (!function->functionScope) + return false; + const Scope *scope = function->functionScope; + for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) { + if (Token::Match(tok, "co_return|co_await|co_yield")) + return true; + } + return false; +} + std::vector Function::findReturns(const Function* f) { std::vector result; @@ -4452,6 +4471,11 @@ void SymbolDatabase::printXml(std::ostream &out) const outs += ErrorLogger::toxml(scope->className); outs += "\""; } + if (scope->classDef) { + outs += " classDef=\""; + outs += id_string(scope->classDef); + outs += "\""; + } if (scope->bodyStart) { outs += " bodyStart=\""; outs += id_string(scope->bodyStart); @@ -4536,7 +4560,7 @@ void SymbolDatabase::printXml(std::ostream &out) const outs += "/>\n"; else { outs += ">\n"; - for (unsigned int argnr = 0; argnr < function->argCount(); ++argnr) { + for (size_t argnr = 0; argnr < function->argCount(); ++argnr) { const Variable *arg = function->getArgumentVar(argnr); outs += " & matches) const +void Scope::findFunctionInBase(const Token* tok, size_t args, std::vector & matches) const { if (isClassOrStruct() && definedType && !definedType->derivedFrom.empty()) { const std::vector &derivedFrom = definedType->derivedFrom; @@ -7017,6 +7040,10 @@ void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, const setAutoTokenProperties(autoTok); if (vt2->pointer > vt.pointer) vt.pointer++; + if (Token::simpleMatch(autoTok->next(), "&")) + vt.reference = Reference::LValue; + if (Token::simpleMatch(autoTok->next(), "&&")) + vt.reference = Reference::RValue; setValueType(var1Tok, vt); if (var1Tok != parent->previous()) setValueType(parent->previous(), vt); @@ -7049,7 +7076,7 @@ void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, const return; } - if (parent->str() == "[" && (!parent->isCpp() || parent->astOperand1() == tok) && valuetype.pointer > 0U && !Token::Match(parent->previous(), "[{,]")) { + if (parent->str() == "[" && (!parent->isCpp() || parent->astOperand1() == tok) && valuetype.pointer > 0 && !Token::Match(parent->previous(), "[{,]")) { const Token *op1 = parent->astOperand1(); while (op1 && op1->str() == "[") op1 = op1->astOperand1(); @@ -7061,7 +7088,7 @@ void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, const setValueType(parent, vt); return; } - if (Token::Match(parent->tokAt(-1), "%name% (") && !parent->tokAt(-1)->isKeyword() && parent->astOperand1() == tok && valuetype.pointer > 0U) { + if (Token::Match(parent->tokAt(-1), "%name% (") && !parent->tokAt(-1)->isKeyword() && parent->astOperand1() == tok && valuetype.pointer > 0) { ValueType vt(valuetype); vt.pointer -= 1U; setValueType(parent, vt); @@ -7074,7 +7101,7 @@ void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, const setValueType(parent, vt); return; } - if (parent->str() == "*" && !parent->astOperand2() && valuetype.pointer > 0U) { + if (parent->str() == "*" && !parent->astOperand2() && valuetype.pointer > 0) { ValueType vt(valuetype); vt.pointer -= 1U; setValueType(parent, vt); @@ -7107,7 +7134,7 @@ void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, const return; } } - if (parent->str() == "*" && Token::simpleMatch(parent->astOperand2(), "[") && valuetype.pointer > 0U) { + if (parent->str() == "*" && Token::simpleMatch(parent->astOperand2(), "[") && valuetype.pointer > 0) { const Token *op1 = parent->astOperand2()->astOperand1(); while (op1 && op1->str() == "[") op1 = op1->astOperand1(); @@ -7291,15 +7318,55 @@ void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, const } // c++17 auto type deduction of braced init list - if (parent->isCpp() && mSettings.standards.cpp >= Standards::CPP17 && vt2 && Token::Match(parent->tokAt(-2), "auto %var% {")) { - Token *autoTok = parent->tokAt(-2); - setValueType(autoTok, *vt2); - setAutoTokenProperties(autoTok); - if (parent->previous()->variable()) - const_cast(parent->previous()->variable())->setValueType(*vt2); - else - debugMessage(parent->previous(), "debug", "Missing variable class for variable with varid"); - return; + if (parent->isCpp() && mSettings.standards.cpp >= Standards::CPP17 + && Token::Match(parent->astOperand1(), "%var% {") && vt2) { + + auto reference = Reference::None; + nonneg int pointer = 0; + nonneg int constness = 0; + nonneg int volatileness = 0; + + Token *varTok = parent->astOperand1(); + Token *typeTok = varTok->previous(); + + while (Token::Match(typeTok, "&|&&|*|const|volatile")) { + if (typeTok->str() == "&") + reference = Reference::LValue; + else if (typeTok->str() == "&&") + reference = Reference::RValue; + else if (typeTok->str() == "*") + pointer++; + else if (typeTok->str() == "const") + constness |= 1 << pointer; + else if (typeTok->str() == "volatile") + volatileness |= 1 << pointer; + typeTok = typeTok->previous(); + } + + if (typeTok->str() == "auto") { + setValueType(typeTok, *vt2); + setAutoTokenProperties(typeTok); + + auto *varVt = new ValueType(*vt2); + + varVt->reference = reference; + varVt->constness |= constness; + varVt->volatileness |= volatileness; + + if (Token::simpleMatch(typeTok->previous(), "const auto")) + varVt->constness |= 1 << pointer; + + if (Token::simpleMatch(typeTok->previous(), "volatile auto")) + varVt->volatileness |= 1 << pointer; + + varTok->setValueType(varVt); + + if (varTok->variable()) + const_cast(varTok->variable())->setValueType(*varVt); + else + debugMessage(varTok, "debug", "Missing variable class for variable with varid"); + return; + } } if (!vt1) @@ -7819,7 +7886,7 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to setValueType(tok, ValueType(sign, type, 0U)); } - } else if (tok->isComparisonOp() || tok->tokType() == Token::eLogicalOp) { + } else if ((tok->isComparisonOp() || tok->tokType() == Token::eLogicalOp) && tok->astOperand1()) { if (tok->isCpp() && tok->isComparisonOp() && (getClassScope(tok->astOperand1()) || getClassScope(tok->astOperand2()))) { const Function *function = getOperatorFunction(tok); if (function) { @@ -8478,7 +8545,7 @@ namespace { } template -static Result accumulateStructMembers(const Scope* scope, F f, ValueType::Accuracy accuracy) +static Result accumulateStructMembers(const Scope* scope, F f, ValueType::Accuracy accuracy, const Settings& settings) { size_t total = 0; std::set anonScopes; @@ -8497,6 +8564,10 @@ static Result accumulateStructMembers(const Scope* scope, F f, ValueType::Accura if (ret.second) total = f(total, *vt, dim, bits); } + else if (vt->container && vt->container->startPattern == "std :: array <") { + const ValueType vtElement = ValueType::parseDecl(vt->containerTypeToken, settings); + total = f(total, vtElement, dim, bits); + } else total = f(total, *vt, dim, bits); } @@ -8536,12 +8607,12 @@ static size_t getAlignOf(const ValueType& vt, const Settings& settings, ValueTyp size_t a = getAlignOf(vt2, settings, accuracy, ValueType::SizeOf::Pointer, ++maxRecursion); return std::max(max, a); }; - Result result = accumulateStructMembers(vt.typeScope, accHelper, accuracy); + Result result = accumulateStructMembers(vt.typeScope, accHelper, accuracy, settings); size_t total = result.total; if (const Type* dt = vt.typeScope->definedType) { total = std::accumulate(dt->derivedFrom.begin(), dt->derivedFrom.end(), total, [&](size_t v, const Type::BaseInfo& bi) { if (bi.type && bi.type->classScope) - v += accumulateStructMembers(bi.type->classScope, accHelper, accuracy).total; + v += accumulateStructMembers(bi.type->classScope, accHelper, accuracy, settings).total; return v; }); } @@ -8629,14 +8700,14 @@ size_t ValueType::getSizeOf( const Settings& settings, Accuracy accuracy, SizeOf } return typeScope->type == ScopeType::eUnion ? std::max(total, n) : total + padding + n; }; - Result result = accumulateStructMembers(typeScope, accHelper, accuracy); + Result result = accumulateStructMembers(typeScope, accHelper, accuracy, settings); size_t total = result.total; if (currentBitCount > 0) total += currentBitfieldAlloc; if (const ::Type* dt = typeScope->definedType) { total = std::accumulate(dt->derivedFrom.begin(), dt->derivedFrom.end(), total, [&](size_t v, const ::Type::BaseInfo& bi) { if (bi.type && bi.type->classScope) - v += accumulateStructMembers(bi.type->classScope, accHelper, accuracy).total; + v += accumulateStructMembers(bi.type->classScope, accHelper, accuracy, settings).total; return v; }); } @@ -8714,7 +8785,7 @@ std::string ValueType::str() const } else if (type == ValueType::Type::SMART_POINTER && smartPointer) { ret += " smart-pointer(" + smartPointer->name + ")"; } - for (unsigned int p = 0; p < pointer; p++) { + for (nonneg int p = 0; p < pointer; p++) { ret += " *"; if (constness & (2 << p)) ret += " const"; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index a4a07fd2083..7d52d0bfb32 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -767,14 +767,14 @@ class CPPCHECKLIB Function { std::string fullName() const; - nonneg int argCount() const { + size_t argCount() const { return argumentList.size(); } - nonneg int minArgCount() const { + size_t minArgCount() const { return argumentList.size() - initArgCount; } - const Variable* getArgumentVar(nonneg int num) const; - nonneg int initializedArgCount() const { + const Variable* getArgumentVar(size_t num) const; + size_t initializedArgCount() const { return initArgCount; } /** @@ -928,7 +928,7 @@ class CPPCHECKLIB Function { const Scope* functionScope{}; ///< scope of function body const Scope* nestedIn{}; ///< Scope the function is declared in std::list argumentList; ///< argument list, must remain list due to clangimport usage! - nonneg int initArgCount{}; ///< number of args with default values + size_t initArgCount{}; ///< number of args with default values FunctionType type = FunctionType::eFunction; ///< constructor, destructor, ... const Token* noexceptArg{}; ///< noexcept token const Token* throwArg{}; ///< throw token @@ -945,6 +945,7 @@ class CPPCHECKLIB Function { static bool returnsStandardType(const Function* function, bool unknown = false); static bool returnsVoid(const Function* function, bool unknown = false); + static bool isCoroutine(const Function* function, const Standards &standards, const Tokenizer &tokens); static std::vector findReturns(const Function* f); @@ -1209,7 +1210,7 @@ class CPPCHECKLIB Scope { */ bool isVariableDeclaration(const Token* tok, const Token*& vartok, const Token*& typetok) const; - void findFunctionInBase(const Token* tok, nonneg int args, std::vector & matches) const; + void findFunctionInBase(const Token* tok, size_t args, std::vector & matches) const; /** @brief initialize varlist */ void getVariableList(const Token *start, const Token *end); diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 1fe1df10037..24cc0bcbe1d 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -170,8 +170,12 @@ TemplateSimplifier::TokenAndName::TokenAndName(Token *token, std::string scope, if (isFunction()) tok1 = tok1->link()->next(); while (tok1 && !Token::Match(tok1, ";|{")) { - if (tok1->str() == "<") - tok1 = tok1->findClosingBracket(); + if (tok1->str() == "<") { + if (const Token* closing = tok1->findClosingBracket()) + tok1 = closing; + else + syntaxError(tok1); + } else if (Token::Match(tok1, "(|[") && tok1->link()) tok1 = tok1->link(); if (tok1) @@ -492,7 +496,7 @@ unsigned int TemplateSimplifier::templateParameters(const Token *tok) return 0; // num/type .. - if (!tok->isNumber() && tok->tokType() != Token::eChar && tok->tokType() != Token::eString && !tok->isName() && !tok->isOp()) + if (!tok->isNumber() && tok->tokType() != Token::eChar && tok->tokType() != Token::eString && !tok->isName() && !tok->isOp() && tok->str() != ".") return 0; tok = tok->next(); if (!tok) @@ -623,7 +627,7 @@ void TemplateSimplifier::deleteToken(Token *tok) tok->deleteThis(); } -static void invalidateForwardDecls(const Token* beg, const Token* end, std::map* forwardDecls) { +static void invalidateForwardDecls(const Token* beg, const Token* end, std::map* forwardDecls) { if (!forwardDecls) return; for (auto& fwd : *forwardDecls) { @@ -635,7 +639,7 @@ static void invalidateForwardDecls(const Token* beg, const Token* end, std::map< } } -bool TemplateSimplifier::removeTemplate(Token *tok, std::map* forwardDecls) +bool TemplateSimplifier::removeTemplate(Token *tok, std::map* forwardDecls) { if (!Token::simpleMatch(tok, "template <")) return false; @@ -2258,7 +2262,7 @@ void TemplateSimplifier::expandTemplate( Token::Match(tok3->next()->findClosingBracket(), ">|>>")) { const Token *closingBracket = tok3->next()->findClosingBracket(); if (Token::simpleMatch(closingBracket->next(), "&")) { - int num = 0; + size_t num = 0; const Token *par = tok3->next(); while (num < typeParametersInDeclaration.size() && par != closingBracket) { const std::string pattern("[<,] " + typeParametersInDeclaration[num]->str() + " [,>]"); @@ -3041,7 +3045,7 @@ bool TemplateSimplifier::matchSpecialization( declToken->isSigned() != instToken->isSigned() || declToken->isUnsigned() != instToken->isUnsigned() || declToken->isLong() != instToken->isLong()) { - int nr = 0; + size_t nr = 0; while (nr < templateParameters.size() && templateParameters[nr]->str() != declToken->str()) ++nr; @@ -3139,7 +3143,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations( // locate template usage.. std::string::size_type numberOfTemplateInstantiations = mTemplateInstantiations.size(); - unsigned int recursiveCount = 0; + int recursiveCount = 0; bool instantiated = false; @@ -3916,6 +3920,7 @@ void TemplateSimplifier::simplifyTemplates(const std::time_t maxtime) std::unordered_map nameOrdinal; int ordinal = 0; for (const auto& decl : mTemplateDeclarations) { + // cppcheck-suppress useStlAlgorithm - std::transform is cumbersome nameOrdinal.emplace(decl.fullName(), ordinal++); } diff --git a/lib/templatesimplifier.h b/lib/templatesimplifier.h index f6e507459a9..3c5fed3ea1c 100644 --- a/lib/templatesimplifier.h +++ b/lib/templatesimplifier.h @@ -463,7 +463,7 @@ class CPPCHECKLIB TemplateSimplifier { /** * Remove a specific "template < ..." template class/function */ - static bool removeTemplate(Token *tok, std::map* forwardDecls = nullptr); + static bool removeTemplate(Token *tok, std::map* forwardDecls = nullptr); /** Syntax error * @throws InternalError thrown unconditionally @@ -512,9 +512,9 @@ class CPPCHECKLIB TemplateSimplifier { std::list mTemplateDeclarations; std::list mTemplateForwardDeclarations; - std::map mTemplateForwardDeclarationsMap; - std::map mTemplateSpecializationMap; - std::map mTemplatePartialSpecializationMap; + std::map mTemplateForwardDeclarationsMap; + std::map mTemplateSpecializationMap; + std::map mTemplatePartialSpecializationMap; std::list mTemplateInstantiations; std::list mInstantiatedTemplates; std::list mMemberFunctionsToDelete; diff --git a/lib/token.cpp b/lib/token.cpp index 539141c0b0f..d8b438c5073 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -204,7 +204,6 @@ static const std::unordered_set stdTypes = { "bool" , "int" , "long" , "short" - , "size_t" , "void" , "wchar_t" , "signed" @@ -614,7 +613,6 @@ bool Token::simpleMatch(const Token *tok, const char pattern[], size_t pattern_l return false; // shortcut const char *current = pattern; const char *end = pattern + pattern_len; - // cppcheck-suppress shadowFunction - TODO: fix this const char *next = static_cast(std::memchr(pattern, ' ', pattern_len)); if (!next) next = end; @@ -769,7 +767,6 @@ nonneg int Token::getStrArraySize(const Token *tok) { assert(tok != nullptr); assert(tok->tokType() == eString); - // cppcheck-suppress shadowFunction - TODO: fix this const std::string str(getStringLiteral(tok->str())); int sizeofstring = 1; for (int i = 0; i < static_cast(str.size()); i++) { @@ -1333,10 +1330,10 @@ std::string Token::stringifyList(const stringifyOptions& options, const std::vec std::string ret; - unsigned int lineNumber = mImpl->mLineNumber - (options.linenumbers ? 1U : 0U); + nonneg int lineNumber = mImpl->mLineNumber - (options.linenumbers ? 1 : 0); // cppcheck-suppress shadowFunction - TODO: fix this - unsigned int fileIndex = options.files ? ~0U : mImpl->mFileIndex; - std::map lineNumbers; + nonneg int fileIndex = options.files ? ~0U : mImpl->mFileIndex; + std::map lineNumbers; for (const Token *tok = this; tok != end; tok = tok->next()) { assert(tok && "end precedes token"); if (!tok) @@ -2359,11 +2356,9 @@ const ::Type* Token::typeOf(const Token* tok, const Token** typeTok) 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(); if (!scope) return nullptr; - // cppcheck-suppress shadowFunction - TODO: fix this const Function *function = scope->function; if (!function) return nullptr; @@ -2473,18 +2468,15 @@ std::pair Token::typeDecl(const Token* tok, bool poi return {var->typeStartToken(), var->typeEndToken()->next()}; } if (Token::simpleMatch(tok, "return")) { - // cppcheck-suppress shadowFunction - TODO: fix this const Scope* scope = tok->scope(); if (!scope) return {}; - // cppcheck-suppress shadowFunction - TODO: fix this const Function* function = scope->function; if (!function) return {}; return { function->retDef, function->returnDefEnd() }; } if (tok->previous() && tok->previous()->function()) { - // cppcheck-suppress shadowFunction - TODO: fix this const Function *function = tok->previous()->function(); return {function->retDef, function->returnDefEnd()}; } diff --git a/lib/token.h b/lib/token.h index ca945fcab22..fd4804ec980 100644 --- a/lib/token.h +++ b/lib/token.h @@ -249,35 +249,35 @@ class CPPCHECKLIB Token { * For example index 1 would return next token, and 2 * would return next from that one. */ - const Token *tokAt(int index) const + const Token *tokAt(int idx) const { - return tokAtImpl(this, index); + return tokAtImpl(this, idx); } - Token *tokAt(int index) + Token *tokAt(int idx) { - return tokAtImpl(this, index); + return tokAtImpl(this, idx); } /** * @return the link to the token in given index, related to this token. * For example index 1 would return the link to next token. */ - const Token *linkAt(int index) const + const Token *linkAt(int idx) const { - return linkAtImpl(this, index); + return linkAtImpl(this, idx); } - Token *linkAt(int index) + Token *linkAt(int idx) { - return linkAtImpl(this, index); + return linkAtImpl(this, idx); } /** * @return String of the token in given index, related to this token. * If that token does not exist, an empty string is being returned. */ - const std::string &strAt(int index) const + const std::string &strAt(int idx) const { - const Token *tok = this->tokAt(index); + const Token *tok = this->tokAt(idx); return tok ? tok->mStr : mEmptyString; } @@ -604,11 +604,11 @@ class CPPCHECKLIB Token { bool hasAttributeCleanup() const { return !mImpl->mAttributeCleanup.empty(); } - void setCppcheckAttribute(CppcheckAttributesType type, MathLib::bigint value) { - mImpl->setCppcheckAttribute(type, value); + void setCppcheckAttribute(CppcheckAttributesType attrType, MathLib::bigint value) { + mImpl->setCppcheckAttribute(attrType, value); } - bool getCppcheckAttribute(CppcheckAttributesType type, MathLib::bigint &value) const { - return mImpl->getCppcheckAttribute(type, value); + bool getCppcheckAttribute(CppcheckAttributesType attrType, MathLib::bigint &value) const { + return mImpl->getCppcheckAttribute(attrType, value); } // cppcheck-suppress unusedFunction bool hasCppcheckAttributes() const { @@ -732,11 +732,11 @@ class CPPCHECKLIB Token { setFlag(fIsTemplate, b); } - bool isSimplifiedScope() const { - return getFlag(fIsSimplifedScope); + bool isSimplifiedIfInitStmt() const { + return getFlag(fIsSimplifiedIfInitStmt); } - void isSimplifiedScope(bool b) { - setFlag(fIsSimplifedScope, b); + void isSimplifiedIfInitStmt(bool b) { + setFlag(fIsSimplifiedIfInitStmt, b); } bool isFinalType() const { @@ -767,6 +767,14 @@ class CPPCHECKLIB Token { setFlag(fIsAnonymous, b); } + bool isInsertedBrace() const { + return getFlag(fIsInsertedBrace); + } + Token* isInsertedBrace(bool b) { + setFlag(fIsInsertedBrace, b); + return this; + } + // cppcheck-suppress unusedFunction bool isBitfield() const { return mImpl->mBits >= 0; @@ -891,15 +899,15 @@ class CPPCHECKLIB Token { private: template )> - static T *tokAtImpl(T *tok, int index) + static T *tokAtImpl(T *tok, int idx) { - while (index > 0 && tok) { + while (idx > 0 && tok) { tok = tok->next(); - --index; + --idx; } - while (index < 0 && tok) { + while (idx < 0 && tok) { tok = tok->previous(); - ++index; + ++idx; } return tok; } @@ -908,9 +916,9 @@ class CPPCHECKLIB Token { * @throws InternalError thrown if index is out of range */ template )> - static T *linkAtImpl(T *thisTok, int index) + static T *linkAtImpl(T *thisTok, int idx) { - T *tok = thisTok->tokAt(index); + T *tok = thisTok->tokAt(idx); if (!tok) { throw InternalError(thisTok, "Internal error. Token::linkAt called with index outside the tokens range."); } @@ -1498,7 +1506,7 @@ class CPPCHECKLIB Token { fIsImplicitInt = (1ULL << 33), // Is "int" token implicitly added? fIsInline = (1ULL << 34), // Is this a inline type fIsTemplate = (1ULL << 35), - fIsSimplifedScope = (1ULL << 36), // scope added when simplifying e.g. if (int i = ...; ...) + fIsSimplifiedIfInitStmt = (1ULL << 36), // simplified if/switch/while init statement e.g. if (int i = ...; ...) => { int i = ...; if (..) .. } fIsRemovedVoidParameter = (1ULL << 37), // A void function parameter has been removed fIsIncompleteConstant = (1ULL << 38), fIsRestrict = (1ULL << 39), // Is this a restrict pointer type @@ -1508,6 +1516,7 @@ class CPPCHECKLIB Token { fIsInitComma = (1ULL << 43), // Is this comma located inside some {..}. i.e: {1,2,3,4} fIsInitBracket = (1ULL << 44), // Is this bracket used as a part of variable initialization i.e: int a{5}, b(2); fIsAnonymous = (1ULL << 45), // Is this a token added for an unnamed member + fIsInsertedBrace = (1ULL << 46), // brace added when simplifying e.g. if (x) f(); => if (x) { f(); } }; enum : std::uint8_t { diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 6f9cf90a852..031ab624bfb 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -549,9 +549,9 @@ namespace { private: Token* mTypedefToken; // The "typedef" token Token* mEndToken{nullptr}; // Semicolon - std::pair mRangeType; - std::pair mRangeTypeQualifiers; - std::pair mRangeAfterVar; + std::pair mRangeType; + std::pair mRangeTypeQualifiers; + std::pair mRangeAfterVar; Token* mNameToken{nullptr}; bool mFail = false; bool mReplaceFailed = false; @@ -565,36 +565,51 @@ namespace { // TODO handle unnamed structs etc if (Token::Match(start, "const| enum|struct|union|class %name%| {")) { - const std::pair rangeBefore(start, Token::findsimplematch(start, "{")); + const std::pair rangeBefore(start, Token::findsimplematch(start, "{")); // find typedef name token - Token* nameToken = rangeBefore.second->link()->next(); - while (Token::Match(nameToken, "%name%|* %name%|*")) - nameToken = nameToken->next(); - const std::pair rangeQualifiers(rangeBefore.second->link()->next(), nameToken); + Token* nameTok = rangeBefore.second->link()->next(); + while (Token::Match(nameTok, "%name%|* %name%|*")) + nameTok = nameTok->next(); + const std::pair rangeQualifiers(rangeBefore.second->link()->next(), nameTok); - if (Token::Match(nameToken, "%name% ;")) { + if (Token::Match(nameTok, "%name% ;")) { if (Token::Match(rangeBefore.second->previous(), "enum|struct|union|class {")) - rangeBefore.second->previous()->insertToken(nameToken->str()); + rangeBefore.second->previous()->insertToken(nameTok->str()); mRangeType = rangeBefore; mRangeTypeQualifiers = rangeQualifiers; Token* typeName = rangeBefore.second->previous(); if (typeName->isKeyword()) { // TODO typeName->insertToken("T:" + std::to_string(num++)); - typeName->insertToken(nameToken->str()); + typeName->insertToken(nameTok->str()); } - mNameToken = nameToken; - mEndToken = nameToken->next(); + mNameToken = nameTok; + mEndToken = nameTok->next(); return; } } + const auto checkForRecursion = [this]() { + if (Token::Match(mTypedefToken, "typedef %name% %name% ;")) + return; + for (const Token *tok = mTypedefToken; tok != mEndToken; tok = tok->next()) { + if (tok == mNameToken) + continue; + if (tok->str() != mNameToken->str()) + continue; + if (Token::Match(tok->previous(), "struct|class|enum|union")) + continue; + throw InternalError(tok, "recursive typedef encountered"); + } + }; + for (Token* type = start; Token::Match(type, "%name%|*|&|&&"); type = type->next()) { if (type != start && Token::Match(type, "%name% ;") && !type->isStandardType()) { mRangeType.first = start; mRangeType.second = type; mNameToken = type; mEndToken = mNameToken->next(); + checkForRecursion(); return; } if (type != start && Token::Match(type, "%name% [")) { @@ -609,6 +624,7 @@ namespace { mEndToken = end->next(); mRangeAfterVar.first = mNameToken->next(); mRangeAfterVar.second = mEndToken; + checkForRecursion(); return; } if (Token::Match(type->next(), "( * const| %name% ) (") && Token::simpleMatch(type->linkAt(1)->linkAt(1), ") ;")) { @@ -618,6 +634,7 @@ namespace { mRangeType.second = mNameToken; mRangeAfterVar.first = mNameToken->next(); mRangeAfterVar.second = mEndToken; + checkForRecursion(); return; } if (type != start && Token::Match(type, "%name% ( !!(") && Token::simpleMatch(type->linkAt(1), ") ;") && !type->isStandardType()) { @@ -627,6 +644,7 @@ namespace { mRangeType.second = type; mRangeAfterVar.first = mNameToken->next(); mRangeAfterVar.second = mEndToken; + checkForRecursion(); return; } } @@ -723,7 +741,7 @@ namespace { // Special handling of function pointer cast if (isFunctionPointer && isCast(tok->previous())) { tok->insertToken("*"); - Token* const tok_1 = insertTokens(tok, std::pair(mRangeType.first, mNameToken->linkAt(1))); + Token* const tok_1 = insertTokens(tok, std::pair(mRangeType.first, mNameToken->linkAt(1))); tok_1->originalName(originalname); tok->deleteThis(); return; @@ -998,7 +1016,7 @@ namespace { return false; } - static Token* insertTokens(Token* to, std::pair range) { + static Token* insertTokens(Token* to, std::pair range) { for (const Token* from = range.first; from != range.second; from = from->next()) { to->insertToken(from->str()); to->next()->column(to->column()); @@ -2295,6 +2313,13 @@ void Tokenizer::simplifyTypedefCpp() tok2 = tok2->tokAt(2); else tok2 = tok2->tokAt(3); + while (tok2->link()) { + tok2 = tok2->link()->next(); + if (Token::simpleMatch(tok2, ";")) { + tok2 = tok2->previous(); + break; + } + } if (!tok2) syntaxError(nullptr); @@ -2704,7 +2729,7 @@ namespace { { Token *tok1 = tok; - if (tok1 && tok1->str() != nameToken->str()) + if (!tok1 || tok1->str() != nameToken->str()) return false; // skip this using @@ -2713,6 +2738,9 @@ namespace { return false; } + if (!tok->tokAt(-1)) + return false; + // skip other using with this name if (tok1->strAt(-1) == "using") { // fixme: this is wrong @@ -3008,7 +3036,6 @@ bool Tokenizer::simplifyUsing() Token::Match(tok->linkAt(2), "] ] = ::| %name%"))))) continue; - const std::string& name = tok->strAt(1); const Token *nameToken = tok->next(); std::string scope = currentScope->fullName; Token *usingStart = tok; @@ -3057,7 +3084,7 @@ bool Tokenizer::simplifyUsing() if (!hasName) { std::string newName; if (structEnd->strAt(2) == ";") - newName = name; + newName = nameToken->str(); else newName = "Unnamed" + std::to_string(mUnnamedCount++); TokenList::copyTokens(structEnd->next(), tok, start); @@ -3204,7 +3231,7 @@ bool Tokenizer::simplifyUsing() if (!isTypedefInfoAdded && Token::Match(tok1, "%name% (")) { isTypedefInfoAdded = true; TypedefInfo usingInfo; - usingInfo.name = name; + usingInfo.name = nameToken->str(); usingInfo.filename = list.file(nameToken); usingInfo.lineNumber = nameToken->linenr(); usingInfo.column = nameToken->column(); @@ -3380,12 +3407,17 @@ bool Tokenizer::simplifyUsing() } else if (fpArgList && fpQual && Token::Match(tok1->next(), "%name%")) { // function pointer const bool isFuncDecl = Token::simpleMatch(tok1->tokAt(2), "("); - TokenList::copyTokens(tok1->next(), fpArgList, usingEnd->previous()); + Token *dest = tok1->next(); + while (Token::Match(dest, "%name% :: %name%")) + dest = dest->tokAt(2); + TokenList::copyTokens(dest, fpArgList, usingEnd->previous()); Token* const copyEnd = TokenList::copyTokens(tok1, start, fpQual->link()->previous()); Token* leftPar = copyEnd->previous(); while (leftPar->str() != "(") leftPar = leftPar->previous(); - Token* const insertTok = isFuncDecl ? copyEnd->linkAt(2) : copyEnd->next(); + Token *insertTok = isFuncDecl ? copyEnd->linkAt(2) : copyEnd->next(); + while (Token::Match(insertTok, "%name% :: %name%")) + insertTok = insertTok->tokAt(2); Token* const rightPar = insertTok->insertToken(")"); Token::createMutualLinks(leftPar, rightPar); tok1->deleteThis(); @@ -3461,6 +3493,8 @@ bool Tokenizer::simplifyUsing() skip = true; simplifyUsingError(usingStart, usingEnd); } + if (!after) + syntaxError(tok1); tok1 = after->previous(); } @@ -3855,7 +3889,8 @@ void Tokenizer::simplifyRedundantConsecutiveBraces() for (Token *tok = list.front(); tok;) { if (Token::simpleMatch(tok, "= {")) { tok = tok->linkAt(1); - } else if (Token::simpleMatch(tok, "{ {") && Token::simpleMatch(tok->linkAt(1), "} }")) { + } else if (Token::simpleMatch(tok, "{ {") && Token::simpleMatch(tok->linkAt(1), "} }") && + !Token::Match(tok->previous(), "%name%")) { //remove internal parentheses tok->linkAt(1)->deleteThis(); tok->deleteNext(); @@ -5530,7 +5565,7 @@ void Tokenizer::createLinks2() bool isStruct = false; std::stack type; - std::stack templateTokens; + std::stack templateTokens; for (Token *token = list.front(); token; token = token->next()) { if (Token::Match(token, "%name%|> %name% [:<]")) isStruct = true; @@ -6210,6 +6245,8 @@ void Tokenizer::dump(std::ostream &out) const } if (tok->isRemovedVoidParameter()) outs += " isRemovedVoidParameter=\"true\""; + if (tok->isInsertedBrace()) + outs += " isInsertedBrace=\"true\""; if (tok->isSplittedVarDeclComma()) outs += " isSplittedVarDeclComma=\"true\""; if (tok->isSplittedVarDeclEq()) @@ -6883,7 +6920,7 @@ Token *Tokenizer::simplifyAddBracesToCommand(Token *tok) // before the "while" if (tokEnd) { tokEnd=tokEnd->next(); - if (!tokEnd || tokEnd->str()!="while") // no while + if (!Token::simpleMatch(tokEnd, "while (") || !Token::simpleMatch(tokEnd->linkAt(1), ") ;")) // no while syntaxError(tok); } } @@ -6995,10 +7032,13 @@ Token *Tokenizer::simplifyAddBracesPair(Token *tok, bool commandWithCondition) tokAfterCondition->previous()->insertToken("{"); Token * tokOpenBrace=tokAfterCondition->previous(); + tokOpenBrace->column(tokAfterCondition->column()); + tokOpenBrace->isInsertedBrace(true); tokEnd->insertToken("}"); Token * tokCloseBrace=tokEnd->next(); tokCloseBrace->column(tokEnd->column()); + tokCloseBrace->isInsertedBrace(true); Token::createMutualLinks(tokOpenBrace,tokCloseBrace); tokBracesEnd=tokCloseBrace; @@ -7019,7 +7059,7 @@ void Tokenizer::simplifyFunctionParameters() // We have found old style function, now we need to change it // First step: Get list of argument names in parentheses - std::map argumentNames; + std::map argumentNames; bool bailOut = false; const Token * tokparam = nullptr; @@ -7138,7 +7178,7 @@ void Tokenizer::simplifyFunctionParameters() if (argumentNames.size() != argumentNames2.size()) { //move back 'tok1' to the last ';' tok1 = tok1->previous(); - for (const std::pair& argumentName : argumentNames) { + for (const std::pair& argumentName : argumentNames) { if (argumentNames2.find(argumentName.first) == argumentNames2.end()) { //add the missing parameter argument declaration tok1->insertToken(";"); @@ -7326,6 +7366,19 @@ void Tokenizer::simplifyVarDecl(const bool only_k_r_fpar) simplifyVarDecl(list.front(), nullptr, only_k_r_fpar); } +static Token* isTrailingReturnType(Token* tok) +{ + while (Token::Match(tok, "%name%|::|>")) { + if (Token* open = tok->findOpeningBracket()) + tok = open->tokAt(-1); + else + tok = tok->tokAt(-1); + } + if (tok && Token::simpleMatch(tok->tokAt(-1), ") .")) + return tok->tokAt(-1); + return nullptr; +} + // cppcheck-suppress functionConst - has side effects void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, const bool only_k_r_fpar) { @@ -7353,14 +7406,16 @@ void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, co if (!tok->linkAt(1)) syntaxError(tokBegin); // Check for lambdas before skipping - if (Token::Match(tok->tokAt(-2), ") . %name%")) { // trailing return type + if (Token* trailingStart = isTrailingReturnType(tok)) { // TODO: support lambda without parameter clause? - Token* lambdaStart = tok->linkAt(-2)->previous(); + Token* lambdaStart = trailingStart->link()->tokAt(-1); if (Token::simpleMatch(lambdaStart, "]")) lambdaStart = lambdaStart->link(); Token* lambdaEnd = findLambdaEndScope(lambdaStart); if (lambdaEnd) simplifyVarDecl(lambdaEnd->link()->next(), lambdaEnd, only_k_r_fpar); + else + simplifyVarDecl(tok->tokAt(2), tok->linkAt(1), only_k_r_fpar); } else { for (Token* tok2 = tok->next(); tok2 != tok->linkAt(1); tok2 = tok2->next()) { Token* lambdaEnd = findLambdaEndScope(tok2); @@ -8014,8 +8069,8 @@ void Tokenizer::elseif() if (Token::Match(tok2, "}|;")) { if (tok2->next() && tok2->strAt(1) != "else") { - tok->insertToken("{")->isSimplifiedScope(true); - tok2->insertToken("}")->isSimplifiedScope(true); + tok->insertToken("{")->isInsertedBrace(true); + tok2->insertToken("}")->isInsertedBrace(true); Token::createMutualLinks(tok->next(), tok2->next()); break; } @@ -8081,7 +8136,8 @@ void Tokenizer::simplifyIfSwitchForInit() tok->str("{"); endscope->insertToken("}"); Token::createMutualLinks(tok, endscope->next()); - tok->isSimplifiedScope(true); + tok->isInsertedBrace(true); + tok->isSimplifiedIfInitStmt(true); } } @@ -8929,6 +8985,8 @@ void Tokenizer::findGarbageCode() const const Token* const endTok = tok->linkAt(1); for (tok = tok->tokAt(2); tok != endTok; tok = tok->next()) { if (const Token* lam = findLambdaEndTokenWithoutAST(tok)) { + if (lam == endTok) + break; tok = lam; continue; } @@ -8938,7 +8996,7 @@ void Tokenizer::findGarbageCode() const if (tok->strAt(-1) == ",") syntaxError(tok); colons++; - } else if (tok->str() == "(") { // skip pairs of ( ) + } else if (tok->str() == "(" || tok->str() == "{") { // skip pairs of ( ) tok = tok->link(); } } @@ -9110,14 +9168,18 @@ void Tokenizer::findGarbageCode() const } if (!tok2->next() || tok2->isControlFlowKeyword() || Token::Match(tok2, "typedef|static|.")) syntaxError(tok); - if (Token::Match(tok2, "%name% %name%") && tok2->str() == tok2->strAt(1)) { - if (Token::simpleMatch(tok2->tokAt(2), ";")) - continue; - if (tok2->isStandardType() && tok2->str() == "long") - continue; - if (Token::Match(tok2->tokAt(-1), "enum|struct|union") || (isCPP() && Token::Match(tok2->tokAt(-1), "class|::"))) - continue; - syntaxError(tok2); + if (Token::Match(tok2, "%name% %name%")) { + if (tok2->str() == tok2->strAt(1)) { + if (Token::simpleMatch(tok2->tokAt(2), ";")) + continue; + if (tok2->isStandardType() && tok2->str() == "long") + continue; + if (Token::Match(tok2->tokAt(-1), "enum|struct|union") || (isCPP() && Token::Match(tok2->tokAt(-1), "class|::"))) + continue; + syntaxError(tok2); + } + if (Token::Match(tok2->tokAt(2), "%name%") && tok2->isNameOnly() && tok2->tokAt(1)->isNameOnly() && tok2->tokAt(2)->isNameOnly()) + syntaxError(tok2); } } } @@ -9378,6 +9440,7 @@ void Tokenizer::simplifyStructDecl() if (Token::Match(after->next(), "const|static|volatile| *|&| const| (| %type% )| ,|;|[|=|(|{")) { after->insertToken(";"); after = after->next(); + Token *declEnd = after; while (!Token::Match(start, "struct|class|union|enum")) { after->insertToken(start->str()); after = after->next(); @@ -9420,6 +9483,16 @@ void Tokenizer::simplifyStructDecl() } } } + + // pull declaration out of for loop + if (Token::simpleMatch(start->tokAt(-2), "for ( struct")) { + Token *link = start->linkAt(-1); + start->deletePrevious(2); + declEnd->insertToken("("); + declEnd->next()->link(link); + link->link(declEnd->next()); + declEnd->insertToken("for"); + } } } @@ -9741,7 +9814,7 @@ void Tokenizer::simplifyCPPAttribute() if (!head) syntaxError(tok); - if (Token::simpleMatch(head, ";")) { + if (Token::Match(head, ";|,|)")) { Token *backTok = tok; while (Token::Match(backTok, "]|[|)")) { if (Token::Match(backTok, "]|)")) diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index f155a75014a..ca509904db3 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -333,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); @@ -529,7 +547,7 @@ static bool iscast(const Token *tok, bool cpp) if (!Token::Match(tok2, "%name%|*|::")) return false; - if (tok2->isStandardType() && (tok2->strAt(1) != "(" || Token::Match(tok2->next(), "( * *| )"))) + if (tok2->isStandardType() && (tok2->strAt(1) != "(" || Token::simpleMatch(tok2->linkAt(1)->tokAt(-1), "* )"))) type = true; } @@ -591,7 +609,7 @@ static bool iscpp11init_impl(const Token * const tok) if (Token::Match(nameToken, "]|*")) { const Token* tok2 = nameToken; if (tok2->link()) { - while (tok2 && tok2->link()) + while (tok2 && precedes(tok2->link(), nameToken)) tok2 = tok2->link()->previous(); } else @@ -1678,6 +1696,8 @@ static Token * createAstAtToken(Token *tok) tok->next()->astOperand1(tok); tok->next()->astOperand2(colon); + createAstAtTokenInner(colon, tok->linkAt(1), cpp); + return decl; } } @@ -1819,7 +1839,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 @@ -1927,12 +1947,18 @@ void TokenList::validateAst(bool print) const if ((tok->isAssignmentOp() || tok->isComparisonOp() || Token::Match(tok,"[|^/%]")) && tok->astOperand1() && !tok->astOperand2()) throw InternalError(tok, "Syntax Error: AST broken, binary operator has only one operand.", InternalError::AST); + if (!(tok->astOperand1() && tok->astOperand2()) && ((isC() && tok->str() == "&&") || Token::Match(tok, "%or%|%oror%"))) + throw InternalError(tok, "Syntax Error: AST broken, binary operator is missing operand(s).", InternalError::AST); + // Syntax error if we encounter "?" with operand2 that is not ":" if (tok->str() == "?") { if (!tok->astOperand1() || !tok->astOperand2()) throw InternalError(tok, "AST broken, ternary operator missing operand(s)", InternalError::AST); - if (tok->astOperand2()->str() != ":") + const Token* colon = tok->astOperand2(); + if (colon->str() != ":") throw InternalError(tok, "Syntax Error: AST broken, ternary operator lacks ':'.", InternalError::AST); + if ((colon->astOperand1() && !precedes(colon->astOperand1(), colon)) || !succeeds(colon->astOperand2(), colon)) + throw InternalError(tok, "AST broken, ternary operator has bad operand(s)", InternalError::AST); } // Check for endless recursion @@ -1982,7 +2008,7 @@ void TokenList::validateAst(bool print) const if (Token::simpleMatch(tok->previous(), "operator")) continue; // Skip incomplete code - if (!tok->astOperand1() && !tok->astOperand2() && !tok->astParent()) + if (!tok->astOperand1() && !tok->astOperand2() && !tok->astParent() && !(tok->str().size() == 2 && tok->str()[1] == '=')) continue; // Skip lambda assignment and/or initializer if (Token::Match(tok, "= {|^|[")) @@ -2006,9 +2032,9 @@ void TokenList::validateAst(bool print) const "' doesn't have two operands.", InternalError::AST); } - if (tok->str() == "case" && !tok->astOperand1()) { + if (!tok->astOperand1() && Token::Match(tok, "case|!")) { throw InternalError(tok, - "Syntax Error: AST broken, 'case' doesn't have an operand.", + "Syntax Error: AST broken, '" + tok->str() + "' doesn't have an operand.", InternalError::AST); } diff --git a/lib/utils.h b/lib/utils.h index 3f9c4ab949f..410bd7c6040 100644 --- a/lib/utils.h +++ b/lib/utils.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 3819bfc4b41..096e3d56f56 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -1952,6 +1952,35 @@ const Token* ValueFlow::getEndOfExprScope(const Token* tok, const Scope* default return end; } +static void getLhsLifetimeParentsImpl(const Token* lhs, const Library& library, std::vector& result) +{ + if (!lhs) + return; + + if (Token::simpleMatch(lhs, "[")) { + getLhsLifetimeParentsImpl(lhs->astOperand1(), library, result); + } else if (Token::simpleMatch(lhs, ".") && lhs->originalName() != "->") { + const Token* obj = lhs->astOperand1(); + if (Token::simpleMatch(obj, "[") && obj->exprId() > 0) + result.push_back(obj); + getLhsLifetimeParentsImpl(obj, library, result); + } else { + const Token* tok = getParentLifetime(lhs, library); + if (tok && tok->exprId() > 0) { + const Variable* var = tok->variable(); + if (!var || var->isLocal() || var->isArgument()) + result.push_back(tok); + } + } +} + +static std::vector getLhsLifetimeParents(const Token* lhs, const Library& library) +{ + std::vector result; + getLhsLifetimeParentsImpl(lhs, library, result); + return result; +} + static void valueFlowForwardLifetime(Token * tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings) { // Forward lifetimes to constructed variable @@ -2004,14 +2033,8 @@ static void valueFlowForwardLifetime(Token * tok, const TokenList &tokenlist, Er if (val.lifetimeKind == ValueFlow::Value::LifetimeKind::Address) val.lifetimeKind = ValueFlow::Value::LifetimeKind::SubObject; } - // TODO: handle `[` - if (Token::simpleMatch(parent->astOperand1(), ".")) { - const Token* parentLifetime = - getParentLifetime(parent->astOperand1()->astOperand2(), settings.library); - if (parentLifetime && parentLifetime->exprId() > 0) { - valueFlowForward(nextExpression, endOfVarScope, parentLifetime, std::move(values), tokenlist, errorLogger, settings); - } - } + for (const Token *p : getLhsLifetimeParents(parent->astOperand1(), settings.library)) + valueFlowForward(nextExpression, endOfVarScope, p, values, tokenlist, errorLogger, settings); } // Constructor } else if (Token::simpleMatch(parent, "{") && !isScopeBracket(parent)) { @@ -2459,7 +2482,7 @@ static void valueFlowLifetimeFunction(Token *tok, const TokenList &tokenlist, Er const int returnContainer = settings.library.returnValueContainer(tok); if (returnContainer >= 0) { std::vector args = getArguments(tok); - for (int argnr = 1; argnr <= args.size(); ++argnr) { + for (size_t argnr = 1; argnr <= args.size(); ++argnr) { const Library::ArgumentChecks::IteratorInfo *i = settings.library.getArgIteratorInfo(tok, argnr); if (!i) continue; @@ -2591,7 +2614,7 @@ static void valueFlowLifetimeFunction(Token *tok, const TokenList &tokenlist, Er std::vector args = getArguments(tok); if (iArg > 0 && iArg <= args.size()) { const Token* varTok = args[iArg - 1]; - if (varTok->variable() && varTok->variable()->isLocal()) + if (varTok->variable() && varTok->variable()->isLocal() && varTok->variable()->isArray()) LifetimeStore{ varTok, "Passed to '" + tok->str() + "'.", ValueFlow::Value::LifetimeKind::Address }.byRef( tok->next(), tokenlist, errorLogger, settings); } @@ -3296,8 +3319,11 @@ static void valueFlowAfterMove(const TokenList& tokenlist, const SymbolDatabase& ternaryColon = ternaryColon->astParent(); if (Token::simpleMatch(ternaryColon, ":")) { endOfFunctionCall = ternaryColon->astOperand2(); - if (Token::simpleMatch(endOfFunctionCall, "(")) - endOfFunctionCall = endOfFunctionCall->link(); + Token* next = nextAfterAstRightmostLeaf(endOfFunctionCall); + if (next) + endOfFunctionCall = next; + else + endOfFunctionCall = endOfFunctionCall->next(); } } ValueFlow::Value value; @@ -3818,12 +3844,24 @@ static void valueFlowForwardConst(Token* start, { if (!precedes(start, end)) throw InternalError(var->nameToken(), "valueFlowForwardConst: start token does not precede the end token."); + const bool hasContainerSizeValue = std::any_of(values.begin(), values.end(), [](const ValueFlow::Value& value) { + return value.isContainerSizeValue(); + }); for (Token* tok = start; tok != end; tok = tok->next()) { if (tok->varId() == var->declarationId()) { for (const ValueFlow::Value& value : values) setTokenValue(tok, value, settings); } else { [&] { + // Add the container size to iterators of the container (mirrors ContainerExpressionAnalyzer::match) + if (hasContainerSizeValue && astIsIterator(tok) && isAliasOf(tok, var->declarationId())) { + for (const ValueFlow::Value& value : values) { + if (!value.isContainerSizeValue()) + continue; + setTokenValue(tok, value, settings); + } + return; + } // Follow references const auto& refs = tok->refs(); auto it = std::find_if(refs.cbegin(), refs.cend(), [&](const ReferenceToken& ref) { @@ -4096,6 +4134,8 @@ static bool isVariableInit(const Token *tok) return false; if (var->nameToken() != tok->astOperand1()) return false; + if (var->isPointer()) + return true; const ValueType* vt = var->valueType(); if (!vt) return false; @@ -4622,6 +4662,14 @@ struct ConditionHandler { }); } + static void lowerToInconclusive(std::list& values) + { + for (ValueFlow::Value& v : values) { + if (!v.isImpossible()) + v.setInconclusive(); + } + } + void afterCondition(TokenList& tokenlist, const SymbolDatabase& symboldatabase, ErrorLogger& errorLogger, @@ -4854,10 +4902,13 @@ struct ConditionHandler { else if (!dead_if) dead_if = isReturnScope(after, settings.library, &unknownFunction); + // If the taken branch might not return (it ends in a call to an unknown, + // possibly noreturn function) then its values might not flow past the + // conditional code -> lower them to inconclusive. if (!dead_if && unknownFunction) { if (settings.debugwarnings) bailout(tokenlist, errorLogger, unknownFunction, "possible noreturn scope"); - return; + lowerToInconclusive(thenValues); } if (Token::simpleMatch(after, "} else {")) { @@ -4868,7 +4919,7 @@ struct ConditionHandler { if (!dead_else && unknownFunction) { if (settings.debugwarnings) bailout(tokenlist, errorLogger, unknownFunction, "possible noreturn scope"); - return; + lowerToInconclusive(elseValues); } } @@ -4884,11 +4935,15 @@ struct ConditionHandler { std::copy_if(thenValues.cbegin(), thenValues.cend(), std::back_inserter(values), - std::mem_fn(&ValueFlow::Value::isPossible)); + [](const ValueFlow::Value& v) { + return v.isPossible() || v.isInconclusive(); + }); std::copy_if(elseValues.cbegin(), elseValues.cend(), std::back_inserter(values), - std::mem_fn(&ValueFlow::Value::isPossible)); + [](const ValueFlow::Value& v) { + return v.isPossible() || v.isInconclusive(); + }); } if (values.empty()) @@ -5181,8 +5236,18 @@ static bool valueFlowForLoop2(const Token *tok, if (error) return false; execute(secondExpression, programMemory, &result, &error, settings); - if (result == 0) // 2nd expression is false => no looping + if (result == 0) { + if (!error) { // 2nd expression is false => no looping + ProgramMemory startMemory(programMemory); + ProgramMemory endMemory(programMemory); + + memory1.swap(startMemory); + memory2.swap(endMemory); + memoryAfter.swap(programMemory); + return true; + } return false; + } if (error) { // If a variable is reassigned in second expression, return false bool reassign = false; @@ -5388,23 +5453,32 @@ static void valueFlowForLoop(const TokenList &tokenlist, const SymbolDatabase& s } else { ProgramMemory mem1, mem2, memAfter; if (valueFlowForLoop2(tok, mem1, mem2, memAfter, settings)) { - for (const auto& p : mem1) { - if (!p.second.isIntValue()) - continue; - if (p.second.isImpossible()) - continue; - if (p.first.tok->varId() == 0) - continue; - valueFlowForLoopSimplify(bodyStart, p.first.tok, false, p.second.intvalue, tokenlist, errorLogger, settings); - } - for (const auto& p : mem2) { - if (!p.second.isIntValue()) - continue; - if (p.second.isImpossible()) - continue; - if (p.first.tok->varId() == 0) - continue; - valueFlowForLoopSimplify(bodyStart, p.first.tok, false, p.second.intvalue, tokenlist, errorLogger, settings); + if (mem1 == memAfter) { // #8192 check if loop never runs + Token* condTok = getCondTok(tok); + if (condTok && !condTok->hasKnownIntValue()) { + ValueFlow::Value v(0); + v.setKnown(); + ValueFlow::setTokenValue(condTok, std::move(v), settings); + } + } else { + for (const auto& p : mem1) { + if (!p.second.isIntValue()) + continue; + if (p.second.isImpossible()) + continue; + if (p.first.tok->varId() == 0) + continue; + valueFlowForLoopSimplify(bodyStart, p.first.tok, false, p.second.intvalue, tokenlist, errorLogger, settings); + } + for (const auto& p : mem2) { + if (!p.second.isIntValue()) + continue; + if (p.second.isImpossible()) + continue; + if (p.first.tok->varId() == 0) + continue; + valueFlowForLoopSimplify(bodyStart, p.first.tok, false, p.second.intvalue, tokenlist, errorLogger, settings); + } } for (const auto& p : memAfter) { if (!p.second.isIntValue()) @@ -5697,7 +5771,7 @@ static void valueFlowSubFunction(const TokenList& tokenlist, // Remove uninit values if argument is passed by value if (argtok->variable() && !argtok->variable()->isPointer() && argvalues.size() == 1 && argvalues.front().isUninitValue()) { - if (CheckUninitVar::isVariableUsage(argtok, settings.library, false, CheckUninitVar::Alloc::NO_ALLOC, 0)) + if (CheckUninitVarImpl::isVariableUsage(argtok, settings.library, false, CheckUninitVarImpl::Alloc::NO_ALLOC, 0)) continue; } @@ -5736,7 +5810,7 @@ static void valueFlowFunctionDefaultParameter(const TokenList& tokenlist, const const Function* function = scope->function; if (!function) continue; - for (nonneg int arg = function->minArgCount(); arg < function->argCount(); arg++) { + for (size_t arg = function->minArgCount(); arg < function->argCount(); arg++) { const Variable* var = function->getArgumentVar(arg); if (var && var->hasDefault() && Token::Match(var->nameToken(), "%var% = %num%|%str%|%char%|%name% [,)]")) { const std::list &values = var->nameToken()->tokAt(2)->values(); @@ -6136,7 +6210,7 @@ static bool isContainerSizeChangedByFunction(const Token* tok, } bool inconclusive = false; - const bool isChanged = isVariableChangedByFunctionCall(tok, indirect, settings, &inconclusive); + const bool isChanged = isVariableChangedByFunctionCall(tok, indirect, settings.library, &inconclusive); return (isChanged || inconclusive); } @@ -6803,17 +6877,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, settings); + const MathLib::bigint size = ValueFlow::valueFlowGetStrLength(valueTok, settings.library); 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(), settings); + size += ValueFlow::valueFlowGetStrLength(tok2->astOperand2(), settings.library); tok2 = tok2->astOperand1(); } - size += ValueFlow::valueFlowGetStrLength(tok2, settings); + size += ValueFlow::valueFlowGetStrLength(tok2, settings.library); forwardMinimumContainerSize(size, tok, tok->astOperand1()); } } diff --git a/lib/valueptr.h b/lib/valueptr.h index 270b5f58fc6..b6f02ef1186 100644 --- a/lib/valueptr.h +++ b/lib/valueptr.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/version.h b/lib/version.h index 2a64885ffa8..6d25dd4c158 100644 --- a/lib/version.h +++ b/lib/version.h @@ -20,8 +20,8 @@ #ifndef versionH #define versionH -#define CPPCHECK_VERSION_STRING "2.21 dev" -#define CPPCHECK_VERSION 2,20,99,0 +#define CPPCHECK_VERSION_STRING "2.22 dev" +#define CPPCHECK_VERSION 2,21,99,0 #define LEGALCOPYRIGHT L"Copyright (C) 2007-2026 Cppcheck team." diff --git a/lib/vf_analyzers.cpp b/lib/vf_analyzers.cpp index a50a3b1d4a4..cfba7d5f970 100644 --- a/lib/vf_analyzers.cpp +++ b/lib/vf_analyzers.cpp @@ -222,7 +222,7 @@ struct ValueFlowAnalyzer : Analyzer { return Action::Read; } bool inconclusive = false; - if (isVariableChangedByFunctionCall(tok, getIndirect(tok), getSettings(), &inconclusive)) + if (isVariableChangedByFunctionCall(tok, getIndirect(tok), getSettings().library, &inconclusive)) return Action::Read | Action::Invalid; if (inconclusive) return Action::Read | Action::Inconclusive; @@ -678,16 +678,20 @@ struct ValueFlowAnalyzer : Analyzer { if (const ValueFlow::Value* v = tok->getKnownValue(ValueFlow::Value::ValueType::INT)) return {v->intvalue}; std::vector result; - ProgramMemory pm = getProgramMemoryFunc(); + // Pass the tracked values so a cached program-memory value that depends on one (e.g. 'h(p)' + // after 'p' was reassigned) is re-evaluated rather than served stale. The memory is built + // from the same state, so compute it once and hand it to the builder. + const ProgramState vars = getProgramState(); + ProgramMemory pm = getProgramMemoryFunc(vars); if (Token::Match(tok, "&&|%oror%")) { - if (conditionIsTrue(tok, pm, getSettings())) + if (conditionIsTrue(tok, pm, getSettings(), vars)) result.push_back(1); - if (conditionIsFalse(tok, std::move(pm), getSettings())) + if (conditionIsFalse(tok, std::move(pm), getSettings(), vars)) result.push_back(0); } else { MathLib::bigint out = 0; bool error = false; - execute(tok, pm, &out, &error, getSettings()); + execute(tok, pm, &out, &error, getSettings(), vars); if (!error) result.push_back(out); } @@ -696,16 +700,16 @@ struct ValueFlowAnalyzer : Analyzer { std::vector evaluateInt(const Token* tok) const { - return evaluateInt(tok, [&] { - return ProgramMemory{getProgramState()}; + return evaluateInt(tok, [](const ProgramState& vars) { + return ProgramMemory{vars}; }); } std::vector evaluate(Evaluate e, const Token* tok, const Token* ctx = nullptr) const override { if (e == Evaluate::Integral) { - return evaluateInt(tok, [&] { - return pms.get(tok, ctx, getProgramState()); + return evaluateInt(tok, [&](const ProgramState& vars) { + return pms.get(tok, ctx, vars); }); } if (e == Evaluate::ContainerEmpty) { @@ -723,30 +727,43 @@ struct ValueFlowAnalyzer : Analyzer { return {}; } - void assume(const Token* tok, bool state, unsigned int flags) override { - // Update program state - pms.removeModifiedVars(tok); - pms.addState(tok, getProgramState()); - pms.assume(tok, state, flags & Assume::ContainerEmpty); - + void assume(const Token* tok, bool state, unsigned int flags) override + { bool isCondBlock = false; const Token* parent = tok->astParent(); if (parent) { isCondBlock = Token::Match(parent->previous(), "if|while ("); } + const Token* endBlock = nullptr; if (isCondBlock) { const Token* startBlock = parent->link()->next(); if (Token::simpleMatch(startBlock, ";") && Token::simpleMatch(parent->tokAt(-2), "} while (")) startBlock = parent->linkAt(-2); - const Token* endBlock = startBlock->link(); - if (state) { - pms.removeModifiedVars(endBlock); - pms.addState(endBlock->previous(), getProgramState()); - } else { - if (Token::simpleMatch(endBlock, "} else {")) - pms.addState(endBlock->linkAt(2)->previous(), getProgramState()); - } + endBlock = startBlock->link(); + } + + // Without Pending the 'then' block has been traversed and control is leaving it, so anchor + // the assumed state at the block end instead of the condition. That keeps assumptions on + // variables modified inside the block (e.g. an 'if' narrowing a value computed there) from + // being discarded as "modified" once control leaves the block. + const bool scopeEnd = !(flags & Assume::Pending) && state && endBlock; + const Token* anchor = scopeEnd ? endBlock : tok; + const Token* origin = scopeEnd ? endBlock : nullptr; + + // Update program state + pms.removeModifiedVars(anchor); + pms.addState(anchor, getProgramState()); + pms.assume(tok, state, flags & Assume::ContainerEmpty, origin); + + // The false path (the true path uses scopeEnd above): record the assumed state where control + // continues - the end of the else block, or the closing brace when there is no else - so it + // reaches the enclosing scope. + if (isCondBlock && !(flags & Assume::Pending) && !state) { + if (Token::simpleMatch(endBlock, "} else {")) + pms.addState(endBlock->linkAt(2)->previous(), getProgramState()); + else + pms.addState(endBlock, getProgramState()); } if (!(flags & Assume::Quiet)) { @@ -1198,18 +1215,40 @@ struct SingleValueFlowAnalyzer : ValueFlowAnalyzer { bool stopOnCondition(const Token* condTok) const override { - if (value.isNonValue()) - return false; if (value.isImpossible()) return false; - if (isConditional() && !value.isKnown()) + // lifetime values must keep flowing to properly track aliases + if (value.isLifetimeValue()) + return false; + // 'conditional' flag (uninit, or lowered after a modifying branch): may depend on a + // condition that doesn't mention the variable -> stop + if (value.conditional && !value.isKnown()) return true; - if (value.isSymbolicValue()) + if (value.isNonValue()) return false; + if (value.isSymbolicValue()) + return isConditional() && !value.isKnown(); + // conditional via the originating 'condition' (e.g. possible null after 'if (p && ...)'): only flow + // if the condition references the value, else a correlation we can't follow (e.g. + // 'bool ok = (p != nullptr); if (!ok)') could make a later deref safe -> stop + if (value.condition && !value.isKnown() && !conditionReferencesValue(condTok)) + return true; ConditionState cs = analyzeCondition(condTok); return cs.isUnknownDependent(); } + // Does the condition mention the tracked value, either directly or through a symbolic alias? + bool conditionReferencesValue(const Token* condTok) const + { + return findAstNode(condTok, [&](const Token* tok) { + if (match(tok)) + return true; + return std::any_of(tok->values().cbegin(), tok->values().cend(), [&](const ValueFlow::Value& v) { + return v.isSymbolicValue() && !v.isImpossible() && v.tokvalue && match(v.tokvalue); + }); + }) != nullptr; + } + bool updateScope(const Token* endBlock, bool /*modified*/) const override { const Scope* scope = endBlock->scope(); if (!scope) @@ -1547,7 +1586,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), settings); + n = ValueFlow::valueFlowGetStrLength(tok->astParent()->tokAt(3), settings.library); if (n == 0) // TODO: handle known empty append val->setPossible(); break; diff --git a/lib/vf_common.cpp b/lib/vf_common.cpp index 261972cba63..ef48423f38a 100644 --- a/lib/vf_common.cpp +++ b/lib/vf_common.cpp @@ -19,6 +19,7 @@ #include "vf_common.h" #include "astutils.h" +#include "library.h" #include "mathlib.h" #include "path.h" #include "platform.h" @@ -160,11 +161,14 @@ namespace ValueFlow 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 - (tok->next()->astOperand2()->variable() && !tok->next()->astOperand2()->variable()->isArray())) && - !tok->next()->astOperand2()->valueType()->isEnum()) { // <- TODO this is a bailout, handle enum with non-int types - const size_t sz = tok->next()->astOperand2()->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); + const Token* const obj = tok->next()->astOperand2(); + if (obj && !obj->isLiteral() && obj->valueType() && + (obj->valueType()->pointer == 0 || // <- TODO this is a bailout, abort when there are array->pointer conversions + (obj->variable() && !obj->variable()->isArray())) && + !obj->valueType()->isEnum() && // <- TODO this is a bailout, handle enum with non-int types + !(obj->valueType()->container && obj->valueType()->container->startPattern == "std :: array <")) { + const auto ptrPointee = obj->valueType()->pointer > 0 ? ValueType::SizeOf::Pointer : ValueType::SizeOf::Pointee; + const size_t sz = obj->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ptrPointee); if (sz) { Value value(sz); value.setKnown(); @@ -243,7 +247,12 @@ namespace ValueFlow if (var->type()->classScope && var->type()->classScope->enumType) size = getSizeOfType(var->type()->classScope->enumType, settings); } else if (var->valueType()) { - size = var->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); + if (var->valueType()->container && var->valueType()->container->startPattern == "std :: array <") { + const ValueType vtElement = ValueType::parseDecl(var->valueType()->containerTypeToken, settings); + size = vtElement.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); + } + else + size = var->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); } else if (!var->type()) { size = getSizeOfType(var->typeStartToken(), settings); } @@ -389,7 +398,7 @@ namespace ValueFlow v.debugPath.emplace_back(tok, std::move(s)); } - MathLib::bigint valueFlowGetStrLength(const Token* tok, const Settings& settings) + MathLib::bigint valueFlowGetStrLength(const Token* tok, const Library& library) { if (tok->tokType() == Token::eString) return Token::getStrLength(tok); @@ -399,10 +408,10 @@ namespace ValueFlow return v->intvalue; if (const Value* v = tok->getKnownValue(Value::ValueType::TOK)) { if (v->tokvalue != tok) - return valueFlowGetStrLength(v->tokvalue, settings); + return valueFlowGetStrLength(v->tokvalue, library); } - if (const Token* cont = settings.library.getContainerFromYield(tok, Library::Container::Yield::BUFFER_NT)) - return valueFlowGetStrLength(cont, settings); + if (const Token* cont = library.getContainerFromYield(tok, Library::Container::Yield::BUFFER_NT)) + return valueFlowGetStrLength(cont, library); return 0; } } diff --git a/lib/vf_common.h b/lib/vf_common.h index 64e394b2979..aca438a0dff 100644 --- a/lib/vf_common.h +++ b/lib/vf_common.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 @@ -30,6 +30,7 @@ class Token; class Settings; class Platform; +class Library; namespace ValueFlow { @@ -53,7 +54,7 @@ namespace ValueFlow const Token* tok, SourceLocation local = SourceLocation::current()); - MathLib::bigint valueFlowGetStrLength(const Token* tok, const Settings& settings); + MathLib::bigint valueFlowGetStrLength(const Token* tok, const Library& library); } #endif // vfCommonH diff --git a/lib/vf_settokenvalue.cpp b/lib/vf_settokenvalue.cpp index c5fe519b720..315f4a40129 100644 --- a/lib/vf_settokenvalue.cpp +++ b/lib/vf_settokenvalue.cpp @@ -291,9 +291,9 @@ namespace ValueFlow combineValueProperties(value1, value2, result); - if (Token::simpleMatch(parent, "==") && result.intvalue) + if (Token::simpleMatch(parent, "==") && result.intvalue && !(value1.intvalue == 0 && value2.intvalue == 0)) continue; - if (Token::simpleMatch(parent, "!=") && !result.intvalue) + if (Token::simpleMatch(parent, "!=") && !result.intvalue && !(value1.intvalue == 0 && value2.intvalue == 0)) continue; setTokenValue(parent, std::move(result), settings); @@ -613,7 +613,7 @@ namespace ValueFlow } // unary minus - else if (parent->isUnaryOp("-")) { + else if (parent->isUnaryOp("-") && !astIsUnsigned(parent)) { for (const Value &val : tok->values()) { if (!val.isIntValue() && !val.isFloatValue()) continue; diff --git a/man/checkers/algorithmOutOfBounds.md b/man/checkers/algorithmOutOfBounds.md new file mode 100644 index 00000000000..8e446f82895 --- /dev/null +++ b/man/checkers/algorithmOutOfBounds.md @@ -0,0 +1,69 @@ +# algorithmOutOfBounds + +**Message**: The algorithm 'std::copy' accesses 5 elements through the iterator 'v1.begin()' but only 3 elements are available.
+**Category**: Correctness
+**Severity**: Error
+**Language**: C++ + +## Description + +Many STL algorithms take an iterator that denotes the beginning of a second range (typically an output range) and +assume that this range is large enough. If it is not, the algorithm writes or reads past the end of the container, +which is undefined behavior. + +This checker uses the ValueFlow analysis to compare the number of elements an algorithm accesses with the number of +elements that are actually available through the iterator, and warns when the access is out of bounds. Three groups +of algorithms are checked: + +- Algorithms that access exactly `last1 - first1` elements through the other iterator: `std::copy`, `std::move`, + `std::swap_ranges`, `std::transform`, `std::replace_copy`, `std::replace_copy_if`, `std::reverse_copy`, + `std::equal`, `std::mismatch`, `std::is_permutation`, `std::partial_sum`, `std::adjacent_difference` and + `std::inner_product`. +- Algorithms that access at most `last1 - first1` elements, depending on the values in the input range: + `std::copy_if`, `std::remove_copy`, `std::remove_copy_if` and `std::unique_copy`. Since the actual number of + accessed elements is not known, these are only reported as inconclusive warnings (with `--inconclusive`). +- Count-based algorithms that access as many elements as the count argument says: `std::copy_n`, `std::fill_n` and + `std::generate_n`. + +The severity is `error` when the out of bounds access always happens. When the analysis depends on an earlier +condition in the code, the severity is `warning` and the message has the form "Either the condition 'v.size()==3' +is redundant or the algorithm ... ". + +The checker does not warn when: + +- The second range is given with both a begin and an end iterator (for example the two-range overloads of + `std::equal`, `std::mismatch` and `std::is_permutation`), since such overloads do not access the second range out + of bounds. +- An iterator adaptor such as `std::back_inserter` or `std::inserter` is used, since those grow the container as + needed. +- The proof would rely on "possible" (non-known) values on both the accessed and the available side. + +## How to fix + +Make sure the destination range is large enough before calling the algorithm, or use an iterator adaptor such as +`std::back_inserter` that grows the container as needed. + +Before: +```cpp +void f(const std::vector& v0) { + std::vector v1(3); + // If v0 has more than 3 elements, this writes past the end of v1 + std::copy(v0.begin(), v0.end(), v1.begin()); +} +``` + +After: +```cpp +void f(const std::vector& v0) { + std::vector v1(v0.size()); + std::copy(v0.begin(), v0.end(), v1.begin()); +} +``` + +Or let the container grow: +```cpp +void f(const std::vector& v0) { + std::vector v1; + std::copy(v0.begin(), v0.end(), std::back_inserter(v1)); +} +``` 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/ftellTextModeFile.md b/man/checkers/ftellTextModeFile.md new file mode 100644 index 00000000000..6ca6653a6f2 --- /dev/null +++ b/man/checkers/ftellTextModeFile.md @@ -0,0 +1,56 @@ +# ftellModeTextFile + +**Message**: ftell() result is unspecified when file is opened in mode "t".
+**Category**: Portability
+**Severity**: Style
+**Language**: C/C++ + +## Description + +This checker detects the use of ftell() on a file open in text (or translate) mode. The text mode is not consistent + in between Linux and Windows system and may cause ftell() to return the wrong offset inside a text file. + +See section 7.21.9.4p2 of the C11 standard regarding the ftell function states for a text stream: + +- For a text stream, its file position indicator contains unspecified information, usable by the fseek function for returning the file position indicator for the stream to its position at the time of the ftell call; the difference between two such return values is not necessarily a meaningful measure of the number of characters written or read. + +This warning helps improve code quality by: +- Making the intent clear that the use of ftell() in "t" mode may cause portability problem. + +## Motivation + +This checker improves portability accross system. + +## How to fix + +According to C11, the file must be opened in binary mode 'b' to prevent this problem. + +Before: +```cpp + FILE *f = fopen("Example.txt", "rt"); + if (f) + { + fseek(f, 0, SEEK_END); + printf( "File size %d\n", ftell(f)); + fclose(f); + } + +``` + +After: +```cpp + + FILE *f = fopen("Example.txt", "rb"); + if (f) + { + fseek(f, 0, SEEK_END); + printf( "File size %d\n", ftell(f)); + fclose(f); + } + +``` + +## Notes + +See https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fopen-wfopen?view=msvc-170 + diff --git a/man/checkers/wrongfeofUsage.md b/man/checkers/wrongfeofUsage.md new file mode 100644 index 00000000000..9a3d0bbf5f6 --- /dev/null +++ b/man/checkers/wrongfeofUsage.md @@ -0,0 +1,42 @@ +# wrongfeofUsage + +**Message**: Using feof() as a loop condition causes the last line to be processed twice.
+**Category**: Correctness
+**Severity**: Warning
+**Language**: C/C++ + +## Description + +`feof()` returns non-zero only after a read operation has failed because the end of file was reached. When used as the sole condition of a loop, the loop body executes one extra time after the last successful read: the read fails silently (or returns partial data), and only then does `feof()` return true and terminate the loop. + +This checker matches `while (!feof(fp))` and `do { ... } while (!feof(fp))` loops and warns when all of the following are true: + +- The loop body contains at least one file-read call (`fgets`, `fgetc`, `getc`, `fread`, or `fscanf`) on the same file pointer. +- The destination (return value or output buffer) of the **last** file-read call in the loop is used after that call within the same loop iteration. + +The checker skips loops that contain a control-flow statement (`return`, `break`, `goto`, `continue`, `throw`) as those are too complex to analyze reliably, and loops where the file pointer appears in a context other than a recognised I/O function (`fgets`, `fgetc`, `getc`, `fread`, `fscanf`, `fprintf`, `fwrite`, `fputs`, `fputc`, `putc`). + +## How to fix + +Check the return value of the read function directly in the loop condition. + +Before: +```c +void process(FILE *fp) { + char line[256]; + while (!feof(fp)) { /* wrong: processes last line twice */ + fgets(line, sizeof(line), fp); + puts(line); + } +} +``` + +After: +```c +void process(FILE *fp) { + char line[256]; + while (fgets(line, sizeof(line), fp) != NULL) { + puts(line); + } +} +``` \ No newline at end of file diff --git a/man/manual-premium.md b/man/manual-premium.md index 4c30dc6d4b3..c8e38666530 100644 --- a/man/manual-premium.md +++ b/man/manual-premium.md @@ -572,6 +572,34 @@ The usage of the suppressions file is as follows: cppcheck --suppress-xml=suppressions.xml src/ +### The `` element + +Cppcheck calculates a unique ID for each error, called the hash. The hash depends on the code that +is related to the error, not on where that code is located. This means that the hash for an error +stays the same even when unrelated code elsewhere in the file is added, removed or moved, shifting +the line numbers around. The hash only changes if the related code itself is modified. + +This makes hash-based suppressions more robust than line-based suppressions: once you have +reviewed and suppressed a specific warning, the suppression keeps working even after the file is +edited, as long as the offending code is not changed. + +The hash for an error is included as the `hash` attribute in the [XML output](#the-error-element). +You can copy that value into a `` element in a suppressions XML file: + + + + + uninitvar + src/file1.c + 12345678 + + + +A suppression can use `` on its own, without ``, to suppress a specific error regardless +of its id. It is also possible to combine `` with ``, ``, `` and +``; when several of these are specified, all of them must match for the suppression to +apply. + ## Inline suppressions Suppressions can also be added directly in the code by adding comments that contain special keywords. diff --git a/man/manual.md b/man/manual.md index 8d8d5b22350..93d67e8f402 100644 --- a/man/manual.md +++ b/man/manual.md @@ -1,6 +1,6 @@ --- title: Cppcheck manual -subtitle: Version 2.21 dev +subtitle: Version 2.22 dev author: Cppcheck team lang: en documentclass: report @@ -573,6 +573,34 @@ The usage of the suppressions file is as follows: cppcheck --suppress-xml=suppressions.xml src/ +### The `` element + +Cppcheck calculates a unique ID for each error, called the hash. The hash depends on the code that +is related to the error, not on where that code is located. This means that the hash for an error +stays the same even when unrelated code elsewhere in the file is added, removed or moved, shifting +the line numbers around. The hash only changes if the related code itself is modified. + +This makes hash-based suppressions more robust than line-based suppressions: once you have +reviewed and suppressed a specific warning, the suppression keeps working even after the file is +edited, as long as the offending code is not changed. + +The hash for an error is included as the `hash` attribute in the [XML output](#the-error-element). +You can copy that value into a `` element in a suppressions XML file: + + + + + uninitvar + src/file1.c + 12345678 + + + +A suppression can use `` on its own, without ``, to suppress a specific error regardless +of its id. It is also possible to combine `` with ``, ``, `` and +``; when several of these are specified, all of them must match for the suppression to +apply. + ## Inline suppressions Suppressions can also be added directly in the code by adding comments that contain special keywords. @@ -1161,6 +1189,7 @@ To use a `.cfg` file shipped with Cppcheck, pass the `--library=` option. T | `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_gsl.cfg` | [Microsoft.GSL](https://github.com/microsoft/gsl) | | | `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` | | | diff --git a/man/reference-cfg-format.md b/man/reference-cfg-format.md index 3067d0a8f2c..f426057ab47 100644 --- a/man/reference-cfg-format.md +++ b/man/reference-cfg-format.md @@ -1,6 +1,6 @@ --- title: Cppcheck .cfg format -subtitle: Version 2.21 dev +subtitle: Version 2.22 dev author: Cppcheck team lang: en documentclass: report diff --git a/man/writing-addons.md b/man/writing-addons.md index e593c2e9cce..2627671fa87 100644 --- a/man/writing-addons.md +++ b/man/writing-addons.md @@ -1,6 +1,6 @@ --- title: Writing addons -subtitle: Version 2.21 dev +subtitle: Version 2.22 dev author: Cppcheck team lang: en documentclass: report diff --git a/oss-fuzz/Makefile b/oss-fuzz/Makefile index b2a42dba2a7..eeb795bd35c 100644 --- a/oss-fuzz/Makefile +++ b/oss-fuzz/Makefile @@ -45,7 +45,6 @@ LIBOBJ = $(libcppdir)/valueflow.o \ $(libcppdir)/addoninfo.o \ $(libcppdir)/analyzerinfo.o \ $(libcppdir)/astutils.o \ - $(libcppdir)/check.o \ $(libcppdir)/check64bit.o \ $(libcppdir)/checkassert.o \ $(libcppdir)/checkautovariables.o \ @@ -58,6 +57,7 @@ LIBOBJ = $(libcppdir)/valueflow.o \ $(libcppdir)/checkersreport.o \ $(libcppdir)/checkexceptionsafety.o \ $(libcppdir)/checkfunctions.o \ + $(libcppdir)/checkimpl.o \ $(libcppdir)/checkinternal.o \ $(libcppdir)/checkio.o \ $(libcppdir)/checkleakautovar.o \ @@ -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/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 +$(libcppdir)/valueflow.o: ../lib/valueflow.cpp ../lib/analyzer.h ../lib/astutils.h ../lib/calculate.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/tokenize.o: ../lib/tokenize.cpp ../externals/simplecpp/simplecpp.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 $(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/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 +$(libcppdir)/symboldatabase.o: ../lib/symboldatabase.cpp ../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 $(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,28 @@ $(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/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 +$(libcppdir)/astutils.o: ../lib/astutils.cpp ../lib/astutils.h ../lib/check.h ../lib/checkclass.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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/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 +$(libcppdir)/check64bit.o: ../lib/check64bit.cpp ../lib/check.h ../lib/check64bit.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checkassert.o: ../lib/checkassert.cpp ../lib/astutils.h ../lib/check.h ../lib/checkassert.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checkautovariables.o: ../lib/checkautovariables.cpp ../lib/astutils.h ../lib/check.h ../lib/checkautovariables.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checkbool.o: ../lib/checkbool.cpp ../lib/astutils.h ../lib/check.h ../lib/checkbool.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checkbufferoverrun.o: ../lib/checkbufferoverrun.cpp ../externals/tinyxml2/tinyxml2.h ../lib/astutils.h ../lib/check.h ../lib/checkbufferoverrun.h ../lib/checkers.h ../lib/checkimpl.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/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/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 +$(libcppdir)/checkclass.o: ../lib/checkclass.cpp ../externals/tinyxml2/tinyxml2.h ../lib/astutils.h ../lib/check.h ../lib/checkclass.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checkcondition.o: ../lib/checkcondition.cpp ../lib/astutils.h ../lib/check.h ../lib/checkcondition.h ../lib/checkers.h ../lib/checkimpl.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 $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkcondition.cpp $(libcppdir)/checkers.o: ../lib/checkers.cpp ../lib/checkers.h ../lib/config.h @@ -200,58 +198,64 @@ $(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/regex.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/library.h ../lib/mathlib.h ../lib/platform.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/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 +$(libcppdir)/checkexceptionsafety.o: ../lib/checkexceptionsafety.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkexceptionsafety.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checkfunctions.o: ../lib/checkfunctions.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkfunctions.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checkimpl.o: ../lib/checkimpl.cpp ../lib/checkers.h ../lib/checkimpl.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 + $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkimpl.cpp + +$(libcppdir)/checkinternal.o: ../lib/checkinternal.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checkio.o: ../lib/checkio.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checkleakautovar.o: ../lib/checkleakautovar.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checkmemoryleak.o: ../lib/checkmemoryleak.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checknullpointer.o: ../lib/checknullpointer.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checkother.o: ../lib/checkother.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checkpostfixoperator.o: ../lib/checkpostfixoperator.cpp ../lib/check.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(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/checkimpl.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/check.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checkstl.o: ../lib/checkstl.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checkstring.o: ../lib/checkstring.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checktype.o: ../lib/checktype.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checkuninitvar.o: ../lib/checkuninitvar.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checkunusedfunctions.o: ../lib/checkunusedfunctions.cpp ../externals/tinyxml2/tinyxml2.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 $(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/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 +$(libcppdir)/checkunusedvar.o: ../lib/checkunusedvar.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.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 $(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/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 +$(libcppdir)/checkvaarg.o: ../lib/checkvaarg.cpp ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.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 $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkvaarg.cpp $(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 @@ -260,13 +264,13 @@ $(libcppdir)/clangimport.o: ../lib/clangimport.cpp ../lib/clangimport.h ../lib/c $(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/rule.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/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 +$(libcppdir)/errorlogger.o: ../lib/errorlogger.cpp ../externals/tinyxml2/tinyxml2.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 $(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/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 +$(libcppdir)/forwardanalyzer.o: ../lib/forwardanalyzer.cpp ../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 $(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/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 +$(libcppdir)/fwdanalysis.o: ../lib/fwdanalysis.cpp ../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 $(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/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 +$(libcppdir)/importproject.o: ../lib/importproject.cpp ../externals/picojson/picojson.h ../externals/tinyxml2/tinyxml2.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 $(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 @@ -308,55 +312,55 @@ $(libcppdir)/pathmatch.o: ../lib/pathmatch.cpp ../lib/config.h ../lib/path.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/regex.h ../lib/settings.h ../lib/standards.h ../lib/suppressions.h ../lib/utils.h +$(libcppdir)/preprocessor.o: ../lib/preprocessor.cpp ../externals/simplecpp/simplecpp.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 $(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/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 +$(libcppdir)/programmemory.o: ../lib/programmemory.cpp ../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 $(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/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 +$(libcppdir)/reverseanalyzer.o: ../lib/reverseanalyzer.cpp ../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 $(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/regex.h ../lib/sarifreport.h ../lib/settings.h ../lib/standards.h ../lib/utils.h +$(libcppdir)/sarifreport.o: ../lib/sarifreport.cpp ../externals/picojson/picojson.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 $(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/regex.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/rule.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/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 +$(libcppdir)/summaries.o: ../lib/summaries.cpp ../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/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/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 +$(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/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/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 +$(libcppdir)/templatesimplifier.o: ../lib/templatesimplifier.cpp ../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 $(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/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 +$(libcppdir)/token.o: ../lib/token.cpp ../externals/simplecpp/simplecpp.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 $(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/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 +$(libcppdir)/tokenlist.o: ../lib/tokenlist.cpp ../externals/simplecpp/simplecpp.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 $(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/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 +$(libcppdir)/vf_analyzers.o: ../lib/vf_analyzers.cpp ../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 $(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/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 +$(libcppdir)/vf_common.o: ../lib/vf_common.cpp ../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 $(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/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 +$(libcppdir)/vf_settokenvalue.o: ../lib/vf_settokenvalue.cpp ../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 $(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/readme.md b/readme.md index 512a1ec1110..6671fdd4827 100644 --- a/readme.md +++ b/readme.md @@ -108,71 +108,9 @@ If you do not wish to use the Visual Studio IDE, you can compile Cppcheck from t msbuild cppcheck.sln ``` -### VS Code (on Windows) - -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": [ - "--login", - ], - "terminal.integrated.env.windows": { - "CHERE_INVOKING": "1", - "MSYSTEM": "MINGW64", - } -} -``` +### VS Code -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`: - -```json -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "cppcheck", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/cppcheck.exe", - "args": [ - "--dump", - "${workspaceFolder}/addons/test/misra/misra-test.c" - ], - "stopAtEntry": false, - "cwd": "${workspaceFolder}", - "environment": [], - "externalConsole": true, - "MIMode": "gdb", - "miDebuggerPath": "C:/msys64/mingw64/bin/gdb.exe", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ] - }, - { - "name": "misra.py", - "type": "python", - "request": "launch", - "program": "${workspaceFolder}/addons/misra.py", - "console": "integratedTerminal", - "args": [ - "${workspaceFolder}/addons/test/misra/misra-test.c.dump" - ] - } - ] -} -``` +Cppcheck Official is an extension officially supported by the cppcheck team allowing you to easily use cppcheck in VS Code. You can find it in VS Code Marketplace through the extension tab in your IDE. For instructions on how to set it up and use it, see the readme on the github page: ### Qt Creator + MinGW diff --git a/releasenotes.txt b/releasenotes.txt index ec8c6032da9..4b3ef047c5c 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -1,13 +1,13 @@ -Release Notes for Cppcheck 2.21 +Release Notes for Cppcheck 2.22 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. +- Warn when feof() is used as a while loop condition (wrongfeofUsage). +- ftell() result is unspecified when file is opened in mode "t". +- Detect when an STL algorithm such as std::copy, std::equal, std::transform, etc. accesses more elements through an iterator than are available in the container (algorithmOutOfBounds). C/C++ support: - @@ -22,7 +22,4 @@ Infrastructure & dependencies: - Other: -- 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 -- +- Added configuration file for Microsoft.GSL (Guideline Support Library). diff --git a/test/cfg/boost.cpp b/test/cfg/boost.cpp index 7e724a8b472..27fae71b499 100644 --- a/test/cfg/boost.cpp +++ b/test/cfg/boost.cpp @@ -22,6 +22,8 @@ #include // IWYU pragma: keep #include #include // IWYU pragma: keep +#include +#include #include #include @@ -155,6 +157,7 @@ void test_BOOST_FOREACH_5() { std::set data; BOOST_FOREACH(const int& i, get_data()) + // cppcheck-suppress useStlAlgorithm data.insert(i); } @@ -199,3 +202,46 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(my_tuple_test, T, test_types_w_tuples) } BOOST_AUTO_TEST_SUITE_END() + +// https://www.boost.org/doc/libs/latest/libs/test/doc/html/boost_test/tests_organization/test_cases/test_case_generation/datasets.html +namespace bdata = boost::unit_test::data; + +// Dataset generating a Fibonacci sequence +struct fibonacci_dataset { + // the type of the samples is deduced + // cppcheck-suppress unusedStructMember // FP #14795, used in template is_dataset + static const int arity = 1; + + struct iterator { + int operator*() const { return b; } + void operator++() { + a = a + b; + std::swap(a, b); + } + private: + int a = 1; + int b = 1; // b is the output + }; + + // size is infinite + bdata::size_t size() const { return bdata::BOOST_TEST_DS_INFINITE_SIZE; } + + // iterator + static iterator begin() { return iterator(); } +}; + +namespace boost { namespace unit_test { namespace data { namespace monomorphic { + // registering fibonacci_dataset as a proper dataset + template <> + struct is_dataset : boost::mpl::true_ {}; +}}}} + +// Creating a test-driven dataset, the zip is for checking +BOOST_DATA_TEST_CASE( + test1, + fibonacci_dataset() ^ bdata::make( { 1, 2, 3, 5, 8, 13, 21, 35, 56 } ), + fib_sample, exp) +{ + // cppcheck-suppress valueFlowBailoutIncompleteVar // TODO: fib_sample declared in test case + BOOST_TEST(fib_sample == exp); +} diff --git a/test/cfg/gtk.c b/test/cfg/gtk.c index bcee84c8264..6b48bca2f9e 100644 --- a/test/cfg/gtk.c +++ b/test/cfg/gtk.c @@ -59,6 +59,8 @@ void validCode(int argInt, GHashTableIter * hash_table_iter, GHashTable * hash_t g_string_free(pGStr1, TRUE); gchar * pGchar1 = g_strconcat("a", "b", NULL); + g_assert_true(g_str_has_prefix(pGchar1, "a")); + g_assert_true(g_str_has_suffix(pGchar1, "b")); printf("%s", pGchar1); g_free(pGchar1); @@ -406,6 +408,7 @@ void g_error_new_test() g_error_new(1, -2, "a %d", 1); const GError * pNew2 = g_error_new(1, -2, "a %d", 1); + g_assert_true(g_error_matches(pNew2, 1, -2)); printf("%p", pNew2); // cppcheck-suppress memleak } @@ -530,6 +533,16 @@ void g_variant_test() { // cppcheck-suppress memleak } +void g_list_test() { + GList *list1 = NULL; + gchar *c = "c"; + + list1 = g_list_append(list1, c); + g_assert_true(g_list_find(list1, c) != NULL); + + g_list_free(list1); +} + void g_queue_test() { // cppcheck-suppress leakReturnValNotUsed g_queue_new(); @@ -585,3 +598,54 @@ void g_tree_test() { printf("%p\n", tree2); // cppcheck-suppress memleak } + +void gtk_widget_destroy_test() { + GtkWidget *widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_show(widget); + // cppcheck-suppress memleak + + widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_show(widget); + // cppcheck-suppress mismatchAllocDealloc + g_object_unref(widget); +} + +void g_return_if_fail_test(const char *s) { + // cppcheck-suppress valueFlowBailout + g_return_if_fail(s); + + if (*s) + // cppcheck-suppress valueFlowBailout + g_return_if_fail(*s == 'a'); + else + g_info("Test the else branch can be parsed"); +} + +int g_return_val_if_fail_test(const char *s) { + // cppcheck-suppress valueFlowBailout + g_return_val_if_fail(s, 1); + + if (*s) + // cppcheck-suppress valueFlowBailout + g_return_val_if_fail(*s == 'a', 1); + else + g_info("Test the else branch can be parsed"); + + return 0; +} + +void g_return_if_reached_test(const char *s) { + if (s) + g_return_if_reached(); + else + g_info("Test the else branch can be parsed"); +} + +int g_return_val_if_reached_test(const char *s) { + if (s) + g_return_val_if_reached(1); + else + g_info("Test the else branch can be parsed"); + + return 0; +} diff --git a/test/cfg/microsoft_gsl.cpp b/test/cfg/microsoft_gsl.cpp new file mode 100644 index 00000000000..4241cce045d --- /dev/null +++ b/test/cfg/microsoft_gsl.cpp @@ -0,0 +1,72 @@ +// Test library configuration for microsoft_gsl.cfg +// +// Usage: +// $ cppcheck --check-library --library=microsoft_gsl --enable=style,information --inconclusive --error-exitcode=1 --inline-suppr --suppress=autoNoType test/cfg/microsoft_gsl.cpp +// => +// No warnings about bad library configuration, unmatched suppressions, etc. exitcode=0 +// + +// C++ Standard Library +#include + +// Guideline Support Library +#include + +struct owner_type +{ + owner_type() = default; + owner_type(const owner_type &) = delete; + owner_type(owner_type &&) = default; + + ~owner_type() { delete ptr_; } + + auto operator=(const owner_type &) -> owner_type & = delete; + auto operator=(owner_type &&) -> owner_type & = default; + +private: + gsl::owner ptr_{new int(42)}; +}; + +auto pre_and_post_condition_test(int i) -> int +{ + Expects(i > 0); + + const auto result{i * 2}; + + Ensures(result > 0); + return result; +} + +auto suppress_macro_test(std::span s) -> int +{ + GSL_SUPPRESS("bounds.1") + return s[0]; +} + +auto iterate_over_container_test(const std::vector &v) -> int +{ + int sum{0}; + + for (gsl::index i{0}; i < v.size(); ++i) + { + sum += v[i]; + } + return sum; +} + +void not_null_test(gsl::not_null p) +{ + Expects(p != nullptr); + *p = 42; +} + +void strict_not_null_test(gsl::strict_not_null p) +{ + Expects(p != nullptr); + *p = 42; +} + +auto byte_test(gsl::byte b) -> gsl::byte +{ + return b | 0x81; +} diff --git a/test/cfg/qt.cpp b/test/cfg/qt.cpp index 78827d3583c..2b683648dcd 100644 --- a/test/cfg/qt.cpp +++ b/test/cfg/qt.cpp @@ -33,6 +33,7 @@ #include #include #include +#include // 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)) @@ -892,3 +893,13 @@ int qdateIsValid() Q_ASSERT(qd.isValid()); // Should not warn here with assertWithSideEffect return qd.month(); } + +struct S_QTimer_connect : QObject { // #13846 + S_QTimer_connect() { + // cppcheck-suppress checkLibraryFunction - timeout() is a signal from QTimer + QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(update())); + } + QTimer timer; +private slots: + bool update(); +}; diff --git a/test/cfg/runtests.sh b/test/cfg/runtests.sh index c8c1515e66c..4cf17b3a9df 100755 --- a/test/cfg/runtests.sh +++ b/test/cfg/runtests.sh @@ -549,7 +549,7 @@ function check_file { kde.cpp) # TODO: "kde-4config" is no longer commonly available in recent distros #kde_fn - cppcheck_run --library="$lib" --library=qt "${DIR}""$f" + cppcheck_run --library="$lib" --library=qt "${DIR}""$f" ;; libcurl.c) libcurl_fn @@ -563,6 +563,9 @@ function check_file { lua_fn cppcheck_run --library="$lib" "${DIR}""$f" ;; + microsoft_gsl.cpp) + cppcheck_run --suppress=autoNoType --library="$lib" "${DIR}""$f" + ;; mfc.cpp) mfc_fn cppcheck_run --platform=win64 --library="$lib" "${DIR}""$f" diff --git a/test/cfg/std.c b/test/cfg/std.c index 928d52bf116..997f8204f73 100644 --- a/test/cfg/std.c +++ b/test/cfg/std.c @@ -3519,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 0344b98455c..850dd74b997 100644 --- a/test/cfg/std.cpp +++ b/test/cfg/std.cpp @@ -869,7 +869,7 @@ char * overlappingWriteFunction_strncat(const char *src, char *dest, const std:: // cppcheck-suppress overlappingWriteFunction (void)strncat(dest, dest+1, 2); char buffer[] = "strncat"; - // cppcheck-suppress overlappingWriteFunction + // cppcheck-suppress [overlappingWriteFunction,returnDanglingLifetime] return strncat(buffer, buffer + 1, 3); } @@ -882,7 +882,7 @@ wchar_t * overlappingWriteFunction_wcsncat(const wchar_t *src, wchar_t *dest, co // cppcheck-suppress overlappingWriteFunction (void)wcsncat(dest, dest+1, 2); wchar_t buffer[] = L"strncat"; - // cppcheck-suppress overlappingWriteFunction + // cppcheck-suppress [overlappingWriteFunction,returnDanglingLifetime] return wcsncat(buffer, buffer + 1, 3); } @@ -917,8 +917,8 @@ char * overlappingWriteFunction_strncpy(char *buf, const std::size_t count) void * overlappingWriteFunction_memmove(void) { - // No warning shall be shown: char str[] = "memmove handles overlapping data well"; + // cppcheck-suppress returnDanglingLifetime return memmove(str,str+3,4); } @@ -4982,6 +4982,18 @@ std::span returnDanglingLifetime_std_span1() { } #endif +void* returnDanglingLifetime_memcpy() { // #14833 + char a[4]; + // cppcheck-suppress returnDanglingLifetime + return memcpy(a, "abc", 4); +} + +wchar_t* returnDanglingLifetime_wcscat() { + wchar_t a[10]{L"abc"}; + // cppcheck-suppress returnDanglingLifetime + return wcscat(a, L"def"); +} + void beginEnd() { std::vector v; @@ -5367,3 +5379,13 @@ int containerOutOfBounds_std_initializer_list() { // #14340 int i = *x.end(); return i + containerOutOfBounds_std_initializer_list_access(x); } + +int* missingReturn_std_throw_with_nested() { // #14374 + try { + int* p = new int(); + return p; + } + catch (...) { + std::throw_with_nested(std::runtime_error("xyz")); + } +} diff --git a/test/cli/fuzz-crash/crash-17be2b85446aeb0c7722bedfad4b0e4af27fae3d b/test/cli/fuzz-crash/crash-17be2b85446aeb0c7722bedfad4b0e4af27fae3d new file mode 100644 index 00000000000..0f06807b7ba --- /dev/null +++ b/test/cli/fuzz-crash/crash-17be2b85446aeb0c7722bedfad4b0e4af27fae3d @@ -0,0 +1 @@ +{for([]{});} diff --git a/test/cli/fuzz-crash/crash-42dad53b40278386e4ebd224813e26541cc725f1 b/test/cli/fuzz-crash/crash-42dad53b40278386e4ebd224813e26541cc725f1 new file mode 100644 index 00000000000..3a9abbf229f --- /dev/null +++ b/test/cli/fuzz-crash/crash-42dad53b40278386e4ebd224813e26541cc725f1 @@ -0,0 +1 @@ +using C=C*;C{{}} diff --git a/test/cli/fuzz-crash/crash-60d6b7bc43d21f6a8ad8eb8cca551e45c31c6a32 b/test/cli/fuzz-crash/crash-60d6b7bc43d21f6a8ad8eb8cca551e45c31c6a32 new file mode 100644 index 00000000000..4a60eb05b88 --- /dev/null +++ b/test/cli/fuzz-crash/crash-60d6b7bc43d21f6a8ad8eb8cca551e45c31c6a32 @@ -0,0 +1 @@ +ti(){using S}; diff --git a/test/cli/fuzz-crash/crash-6d019f821f348d758d8d88bd7de692af6f9b07f4 b/test/cli/fuzz-crash/crash-6d019f821f348d758d8d88bd7de692af6f9b07f4 new file mode 100644 index 00000000000..cd0cc97f0fb --- /dev/null +++ b/test/cli/fuzz-crash/crash-6d019f821f348d758d8d88bd7de692af6f9b07f4 @@ -0,0 +1 @@ +#error\ \ No newline at end of file diff --git a/test/cli/fuzz-crash/crash-793c09dbb007b0e1a295f592813f40f8d6d449d1 b/test/cli/fuzz-crash/crash-793c09dbb007b0e1a295f592813f40f8d6d449d1 new file mode 100644 index 00000000000..706fe52b407 --- /dev/null +++ b/test/cli/fuzz-crash/crash-793c09dbb007b0e1a295f592813f40f8d6d449d1 @@ -0,0 +1 @@ +enum{A=s(u)0&=s}; diff --git a/test/cli/fuzz-crash/crash-b4bd9ce1af8a423d15d034f42c7b99dc0f8a0a7d b/test/cli/fuzz-crash/crash-b4bd9ce1af8a423d15d034f42c7b99dc0f8a0a7d new file mode 100644 index 00000000000..e7b11b223da --- /dev/null +++ b/test/cli/fuzz-crash/crash-b4bd9ce1af8a423d15d034f42c7b99dc0f8a0a7d @@ -0,0 +1 @@ +d o(n c){do if(c){}while(0)n} diff --git a/test/cli/fuzz-crash/crash-def181ea7bf444e7a9d0f85b3ad264c31a0b90e4 b/test/cli/fuzz-crash/crash-def181ea7bf444e7a9d0f85b3ad264c31a0b90e4 new file mode 100644 index 00000000000..3b609c62362 --- /dev/null +++ b/test/cli/fuzz-crash/crash-def181ea7bf444e7a9d0f85b3ad264c31a0b90e4 @@ -0,0 +1 @@ +enumf:{}; diff --git a/test/cli/fuzz-crash_c/14742 b/test/cli/fuzz-crash_c/14742 new file mode 100644 index 00000000000..a645277c405 --- /dev/null +++ b/test/cli/fuzz-crash_c/14742 @@ -0,0 +1 @@ +i(){b?8:{}!$} diff --git a/test/cli/fuzz-crash_c/crash-401f925d3c6fd78f864ffd7bf0531bd6a76bb832 b/test/cli/fuzz-crash_c/crash-401f925d3c6fd78f864ffd7bf0531bd6a76bb832 new file mode 100644 index 00000000000..a778e6e2823 --- /dev/null +++ b/test/cli/fuzz-crash_c/crash-401f925d3c6fd78f864ffd7bf0531bd6a76bb832 @@ -0,0 +1 @@ +i(){!!:!=!&&d} diff --git a/test/cli/fuzz-crash_c/crash-85cab41781812453dfc8e74e1f0b915225f7a0a1 b/test/cli/fuzz-crash_c/crash-85cab41781812453dfc8e74e1f0b915225f7a0a1 new file mode 100644 index 00000000000..a2e58c69ea7 --- /dev/null +++ b/test/cli/fuzz-crash_c/crash-85cab41781812453dfc8e74e1f0b915225f7a0a1 @@ -0,0 +1 @@ +n(f=n){n&&,n} diff --git a/test/cli/fuzz-timeout/timeout-242e02017d15d072fd7a230de22faeef0816693d b/test/cli/fuzz-timeout/timeout-242e02017d15d072fd7a230de22faeef0816693d new file mode 100644 index 00000000000..c269baf1efe --- /dev/null +++ b/test/cli/fuzz-timeout/timeout-242e02017d15d072fd7a230de22faeef0816693d @@ -0,0 +1 @@ +typedef const v*v,*; \ No newline at end of file diff --git a/test/cli/fuzz-timeout/timeout-5225c0e6e895cdd05a15c388547d13a78a2574e2 b/test/cli/fuzz-timeout/timeout-5225c0e6e895cdd05a15c388547d13a78a2574e2 new file mode 100644 index 00000000000..71e751bb201 --- /dev/null +++ b/test/cli/fuzz-timeout/timeout-5225c0e6e895cdd05a15c388547d13a78a2574e2 @@ -0,0 +1 @@ +templatestruct e<; diff --git a/test/cli/fuzz-timeout/timeout-5e798df7f1bc86caef9901d6662319a4d636f269 b/test/cli/fuzz-timeout/timeout-5e798df7f1bc86caef9901d6662319a4d636f269 new file mode 100644 index 00000000000..35e56badcc8 --- /dev/null +++ b/test/cli/fuzz-timeout/timeout-5e798df7f1bc86caef9901d6662319a4d636f269 @@ -0,0 +1 @@ +typedef consted e,{} diff --git a/test/cli/other_test.py b/test/cli/other_test.py index 243f600b5a6..c48a0b50354 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -1,4 +1,3 @@ - # python -m pytest test-other.py import os @@ -4240,6 +4239,117 @@ def test_no_valid_configuration(tmp_path): ] +# The implementation for "A::a" is missing - so don't check if "A::b" is used or not +def test_unused_private_function_incomplete_impl(tmpdir): + test_inc = os.path.join(tmpdir, 'test.h') + with open(test_inc, 'wt') as f: + f.write( +""" +class A +{ +public: + A(); + void a(); +private: + void b(); +}; +""") + + test_file = os.path.join(tmpdir, 'test.cpp') + with open(test_file, 'wt') as f: + f.write( +""" +#include "test.h" + +A::A() { } +void A::b() { } +""") + + args = [ + '-q', + '--template=simple', + '--enable=style', + '--suppress=functionStatic', # we do not care about this - this was converted from TestUnusedPrivateFunction + test_file + ] + + ret, stdout, stderr = cppcheck(args) + assert stdout == '' + assert stderr.splitlines() == [] + assert ret == 0, stdout + + +def test_unused_private_function_multi_file(tmpdir): # ticket #2567 + test_inc = os.path.join(tmpdir, 'test.h') + with open(test_inc, 'wt') as f: + f.write( +""" +struct Fred +{ + Fred() + { + Init(); + } +private: + void Init(); +}; +""") + + test_file = os.path.join(tmpdir, 'test.cpp') + with open(test_file, 'wt') as f: + f.write( +""" +#include "test.h" + +void Fred::Init() +{ +} +""") + + args = [ + '-q', + '--template=simple', + '--enable=style', + '--suppress=functionStatic', # we do not care about this - this was converted from TestUnusedPrivateFunction + test_file + ] + + ret, stdout, stderr = cppcheck(args) + assert stdout == '' + assert stderr.splitlines() == [] + assert ret == 0, stdout + + +def test_missing_doublequote_include(tmpdir): + test_inc = os.path.join(tmpdir, 'abc.h') + with open(test_inc, 'wt') as f: + f.write( +''' +#define a +" +''') + + test_file = os.path.join(tmpdir, 'test.cpp') + with open(test_file, 'wt') as f: + f.write( +""" +#include "abc.h" +""") + + args = [ + '-q', + '--template=simple', + test_file + ] + + ret, stdout, stderr = cppcheck(args) + assert stdout == '' + assert stderr.splitlines() == [ + f"{test_inc}:3:1: error: No pair for character (\"). Can't process file. File is either invalid or unicode, which is currently not supported. [syntaxError]" + ] + assert ret == 0, stdout + + def test_no_valid_configuration_check_config(tmp_path): test_file = tmp_path / 'test.c' with open(test_file, "w") as f: @@ -4318,25 +4428,25 @@ 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, 186, use_unusedfunction_only=True) + __test_active_checkers(tmp_path, 1, 188, use_unusedfunction_only=True) def test_active_unusedfunction_only_builddir(tmp_path): checkers_exp = [ 'CheckUnusedFunctions::check' ] - __test_active_checkers(tmp_path, 1, 186, use_unusedfunction_only=True, checkers_exp=checkers_exp) + __test_active_checkers(tmp_path, 1, 188, use_unusedfunction_only=True, checkers_exp=checkers_exp) def test_active_unusedfunction_only_misra(tmp_path): - __test_active_checkers(tmp_path, 1, 386, use_unusedfunction_only=True, use_misra=True) + __test_active_checkers(tmp_path, 1, 388, 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, 386, use_unusedfunction_only=True, use_misra=True, checkers_exp=checkers_exp) + __test_active_checkers(tmp_path, 1, 388, use_unusedfunction_only=True, use_misra=True, checkers_exp=checkers_exp) def test_analyzerinfo(tmp_path): diff --git a/test/cli/performance_test.py b/test/cli/performance_test.py index 55da3b3b04e..5be958619fc 100644 --- a/test/cli/performance_test.py +++ b/test/cli/performance_test.py @@ -3,6 +3,7 @@ import os import sys +import time import pytest @@ -413,3 +414,27 @@ class C { } }""") cppcheck([filename]) # should not take more than ~1 second + + +@pytest.mark.timeout(60) +def test_slow_many_headers(tmpdir): + # 14113 + c_file = os.path.join(tmpdir, 'source.c') + h_file = os.path.join(tmpdir, 'header.h') + n_hdr = 128 + with open(c_file, 'wt') as f: + f.write('#include "header.h"\n') + with open(h_file, 'wt') as f: + for i in range(n_hdr): + f.write(f'#ifdef CONFIG{i}\n#include "header{i}.h"\n#endif\n') + for i in range(n_hdr): + h_file_i = os.path.join(tmpdir, f"header{i}.h") + with open(h_file_i, 'wt') as f: + for j in range(2048): + f.write(f'#define MACRO{j}{(" "+str(j))*128}\n') + f.write(f'MACRO{i}\n') + # creating the files used for testing can be slow, so we use perf counter here instead + start = time.perf_counter_ns() + cppcheck(['-DCONFIG0', c_file]) + end = time.perf_counter_ns() + assert end - start < 2 * 10**9 # max 2 sec diff --git a/test/cli/proj-inline-suppress/cfg.c b/test/cli/proj-inline-suppress/cfg.c index b597217fa32..42709095dcf 100644 --- a/test/cli/proj-inline-suppress/cfg.c +++ b/test/cli/proj-inline-suppress/cfg.c @@ -2,9 +2,9 @@ void f() { #if DEF_1 // cppcheck-suppress id - (void)0; + ; #endif // cppcheck-suppress id - (void)0; + ; } diff --git a/test/cli/project_test.py b/test/cli/project_test.py index 7421ca406a6..64bb406a709 100644 --- a/test/cli/project_test.py +++ b/test/cli/project_test.py @@ -147,6 +147,16 @@ def test_slnx_no_xml_root(tmpdir): __test_project_error(tmpdir, "slnx", content, expected) +def test_slnx_invalid_xml_root(tmpdir): + content = '\r\n' \ + "\r\n" \ + "\r\n" + + expected = "Invalid Visual Studio solution file format" + + __test_project_error(tmpdir, "slnx", content, expected) + + def test_slnx_no_projects(tmpdir): content = '\r\n' \ "\r\n" \ @@ -161,6 +171,22 @@ def test_slnx_no_projects(tmpdir): __test_project_error(tmpdir, "slnx", content, expected) +def test_slnx_no_projects_in_folder(tmpdir): + content = '\r\n' \ + "\r\n" \ + " \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" \ @@ -179,6 +205,26 @@ def test_slnx_project_file_not_found(tmpdir): __test_project_error(tmpdir, "slnx", content, expected) +def test_slnx_project_file_in_folder_not_found(tmpdir): + content = '\r\n' \ + "\r\n" \ + " \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, "common/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/slnx-folders/app/app.cpp b/test/cli/slnx-folders/app/app.cpp new file mode 100644 index 00000000000..3454c2de254 --- /dev/null +++ b/test/cli/slnx-folders/app/app.cpp @@ -0,0 +1,7 @@ +#include "../lib/lib.h" + +int main(int argc, char *argv[]) +{ + int x = 3 / 0; (void)x; // ERROR + return foo(); +} diff --git a/test/cli/slnx-folders/app/app.vcxproj b/test/cli/slnx-folders/app/app.vcxproj new file mode 100644 index 00000000000..b72ae55c565 --- /dev/null +++ b/test/cli/slnx-folders/app/app.vcxproj @@ -0,0 +1,102 @@ + + + + + Debug + x64 + + + Release + x64 + + + + 18.0 + Win32Proj + {0de77c38-881a-4f9f-bdfa-2c429968985e} + unused + 10.0 + + + + Application + true + v145 + Unicode + + + Application + false + v145 + true + Unicode + + + + + + + + + + + + + + + ..\x64\Debug\ + x64\Debug\ + + + ..\x64\Release\ + x64\Release\ + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + + + Console + true + ../lib + + + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Console + true + + + true + + + + + + + + {93BE1430-BE74-35DF-1882-AF70E49C9898} + + + + + + diff --git a/test/cli/slnx-folders/lib/lib.cpp b/test/cli/slnx-folders/lib/lib.cpp new file mode 100644 index 00000000000..b4a89cee1c7 --- /dev/null +++ b/test/cli/slnx-folders/lib/lib.cpp @@ -0,0 +1,9 @@ +#include +#include "lib.h" + +int foo() +{ + std::cout << "hello world\n"; + int x = 3 / 0; (void)x; // ERROR + return 0; +} diff --git a/test/cli/slnx-folders/lib/lib.h b/test/cli/slnx-folders/lib/lib.h new file mode 100644 index 00000000000..cf790ac3eab --- /dev/null +++ b/test/cli/slnx-folders/lib/lib.h @@ -0,0 +1 @@ +extern int foo(); diff --git a/test/cli/slnx-folders/lib/lib.vcxproj b/test/cli/slnx-folders/lib/lib.vcxproj new file mode 100644 index 00000000000..232c2478e2f --- /dev/null +++ b/test/cli/slnx-folders/lib/lib.vcxproj @@ -0,0 +1,97 @@ + + + + + Debug + x64 + + + Release + x64 + + + + 18.0 + Win32Proj + {93BE1430-BE74-35DF-1882-AF70E49C9898} + unused + 10.0 + + + + StaticLibrary + true + v145 + Unicode + + + StaticLibrary + false + v145 + true + Unicode + + + + + + + + + + + + + + + ..\x64\Debug\ + x64\Debug\ + + + ..\x64\Release\ + x64\Release\ + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + + + Console + true + ../lib + + + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Console + true + + + true + + + + + + + + + diff --git a/test/cli/slnx-folders/slnx-folders.cppcheck b/test/cli/slnx-folders/slnx-folders.cppcheck new file mode 100644 index 00000000000..4fa0c4e7623 --- /dev/null +++ b/test/cli/slnx-folders/slnx-folders.cppcheck @@ -0,0 +1,17 @@ + + + slnx-folders-cppcheck-build-dir + slnx-folders.slnx + false + true + true + true + 2 + 100 + + Debug + Release + + + slnx-folders + diff --git a/test/cli/slnx-folders/slnx-folders.slnx b/test/cli/slnx-folders/slnx-folders.slnx new file mode 100644 index 00000000000..ce6b9014431 --- /dev/null +++ b/test/cli/slnx-folders/slnx-folders.slnx @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/test/cli/slnx-folders_test.py b/test/cli/slnx-folders_test.py new file mode 100644 index 00000000000..b9dd5f09c92 --- /dev/null +++ b/test/cli/slnx-folders_test.py @@ -0,0 +1,73 @@ + +# python -m pytest slnx-folders_test.py + +import os +import re + +from testutils import cppcheck + +__script_dir = os.path.dirname(os.path.abspath(__file__)) +__proj_dir = os.path.join(__script_dir, 'slnx-folders') + +def get_lines(s): + return sorted(s.split('\n')) + +# Get Visual Studio configurations checking a file +# Checking {file} {config}... +def __getVsConfigs(stdout, filename): + ret = [] + for line in stdout.split('\n'): + if not line.startswith('Checking %s ' % filename): + continue + if not line.endswith('...'): + continue + res = re.match(r'.* ([A-Za-z0-9|]+)...', line) + if res: + ret.append(res.group(1)) + ret.sort() + return ' '.join(ret) + +def test_relative_path(): + args = [ + '--template=cppcheck1', + 'slnx-folders' + ] + ret, stdout, stderr = cppcheck(args, cwd=__script_dir) + filename1 = os.path.join('slnx-folders', 'app', 'app.cpp') + filename2 = os.path.join('slnx-folders', 'lib', 'lib.cpp') + assert ret == 0, stdout + expected = ( + '[%s:5]: (error) Division by zero.\n' + '[%s:7]: (error) Division by zero.\n' % (filename1, filename2) + ) + assert get_lines(stderr) == get_lines(expected) + +def test_local_path(): + args = [ + '--template=cppcheck1', + '.' + ] + ret, stdout, stderr = cppcheck(args, cwd=__proj_dir) + filename1 = os.path.join('app', 'app.cpp') + filename2 = os.path.join('lib', 'lib.cpp') + assert ret == 0, stdout + expected = ( + '[%s:5]: (error) Division by zero.\n' + '[%s:7]: (error) Division by zero.\n' % (filename1, filename2) + ) + assert get_lines(stderr) == get_lines(expected) + +def test_absolute_path(): + args = [ + '--template=cppcheck1', + __proj_dir + ] + ret, stdout, stderr = cppcheck(args) + filename1 = os.path.join(__proj_dir, 'app', 'app.cpp') + filename2 = os.path.join(__proj_dir, 'lib', 'lib.cpp') + assert ret == 0, stdout + expected = ( + '[%s:5]: (error) Division by zero.\n' + '[%s:7]: (error) Division by zero.\n' % (filename1, filename2) + ) + assert get_lines(stderr) == get_lines(expected) diff --git a/test/fixture.h b/test/fixture.h index fe767a3a16a..c5828033fd7 100644 --- a/test/fixture.h +++ b/test/fixture.h @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -135,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); } diff --git a/test/helpers.cpp b/test/helpers.cpp index 252658cc531..70437207a84 100644 --- a/test/helpers.cpp +++ b/test/helpers.cpp @@ -124,7 +124,8 @@ void SimpleTokenizer2::preprocess(const char* code, std::size_t size, std::vecto // Tokenizer.. tokenizer.list.createTokens(std::move(tokens2)); - std::list directives = preprocessor.createDirectives(); + std::list directives; + preprocessor.createDirectives(directives); tokenizer.setDirectives(std::move(directives)); } diff --git a/test/options.cpp b/test/options.cpp index 54527b26ecd..757b6cdff86 100644 --- a/test/options.cpp +++ b/test/options.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 diff --git a/test/options.h b/test/options.h index b327721351c..0bd83cef78b 100644 --- a/test/options.h +++ b/test/options.h @@ -1,5 +1,5 @@ // 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/test/test64bit.cpp b/test/test64bit.cpp index 6f9a5fbda2f..cc96da48577 100644 --- a/test/test64bit.cpp +++ b/test/test64bit.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,8 +49,7 @@ class Test64BitPortability : public TestFixture { SimpleTokenizer tokenizer(settings, *this, cpp); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check char variable usage.. - Check64BitPortability check64BitPortability(&tokenizer, &settings, this); + Check64BitPortabilityImpl check64BitPortability(&tokenizer, settings, *this); check64BitPortability.pointerassignment(); } diff --git a/test/testassert.cpp b/test/testassert.cpp index 412a7cb750b..ea170c43f2d 100644 --- a/test/testassert.cpp +++ b/test/testassert.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,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 { @@ -156,7 +156,7 @@ class TestAssert : public TestFixture { "void foo(SquarePack s) {\n" " assert( s.Foo() );\n" "}"); - ASSERT_EQUALS("[test.cpp:5:14]: (warning) Assert statement calls a function which may have desired side effects: 'Foo'. [assertWithSideEffect]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:5:14]: (warning) Assert statement calls a function which may have desired side effects: 'Foo'. If there are no side effects, consider declaring the method const. [assertWithSideEffect]\n", errout_str()); check("struct SquarePack {\n" " int Foo() const;\n" diff --git a/test/testastutils.cpp b/test/testastutils.cpp index eb9559ed39d..6a6e0624587 100644 --- a/test/testastutils.cpp +++ b/test/testastutils.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 @@ -259,7 +259,7 @@ class TestAstUtils : public TestFixture { const Token * const argtok = Token::findmatch(tokenizer.tokens(), pattern); ASSERT_LOC(argtok, file, line); int indirect = (argtok->variable() && argtok->variable()->isArray()); - return (isVariableChangedByFunctionCall)(argtok, indirect, settingsDefault, inconclusive); + return (isVariableChangedByFunctionCall)(argtok, indirect, settingsDefault.library, inconclusive); } void isVariableChangedByFunctionCallTest() { diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index 008dc645419..df421d6879c 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -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 { @@ -4061,6 +4062,14 @@ class TestAutoVariables : public TestFixture { " struct S s = { .i = 0, true };\n" "}\n"); // don't crash ASSERT_EQUALS("", errout_str()); + + check("struct A { int& r; };\n" // #14772 + "A* f() {\n" + " int x = 0;\n" + " return new A{ x };\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:19] -> [test.cpp:3:9] -> [test.cpp:4:17]: (error) Returning object that points to local variable 'x' that will be invalid when returning. [returnDanglingLifetime]\n", + errout_str()); } void danglingLifetimeInitList() { @@ -4443,6 +4452,99 @@ class TestAutoVariables : public TestFixture { "}\n"); ASSERT_EQUALS("[test.cpp:5:14] -> [test.cpp:5:18] -> [test.cpp:6:7]: (error) Using pointer that is a temporary. [danglingTemporaryLifetime]\n", errout_str()); + + check("struct A { const int* data[2]; };\n" + "A g() {\n" + " int x = 0;\n" + " A a;\n" + " a.data[0] = &x;\n" + " return a;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:17] -> [test.cpp:3:9] -> [test.cpp:6:12]: (error) Returning object that points to local variable 'x' that will be invalid when returning. [returnDanglingLifetime]\n", + errout_str()); + + check("struct A { const int* data[2]; };\n" + "A g() {\n" + " int x = 0;\n" + " A a[2];\n" + " a[0].data[0] = &x;\n" + " return a[0];\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:20] -> [test.cpp:3:9] -> [test.cpp:6:13]: (error) Returning object that points to local variable 'x' that will be invalid when returning. [returnDanglingLifetime]\n", + errout_str()); + + check("struct A { const int* data[2]; };\n" + "A* g() {\n" + " int x = 0;\n" + " static A arr[2];\n" + " arr[0].data[0] = &x;\n" + " return arr;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:22] -> [test.cpp:3:9] -> [test.cpp:6:12]: (error) Returning pointer to local variable 'x' that will be invalid when returning. [returnDanglingLifetime]\n", + errout_str()); + + check("struct A { const int* p; };\n" + "A g(int i) {\n" + " int x = 0;\n" + " A arr[2];\n" + " arr[i].p = &x;\n" + " return arr[i];\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:16] -> [test.cpp:3:9] -> [test.cpp:6:15]: (error) Returning object that points to local variable 'x' that will be invalid when returning. [returnDanglingLifetime]\n", + errout_str()); + + check("struct A { const int* p; };\n" + "A* g(int i) {\n" + " int x = 0;\n" + " static A arr[2];\n" + " arr[i].p = &x;\n" + " return arr;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:16] -> [test.cpp:3:9] -> [test.cpp:6:12]: (error) Returning pointer to local variable 'x' that will be invalid when returning. [returnDanglingLifetime]\n", + errout_str()); + + check("struct A { const int* p; };\n" + "struct B { A arr[2]; };\n" + "B g(int i) {\n" + " int x = 0;\n" + " B b;\n" + " b.arr[i].p = &x;\n" + " return b;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6:18] -> [test.cpp:4:9] -> [test.cpp:7:12]: (error) Returning object that points to local variable 'x' that will be invalid when returning. [returnDanglingLifetime]\n", + errout_str()); + + check("struct A { const int* p; };\n" + "A* g() {\n" + " int x = 0;\n" + " static A a;\n" + " A* ap = &a;\n" + " ap->p = &x;\n" + " (*ap).p = &x;\n" + " return ap;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct A { int* a; int* b; };\n" + "static A g;\n" + "int* f() {\n" + " int x = 0;\n" + " g.a = &x;\n" + " return g.b;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:11] -> [test.cpp:4:9] -> [test.cpp:5:6]: (error) Non-local variable 'g.a' will use pointer to local variable 'x'. [danglingLifetime]\n", + errout_str()); + + check("struct A { int* a; int* b; };\n" + "static A g;\n" + "int* f() {\n" + " int x = 0;\n" + " g.a = &x;\n" + " return g.a;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:11] -> [test.cpp:4:9] -> [test.cpp:5:6]: (error) Non-local variable 'g.a' will use pointer to local variable 'x'. [danglingLifetime]\n" + "[test.cpp:5:11] -> [test.cpp:4:9] -> [test.cpp:6:13]: (error) Returning pointer to local variable 'x' that will be invalid when returning. [returnDanglingLifetime]\n", + errout_str()); } void danglingLifetimeClassMemberFunctions() @@ -4839,7 +4941,9 @@ class TestAutoVariables : public TestFixture { " return *iPtr;\n" " return 0;\n" "}"); - ASSERT_EQUALS("[test.cpp:5:16] -> [test.cpp:4:13] -> [test.cpp:8:17]: (error) Using pointer to local variable 'x' that is out of scope. [invalidLifetime]\n", errout_str()); + ASSERT_EQUALS( + "[test.cpp:5:16] -> [test.cpp:7:10] -> [test.cpp:4:13] -> [test.cpp:8:17]: (error) Using pointer to local variable 'x' that is out of scope. [invalidLifetime]\n", + errout_str()); // #11753 check("int main(int argc, const char *argv[]) {\n" diff --git a/test/testbool.cpp b/test/testbool.cpp index 61bc1b36d9e..6074bbab46a 100644 --- a/test/testbool.cpp +++ b/test/testbool.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 @@ -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); } diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 8a7c1d311b0..b44fd742ab1 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -56,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 @@ -66,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__) @@ -79,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 { @@ -227,6 +227,7 @@ class TestBufferOverrun : public TestFixture { TEST_CASE(buffer_overrun_35); //#2304 TEST_CASE(buffer_overrun_36); TEST_CASE(buffer_overrun_37); + TEST_CASE(buffer_overrun_38); TEST_CASE(buffer_overrun_errorpath); TEST_CASE(buffer_overrun_bailoutIfSwitch); // ticket #2378 : bailoutIfSwitch TEST_CASE(buffer_overrun_function_array_argument); @@ -3507,6 +3508,57 @@ class TestBufferOverrun : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void buffer_overrun_38() { // #9173 + check("void f() {\n" + " int a[10];\n" + " memset(&a[0], 0, 20 * sizeof(int));\n" + "}\n" + "void g() {\n" + " int a[10];\n" + " memset(&a[0], 0, 10 * sizeof(int));\n" + "}\n" + "void h() {\n" + " int a[10];\n" + " memset(&a[5], 0, 5 * sizeof(int));\n" + "}\n" + "void i() {\n" + " int a[10][10];\n" + " memset(&a[0][0], 0, 100 * sizeof(int));\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:12]: (error) Buffer is accessed out of bounds: &a[0] [bufferAccessOutOfBounds]\n", errout_str()); + + check("void f() {\n" + " int a[10];\n" + " memset(&a[5], 0, 10 * sizeof(int));\n" + "}\n" + "void g() {\n" + " int a[1][1];\n" + " memset(&a[0][0], 0, 10 * sizeof(int));\n" + "}\n"); + TODO_ASSERT_EQUALS("[test.cpp:3:12]: (error) Buffer is accessed out of bounds: &a[5] [bufferAccessOutOfBounds]\n" + "[test.cpp:7:12]: (error) Buffer is accessed out of bounds: &a[0][0] [bufferAccessOutOfBounds]\n", + "", + errout_str()); + + check("void f() {\n" // #14866 + " std::vector buf(25);\n" + " std::memset(&buf[0], 0, 25);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" // #14859 + " std::vector buf(25);\n" + " std::memset(&buf[0], 0, 26);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:17]: (error) Buffer is accessed out of bounds: &buf[0] [bufferAccessOutOfBounds]\n", errout_str()); + + check("void f(FILE *fp) {\n" // #14929 + " std::string s;\n" + " fwrite(&s, 1, 1, fp);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); // don't crash + } + void buffer_overrun_errorpath() { setMultiline(); Settings s = settings0; @@ -5169,8 +5221,9 @@ class TestBufferOverrun : public TestFixture { void getErrorMessages() { // Ticket #2292: segmentation fault when using --errorlist - const Check& c = getCheck(); - c.getErrorMessages(this, nullptr); + CheckBufferOverrun check; + const Check& c = getCheck(check); + c.getErrorMessages(*this, settingsDefault); // we are not interested in the output - just consume it ignore_errout(); } @@ -5360,11 +5413,11 @@ class TestBufferOverrun : public TestFixture { SimpleTokenizer tokenizer(settings0, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - CTU::FileInfo *ctu = CTU::getFileInfo(tokenizer); + const CTU::FileInfo *ctu = CTU::getFileInfo(tokenizer); - // Check code.. - std::list fileInfo; - Check& c = getCheck(); + std::list fileInfo; + 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()) { @@ -5816,7 +5869,29 @@ class TestBufferOverrun : public TestFixture { " (void)y[1];\n" " (void)y[2];\n" "}\n"); - TODO_ASSERT_EQUALS("error", "", errout_str()); + ASSERT_EQUALS("[test.cpp:7:20] -> [test.cpp:9:12]: (error) The address of variable 's.a' is accessed at non-zero index. [objectIndex]\n" + "[test.cpp:7:20] -> [test.cpp:10:12]: (error) The address of variable 's.a' is accessed at non-zero index. [objectIndex]\n", + errout_str()); + + check("const int N = 12;\n" // #14887 + "struct S {\n" + " void f() const;\n" + " int a[N];\n" + "};\n" + "struct T {\n" + " void f() const;\n" + " S s;\n" + "};\n" + "int g(const int* p) { return p[5]; }\n" + "void S::f() const {\n" + " const int* q = a;\n" + " g(q);\n" + "}\n" + "void T::f() const {\n" + " const int* q = s.a;\n" + " g(q);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void checkPipeParameterSize() { // #3521 diff --git a/test/testcharvar.cpp b/test/testcharvar.cpp index 624efcff539..7d4a17489fc 100644 --- a/test/testcharvar.cpp +++ b/test/testcharvar.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 @@ class TestCharVar : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check char variable usage.. - CheckOther checkOther(&tokenizer, &settings, this); + CheckOtherImpl checkOther(&tokenizer, settings, *this); checkOther.checkCharVariable(); } diff --git a/test/testcheck.cpp b/test/testcheck.cpp index 8ea4cef38d8..254519da2eb 100644 --- a/test/testcheck.cpp +++ b/test/testcheck.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 "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 index eafe7b8848f..39a6f2a9997 100644 --- a/test/testcheckersreport.cpp +++ b/test/testcheckersreport.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/testclass.cpp b/test/testclass.cpp index 2cecdfe80f6..1d647eb33a1 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -196,6 +196,7 @@ class TestClass : public TestFixture { TEST_CASE(const99); TEST_CASE(const100); TEST_CASE(const101); + TEST_CASE(const102); TEST_CASE(const_handleDefaultParameters); TEST_CASE(const_passThisToMemberOfOtherClass); @@ -270,7 +271,7 @@ class TestClass : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check.. - CheckClass checkClass(&tokenizer, &settings, this); + CheckClassImpl checkClass(&tokenizer, settings, *this); (checkClass.checkCopyCtorAndEqOperator)(); } @@ -371,7 +372,7 @@ class TestClass : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check.. - CheckClass checkClass(&tokenizer, &settings0, this); + CheckClassImpl checkClass(&tokenizer, settings0, *this); (checkClass.checkExplicitConstructors)(); } @@ -528,7 +529,7 @@ class TestClass : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check.. - CheckClass checkClass(&tokenizer, &settings1, this); + CheckClassImpl checkClass(&tokenizer, settings1, *this); (checkClass.checkDuplInheritedMembers)(); } @@ -752,7 +753,7 @@ class TestClass : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check.. - CheckClass checkClass(&tokenizer, &settings3, this); + CheckClassImpl checkClass(&tokenizer, settings3, *this); checkClass.copyconstructors(); } @@ -1223,7 +1224,7 @@ class TestClass : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check.. - CheckClass checkClass(&tokenizer, &settings0, this); + CheckClassImpl checkClass(&tokenizer, settings0, *this); checkClass.operatorEqRetRefThis(); } @@ -1694,7 +1695,7 @@ class TestClass : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check.. - CheckClass checkClass(&tokenizer, &settings1, this); + CheckClassImpl checkClass(&tokenizer, settings1, *this); checkClass.operatorEqToSelf(); } @@ -2657,7 +2658,7 @@ class TestClass : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check.. - CheckClass checkClass(&tokenizer, &s, this); + CheckClassImpl checkClass(&tokenizer, s, *this); checkClass.virtualDestructor(); } @@ -2994,7 +2995,7 @@ class TestClass : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check.. - CheckClass checkClass(&tokenizer, &settings, this); + CheckClassImpl checkClass(&tokenizer, settings, *this); checkClass.checkMemset(); } @@ -3640,7 +3641,7 @@ class TestClass : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check.. - CheckClass checkClass(&tokenizer, &settings1, this); + CheckClassImpl checkClass(&tokenizer, settings1, *this); checkClass.thisSubtraction(); } @@ -3680,7 +3681,7 @@ class TestClass : public TestFixture { SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - CheckClass checkClass(&tokenizer, &settings, this); + CheckClassImpl checkClass(&tokenizer, settings, *this); (checkClass.checkConst)(); } @@ -6998,6 +6999,22 @@ class TestClass : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void const102() { + checkConst("struct S {\n" // #14888 + " void f() {\n" + " int *p = a;\n" + " *p = 0;\n" + " }\n" + " void g() {\n" + " const int *p = a;\n" + " if (*p) {}\n" + " }\n" + " int a[3];\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:6:10]: (style, inconclusive) Technically the member function 'S::g' can be const. [functionConst]\n", + errout_str()); + } + void const_handleDefaultParameters() { checkConst("struct Foo {\n" " void foo1(int i, int j = 0) {\n" @@ -7863,7 +7880,7 @@ class TestClass : public TestFixture { SimpleTokenizer tokenizer(settings2, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - CheckClass checkClass(&tokenizer, &settings2, this); + CheckClassImpl checkClass(&tokenizer, settings2, *this); checkClass.initializerListOrder(); } @@ -8017,7 +8034,7 @@ class TestClass : public TestFixture { SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - CheckClass checkClass(&tokenizer, &settings, this); + CheckClassImpl checkClass(&tokenizer, settings, *this); checkClass.initializationListUsage(); } @@ -8241,7 +8258,7 @@ class TestClass : public TestFixture { SimpleTokenizer tokenizer(settings0, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - CheckClass checkClass(&tokenizer, &settings0, this); + CheckClassImpl checkClass(&tokenizer, settings0, *this); (checkClass.checkSelfInitialization)(); } @@ -8351,7 +8368,7 @@ class TestClass : public TestFixture { SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - CheckClass checkClass(&tokenizer, &settings, this); + CheckClassImpl checkClass(&tokenizer, settings, *this); checkClass.checkVirtualFunctionCallInConstructor(); } @@ -8696,7 +8713,7 @@ class TestClass : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check.. - CheckClass checkClass(&tokenizer, &settings, this); + CheckClassImpl checkClass(&tokenizer, settings, *this); (checkClass.checkOverride)(); } @@ -8908,7 +8925,7 @@ class TestClass : public TestFixture { ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); // Check.. - CheckClass checkClass(&tokenizer, &settings, this); + CheckClassImpl checkClass(&tokenizer, settings, *this); (checkClass.checkUselessOverride)(); } @@ -9098,7 +9115,7 @@ class TestClass : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check.. - CheckClass checkClass(&tokenizer, &settings, this); + CheckClassImpl checkClass(&tokenizer, settings, *this); (checkClass.checkUnsafeClassRefMember)(); } @@ -9116,7 +9133,7 @@ class TestClass : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check.. - CheckClass checkClass(&tokenizer, &settings1, this); + CheckClassImpl checkClass(&tokenizer, settings1, *this); (checkClass.checkThisUseAfterFree)(); } @@ -9278,10 +9295,11 @@ class TestClass : public TestFixture { void ctu(const std::vector &code) { - Check &check = getCheck(); + CheckClass checkClass; + Check &check = getCheck(checkClass); // getFileInfo - std::list fileInfo; + std::list fileInfo; for (const std::string& c: code) { const std::string filename = std::to_string(fileInfo.size()) + ".cpp"; SimpleTokenizer tokenizer{settingsDefault, *this, filename}; @@ -9330,9 +9348,9 @@ class TestClass : public TestFixture { SimpleTokenizer tokenizer(settings1, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check.. - const Check& c = getCheck(); - Check::FileInfo * fileInfo = (c.getFileInfo)(tokenizer, settings1, ""); + CheckClass check; + const Check& c = getCheck(check); + const Check::FileInfo * fileInfo = (c.getFileInfo)(tokenizer, settings1, ""); delete fileInfo; } @@ -9352,7 +9370,7 @@ class TestClass : public TestFixture { ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); // Check.. - CheckClass checkClass(&tokenizer, &settings, this); + CheckClassImpl checkClass(&tokenizer, settings, *this); (checkClass.checkReturnByReference)(); } diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index 135b7c782be..326b7ad613d 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -33,6 +33,11 @@ #include "suppressions.h" #include "utils.h" +#ifdef HAVE_RULES +#include "regex.h" +#include "rule.h" +#endif + #include #include #include @@ -257,6 +262,7 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(premiumOptionsMetrics); TEST_CASE(premiumOptionsCertCIntPrecision); TEST_CASE(premiumOptionsLicenseFile); + TEST_CASE(premiumOptionsLicenseFilePathWithSpace); TEST_CASE(premiumOptionsInvalid1); TEST_CASE(premiumOptionsInvalid2); TEST_CASE(premiumSafety); @@ -1637,6 +1643,14 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS("--license-file=file.lic", settings->premiumArgs); } + void premiumOptionsLicenseFilePathWithSpace() { + REDIRECT; + asPremium(); + const char * const argv[] = {"cppcheck", "--premium-license-file=license folder/file.lic", "file.c"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS("\"--license-file=license folder/file.lic\"", settings->premiumArgs); + } + void premiumOptionsInvalid1() { REDIRECT; asPremium(); @@ -2728,14 +2742,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_ENUM(Regex::Engine::Pcre, it->regex->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_ENUM(Regex::Engine::Pcre, it->regex->engine()); ASSERT_EQUALS("define", it->tokenlist); ASSERT_EQUALS(".*", it->pattern); ASSERT_EQUALS_ENUM(Severity::warning, it->severity); @@ -2759,7 +2773,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_ENUM(Regex::Engine::Pcre, it->regex->engine()); ASSERT_EQUALS("define", it->tokenlist); ASSERT_EQUALS(".+", it->pattern); ASSERT_EQUALS_ENUM(Severity::error, it->severity); diff --git a/test/testcondition.cpp b/test/testcondition.cpp index f0764dd2bd6..da4ecae43b3 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -149,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__) @@ -162,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() { @@ -527,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() { @@ -3674,7 +3675,7 @@ class TestCondition : public TestFixture { " f ? result = 42 : ret = -1;\n" " return ret;\n" "}"); - ASSERT_EQUALS("", errout_str()); + ASSERT_EQUALS("[test.cpp:4:9]: (style) Condition 'f' is always false [knownConditionTrueFalse]\n", errout_str()); check("int f(void *handle) {\n" " if (!handle) return 0;\n" @@ -4910,6 +4911,44 @@ class TestCondition : public TestFixture { 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()); + + check("int g();\n" // a value modified inside a nested branch must be lowered to possible + "void f(int outer, int inner) {\n" + " int bits = 0;\n" + " if (outer) {\n" + " if (inner == 1)\n" + " bits = g();\n" + " }\n" + " if (bits > 0) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("int g();\n" // the modifying branch has an escaping sibling - still must be lowered + "void f(int t, int u) {\n" + " int v = 0;\n" + " if (t) {\n" + " if (u == 2)\n" + " v = g();\n" + " else\n" + " return;\n" + " }\n" + " if (v > 0) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("bool f(int x) {\n" // only the innermost else escapes - x is 0 or >1 afterwards, not known + " if (!x) {}\n" + " else if (x > 1) {}\n" + " else return false;\n" + " return x ? false : true;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("bool f(int x) {\n" // the branch's fall-through path must clear the escape + " if (x) { if (x > 1) {} else return false; }\n" + " return x ? false : true;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void alwaysTrueSymbolic() @@ -5679,7 +5718,7 @@ class TestCondition : public TestFixture { check("void f() {\n" // #8192 " for (int i = 0; i > 10; ++i) {}\n" "}\n"); - TODO_ASSERT_EQUALS("[test.cpp:2]: (style) Condition 'i>10' is always false\n", "", errout_str()); + ASSERT_EQUALS("[test.cpp:2:23]: (style) Condition 'i>10' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f() {\n" " for (int i = 1000; i < 20; ++i) {}\n" @@ -6226,6 +6265,20 @@ class TestCondition : public TestFixture { check("enum E { E1 = 1, E2 = 2 };\n" "void f(int i) { if (i == E1 || E2) {} }\n"); ASSERT_EQUALS("[test.cpp:2:29]: (style) Condition 'i==E1||E2' is always true [knownConditionTrueFalse]\n", errout_str()); + + check("void f(bool a, bool b) {\n" // #11614 + " if (b) {\n" + " bool x = !b || a;\n" + " }\n" + "}\n" + "void g(bool a, bool b) {\n" + " if (!b) {\n" + " bool x = a || b;\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:18]: (style) Condition '!b' is always false [knownConditionTrueFalse]\n" + "[test.cpp:7:9] -> [test.cpp:8:23]: (style) Condition 'b' is always false [knownConditionTrueFalse]\n", + errout_str()); } void pointerAdditionResultNotNull() { @@ -6471,6 +6524,19 @@ class TestCondition : public TestFixture { " 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 61916e1d0bb..5f2fd228dc4 100644 --- a/test/testconstructors.cpp +++ b/test/testconstructors.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,7 +52,7 @@ class TestConstructors : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check class constructors.. - CheckClass checkClass(&tokenizer, &settings1, this); + CheckClassImpl checkClass(&tokenizer, settings1, *this); checkClass.constructors(); } @@ -763,12 +763,40 @@ class TestConstructors : public TestFixture { check("struct S {\n" // #14546 " int a = 0, b;\n" "};\n"); - ASSERT_EQUALS("[test.cpp:1:10]: (warning) Member variable 'S::b' has no initializer. [uninitMemberVarNoCtor]\n", errout_str()); + 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." diff --git a/test/testcppcheck.cpp b/test/testcppcheck.cpp index 84db6db6c28..17c5b8eff3c 100644 --- a/test/testcppcheck.cpp +++ b/test/testcppcheck.cpp @@ -527,7 +527,6 @@ class TestCppcheck : public TestFixture { void checkPlistOutput() const { Suppressions supprs; ErrorLogger2 errorLogger; - std::vector files = {"textfile.txt"}; { const auto s = dinit(Settings, $.templateFormat = templateFormat, $.plistOutput = "output"); @@ -535,7 +534,7 @@ class TestCppcheck : public TestFixture { CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, {}); const FileWithDetails fileWithDetails {file.path(), Path::identify(file.path(), false), 0}; - cppcheck.checkPlistOutput(fileWithDetails, files); + cppcheck.checkPlistOutput(fileWithDetails); const std::string outputFile {"outputfile_" + std::to_string(std::hash {}(fileWithDetails.spath())) + ".plist"}; ASSERT(Path::exists(outputFile)); std::remove(outputFile.c_str()); @@ -547,7 +546,7 @@ class TestCppcheck : public TestFixture { CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, {}); const FileWithDetails fileWithDetails {file.path(), Path::identify(file.path(), false), 0}; - cppcheck.checkPlistOutput(fileWithDetails, files); + cppcheck.checkPlistOutput(fileWithDetails); const std::string outputFile {"outputfile_" + std::to_string(std::hash {}(fileWithDetails.spath())) + ".plist"}; ASSERT(Path::exists(outputFile)); std::remove(outputFile.c_str()); @@ -557,7 +556,7 @@ class TestCppcheck : public TestFixture { Settings s; const ScopedFile file("file.c", ""); CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, {}); - cppcheck.checkPlistOutput(FileWithDetails(file.path(), Path::identify(file.path(), false), 0), files); + cppcheck.checkPlistOutput(FileWithDetails(file.path(), Path::identify(file.path(), false), 0)); } } diff --git a/test/testerrorlogger.cpp b/test/testerrorlogger.cpp index 23b3233995c..014ac3a0a8f 100644 --- a/test/testerrorlogger.cpp +++ b/test/testerrorlogger.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/testexceptionsafety.cpp b/test/testexceptionsafety.cpp index 58b26ecbc27..1be46fbf282 100644 --- a/test/testexceptionsafety.cpp +++ b/test/testexceptionsafety.cpp @@ -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() { diff --git a/test/testfunctions.cpp b/test/testfunctions.cpp index 8bbd3d92c6b..f5067bc31dc 100644 --- a/test/testfunctions.cpp +++ b/test/testfunctions.cpp @@ -86,6 +86,7 @@ class TestFunctions : public TestFixture { TEST_CASE(checkMissingReturn5); TEST_CASE(checkMissingReturn6); // #13180 TEST_CASE(checkMissingReturn7); // #14370 - FN try/catch + TEST_CASE(checkMissingReturn8); TEST_CASE(checkMissingReturnStdInt); // #14482 - FN std::int32_t // std::move for locar variable @@ -132,7 +133,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() { @@ -1926,6 +1928,14 @@ 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 checkMissingReturn8() { + const Settings s = settingsBuilder(settings).cpp(Standards::CPP20).build(); + check("boost::asio::awaitable test() {\n" + " co_return;\n" + "}\n",s); + ASSERT_EQUALS("", 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()); diff --git a/test/testgarbage.cpp b/test/testgarbage.cpp index 44f163a53c1..7d91a013940 100644 --- a/test/testgarbage.cpp +++ b/test/testgarbage.cpp @@ -17,6 +17,7 @@ */ #include "check.h" +#include "checks.h" #include "errortypes.h" #include "fixture.h" #include "helpers.h" @@ -285,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); diff --git a/test/testimportproject.cpp b/test/testimportproject.cpp index 6f8633dbeea..c9889445c3c 100644 --- a/test/testimportproject.cpp +++ b/test/testimportproject.cpp @@ -42,6 +42,7 @@ class TestImporter final : public ImportProject { using ImportProject::collectArgs; using ImportProject::fsSetDefines; using ImportProject::fsSetIncludePaths; + using ImportProject::setRelativePaths; }; @@ -56,6 +57,7 @@ class TestImportProject : public TestFixture { TEST_CASE(setIncludePaths1); TEST_CASE(setIncludePaths2); TEST_CASE(setIncludePaths3); // macro names are case insensitive + TEST_CASE(setRelativePathsInclude); // #14746 TEST_CASE(importCompileCommands1); TEST_CASE(importCompileCommands2); // #8563, #9567 TEST_CASE(importCompileCommands3); // check with existing trailing / in directory @@ -71,6 +73,7 @@ class TestImportProject : public TestFixture { TEST_CASE(importCompileCommands13); // #13333: duplicate file entries TEST_CASE(importCompileCommands14); // #14156 TEST_CASE(importCompileCommands15); // #14306 + TEST_CASE(importCompileCommandsForcedInclude); // -include / /FI force-include TEST_CASE(importCompileCommandsArgumentsSection); // Handle arguments section TEST_CASE(importCompileCommandsNoCommandSection); // gracefully handles malformed json TEST_CASE(importCompileCommandsDirectoryMissing); // 'directory' field missing @@ -134,6 +137,18 @@ class TestImportProject : public TestFixture { ASSERT_EQUALS("c:/abc/other/", fs.includePaths.front()); } + void setRelativePathsInclude() const { + const std::string cwd = Path::fromNativeSeparators(Path::getCurrentPath()); + TestImporter importer; + FileSettings fs{cwd + "/sub/a.c", Standards::Language::C, 0}; + fs.includePaths.push_back(cwd + "/"); + importer.fileSettings.push_back(fs); + importer.setRelativePaths("compile_commands.json"); + fs = importer.fileSettings.front(); + ASSERT_EQUALS(".", fs.includePaths.front()); + ASSERT_EQUALS("sub/a.c", fs.filename()); + } + void importCompileCommands1() const { REDIRECT; constexpr char json[] = R"([{ @@ -422,6 +437,24 @@ class TestImportProject : public TestFixture { ASSERT_EQUALS("C:/Users/abcd/efg/hijk/path/123/", fs.includePaths.front()); } + void importCompileCommandsForcedInclude() const { // -include / /FI force-include + REDIRECT; + constexpr char json[] = + R"([{ + "file": "/x/a.c", + "directory": "/x", + "command": "cc -include prefix.h /FIplatform.h -c a.c" + }])"; + std::istringstream istr(json); + TestImporter importer; + ASSERT_EQUALS(true, importer.importCompileCommands(istr)); + ASSERT_EQUALS(1, importer.fileSettings.size()); + const FileSettings &fs = importer.fileSettings.front(); + ASSERT_EQUALS(2, fs.forcedIncludes.size()); + ASSERT_EQUALS("prefix.h", fs.forcedIncludes.front()); // gcc/clang -include + ASSERT_EQUALS("platform.h", fs.forcedIncludes.back()); // MSVC/clang-cl /FI + } + void importCompileCommandsArgumentsSection() const { REDIRECT; constexpr char json[] = "[ { \"directory\": \"/tmp/\"," diff --git a/test/testincompletestatement.cpp b/test/testincompletestatement.cpp index 3d8f5d4d713..da238d304b2 100644 --- a/test/testincompletestatement.cpp +++ b/test/testincompletestatement.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,7 +50,7 @@ class TestIncompleteStatement : public TestFixture { ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); // Check for incomplete statements.. - CheckOther checkOther(&tokenizer, &settings1, this); + CheckOtherImpl checkOther(&tokenizer, settings1, *this); checkOther.checkIncompleteStatement(); } @@ -180,9 +180,25 @@ class TestIncompleteStatement : public TestFixture { } void void0() { // #6327 - check("void f() { (void*)0; }"); + check("#define assert(x) ((void)0)\n" + "void f(int* p) {\n" + " assert(p);\n" + "}\n"); ASSERT_EQUALS("", errout_str()); + check("void f() { (void*)0; }"); + ASSERT_EQUALS("[test.cpp:1:12]: (warning) Redundant code: Found unused cast in expression '(void*)0'. [constStatement]\n", errout_str()); + + check("void f() {\n" // #13148 + " static_cast(1);\n" + " static_cast(nullptr);\n" + " (void)NULL;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:22]: (warning) Redundant code: Found unused cast in expression 'static_cast(1)'. [constStatement]\n" + "[test.cpp:3:22]: (warning) Redundant code: Found unused cast in expression 'static_cast(nullptr)'. [constStatement]\n" + "[test.cpp:4:5]: (warning) Redundant code: Found unused cast in expression '(void)NULL'. [constStatement]\n", + errout_str()); + check("#define X 0\n" "void f() { X; }"); ASSERT_EQUALS("", errout_str()); @@ -432,11 +448,11 @@ class TestIncompleteStatement : public TestFixture { "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2:5]: (warning) Redundant code: Found a statement that begins with numeric constant. [constStatement]\n" "[test.cpp:3:6]: (warning) Redundant code: Found a statement that begins with numeric constant. [constStatement]\n" - "[test.cpp:4:5]: (warning) Redundant code: Found a statement that begins with numeric constant. [constStatement]\n" - "[test.cpp:5:6]: (warning) Redundant code: Found a statement that begins with numeric constant. [constStatement]\n" + "[test.cpp:4:5]: (warning) Redundant code: Found unused cast in expression '(char)1'. [constStatement]\n" + "[test.cpp:5:6]: (warning) Redundant code: Found unused cast in expression '(char)1'. [constStatement]\n" "[test.cpp:6:5]: (warning, inconclusive) Found suspicious operator '!', result is not used. [constStatement]\n" "[test.cpp:7:6]: (warning, inconclusive) Found suspicious operator '!', result is not used. [constStatement]\n" - "[test.cpp:8:5]: (warning) Redundant code: Found unused cast of expression '!x'. [constStatement]\n" + "[test.cpp:8:5]: (warning) Redundant code: Found unused cast in expression '(unsigned int)!x'. [constStatement]\n" "[test.cpp:9:5]: (warning, inconclusive) Found suspicious operator '~', result is not used. [constStatement]\n", errout_str()); @@ -447,7 +463,7 @@ class TestIncompleteStatement : public TestFixture { ASSERT_EQUALS("", errout_str()); check("void f(int x) { static_cast(x); }"); - ASSERT_EQUALS("[test.cpp:1:38]: (warning) Redundant code: Found unused cast of expression 'x'. [constStatement]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:1:38]: (warning) Redundant code: Found unused cast in expression 'static_cast(x)'. [constStatement]\n", errout_str()); check("void f(int x, int* p) {\n" " static_cast(x);\n" @@ -465,9 +481,9 @@ class TestIncompleteStatement : public TestFixture { " static_cast((char)i);\n" " (char)static_cast(i);\n" "}\n"); - ASSERT_EQUALS("[test.cpp:2:5]: (warning) Redundant code: Found unused cast of expression 'i'. [constStatement]\n" - "[test.cpp:3:23]: (warning) Redundant code: Found unused cast of expression 'i'. [constStatement]\n" - "[test.cpp:4:5]: (warning) Redundant code: Found unused cast of expression 'i'. [constStatement]\n", + ASSERT_EQUALS("[test.cpp:2:5]: (warning) Redundant code: Found unused cast in expression '(float)(char)i'. [constStatement]\n" + "[test.cpp:3:23]: (warning) Redundant code: Found unused cast in expression 'static_cast((char)i)'. [constStatement]\n" + "[test.cpp:4:5]: (warning) Redundant code: Found unused cast in expression '(char)static_cast(i)'. [constStatement]\n", errout_str()); check("namespace M {\n" @@ -476,7 +492,7 @@ class TestIncompleteStatement : public TestFixture { "void f(int i) {\n" " (M::N::T)i;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:5:5]: (warning) Redundant code: Found unused cast of expression 'i'. [constStatement]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:5:5]: (warning) Redundant code: Found unused cast in expression '(char)i'. [constStatement]\n", errout_str()); check("void f(int (g)(int a, int b)) {\n" // #10873 " int p = 0, q = 1;\n" @@ -528,7 +544,7 @@ class TestIncompleteStatement : public TestFixture { " for (L\"y\"; ;) {}\n" "}\n"); ASSERT_EQUALS("[test.cpp:2:10]: (warning) Unused variable value 'i' [constStatement]\n" - "[test.cpp:3:10]: (warning) Redundant code: Found unused cast of expression 'i'. [constStatement]\n" + "[test.cpp:3:10]: (warning) Redundant code: Found unused cast in expression '(long)i'. [constStatement]\n" "[test.cpp:4:10]: (warning) Redundant code: Found a statement that begins with numeric constant. [constStatement]\n" "[test.cpp:5:10]: (warning) Redundant code: Found a statement that begins with bool constant. [constStatement]\n" "[test.cpp:6:10]: (warning) Redundant code: Found a statement that begins with character constant. [constStatement]\n" @@ -696,8 +712,8 @@ class TestIncompleteStatement : public TestFixture { " NULL;\n" " nullptr;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:2:5]: (warning) Redundant code: Found a statement that begins with NULL constant. [constStatement]\n" - "[test.cpp:3:5]: (warning) Redundant code: Found a statement that begins with NULL constant. [constStatement]\n", + ASSERT_EQUALS("[test.cpp:2:5]: (warning) Redundant code: Found a statement that begins with null constant. [constStatement]\n" + "[test.cpp:3:5]: (warning) Redundant code: Found a statement that begins with null constant. [constStatement]\n", errout_str()); check("struct S { int i; };\n" // #6504 @@ -758,6 +774,11 @@ class TestIncompleteStatement : public TestFixture { "}\n"); ASSERT_EQUALS("[test.cpp:4:6]: (warning) Redundant code: Found unused array access. [constStatement]\n", errout_str()); + + check("int f(int i) {\n" // #14889 + " return i ? 8 : ({ int x = 2; x; });\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void vardecl() { diff --git a/test/testinternal.cpp b/test/testinternal.cpp index 009129c5dc1..61c36a8e7dd 100644 --- a/test/testinternal.cpp +++ b/test/testinternal.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,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 02180f12376..2d191555ba6 100644 --- a/test/testio.cpp +++ b/test/testio.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,13 +44,16 @@ class TestIO : public TestFixture { TEST_CASE(fileIOwithoutPositioning); TEST_CASE(seekOnAppendedFile); TEST_CASE(fflushOnInputStream); + TEST_CASE(ftellCompatibility); TEST_CASE(incompatibleFileOpen); + TEST_CASE(testWrongfeofUsage); // #958 TEST_CASE(testScanf1); // Scanf without field limiters TEST_CASE(testScanf2); TEST_CASE(testScanf3); // #3494 TEST_CASE(testScanf4); // #ticket 2553 TEST_CASE(testScanf5); // #10632 + TEST_CASE(testScanf6); mNewTemplate = false; TEST_CASE(testScanfArgument); @@ -109,11 +112,12 @@ class TestIO : public TestFixture { // Check.. if (options.onlyFormatStr) { - CheckIO checkIO(&tokenizer, &settings1, this); + CheckIOImpl checkIO(&tokenizer, settings1, *this); checkIO.checkWrongPrintfScanfArguments(); return; } - runChecks(tokenizer, this); + CheckIO check; + runChecks(check, tokenizer, *this); } void coutCerrMisusage() { @@ -544,7 +548,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" @@ -668,6 +694,23 @@ class TestIO : public TestFixture { " fwrite(X::data(), sizeof(char), buffer.size(), d->file);\n" "}"); ASSERT_EQUALS("[test.cpp:9:5]: (error) Read and write operations without a call to a positioning function (fseek, fsetpos or rewind) or fflush in between result in undefined behaviour. [IOWithoutPositioning]\n", errout_str()); + + check("struct MemStream {\n" + " char buf[1024];\n" + " int pos = 0;\n" + " void fwrite(const void *ptr, size_t n) { memcpy(buf + pos, ptr, n); pos += (int)n; }\n" + "};\n" + "struct FileStream {\n" + " FILE *fp;\n" + " size_t _fread(void *ptr, size_t n) { return ::fread(ptr, 1, n, fp); }\n" + " size_t fread(void *ptr, size_t n) { return _fread(ptr, n); }\n" + " void copy_to(MemStream *dst, size_t n) {\n" + " char tmp[256];\n" + " fread(tmp, n);\n" + " dst->fwrite(tmp, n);\n" + " }\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); } void seekOnAppendedFile() { @@ -704,6 +747,22 @@ class TestIO : public TestFixture { ASSERT_EQUALS("", errout_str()); // #6566 } + void ftellCompatibility() { + + check("void foo() {\n" + " FILE *f = fopen(\"\", \"rt\");\n" + " if (f)\n" + " {\n" + " extern long position;\n" + " fseek(f, 0, SEEK_END);\n" + " position = ftell(f);\n" + " fclose(f);\n" + " }\n" + "}\n", dinit(CheckOptions, $.portability = true)); + ASSERT_EQUALS("[test.cpp:7:21]: (portability) ftell() result is unspecified when file is opened in mode \"t\" [ftellTextModeFile]\n", errout_str()); + } + + void fflushOnInputStream() { check("void foo()\n" "{\n" @@ -743,6 +802,55 @@ class TestIO : public TestFixture { ASSERT_EQUALS("[test.cpp:3:16]: (warning) The file '\"tmp\"' is opened for read and write access at the same time on different streams [incompatibleFileOpen]\n", errout_str()); } + void testWrongfeofUsage() { // ticket #958 + check("void foo(FILE * fp) {\n" + " while (!feof(fp)) \n" + " {\n" + " char line[100];\n" + " fgets(line, sizeof(line), fp);\n" + " dostuff(line);\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2:10]: (warning) Using feof() as a loop condition causes the last line to be processed twice. [wrongfeofUsage]\n", errout_str()); + + check("int foo(FILE *fp) {\n" + " char line[100];\n" + " while (fgets(line, sizeof(line), fp)) {}\n" + " if (!feof(fp))\n" + " return 1;\n" + " return 0;\n" + "}"); + ASSERT_EQUALS("", errout_str()); + + check("void foo(FILE *fp){\n" + " char line[100];\n" + " fgets(line, sizeof(line), fp);\n" + " while (!feof(fp)){\n" + " dostuff(line);\n" + " fgets(line, sizeof(line), fp);" + " }\n" + "}"); + ASSERT_EQUALS("", errout_str()); + + check("void foo(FILE *fp) {\n" + " char line[100];\n" + " do {\n" + " fgets(line, sizeof(line), fp);\n" + " dostuff(line);\n" + " } while (!feof(fp));\n" + "}"); + ASSERT_EQUALS("[test.cpp:6:12]: (warning) Using feof() as a loop condition causes the last line to be processed twice. [wrongfeofUsage]\n", errout_str()); + + check("void foo(FILE *fp) {\n" + " char line[100];\n" + " do {\n" + " dostuff(line);\n" + " fgets(line, sizeof(line), fp);\n" + " } while (!feof(fp));\n" + "}"); + ASSERT_EQUALS("", errout_str()); + } + void testScanf1() { check("void foo() {\n" @@ -802,6 +910,14 @@ class TestIO : public TestFixture { "[test.cpp:3:5]: (error) Width 42 given in format string (no. 2) is larger than destination buffer 's2[42]', use %41[a-z] to prevent overflowing it. [invalidScanfFormatWidth]\n", errout_str()); } + void testScanf6() { + ASSERT_NO_THROW(check("int f(const char *p) {\n" + " char a[3];\n" + " return sscanf(p, \"%02s\", a);\n" + "}\n")); + ASSERT_EQUALS("", errout_str()); + } + #define TEST_SCANF_CODE(format, type) \ "void f(){" type " x; scanf(\"" format "\", &x);}" diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index b038270dcb7..b7f8b024a8c 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -226,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() { @@ -3272,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 { @@ -3319,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 { @@ -3424,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 { @@ -3497,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/testmemleak.cpp b/test/testmemleak.cpp index 1ed88120886..783a10ad089 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -39,13 +39,12 @@ class TestMemleak : public TestFixture { #define functionReturnType(...) functionReturnType_(__FILE__, __LINE__, __VA_ARGS__) template - CheckMemoryLeak::AllocType functionReturnType_(const char* file, int line, const char (&code)[size]) { + CheckMemoryLeakImpl::AllocType functionReturnType_(const char* file, int line, const char (&code)[size]) { // Tokenize.. SimpleTokenizer tokenizer(settingsDefault, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - const CheckMemoryLeak c(&tokenizer, this, &settingsDefault); - + const CheckMemoryLeakImpl c(&tokenizer, settingsDefault, *this); return (c.functionReturnType)(&tokenizer.getSymbolDatabase()->scopeList.front().functionList.front()); } @@ -53,19 +52,19 @@ class TestMemleak : public TestFixture { { const char code[] = "const char *foo()\n" "{ return 0; }"; - ASSERT_EQUALS(CheckMemoryLeak::No, functionReturnType(code)); + ASSERT_EQUALS(CheckMemoryLeakImpl::No, functionReturnType(code)); } { const char code[] = "Fred *newFred()\n" "{ return new Fred; }"; - ASSERT_EQUALS(CheckMemoryLeak::New, functionReturnType(code)); + ASSERT_EQUALS(CheckMemoryLeakImpl::New, functionReturnType(code)); } { const char code[] = "char *foo()\n" "{ return new char[100]; }"; - ASSERT_EQUALS(CheckMemoryLeak::NewArray, functionReturnType(code)); + ASSERT_EQUALS(CheckMemoryLeakImpl::NewArray, functionReturnType(code)); } { @@ -74,7 +73,7 @@ class TestMemleak : public TestFixture { " char *p = new char[100];\n" " return p;\n" "}"; - ASSERT_EQUALS(CheckMemoryLeak::NewArray, functionReturnType(code)); + ASSERT_EQUALS(CheckMemoryLeakImpl::NewArray, functionReturnType(code)); } } @@ -94,8 +93,8 @@ class TestMemleak : public TestFixture { // there is no allocation const Token *tok = Token::findsimplematch(tokenizer.tokens(), "ret ="); - const CheckMemoryLeak check(&tokenizer, nullptr, &settingsDefault); - ASSERT_EQUALS(CheckMemoryLeak::No, check.getAllocationType(tok->tokAt(2), 1)); + const CheckMemoryLeakImpl check(&tokenizer, settingsDefault, *this); + ASSERT_EQUALS(CheckMemoryLeakImpl::No, check.getAllocationType(tok->tokAt(2), 1)); } }; @@ -120,7 +119,7 @@ class TestMemleakInFunction : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check for memory leaks.. - CheckMemoryLeakInFunction checkMemoryLeak(&tokenizer, &settings, this); + CheckMemoryLeakInFunctionImpl checkMemoryLeak(&tokenizer, settings, *this); checkMemoryLeak.checkReallocUsage(); } @@ -502,7 +501,7 @@ class TestMemleakInClass : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check for memory leaks.. - CheckMemoryLeakInClass checkMemoryLeak(&tokenizer, &settings, this); + CheckMemoryLeakInClassImpl checkMemoryLeak(&tokenizer, settings, *this); (checkMemoryLeak.check)(); } @@ -1707,7 +1706,7 @@ class TestMemleakStructMember : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check for memory leaks.. - CheckMemoryLeakStructMember checkMemoryLeakStructMember(&tokenizer, &settings, this); + CheckMemoryLeakStructMemberImpl checkMemoryLeakStructMember(&tokenizer, settings, *this); (checkMemoryLeakStructMember.check)(); } @@ -2389,7 +2388,7 @@ class TestMemleakNoVar : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check for memory leaks.. - CheckMemoryLeakNoVar checkMemoryLeakNoVar(&tokenizer, &settings, this); + CheckMemoryLeakNoVarImpl checkMemoryLeakNoVar(&tokenizer, settings, *this); (checkMemoryLeakNoVar.check)(); } @@ -2603,6 +2602,32 @@ class TestMemleakNoVar : public TestFixture { " a.g(new int);\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("int f() {\n" // #11184 + " return strlen(new char[4]{});\n" + "}\n" + "int g() {\n" + " int i = strlen(new char[4]{});\n" + " return i;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:19]: (error) Allocation with new, strlen doesn't release it. [leakNoVarFunctionCall]\n" + "[test.cpp:5:20]: (error) Allocation with new, strlen doesn't release it. [leakNoVarFunctionCall]\n", + errout_str()); + + check("int* f1() { return new int; }\n" // #14808 + "std::string* f2() { return new std::string(\"abc\"); }\n" + "std::clock_t* f3() { return new std::clock_t; }\n" + "QWidget* f4(QObject* parent) { return new QWidget(parent); }\n" + "void g(QObject* parent) {\n" + " assert(f1());\n" + " assert(f2());\n" + " assert(f3());\n" + " assert(f4(parent));\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6:12]: (error) Allocation with f1, assert doesn't release it. [leakNoVarFunctionCall]\n" + "[test.cpp:7:12]: (error) Allocation with f2, assert doesn't release it. [leakNoVarFunctionCall]\n" + "[test.cpp:8:12]: (error) Allocation with f3, assert doesn't release it. [leakNoVarFunctionCall]\n", + errout_str()); } void missingAssignment() { diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index c025d7462d4..698946b8efa 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -143,6 +143,10 @@ class TestNullPointer : public TestFixture { TEST_CASE(nullpointer103); TEST_CASE(nullpointer104); // #13881 TEST_CASE(nullpointer105); // #13861 + TEST_CASE(nullpointer106); // #13682 + TEST_CASE(nullpointer107); // #13682 (FP/FN cases around guards that depend on the pointer indirectly) + TEST_CASE(nullpointer108); + TEST_CASE(nullpointer109); TEST_CASE(nullpointer_addressOf); // address of TEST_CASE(nullpointerSwitch); // #2626 TEST_CASE(nullpointer_cast); // #4692 @@ -190,23 +194,17 @@ class TestNullPointer : public TestFixture { template void check_(const char* file, int line, const char (&code)[size], const CheckOptions& options = make_default_obj()) { const Settings& settings1 = options.inconclusive ? settings_i : settings; - - // Tokenize.. - SimpleTokenizer tokenizer(settings1, *this, options.cpp); - ASSERT_LOC(tokenizer.tokenize(code), file, line); - - // Check for null pointer dereferences.. - runChecks(tokenizer, this); + check_(file, line, code, settings1, options.cpp); } template - void check_(const char* file, int line, const char (&code)[size], bool cpp, 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, 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__) @@ -217,8 +215,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); } @@ -1349,7 +1347,7 @@ class TestNullPointer : public TestFixture { ASSERT_EQUALS("[test.cpp:4:11]: (error) Null pointer dereference: i [nullPointer]\n", errout_str()); const Settings s = settingsBuilder(settings).c(Standards::C17).build(); - check(code, false, s); // C17 file => nullptr does not mean NULL + check(code, s, false); // C17 file => nullptr does not mean NULL ASSERT_EQUALS("", errout_str()); check(code, dinit(CheckOptions, $.cpp = false)); @@ -2454,6 +2452,9 @@ class TestNullPointer : public TestFixture { void nullpointer77() { + // No warning: 'i' is passed to the unknown function 'h' in the same condition that guards the + // dereference. 'h' may validate the pointer (e.g. return false for null), so '*i' can be safe + // - this is the common "if (check(p) && p->...)" pattern, so we must not assume 'i' is null. check("bool h(int*);\n" "void f(int* i) {\n" " int* i = nullptr;\n" @@ -2469,6 +2470,8 @@ class TestNullPointer : public TestFixture { "}\n"); ASSERT_EQUALS("", errout_str()); + // Likewise here, even though 'i' is null when the first 'h(i)' was true: the second 'h(i)' is an + // independent call that may validate 'i', so '*i' is not necessarily a null dereference. check("bool h(int*);\n" "void f(int* x) {\n" " int* i = x;\n" @@ -2972,6 +2975,159 @@ class TestNullPointer : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void nullpointer106() // #13682 + { + // An unrelated condition between the null check and the dereference must not stop the analysis + check("struct S {\n" + " bool b;\n" + " bool f() const;\n" + "};\n" + "void f(const S* p, const S* o) {\n" + " const S* p1 = p;\n" + " if (p1 && p1->f())\n" + " return;\n" + " if (p == o)\n" + " return;\n" + " if (p1->b) {}\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:7:9] -> [test.cpp:11:9]: (warning) Either the condition 'p1' is redundant or there is possible null pointer dereference: p1. [nullPointerRedundantCheck]\n", + errout_str()); + } + + void nullpointer107() // #13682 - guards that depend on the pointer indirectly + { + // cached null-check 'ok'; guard 'if (!ok)' is safe -> no FP + check("struct S { void g(); bool f() const; };\n" + "void f(S* p) {\n" + " bool ok = (p != nullptr);\n" + " if (p && p->f())\n" + " return;\n" + " if (!ok)\n" + " return;\n" + " p->g();\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // unrelated bool guard -> conservative, no FP + check("struct S { void g(); bool f() const; };\n" + "void f(S* p, bool valid) {\n" + " S* p1 = p;\n" + " if (p1 && p1->f())\n" + " return;\n" + " if (!valid)\n" + " return;\n" + " p1->g();\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // guard on a different pointer -> no FP + check("struct S { void g(); bool f() const; };\n" + "void f(S* p, S* q) {\n" + " S* p1 = p;\n" + " if (p1 && p1->f())\n" + " return;\n" + " if (!q)\n" + " return;\n" + " p1->g();\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // direct null guard on the alias -> no FP + check("struct S { void g(); bool f() const; };\n" + "void f(S* p) {\n" + " S* p1 = p;\n" + " if (p1 && p1->f())\n" + " return;\n" + " if (!p)\n" + " return;\n" + " p1->g();\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // FN: 'if (ok)' => survivor has p==nullptr, but the cached 'ok' is not followed -> should warn + check("struct S { void g(); bool f() const; };\n" + "void f(S* p) {\n" + " bool ok = (p != nullptr);\n" + " if (p && p->f())\n" + " return;\n" + " if (ok)\n" + " return;\n" + " p->g();\n" + "}\n"); + TODO_ASSERT_EQUALS( + "[test.cpp:4:9] -> [test.cpp:8:5]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", + "", + errout_str()); + + // FN: sink(q) drops the q==p symbolic, so guard 'if (q)' is no longer seen to relate to p -> should warn + check("struct S { void g(); bool f() const; };\n" + "void sink(S*&);\n" + "void f(S* p) {\n" + " S* q = p;\n" + " if (p && p->f())\n" + " return;\n" + " sink(q);\n" + " if (q)\n" + " return;\n" + " p->g();\n" + "}\n"); + TODO_ASSERT_EQUALS( + "[test.cpp:5:9] -> [test.cpp:10:5]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", + "", + errout_str()); + + // a conditional modification makes ProgramMemory drop the guard (FP-prone) -> must stay quiet: + // alias 'q==p' re-assigned to p under a condition + check("struct S { void g(); bool f() const; };\n" + "void f(S* p, bool c) {\n" + " S* q = p;\n" + " if (p && p->f())\n" + " return;\n" + " if (c)\n" + " q = p;\n" + " if (!q)\n" + " return;\n" + " p->g();\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // cached 'ok' refreshed under a condition + check("struct S { void g(); bool f() const; };\n" + "void f(S* p, bool c) {\n" + " bool ok = (p != nullptr);\n" + " if (p && p->f())\n" + " return;\n" + " if (c)\n" + " ok = (p != nullptr);\n" + " if (!ok)\n" + " return;\n" + " p->g();\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + + void nullpointer108() { // #14422 + check("void f() {\n" + " int *p{};\n" + " int *&r{p};\n" + " if (*r) {}\n" + "}"); + ASSERT_EQUALS("[test.cpp:4:10]: (error) Null pointer dereference: r [nullPointer]\n", errout_str()); + } + + void nullpointer109() + { + check("boost::asio::awaitable test()\n" + "{\n" + " const auto *s = getStr();\n" + " if(!s) co_return int{1};\n" + " std::print(\"{}\",*s);\n" + " co_return int{9};\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void nullpointer_addressOf() { // address of check("void f() {\n" " struct X *x = 0;\n" @@ -4335,6 +4491,59 @@ class TestNullPointer : public TestFixture { "[test.cpp:3:13]: (warning) If resource allocation fails, then there is a possible null pointer dereference: fid [nullPointerOutOfResources]\n" "[test.cpp:4:12]: (warning) If resource allocation fails, then there is a possible null pointer dereference: fid [nullPointerOutOfResources]\n", errout_str()); + + // the guard might call an unknown, possibly noreturn function -> no warning + check("void f() {\n" + " FILE* fid = fopen(\"x.txt\", \"w\");\n" + " if (fid == NULL)\n" + " g();\n" + " fclose(fid);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // .. but an inconclusive warning is reported with --inconclusive + check("void f() {\n" + " FILE* fid = fopen(\"x.txt\", \"w\");\n" + " if (fid == NULL)\n" + " g();\n" + " fclose(fid);\n" + "}\n", + dinit(CheckOptions, $.inconclusive = true)); + ASSERT_EQUALS( + "[test.cpp:5:12]: (warning, inconclusive) If resource allocation fails, then there is a possible null pointer dereference: fid [nullPointerOutOfResources]\n", + errout_str()); + + check("int f(const int* p) {\n" + " if (p == nullptr)\n" + " g();\n" + " return *p;\n" + "}\n", + dinit(CheckOptions, $.inconclusive = true)); + ASSERT_EQUALS( + "[test.cpp:2:11] -> [test.cpp:4:13]: (warning, inconclusive) Either the condition 'p==nullptr' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", + errout_str()); + + check("void f() {\n" + " FILE* fid = fopen(\"x.txt\", \"w\");\n" + " if (fid != NULL)\n" + " ;\n" + " else\n" + " g();\n" + " fclose(fid);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // guard function is known to return -> warning + check("void g() {}\n" + "void f() {\n" + " FILE* fid = fopen(\"x.txt\", \"w\");\n" + " if (fid == NULL)\n" + " g();\n" + " fclose(fid);\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:6:12]: (warning) If resource allocation fails, then there is a possible null pointer dereference: fid [nullPointerOutOfResources]\n", + errout_str()); } void functioncalllibrary() { @@ -4357,7 +4566,7 @@ class TestNullPointer : public TestFixture { Library library; ASSERT(LibraryHelper::loadxmldata(library, xmldata, sizeof(xmldata))); - const std::list null = CheckNullPointer::parseFunctionCall(*xtok, library); + const std::list null = CheckNullPointerImpl::parseFunctionCall(*xtok, library); ASSERT_EQUALS(0U, null.size()); } @@ -4375,7 +4584,7 @@ class TestNullPointer : public TestFixture { Library library; ASSERT(LibraryHelper::loadxmldata(library, xmldata, sizeof(xmldata))); - const std::list null = CheckNullPointer::parseFunctionCall(*xtok, library); + const std::list null = CheckNullPointerImpl::parseFunctionCall(*xtok, library); ASSERT_EQUALS(1U, null.size()); ASSERT_EQUALS("a", null.front()->str()); } @@ -4696,11 +4905,11 @@ class TestNullPointer : public TestFixture { SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - CTU::FileInfo *ctu = CTU::getFileInfo(tokenizer); + const CTU::FileInfo *ctu = CTU::getFileInfo(tokenizer); - // Check code.. - std::list fileInfo; - Check& c = getCheck(); + CheckNullPointer check; + Check& c = getCheck(check); + std::list fileInfo; fileInfo.push_back(c.getFileInfo(tokenizer, settings, "")); c.analyseWholeProgram(*ctu, fileInfo, settings, *this); // TODO: check result while (!fileInfo.empty()) { diff --git a/test/testoptions.cpp b/test/testoptions.cpp index 0dec04927e4..af164fb43cc 100644 --- a/test/testoptions.cpp +++ b/test/testoptions.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/testother.cpp b/test/testother.cpp index c5a94a673fe..92fefb72fd3 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -367,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 @@ -384,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 @@ -2055,7 +2055,7 @@ class TestOther : public TestFixture { SimpleTokenizer tokenizerCpp(settings, *this); ASSERT_LOC(tokenizerCpp.tokenize(code), file, line); - CheckOther checkOtherCpp(&tokenizerCpp, &settings, this); + CheckOtherImpl checkOtherCpp(&tokenizerCpp, settings, *this); checkOtherCpp.warningOldStylePointerCast(); checkOtherCpp.warningDangerousTypeCast(); } @@ -2341,7 +2341,7 @@ class TestOther : public TestFixture { SimpleTokenizer tokenizerCpp(settings, *this); ASSERT_LOC(tokenizerCpp.tokenize(code), file, line); - CheckOther checkOtherCpp(&tokenizerCpp, &settings, this); + CheckOtherImpl checkOtherCpp(&tokenizerCpp, settings, *this); checkOtherCpp.warningIntToPointerCast(); } @@ -2362,6 +2362,9 @@ class TestOther : public TestFixture { checkIntToPointerCast("struct S { int i; };\n" // #13886, don't crash "int f() { return sizeof(((struct S*)0)->i); }"); ASSERT_EQUALS("", errout_str()); + + checkIntToPointerCast("auto p = (int*)0b10;"); // #14180 + ASSERT_EQUALS("[test.cpp:1:10]: (portability) Casting non-zero binary integer literal to pointer. [intToPointerCast]\n", errout_str()); } struct CheckInvalidPointerCastOptions @@ -2380,7 +2383,7 @@ class TestOther : public TestFixture { SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - CheckOther checkOtherCpp(&tokenizer, &settings, this); + CheckOtherImpl checkOtherCpp(&tokenizer, settings, *this); checkOtherCpp.invalidPointerCast(); } @@ -3911,7 +3914,9 @@ class TestOther : public TestFixture { " (void)(true);\n" " if (r) {}\n" "}\n"); - ASSERT_EQUALS("[test.cpp:1:13]: (style) Parameter 'r' can be declared as reference to const [constParameterReference]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:2:5]: (warning) Redundant code: Found unused cast in expression '(void)(true)'. [constStatement]\n" + "[test.cpp:1:13]: (style) Parameter 'r' can be declared as reference to const [constParameterReference]\n", + errout_str()); check("struct S { void f(int&); };\n" // #12216 "void g(S& s, int& r, void (S::* p2m)(int&)) {\n" @@ -4141,6 +4146,14 @@ class TestOther : public TestFixture { " *o = 1;\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("int f() {\n" + " int x = 0;\n" + " int& r(x);\n" + " r = x;\n" + " return r;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void constParameterCallback() { @@ -4844,6 +4857,85 @@ class TestOther : public TestFixture { " 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()); + + check("int f(std::vector* p) {\n" // #14810 + " return *p->cbegin();\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:1:25]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("struct S {\n" // #14817 + " explicit S(int *a) : m{ a[0], a[1] } {}\n" + " int m[2];\n" + "}" + "struct T {\n" + " explicit T(int *a) : m{ &a[0], &a[1] } {}\n" + " int* m[2];\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:21]: (style) Parameter 'a' can be declared as pointer to const [constParameterPointer]\n", + errout_str()); + + check("class A {\n" // #11471 + "public:\n" + " A(const int& i, int) : m_i(&i) {}\n" + " const int* m_i;\n" + "};\n" + "A f(int& s) {\n" + " return A(s, 0);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6:10]: (style) Parameter 's' can be declared as reference to const [constParameterReference]\n", + errout_str()); + + check("struct S { std::string a; };\n" // #13678 + "struct T { S s; };\n" + "bool f(S* s) {\n" + " return s->a.empty();\n" + "}\n" + "bool g(T* t) {\n" + " return t->s.a.empty();\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:11]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n" + "[test.cpp:6:11]: (style) Parameter 't' can be declared as pointer to const [constParameterPointer]\n", + errout_str()); + + check("struct S { int i; };\n" // #13099 + "double f(S * s, int n, int a, int b, double* p) {\n" + " return (s + (n * (a + 1) + b))->i / *(p + b);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:14]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n" + "[test.cpp:2:46]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", + errout_str()); + + check("struct S : U {\n" // #13944 + " void f(int* p) const {\n" + " if (m == p) {}\n" + " }\n" + " void g(int* p) final {\n" + " if (m == p) {}\n" + " }\n" + " int* m;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:17]: (style) Either there is a missing override/final keyword, or the parameter 'p' can be declared as pointer to const [constParameterPointer]\n", + errout_str()); } void constArray() { @@ -6930,7 +7022,8 @@ class TestOther : public TestFixture { " std::pair(1, 2);\n" " (void)0;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:2:10]: (style) Instance of 'std::string' object is destroyed immediately. [unusedScopedObject]\n" + ASSERT_EQUALS("[test.cpp:5:5]: (warning) Redundant code: Found unused cast in expression '(void)0'. [constStatement]\n" + "[test.cpp:2:10]: (style) Instance of 'std::string' object is destroyed immediately. [unusedScopedObject]\n" "[test.cpp:3:10]: (style) Instance of 'std::string' object is destroyed immediately. [unusedScopedObject]\n" "[test.cpp:4:10]: (style) Instance of 'std::pair' object is destroyed immediately. [unusedScopedObject]\n", errout_str()); @@ -11429,8 +11522,9 @@ class TestOther : public TestFixture { " x = a + b;\n" " return x;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:4:9]: (style) Variable 'x' is assigned an expression that holds the same value. [redundantAssignment]\n", - errout_str()); + ASSERT_EQUALS( + "[test.cpp:2:11] -> [test.cpp:3:9] -> [test.cpp:4:9]: (style) Variable 'x' is assigned an expression that holds the same value. [redundantAssignment]\n", + errout_str()); } void varFuncNullUB() { // #4482 @@ -12294,8 +12388,8 @@ class TestOther : public TestFixture { SimpleTokenizer tokenizer(settings, *this, cpp); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check.. - runChecks(tokenizer, this); + CheckOther check; + runChecks(check, tokenizer, *this); } void testEvaluationOrder() { @@ -12838,6 +12932,18 @@ class TestOther : public TestFixture { " h(b ? h(gA(5, std::move(s))) : h(gB(7, std::move(s))));\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("int cb(std::string);\n" // #13628 + "void f(bool b, std::string s1) {\n" + " std::string s2 = b ? cb(std::move(s1)) : s1;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("int cb(std::string);\n" + "void f(bool b, std::string s1) {\n" + " std::string s2 = b ? cb(std::move(s1)) : s1 + s1;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void movePointerAlias() @@ -12932,6 +13038,14 @@ class TestOther : public TestFixture { "[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()); + + check("void f(void (*fp)(), int x);\n" // #14847 + "void f(void (*fp)(), int x) {}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f(void (*fp)(int a, int b), int b);\n" // #14853 + "void f(void (*fp)(int a, int b), int b) {}\n"); + ASSERT_EQUALS("", errout_str()); } void funcArgOrderDifferent() { @@ -13098,6 +13212,15 @@ class TestOther : public TestFixture { 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 i(); static void f(int i) {} };\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct S { static int i(); static void f(int i) {} };\n"); + ASSERT_EQUALS("[test.cpp:1:23] -> [test.cpp:1:46]: (style) Argument 'i' shadows outer function [shadowFunction]\n", errout_str()); + + check("struct S { void g(float f) {} void f() {} };\n"); + ASSERT_EQUALS("[test.cpp:1:36] -> [test.cpp:1:25]: (style) Argument 'f' shadows outer function [shadowFunction]\n", errout_str()); } void knownArgument() { diff --git a/test/testpostfixoperator.cpp b/test/testpostfixoperator.cpp index 9e95fabc949..2277039820f 100644 --- a/test/testpostfixoperator.cpp +++ b/test/testpostfixoperator.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 @@ -38,8 +38,7 @@ class TestPostfixOperator : public TestFixture { SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check for postfix operators.. - CheckPostfixOperator checkPostfixOperator(&tokenizer, &settings, this); + CheckPostfixOperatorImpl checkPostfixOperator(&tokenizer, settings, *this); checkPostfixOperator.postfixOperator(); } diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 6846d49ff30..55fcafd4f4f 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -32,7 +32,9 @@ #include "fixture.h" #include "helpers.h" +#include #include +#include #include #include #include @@ -50,13 +52,14 @@ class TestPreprocessor : public TestFixture { TestPreprocessor() : TestFixture("TestPreprocessor") {} private: + #define expandMacros(...) expandMacros_(__FILE__, __LINE__, __VA_ARGS__) template - std::string expandMacros(const char (&code)[size], ErrorLogger &errorLogger) const { + std::string expandMacros_(const char* file, int line, const char (&code)[size], ErrorLogger &errorLogger) const { simplecpp::OutputList outputList; std::vector files; simplecpp::TokenList tokens1 = simplecpp::TokenList(code, files, "file.cpp", &outputList); Preprocessor p(tokens1, settingsDefault, errorLogger, Path::identify(tokens1.getFiles()[0], false)); - ASSERT(p.loadFiles(files)); + ASSERT_LOC(p.loadFiles(files), file, line); simplecpp::TokenList tokens2 = p.preprocess("", files, outputList); (void)p.reportOutput(outputList, true); return tokens2.stringify(); @@ -136,12 +139,15 @@ class TestPreprocessor : public TestFixture { preprocessor.simplifyPragmaAsm(); std::map cfgcode; - if (cfgs.empty()) - cfgs = preprocessor.getConfigs(); + if (cfgs.empty()) { + cfgs.insert(""); + std::set configDefines = { "__cplusplus" }; + preprocessor.getConfigs(configDefines, cfgs); + } for (const std::string & config : cfgs) { try { - const bool writeLocations = (strstr(code, "#file") != nullptr) || (strstr(code, "#include") != nullptr); - cfgcode[config] = preprocessor.getcode(config, files, writeLocations); + const bool writeLocs = (strstr(code, "#include") != nullptr); + cfgcode[config] = preprocessor.getcode(config, files, writeLocs); } catch (const simplecpp::Output &) { cfgcode[config] = ""; } @@ -367,6 +373,8 @@ class TestPreprocessor : public TestFixture { TEST_CASE(testMissingIncludeMixed); TEST_CASE(testMissingIncludeCheckConfig); + TEST_CASE(testLazyInclude); + TEST_CASE(hasInclude); TEST_CASE(limitsDefines); @@ -392,11 +400,24 @@ class TestPreprocessor : public TestFixture { std::vector files; simplecpp::OutputList outputList; simplecpp::TokenList tokens(code,files,"test.c",&outputList); - Preprocessor preprocessor(tokens, settings, *this, Standards::Language::C); // TODO: do we need to consider #file? + Preprocessor preprocessor(tokens, settings, *this, Standards::Language::C); + std::set configs = { "" }; + std::set configDefines = { "__cplusplus" }; + const auto getDefineName = [](const std::string &defineString) { + return defineString.substr(0, defineString.find_first_of("( ")); + }; + std::transform(settings.library.defines().begin(), + settings.library.defines().end(), + std::inserter(configDefines, configDefines.end()), + getDefineName); + preprocessor.setLoadCallback([&](simplecpp::FileData &data) { + Preprocessor::removeComments(data.tokens); + preprocessor.getConfigs(data.filename, data.tokens, configDefines, configs); + }); + preprocessor.removeComments(); + preprocessor.getConfigs(configDefines, configs); ASSERT(preprocessor.loadFiles(files)); ASSERT(!preprocessor.reportOutput(outputList, true)); - preprocessor.removeComments(); - const std::set configs = preprocessor.getConfigs(); std::string ret; for (const std::string & config : configs) ret += config + '\n'; @@ -407,9 +428,12 @@ class TestPreprocessor : public TestFixture { std::size_t getHash(const char (&code)[size]) { std::vector files; simplecpp::TokenList tokens(code,files,"test.c"); - Preprocessor preprocessor(tokens, settingsDefault, *this, Standards::Language::C); // TODO: do we need to consider #file? - ASSERT(preprocessor.loadFiles(files)); + Preprocessor preprocessor(tokens, settingsDefault, *this, Standards::Language::C); + preprocessor.setLoadCallback([](simplecpp::FileData &data) { + Preprocessor::removeComments(data.tokens); + }); preprocessor.removeComments(); + ASSERT(preprocessor.loadFiles(files)); return preprocessor.calculateHash(""); } @@ -472,16 +496,19 @@ class TestPreprocessor : public TestFixture { void error4() { // In included file { + ScopedFile header("ab.h", "#error hello world!\n"); const auto settings = dinit(Settings, $.userDefines = "TEST"); - const char code[] = "#file \"ab.h\"\n#error hello world!\n#endfile"; + const char code[] = "#include \"ab.h\""; (void)getcodeforcfg(settings, *this, code, "TEST", "test.c"); ASSERT_EQUALS("[ab.h:1:2]: (error) #error hello world! [preprocessorErrorDirective]\n", errout_str()); } // After including a file { + ScopedFile header("ab.h", ""); const auto settings = dinit(Settings, $.userDefines = "TEST"); - const char code[] = "#file \"ab.h\"\n\n#endfile\n#error aaa"; + const char code[] = "#include \"ab.h\"\n" + "#error aaa"; (void)getcodeforcfg(settings, *this, code, "TEST", "test.c"); ASSERT_EQUALS("[test.c:2:2]: (error) #error aaa [preprocessorErrorDirective]\n", errout_str()); } @@ -584,35 +611,35 @@ class TestPreprocessor : public TestFixture { } void includeguard1() { + ScopedFile header("abc.h", + "#ifndef abcH\n" + "#define abcH\n" + "#endif\n"); // Handling include guards.. - const char filedata[] = "#file \"abc.h\"\n" - "#ifndef abcH\n" - "#define abcH\n" - "#endif\n" - "#endfile\n" + const char filedata[] = "#include \"abc.h\"\n" "#ifdef ABC\n" "#endif"; ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } void includeguard2() { + ScopedFile header("abc.h", + "foo\n" + "#ifdef ABC\n" + "\n" + "#endif\n"); // Handling include guards.. - const char filedata[] = "#file \"abc.h\"\n" - "foo\n" - "#ifdef ABC\n" - "\n" - "#endif\n" - "#endfile\n"; + const char filedata[] = "#include \"abc.h\"\n"; ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } void ifdefwithfile() { + ScopedFile header("abc.h", "class A{};/*\n\n\n\n\n\n\n*/\n"); + // Handling include guards.. const char filedata[] = "#ifdef ABC\n" - "#file \"abc.h\"\n" - "class A{};/*\n\n\n\n\n\n\n*/\n" - "#endfile\n" + "#include \"abc.h\"\n" "#endif\n" "int main() {}\n"; @@ -1576,22 +1603,9 @@ class TestPreprocessor : public TestFixture { } { - const char filedata[] = "#file \"abc.h\"\n" - "#define a\n" - "\"\n" - "#endfile\n"; - - // expand macros.. - const std::string actual(expandMacros(filedata, *this)); - - ASSERT_EQUALS("", actual); - ASSERT_EQUALS("[abc.h:2:1]: (error) No pair for character (\"). Can't process file. File is either invalid or unicode, which is currently not supported. [syntaxError]\n", errout_str()); - } - - { - const char filedata[] = "#file \"abc.h\"\n" - "#define a\n" - "#endfile\n" + ScopedFile header("abc.h", + "#define a\n"); + const char filedata[] = "#include \"abc.h\"\n" "\"\n"; // expand macros.. @@ -1996,12 +2010,12 @@ class TestPreprocessor : public TestFixture { void invalid_define_1() { (void)getcode(settings0, *this, "#define =\n"); - ASSERT_EQUALS("[file.c:1:2]: (error) Failed to parse #define [syntaxError]\n", errout_str()); + ASSERT_EQUALS("[file.c:1:2]: (error) Failed to parse #define, bad macro syntax [syntaxError]\n", errout_str()); } void invalid_define_2() { // #4036 (void)getcode(settings0, *this, "#define () {(int f(x) }\n"); - ASSERT_EQUALS("[file.c:1:2]: (error) Failed to parse #define [syntaxError]\n", errout_str()); + ASSERT_EQUALS("[file.c:1:2]: (error) Failed to parse #define, bad macro syntax [syntaxError]\n", errout_str()); } void inline_suppressions() { @@ -2286,14 +2300,14 @@ class TestPreprocessor : public TestFixture { } void getConfigs7e() { + ScopedFile header("test.h", + "#ifndef test_h\n" + "#define test_h\n" + "#ifdef ABC\n" + "#endif\n" + "#endif\n"); const char filedata[] = "#ifdef ABC\n" - "#file \"test.h\"\n" - "#ifndef test_h\n" - "#define test_h\n" - "#ifdef ABC\n" - "#endif\n" - "#endif\n" - "#endfile\n" + "#include \"test.h\"\n" "#endif\n"; ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } @@ -2315,12 +2329,12 @@ class TestPreprocessor : public TestFixture { } void getConfigs11() { // #9832 - include guards - const char filedata[] = "#file \"test.h\"\n" - "#if !defined(test_h)\n" - "#define test_h\n" - "123\n" - "#endif\n" - "#endfile\n"; + ScopedFile header("test.h", + "#if !defined(test_h)\n" + "#define test_h\n" + "123\n" + "#endif\n"); + const char filedata[] = "#include \"test.h\"\n"; ASSERT_EQUALS("\n", getConfigsStr(filedata)); } @@ -3042,6 +3056,36 @@ class TestPreprocessor : public TestFixture { "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 testLazyInclude() { + const char *code = "#ifdef CONFIG1\n" + "#include \"header1.h\"\n" + "#include \"missing1.h\"\n" + "#else\n" + "#include \"header2.h\"\n" + "#include \"missing2.h\"\n" + "#endif\n"; + + std::vector files; + simplecpp::TokenList tokens(code, files, "test.c"); + + ScopedFile header1("header1.h", "1"); + ScopedFile header2("header2.h", "2"); + + Settings settings; + Preprocessor preprocessor(tokens, settings, *this, Standards::Language::CPP); + + simplecpp::OutputList outputList; + simplecpp::TokenList tokens2 = preprocessor.preprocess("CONFIG1", files, outputList); + std::string out = tokens2.stringify(); + + const simplecpp::FileDataCache &cache = preprocessor.mFileCache; + + ASSERT_EQUALS("\n#line 1 \"header1.h\"\n1", out); + ASSERT_EQUALS(1, outputList.size()); + ASSERT_EQUALS("Header not found: \"missing1.h\"", outputList.begin()->msg); + ASSERT_EQUALS(1, cache.size()); + } + void hasInclude() { const char code[] = "#if __has_include()\n123\n#endif"; Settings settings; diff --git a/test/testregex.cpp b/test/testregex.cpp index 4b6b2781cc8..f26a9fee4fa 100644 --- a/test/testregex.cpp +++ b/test/testregex.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,8 +47,10 @@ class TestRegExBase : public TestFixture { 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), mEngine, regex_err); - if (exp_err.empty()) + if (exp_err.empty()) { ASSERT_LOC(!!r.get(), file, line); + ASSERT_EQUALS_ENUM_LOC(mEngine, r->engine(), file, line); + } else ASSERT_LOC(!r.get(), file, line); // only not set if we encountered an error ASSERT_EQUALS_LOC(exp_err, regex_err, file, line); diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index b28bc503869..6960b791426 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -320,6 +320,8 @@ class TestSimplifyTemplate : public TestFixture { TEST_CASE(templateArgPreserveType); // #13882 - type of template argument + TEST_CASE(template_shift_negative); // shift folding with a negative operand + TEST_CASE(dumpTemplateArgFrom); } @@ -6715,6 +6717,21 @@ class TestSimplifyTemplate : public TestFixture { tok(code)); } + void template_shift_negative() { + // a large hex literal is not negative as a string but parses to a negative + // bigint, so folding the shift in simplifyNumericCalculations would left-shift + // a negative value / shift by a negative count, both UB. the operand must be + // returned unchanged. parentheses are needed so the numeric folding is reached. + const char code[] = "template struct S { };\n" + "S<(0x8000000000000000 << 1)> s1;\n" + "S<(1 << 0x8000000000000000)> s2;\n" + "S<(1 >> 0x8000000000000000)> s3;"; + const char expected[] = "struct S<9223372036854775808U> ; struct S<1> ; " + "S<9223372036854775808U> s1 ; S<1> s2 ; S<1> s3 ; " + "struct S<9223372036854775808U> { } ; struct S<1> { } ;"; + ASSERT_EQUALS(expected, tok(code)); + } + void dumpTemplateArgFrom() { const char code[] = "template void foo(T t) {}\n" "foo(23);"; diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 88d1a4b2725..2f04653a379 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.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 @@ -1422,6 +1422,7 @@ class TestSimplifyTokens : public TestFixture { ASSERT_EQUALS("void f ( ) { }", tok("void f(){{{}}}")); ASSERT_EQUALS("void f ( ) { for ( ; ; ) { } }", tok("void f () { for(;;){} }")); ASSERT_EQUALS("void f ( ) { { scope_lock lock ; foo ( ) ; } { scope_lock lock ; bar ( ) ; } }", tok("void f () { {scope_lock lock; foo();} {scope_lock lock; bar();} }")); + ASSERT_EQUALS("std :: map < int , int > m { { } } ;", tok("std::map m{ {} };")); } void simplifyOverride() { // ticket #5069 diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 342cda59dc8..5a14399e406 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -231,6 +231,9 @@ class TestSimplifyTypedef : public TestFixture { TEST_CASE(simplifyTypedef158); TEST_CASE(simplifyTypedef159); TEST_CASE(simplifyTypedef160); + TEST_CASE(simplifyTypedef161); + TEST_CASE(simplifyTypedef162); + TEST_CASE(simplifyTypedef163); TEST_CASE(simplifyTypedefFunction1); TEST_CASE(simplifyTypedefFunction2); // ticket #1685 @@ -3834,14 +3837,43 @@ class TestSimplifyTypedef : public TestFixture { "}"; ASSERT_EQUALS(exp, tok(code)); - const char code2[] = "typedef stuct T* T;\n" // #14669 + const char code2[] = "typedef struct T* T;\n" // #14669 "struct T {\n" " T p;\n" "};\n"; - const char exp2[] = "struct T { stuct T * p ; } ;"; + const char exp2[] = "struct T { struct T * p ; } ;"; ASSERT_EQUALS(exp2, simplifyTypedefC(code2)); } + void simplifyTypedef161() { + const char code[] = "namespace N {\n" // #11775 + " typedef int A[3];\n" + " p = new A*[n];\n" + "}\n"; + const char cur[] = "namespace N { p = new int ( * [ n ] ) [ 3 ] ; }"; + const char exp[] = "namespace N { p = new ( int ( * [ n ] ) [ 3 ] ) ; }"; + TODO_ASSERT_EQUALS(exp, cur, tok(code)); + + const char code2[] = "typedef int A[3];\n" + "p = new A*[n];\n"; + const char cur2[] = "p = new int ( * ) [ n ] [ 3 ] ;"; + const char exp2[] = "p = new ( int ( * [ n ] ) [ 3 ] ) ;"; + TODO_ASSERT_EQUALS(exp2, cur2, tok(code2)); + } + + void simplifyTypedef162() { + const char code[] = "using std::vector;\n" // #12041 + "typedef vector ints;\n" + "void f(ints v);\n"; + const char exp[] = "void f ( std :: vector < int > v ) ;"; + ASSERT_EQUALS(exp, tok(code)); + } + + void simplifyTypedef163() { + const char code[] = "typedef v *v;"; + ASSERT_THROW_INTERNAL(tok(code), INTERNAL); + } + void simplifyTypedefFunction1() { { const char code[] = "typedef void (*my_func)();\n" diff --git a/test/testsimplifyusing.cpp b/test/testsimplifyusing.cpp index 7359613510f..5210d484d40 100644 --- a/test/testsimplifyusing.cpp +++ b/test/testsimplifyusing.cpp @@ -77,6 +77,8 @@ class TestSimplifyUsing : public TestFixture { TEST_CASE(simplifyUsing37); TEST_CASE(simplifyUsing38); TEST_CASE(simplifyUsing39); + TEST_CASE(simplifyUsing40); + TEST_CASE(simplifyUsing41); TEST_CASE(simplifyUsing8970); TEST_CASE(simplifyUsing8971); @@ -98,6 +100,7 @@ class TestSimplifyUsing : public TestFixture { TEST_CASE(simplifyUsing10335); TEST_CASE(simplifyUsing10720); TEST_CASE(simplifyUsing13873); // function declaration + TEST_CASE(simplifyUsing14877); TEST_CASE(scopeInfo1); TEST_CASE(scopeInfo2); @@ -939,6 +942,20 @@ class TestSimplifyUsing : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void simplifyUsing40() { + const char code[] = "uint8_t f();\n" // #14876 + "using ::std::uint8_t;"; + const char expected[] = "uint8_t f ( ) ;"; + ASSERT_EQUALS(expected, tok(code)); + } + + void simplifyUsing41() { + const char code[] = "using FpHandler = void(*)(const SourceLocation&);\n" + "inline FpHandler AssertImpl::m_fpHandler = nullptr;\n"; + const char expected[] = "void ( * AssertImpl :: m_fpHandler ) ( const SourceLocation & ) ; m_fpHandler = nullptr ;"; + ASSERT_EQUALS(expected, tok(code)); + } + void simplifyUsing8970() { const char code[] = "using V = std::vector;\n" "struct A {\n" @@ -1667,6 +1684,12 @@ class TestSimplifyUsing : public TestFixture { ASSERT_EQUALS("namespace NS1 { void * f ( ) ; }", tok(code3)); } + void simplifyUsing14877() { + const char code[] = "using C = struct C { C() {} };"; + const char expected[] = "struct C { C ( ) { } } ;"; + ASSERT_EQUALS(expected, tok(code)); + } + void scopeInfo1() { const char code[] = "struct A {\n" " enum class Mode { UNKNOWN, ENABLED, NONE, };\n" diff --git a/test/testsizeof.cpp b/test/testsizeof.cpp index ad8aa3192af..f955242019f 100644 --- a/test/testsizeof.cpp +++ b/test/testsizeof.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 @@ -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() { @@ -334,6 +334,14 @@ class TestSizeof : public TestFixture { "}"); ASSERT_EQUALS("", errout_str()); + check("int f(std::array a) {\n" // #14860 + " return sizeof(a);\n" + "}\n" + "int g(std::string a[2]) {\n" + " return sizeof(a);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:12]: (warning) Using 'sizeof' on array given as function argument returns size of a pointer. [sizeofwithsilentarraypointer]\n", + errout_str()); } void sizeofForNumericParameter() { @@ -722,6 +730,12 @@ class TestSizeof : public TestFixture { " return AtomName;\n" "}"); ASSERT_EQUALS("", errout_str()); + + check("void* f(size_t n) {\n" // #11754 + " char* p = malloc(n * sizeof(void*));\n" + " return p;\n" + "}"); + ASSERT_EQUALS("", errout_str()); } void checkPointerSizeofStruct() { diff --git a/test/teststl.cpp b/test/teststl.cpp index 92933c37449..c030fb4c6f6 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -78,6 +78,7 @@ class TestStl : public TestFixture { TEST_CASE(iteratorSameExpression); TEST_CASE(mismatchingContainerIterator); TEST_CASE(eraseIteratorOutOfBounds); + TEST_CASE(algorithmOutOfBounds); TEST_CASE(dereference); TEST_CASE(dereference_break); // #3644 - handle "break" @@ -199,7 +200,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 +211,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 +222,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() { @@ -366,7 +369,9 @@ class TestStl : public TestFixture { " if(b) ++x;\n" " return s[x];\n" "}"); - ASSERT_EQUALS("[test.cpp:5:13]: error: Out of bounds access in 's[x]', if 's' size is 6 and 'x' is 6 [containerOutOfBounds]\n", errout_str()); + ASSERT_EQUALS( + "[test.cpp:5:13]: error: Out of bounds access in 's[x]', if 's' size is 6 and 'x' is 7 [containerOutOfBounds]\n", + errout_str()); checkNormal("void f() {\n" " static const int N = 4;\n" @@ -611,7 +616,7 @@ class TestStl : public TestFixture { " return i;\n" " return 0;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:8:0]: style: Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:8:13]: style: Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); checkNormal("bool g();\n" "int f(int x) {\n" @@ -624,7 +629,7 @@ class TestStl : public TestFixture { " return i;\n" " return 0;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:8:0]: style: Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:8:13]: style: Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); checkNormal("bool g();\n" "void f(int x) {\n" @@ -998,6 +1003,18 @@ class TestStl : public TestFixture { "}\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()); + + checkNormal("std::string f(const std::string& str) {\n" // do not warn, the copy has the same size as 'str' + " std::string outStr = str;\n" + " if (!outStr.empty())\n" + " outStr[0] = 'a';\n" + " for (int i = 0; i < str.size(); ++i) {\n" + " if (outStr[i] == '_')\n" + " outStr[i] = ' ';\n" + " }\n" + " return outStr;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void outOfBoundsSymbolic() @@ -2343,6 +2360,15 @@ class TestStl : public TestFixture { " } \n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("std::string g1();\n" // #12520 + "const std::string& g2();\n" + "void f() {\n" + " g1().erase(g1().begin());\n" + " g2().erase(g2().begin());\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:7]: (error) Iterator 'g1().begin()' referring to temporary container 'g1()' is used with temporary container 'g1()'. [mismatchingContainerIterator]\n", + errout_str()); } void eraseIteratorOutOfBounds() { @@ -2408,6 +2434,372 @@ class TestStl : public TestFixture { errout_str()); } + void algorithmOutOfBounds() + { + check("void f() {\n" + " const std::deque d0{1,2,3,4,5,6,7,8,9,10};\n" + " const std::deque d1{1,2,3,4,5,6};\n" + " if(std::equal(d0.cbegin(), d0.cend(), d1.cbegin())) {}\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4:52]: (error) The algorithm 'std::equal' accesses 10 elements through the iterator 'd1.cbegin()' but only 6 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f() {\n" + " const std::deque d0{1,2,3,4,5,6};\n" + " const std::deque d1{1,2,3,4,5,6};\n" + " if(std::equal(d0.cbegin(), d0.cend(), d1.cbegin())) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // two-range overload does not access the second range out of bounds + check("void f() {\n" + " const std::deque d0{1,2,3,4,5,6,7,8,9,10};\n" + " const std::deque d1{1,2,3,4,5,6};\n" + " if(std::equal(d0.cbegin(), d0.cend(), d1.cbegin(), d1.cend())) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(3);\n" + " std::copy(v0.begin(), v0.end(), v1.begin());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4:45]: (error) The algorithm 'std::copy' accesses 5 elements through the iterator 'v1.begin()' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(5);\n" + " std::copy(v0.begin(), v0.end(), v1.begin());\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // iterator arithmetic + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(6);\n" + " std::copy(v0.begin(), v0.end(), v1.begin() + 3);\n" + " std::copy(v0.begin() + 3, v0.end(), v1.begin());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4:48]: (error) The algorithm 'std::copy' accesses 5 elements through the iterator 'v1.begin()+3' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // don't warn when using iterator adaptors + check("void f() {\n" + " const std::deque d0{1,2,3,4,5,6,7,8,9,10};\n" + " std::deque d1;\n" + " std::copy(d0.cbegin(), d0.cend(), std::back_inserter(d1));\n" + " std::copy(d0.cbegin(), d0.cend(), std::inserter(d1, d1.begin()));\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // algorithms that access at most last-first elements are inconclusive + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(3);\n" + " std::copy_if(v0.begin(), v0.end(), v1.begin(), [](int i) { return i != 3; });\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(3);\n" + " std::copy_if(v0.begin(), v0.end(), v1.begin(), [](int i) { return i != 3; });\n" + "}\n", + dinit(CheckOptions, $.inconclusive = true)); + ASSERT_EQUALS( + "[test.cpp:4:48]: (warning, inconclusive) The algorithm 'std::copy_if' may access up to 5 elements through the iterator 'v1.begin()' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(3);\n" + " std::transform(v0.begin(), v0.end(), v1.begin(), [](int i) { return i * 2; });\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4:50]: (error) The algorithm 'std::transform' accesses 5 elements through the iterator 'v1.begin()' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // binary transform reads the third argument and writes the fourth argument + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " const std::vector v1{1,2,3};\n" + " std::vector v2(5);\n" + " std::transform(v0.begin(), v0.end(), v1.begin(), v2.begin(), [](int a, int b) { return a + b; });\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:5:50]: (error) The algorithm 'std::transform' accesses 5 elements through the iterator 'v1.begin()' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " const std::vector v1{1,2,3,4,5};\n" + " std::vector v2(3);\n" + " std::transform(v0.begin(), v0.end(), v1.begin(), v2.begin(), [](int a, int b) { return a + b; });\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:5:62]: (error) The algorithm 'std::transform' accesses 5 elements through the iterator 'v2.begin()' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // copying a range within the same container + check("void f() {\n" + " std::vector v{1,2,3,4,5,6,7,8,9,10};\n" + " std::copy(v.begin(), v.begin() + 3, v.begin() + 7);\n" + " std::copy(v.begin(), v.begin() + 4, v.begin() + 7);\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4:51]: (error) The algorithm 'std::copy' accesses 4 elements through the iterator 'v.begin()+7' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // unknown container sizes + check("void f(const std::vector& v0, std::vector& v1) {\n" + " std::copy(v0.begin(), v0.end(), v1.begin());\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // don't warn for iterator variables when the container size changes before the algorithm is called + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::list l1(3);\n" + " auto it = l1.begin();\n" + " l1.resize(10);\n" + " std::copy(v0.begin(), v0.end(), it);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // iterator variables carry the container size + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(3);\n" + " auto it = v1.begin();\n" + " std::copy(v0.begin(), v0.end(), it);\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:5:37]: (error) The algorithm 'std::copy' accesses 5 elements through the iterator 'it' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // ..and the size is the size at the call, not at the creation of the iterator + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::list l1(10);\n" + " auto it = l1.begin();\n" + " l1.resize(3);\n" + " std::copy(v0.begin(), v0.end(), it);\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:6:37]: (error) The algorithm 'std::copy' accesses 5 elements through the iterator 'it' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // conditional container size + check("void f(std::vector& v) {\n" + " const std::vector v0{1,2,3,4,5};\n" + " if (v.size() == 3)\n" + " std::copy(v0.begin(), v0.end(), v.begin());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:3:18] -> [test.cpp:4:48]: (warning) Either the condition 'v.size()==3' is redundant or the algorithm 'std::copy' accesses 5 elements through the iterator 'v.begin()' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f(std::vector& v) {\n" + " const std::vector v0{1,2,3,4,5};\n" + " if (v.size() < 5)\n" + " std::copy(v0.begin(), v0.end(), v.begin());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:3:18] -> [test.cpp:4:48]: (warning) Either the condition 'v.size()<5' is redundant or the algorithm 'std::copy' accesses 5 elements through the iterator 'v.begin()' but only 4 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f(std::vector& v) {\n" + " const std::vector v0{1,2,3,4,5};\n" + " if (v.size() >= 5)\n" + " std::copy(v0.begin(), v0.end(), v.begin());\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // writing through the end iterator + check("void f() {\n" + " const std::vector v0{1,2,3};\n" + " std::vector v1(10);\n" + " std::copy(v0.begin(), v0.end(), v1.end());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4:43]: (error) The algorithm 'std::copy' accesses 3 elements through the iterator 'v1.end()' but only 0 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // the source range is known even when the container size is not + check("void f(const std::vector& v) {\n" + " std::vector v1(3);\n" + " std::copy(v.begin(), v.begin() + 5, v1.begin());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:3:49]: (error) The algorithm 'std::copy' accesses 5 elements through the iterator 'v1.begin()' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // count-based algorithms access both iterator arguments times + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(3);\n" + " std::copy_n(v0.begin(), 5, v1.begin());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4:40]: (error) The algorithm 'std::copy_n' accesses 5 elements through the iterator 'v1.begin()' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(10);\n" + " std::copy_n(v0.begin(), 10, v1.begin());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4:25]: (error) The algorithm 'std::copy_n' accesses 10 elements through the iterator 'v0.begin()' but only 5 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f() {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1(5);\n" + " std::copy_n(v0.begin(), 5, v1.begin());\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" + " std::vector v(5);\n" + " std::fill_n(v.begin(), 10, 0);\n" + " std::fill_n(v.begin() + 3, 3, 0);\n" + " std::fill_n(v.begin(), 5, 0);\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:3:24]: (error) The algorithm 'std::fill_n' accesses 10 elements through the iterator 'v.begin()' but only 5 elements are available. [algorithmOutOfBounds]\n" + "[test.cpp:4:27]: (error) The algorithm 'std::fill_n' accesses 3 elements through the iterator 'v.begin()+3' but only 2 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f() {\n" + " std::vector v;\n" + " std::fill_n(std::back_inserter(v), 10, 0);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" + " std::vector v(5);\n" + " std::generate_n(v.begin(), 6, [] { return 1; });\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:3:28]: (error) The algorithm 'std::generate_n' accesses 6 elements through the iterator 'v.begin()' but only 5 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // conditional count + check("void f(std::vector& v, int n) {\n" + " if (v.size() == 5 && n > 5)\n" + " std::fill_n(v.begin(), n, 0);\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:2:28] -> [test.cpp:3:28]: (warning) Either the condition 'n>5' is redundant or the algorithm 'std::fill_n' accesses 6 elements through the iterator 'v.begin()' but only 5 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // an upper bound of the count cannot tell whether the access is out of bounds + check("void f(int n) {\n" + " std::vector v(3);\n" + " if (n < 5)\n" + " std::fill_n(v.begin(), n, 0);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // a lower bound of the container size cannot tell whether the access is out of bounds + check("void f(std::vector& v) {\n" + " const std::vector v0{1,2,3,4,5};\n" + " if (v.size() >= 4)\n" + " std::copy(v0.begin(), v0.end(), v.begin());\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // unknown count + check("void f(std::vector& v, int n) {\n" + " std::fill_n(v.begin(), n, 0);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // all container size values are checked, not only the first one + check("void f(bool b) {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1;\n" + " if (b)\n" + " v1.resize(3);\n" + " else\n" + " v1.resize(10);\n" + " std::copy(v0.begin(), v0.end(), v1.begin());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:8:45]: (error) The algorithm 'std::copy' accesses 5 elements through the iterator 'v1.begin()' but only 3 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f(bool b) {\n" + " const std::vector v0{1,2,3,4,5};\n" + " std::vector v1;\n" + " if (b)\n" + " v1.resize(5);\n" + " else\n" + " v1.resize(10);\n" + " std::copy(v0.begin(), v0.end(), v1.begin());\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // all iterator position values are checked as well + check("void f(bool b) {\n" + " const std::vector v0{1,2,3,4};\n" + " std::vector v1(5);\n" + " auto it = b ? v1.begin() : v1.begin() + 3;\n" + " std::copy(v0.begin(), v0.end(), it);\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:5:37]: (error) The algorithm 'std::copy' accesses 4 elements through the iterator 'it' but only 2 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + // do not combine possible values on both sides + check("void f(bool b, std::vector& v0, std::vector& v1) {\n" + " if (b) v0.resize(5); else v0.resize(2);\n" + " if (b) v1.resize(3); else v1.resize(10);\n" + " std::copy(v0.begin(), v0.end(), v1.begin());\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // all source range values are checked against the preferred destination values + check("void f(bool b) {\n" + " std::vector v0;\n" + " if (b)\n" + " v0.resize(3);\n" + " else\n" + " v0.resize(10);\n" + " std::vector v1(5);\n" + " std::copy(v0.begin(), v0.end(), v1.begin());\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:8:45]: (error) The algorithm 'std::copy' accesses 10 elements through the iterator 'v1.begin()' but only 5 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + + check("void f(bool b) {\n" + " std::vector v0;\n" + " if (b)\n" + " v0.resize(3);\n" + " else\n" + " v0.resize(5);\n" + " std::vector v1(5);\n" + " std::copy(v0.begin(), v0.end(), v1.begin());\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + // all count values are checked as well + check("void f(bool b) {\n" + " std::vector v(5);\n" + " const int n = b ? 3 : 10;\n" + " std::fill_n(v.begin(), n, 0);\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:4:24]: (error) The algorithm 'std::fill_n' accesses 10 elements through the iterator 'v.begin()' but only 5 elements are available. [algorithmOutOfBounds]\n", + errout_str()); + } + // Dereferencing invalid pointer void dereference() { check("void f()\n" @@ -4833,6 +5225,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" @@ -5252,7 +5650,7 @@ class TestStl : public TestFixture { " return s.erase(it);\n" " return s.end();\n" "}\n"); - ASSERT_EQUALS("[test.cpp:3:0]: (style) Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:3:9]: (style) Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); // #11381 check("int f(std::map& map) {\n" @@ -5653,6 +6051,14 @@ class TestStl : public TestFixture { "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); + + check("void f(const std::vector& v) {\n" // #14812 + " std::set s;\n" + " for (const std::string& a : v) {\n" + " s.insert(a);\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:11]: (style) Consider using std::copy algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); } void loopAlgoIncrement() { @@ -5945,7 +6351,7 @@ class TestStl : public TestFixture { " v1.erase(it1);\n" " }\n" "}\n"); - ASSERT_EQUALS("[test.cpp:9:0]: (style) Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:9:17]: (style) Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); check("bool f(const std::set& set, const std::string& f) {\n" // #11595 " for (const std::string& s : set) {\n" @@ -7020,7 +7426,10 @@ class TestStl : public TestFixture { " std::copy(v1.begin(), v1.end(), v2.begin());\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); - ASSERT_EQUALS("[test.cpp:4:45]: (style) Using copy with iterator 'v2.begin()' that is always empty. [knownEmptyContainer]\n", errout_str()); + ASSERT_EQUALS( + "[test.cpp:4:45]: (style) Using copy with iterator 'v2.begin()' that is always empty. [knownEmptyContainer]\n" + "[test.cpp:4:45]: (error) The algorithm 'std::copy' accesses 2 elements through the iterator 'v2.begin()' but only 0 elements are available. [algorithmOutOfBounds]\n", + errout_str()); check("void f() {\n" " std::vector v;\n" diff --git a/test/teststring.cpp b/test/teststring.cpp index 051aa870788..80073ac7d91 100644 --- a/test/teststring.cpp +++ b/test/teststring.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 @@ -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 49d46149c90..90c64eb809e 100644 --- a/test/testsuppressions.cpp +++ b/test/testsuppressions.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index e981c8ea546..69d345a1cc5 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -220,6 +220,8 @@ class TestSymbolDatabase : public TestFixture { TEST_CASE(VariableValueType4); // smart pointer type TEST_CASE(VariableValueType5); // smart pointer type TEST_CASE(VariableValueType6); // smart pointer type + TEST_CASE(VariableValueType7); + TEST_CASE(VariableValueType8); TEST_CASE(VariableValueTypeReferences); TEST_CASE(VariableValueTypeTemplate); @@ -430,6 +432,7 @@ class TestSymbolDatabase : public TestFixture { TEST_CASE(symboldatabase110); TEST_CASE(symboldatabase111); // [[fallthrough]] TEST_CASE(symboldatabase112); // explicit operator + TEST_CASE(symboldatabase113); TEST_CASE(createSymbolDatabaseFindAllScopes1); TEST_CASE(createSymbolDatabaseFindAllScopes2); @@ -1315,6 +1318,71 @@ class TestSymbolDatabase : public TestFixture { ASSERT(check->valueType()->smartPointerTypeToken); } + void VariableValueType7() { + GET_SYMBOL_DB("void f() {\n" + " auto x0 = 0;\n" + " auto &x1 = x0;\n" + " auto &x2 {x0};\n" + " auto &&x3 = 0;\n" + " auto &&x4 {0};\n" + "}\n"); + + const Token* x1 = Token::findsimplematch(tokenizer.tokens(), "x1"); + const Token* x2 = Token::findsimplematch(tokenizer.tokens(), "x2"); + const Token* x3 = Token::findsimplematch(tokenizer.tokens(), "x3"); + const Token* x4 = Token::findsimplematch(tokenizer.tokens(), "x4"); + + ASSERT(x1); + ASSERT(x2); + ASSERT(x3); + ASSERT(x4); + + ASSERT_EQUALS_ENUM(ValueType::INT, x1->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::INT, x2->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::INT, x3->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::INT, x4->valueType()->type); + + ASSERT_EQUALS_ENUM(Reference::LValue, x1->valueType()->reference); + ASSERT_EQUALS_ENUM(Reference::LValue, x2->valueType()->reference); + ASSERT_EQUALS_ENUM(Reference::RValue, x3->valueType()->reference); + ASSERT_EQUALS_ENUM(Reference::RValue, x4->valueType()->reference); + } + + void VariableValueType8() { + GET_SYMBOL_DB("void f() {\n" + " char buf[128];\n" + " const auto *const x0 {buf};\n" + " auto *const x1 {buf};\n" + " const auto *x2 {buf};\n" + " auto x3 {buf};\n" + "}\n"); + + const Token* x0 = Token::findsimplematch(tokenizer.tokens(), "x0"); + const Token* x1 = Token::findsimplematch(tokenizer.tokens(), "x1"); + const Token* x2 = Token::findsimplematch(tokenizer.tokens(), "x2"); + const Token* x3 = Token::findsimplematch(tokenizer.tokens(), "x3"); + + ASSERT(x0); + ASSERT(x1); + ASSERT(x2); + ASSERT(x3); + + ASSERT_EQUALS_ENUM(ValueType::CHAR, x0->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::CHAR, x1->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::CHAR, x2->valueType()->type); + ASSERT_EQUALS_ENUM(ValueType::CHAR, x3->valueType()->type); + + ASSERT_EQUALS(3, x0->valueType()->constness); + ASSERT_EQUALS(1, x1->valueType()->constness); + ASSERT_EQUALS(2, x2->valueType()->constness); + ASSERT_EQUALS(0, x3->valueType()->constness); + + ASSERT_EQUALS(1, x0->valueType()->pointer); + ASSERT_EQUALS(1, x1->valueType()->pointer); + ASSERT_EQUALS(1, x2->valueType()->pointer); + ASSERT_EQUALS(1, x3->valueType()->pointer); + } + void VariableValueTypeReferences() { { GET_SYMBOL_DB("void foo(int x) {}\n"); @@ -5864,6 +5932,33 @@ class TestSymbolDatabase : public TestFixture { ASSERT(f && f->function() && f->function()->isExplicit()); } + void symboldatabase113() { // #11841 + GET_SYMBOL_DB("template \n" + "struct S {\n" + " S();\n" + " int& g() { return a; }\n" + " struct I;\n" + "private:\n" + " int a;\n" + "};\n" + "template <>\n" + "struct S::I{};\n"); + ASSERT(db->scopeList.size() == 4); + auto it = db->scopeList.begin(); + ++it; + ASSERT_EQUALS_ENUM(ScopeType::eStruct, it->type); + ASSERT_EQUALS("I", it->className); + ASSERT_EQUALS(0, it->varlist.size()); + ++it; + ASSERT_EQUALS_ENUM(ScopeType::eStruct, it->type); + ASSERT_EQUALS("S < int >", it->className); + ASSERT_EQUALS(1, it->varlist.size()); + ++it; + ASSERT_EQUALS_ENUM(ScopeType::eFunction, it->type); + ASSERT_EQUALS("g", it->className); + ASSERT_EQUALS(0, it->varlist.size()); + } + void createSymbolDatabaseFindAllScopes1() { GET_SYMBOL_DB("void f() { union {int x; char *p;} a={0}; }"); ASSERT(db->scopeList.size() == 3); @@ -10164,6 +10259,15 @@ class TestSymbolDatabase : public TestFixture { ASSERT(tok); TODO_ASSERT(tok->valueType() && "container(std :: string|wstring|u16string|u32string)" == tok->valueType()->str()); } + { + GET_SYMBOL_DB("void f() {\n" + " int &&x = 0;\n" + "}\n"); + + const Token* tok = Token::findsimplematch(tokenizer.tokens(), "&&"); + ASSERT(tok); + ASSERT_EQUALS(static_cast(nullptr), tok->valueType()); + } } void valueTypeThis() { diff --git a/test/testtoken.cpp b/test/testtoken.cpp index 83a514eb963..92c111c810c 100644 --- a/test/testtoken.cpp +++ b/test/testtoken.cpp @@ -1059,7 +1059,6 @@ class TestToken : public TestFixture { standard_types.emplace_back("long"); standard_types.emplace_back("float"); standard_types.emplace_back("double"); - standard_types.emplace_back("size_t"); for (auto test_op = standard_types.cbegin(); test_op != standard_types.cend(); ++test_op) { auto tokensFrontBack = std::make_shared(); @@ -1484,13 +1483,6 @@ class TestToken : public TestFixture { tok.str("char"); // not treated as keyword in TokenList::isKeyword() assert_tok(&tok, Token::Type::eType, /*l=*/ false, /*std=*/ true); } - { - TokenList list_c{settingsDefault, Standards::Language::C}; - auto tokensFrontBack = std::make_shared(); - Token tok(list_c, std::move(tokensFrontBack)); - tok.str("size_t"); // not treated as keyword in TokenList::isKeyword() - assert_tok(&tok, Token::Type::eType, /*l=*/ false, /*std=*/ true); - } } void update_property_info_etype_cpp() const @@ -1502,21 +1494,12 @@ class TestToken : public TestFixture { tok.str("bool"); // not treated as keyword in TokenList::isKeyword() assert_tok(&tok, Token::Type::eType, /*l=*/ false, /*std=*/ true); } - { - TokenList list_cpp{settingsDefault, Standards::Language::CPP}; - auto tokensFrontBack = std::make_shared(); - Token tok(list_cpp, std::move(tokensFrontBack)); - tok.str("size_t"); - assert_tok(&tok, Token::Type::eType, /*l=*/ false, /*std=*/ true); - } } void update_property_info_replace() const // #13743 { auto tokensFrontBack = std::make_shared(); Token tok(list, std::move(tokensFrontBack)); - tok.str("size_t"); - assert_tok(&tok, Token::Type::eType, false, true); tok.str("long"); assert_tok(&tok, Token::Type::eType, false, true); } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 7b2bee0d80e..79da0177e19 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -92,6 +92,7 @@ class TestTokenizer : public TestFixture { TEST_CASE(tokenize40); // #13181 TEST_CASE(tokenize41); // #13847 TEST_CASE(tokenize42); // #13861 + TEST_CASE(tokenize43); // #13861 TEST_CASE(validate); @@ -140,6 +141,7 @@ class TestTokenizer : public TestFixture { TEST_CASE(whileAddBraces); TEST_CASE(whileAddBracesLabels); + TEST_CASE(whileAddBracesDump); TEST_CASE(doWhileAddBraces); TEST_CASE(doWhileAddBracesLabels); @@ -233,11 +235,13 @@ class TestTokenizer : public TestFixture { TEST_CASE(vardecl32); TEST_CASE(vardecl33); TEST_CASE(vardecl34); + TEST_CASE(vardecl35); TEST_CASE(vardecl_stl_1); TEST_CASE(vardecl_stl_2); TEST_CASE(vardecl_stl_3); TEST_CASE(vardecl_template_1); TEST_CASE(vardecl_template_2); + TEST_CASE(vardecl_template_3); TEST_CASE(vardecl_union); TEST_CASE(vardecl_par); // #2743 - set links if variable type contains parentheses TEST_CASE(vardecl_par2); // #3912 - set correct links @@ -288,6 +292,7 @@ class TestTokenizer : public TestFixture { TEST_CASE(cppMaybeUnusedBefore); TEST_CASE(cppMaybeUnusedAfter1); TEST_CASE(cppMaybeUnusedAfter2); + TEST_CASE(cppMaybeUnusedAfter3); TEST_CASE(cppMaybeUnusedStructuredBinding); TEST_CASE(attributeAlignasBefore); @@ -439,6 +444,7 @@ class TestTokenizer : public TestFixture { TEST_CASE(astcompound); TEST_CASE(astfuncdecl); TEST_CASE(astarrayinit); + TEST_CASE(astbracedinit); TEST_CASE(startOfExecutableScope); @@ -478,6 +484,7 @@ class TestTokenizer : public TestFixture { TEST_CASE(cppKeywordInCSource); TEST_CASE(cppcast); + TEST_CASE(ccast); TEST_CASE(checkHeader1); @@ -599,9 +606,13 @@ class TestTokenizer : public TestFixture { std::vector files; simplecpp::TokenList tokens1(code, files, filename, &outputList); Preprocessor preprocessor(tokens1, settings, *this, Path::identify(tokens1.getFiles()[0], false)); - (void)preprocessor.reportOutput(outputList, true); + std::list directives; + preprocessor.setLoadCallback([&](const simplecpp::FileData &data) { + Preprocessor::createDirectives(data.tokens, directives); + }); + preprocessor.createDirectives(directives); ASSERT(preprocessor.loadFiles(files)); - std::list directives = preprocessor.createDirectives(); + (void)preprocessor.reportOutput(outputList, true); TokenList tokenlist{settings, Path::identify(filename, false)}; Tokenizer tokenizer(std::move(tokenlist), *this); @@ -932,6 +943,12 @@ class TestTokenizer : public TestFixture { (void)errout_str(); } + void tokenize43() { + const char code[] = "void f(int i) { do if (i &= 1) {} while (0); }"; + ASSERT_NO_THROW(tokenizeAndStringify(code)); + (void)errout_str(); + } + void validate() { // C++ code in C file ASSERT_THROW_INTERNAL(tokenizeAndStringify(";using namespace std;",dinit(TokenizeOptions, $.expand = false, $.cpp = false)), SYNTAX); @@ -1529,6 +1546,17 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("", filter_valueflow(errout_str())); } + void whileAddBracesDump() { + const char code[] = "void f(){while(a);}"; + SimpleTokenizer tokenizer(settingsDefault, *this, false); + ASSERT(tokenizer.tokenize(code)); + ASSERT(Token::simpleMatch(tokenizer.tokens(), "void f ( ) { while ( a ) { ; } }")); + std::ostringstream ostr; + tokenizer.dump(ostr); + const std::string dump = ostr.str(); + ASSERT(dump.find("isInsertedBrace=\"true\"") != std::string::npos); + } + void doWhileAddBraces() { { const char code[] = "{do ; while (0);}"; @@ -2254,6 +2282,11 @@ class TestTokenizer : public TestFixture { const char code4[] = "union U { struct { int a; int b; }; int ab[2]; };"; const char expected4[] = "union U { struct { int a ; int b ; } ; int ab [ 2 ] ; } ;"; ASSERT_EQUALS(expected4, tokenizeAndStringify(code4)); + + // #14836: FP syntaxError for anonymous struct in for loop + const char code5[] = "void f(void) { for (struct { int a; } it = {0}; it.a < 10; it.a++) {} }"; + const char expected5[] = "void f ( ) { struct Anonymous0 { int a ; } ; for ( struct Anonymous0 it = { 0 } ; it . a < 10 ; it . a ++ ) { } }"; + ASSERT_EQUALS(expected5, tokenizeAndStringify(code5)); } void vardecl1() { @@ -2362,6 +2395,19 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS(expected, tokenizeAndStringify(code)); } + void vardecl_template_3() { + const char code[] = "template \n" // #14909 + "void f(T x) {\n" + " const auto y = h;\n" + "}"; + const char expected[] = "template < class T >\n" + "void f ( T x ) {\n" + "const auto y = h < T , x . size ( ) > ;\n" + "}"; + ASSERT_EQUALS(expected, tokenizeAndStringify(code)); + ASSERT_EQUALS("[test.cpp:3:11]: (debug) auto token with no type. [autoNoType]\n", errout_str()); + } + void vardecl_union() { // ticket #1976 const char code1[] = "class Fred { public: union { int a ; int b ; } ; } ;"; @@ -2855,6 +2901,32 @@ class TestTokenizer : public TestFixture { } } + void vardecl35() { // #14842 + { + const char code[] = "auto f() -> void {\n" + " auto p = new int;\n" + " *p = 0;\n" + "}\n"; + ASSERT_EQUALS("auto f ( ) . void {\n" + "auto p ; p = new int ;\n" + "* p = 0 ;\n" + "}", tokenizeAndStringify(code)); + ignore_errout(); + } + { + const char code[] = "auto f() -> ::std::vector {\n" + " int i = 0;\n" + " return { i };\n" + "}"; + ASSERT_EQUALS("auto f ( ) . :: std :: vector < int > {\n" + "int i ; i = 0 ;\n" + "return { i } ;\n" + "}", + tokenizeAndStringify(code)); + ignore_errout(); + } + } + void volatile_variables() { { const char code[] = "volatile int a=0;\n" @@ -4336,6 +4408,19 @@ class TestTokenizer : public TestFixture { ASSERT(var && var->isAttributeMaybeUnused()); } + void cppMaybeUnusedAfter3() { + const char code[] = "void foo(int x [[maybe_unused]]) {}"; + const char expected[] = "void foo ( int x ) { }"; + + SimpleTokenizer tokenizer(settingsDefault, *this); + ASSERT(tokenizer.tokenize(code)); + + ASSERT_EQUALS(expected, tokenizer.tokens()->stringifyList(nullptr, false)); + + const Token *x = Token::findsimplematch(tokenizer.tokens(), "x"); + ASSERT(x && x->isAttributeMaybeUnused()); + } + void cppMaybeUnusedStructuredBinding() { const char code[] = "[[maybe_unused]] auto [var1, var2] = f();"; const char expected[] = "auto [ var1 , var2 ] = f ( ) ;"; @@ -6522,21 +6607,21 @@ class TestTokenizer : public TestFixture { tokenizer.createLinks2(); tokenizer.simplifyCAlternativeTokens(); tokenizer.list.front()->assignIndexes(); - } else { // Full - tokenizer.simplifyTokens1(""); - } - // set varid.. - for (Token *tok = tokenizer.list.front(); tok; tok = tok->next()) { - if (tok->str() == "var") - tok->varId(1); - } + // set varid.. + for (Token *tok = tokenizer.list.front(); tok; tok = tok->next()) { + if (tok->str() == "var") + tok->varId(1); + } - // Create AST.. - tokenizer.prepareTernaryOpForAST(); - tokenizer.list.createAst(); + // Create AST.. + tokenizer.prepareTernaryOpForAST(); + tokenizer.list.createAst(); - tokenizer.list.validateAst(false); + tokenizer.list.validateAst(false); + } else { // Full + tokenizer.simplifyTokens1(""); + } // Basic AST validation for (const Token *tok = tokenizer.list.front(); tok; tok = tok->next()) { @@ -6660,6 +6745,7 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("foria:( asize.(", testAst("for(decltype(a.size()) i:a);")); ASSERT_EQUALS("forec0{([,(:( fb.return", testAst("for (auto e : c(0, [](auto f) { return f->b; }));")); // #10802 ASSERT_EQUALS("forvar1{;;(", testAst("for(int var{1};;)")); // #12867 + ASSERT_EQUALS("forxg{([(:( si.return", testAst("for (auto [x] : g([](S s) { return s.i; })) {}")); // #11861 // for with initializer (c++20) ASSERT_EQUALS("forab=ca:;(", testAst("for(a=b;int c:a)")); @@ -7535,6 +7621,12 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("a2[2[ 12, 34,{", testAst("int a[2][2]{ { 1, 2 }, { 3, 4 } };")); } + void astbracedinit() { + ASSERT_EQUALS("ab{", testAst("int &a { b };", AstStyle::Simple, ListSimplification::Full)); + ASSERT_EQUALS("a0{", testAst("int &&a { 0 };", AstStyle::Simple, ListSimplification::Full)); + ASSERT_EQUALS("anullptr{", testAst("int *a { nullptr };", AstStyle::Simple, ListSimplification::Full)); + } + #define isStartOfExecutableScope(offset, code) isStartOfExecutableScope_(offset, code, __FILE__, __LINE__) template bool isStartOfExecutableScope_(int offset, const char (&code)[size], const char* file, int line) { @@ -7845,6 +7937,8 @@ class TestTokenizer : public TestFixture { "}\n")); ignore_errout(); + + ASSERT_EQUALS(";", tokenizeAndStringify("typedef std::size_t size_t;\n")); // #14809 } @@ -8411,6 +8505,22 @@ class TestTokenizer : public TestFixture { } } + void ccast() { + const char code[] = "a = (int)x;\n" // #13579 + "int (*p)[10];\n" + "b = (void (S::*)(int) const)&y;"; + + SimpleTokenizer tokenizer(settingsDefault, *this); + ASSERT(tokenizer.tokenize(code)); + + const Token* par = Token::findsimplematch(tokenizer.tokens(), "("); + ASSERT(par->isCast()); + par = Token::findsimplematch(par->next(), "("); + ASSERT(!par->isCast()); + par = Token::findsimplematch(par->next(), "("); + ASSERT(par->isCast()); + } + #define checkHdrs(...) checkHdrs_(__FILE__, __LINE__, __VA_ARGS__) template std::string checkHdrs_(const char* file, int line, const char (&code)[size], bool checkHeadersFlag) { @@ -8688,6 +8798,10 @@ class TestTokenizer : public TestFixture { "{ 1", Token::Cpp11init::CPP11INIT); + testIsCpp11init("void f() { g([] { if (int x = 1; x) {} }); }", // #14790 + "{ int", + Token::Cpp11init::NOINIT); // don't hang + ASSERT_NO_THROW(tokenizeAndStringify("template struct X {};\n" // don't crash "template auto f(T t) -> X {}\n")); ASSERT_EQUALS("[test.cpp:2:22]: (debug) auto token with no type. [autoNoType]\n", errout_str()); @@ -8793,14 +8907,11 @@ class TestTokenizer : public TestFixture { } void testDirectiveIncludeLocations() { + ScopedFile inc1("inc1.h", "#define macro2 val\n#include \"inc2.h\"\n#define macro4 val\n"); + ScopedFile inc2("inc2.h", "#define macro3 val\n"); + // TODO: preprocess? const char filedata[] = "#define macro1 val\n" - "#file \"inc1.h\"\n" - "#define macro2 val\n" - "#file \"inc2.h\"\n" - "#define macro3 val\n" - "#endfile\n" - "#define macro4 val\n" - "#endfile\n" + "#include \"inc1.h\"\n" "#define macro5 val\n"; const char dumpdata[] = " \n" " \n" @@ -8811,8 +8922,14 @@ class TestTokenizer : public TestFixture { " \n" " \n" " \n" - " \n" - " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" " \n" " \n" " \n" @@ -8822,14 +8939,8 @@ class TestTokenizer : public TestFixture { " \n" " \n" " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" + " \n" + " \n" " \n" " \n" " \n" @@ -8837,10 +8948,10 @@ class TestTokenizer : public TestFixture { " \n" " \n" " \n" - " \n" + " \n" " \n" " \n" - " \n" + " \n" " \n" " \n" " \n" diff --git a/test/testtype.cpp b/test/testtype.cpp index 280e3357f85..2bcab8c91dc 100644 --- a/test/testtype.cpp +++ b/test/testtype.cpp @@ -61,8 +61,8 @@ class TestType : public TestFixture { SimpleTokenizer tokenizer(settings1, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check.. - runChecks(tokenizer, this); + CheckType check; + runChecks(check, tokenizer, *this); } // TODO: get rid of this @@ -73,8 +73,8 @@ class TestType : public TestFixture { SimpleTokenizer tokenizer(settings1, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check.. - runChecks(tokenizer, this); + CheckType check; + runChecks(check, tokenizer, *this); } struct CheckPOptions @@ -93,8 +93,8 @@ class TestType : public TestFixture { // Tokenizer.. ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); - // Check.. - runChecks(tokenizer, this); + CheckType check; + runChecks(check, tokenizer, *this); } void checkTooBigShift_Unix32() { diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index db499dabf72..6a43493cd0d 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -127,7 +127,7 @@ class TestUninitVar : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check for redundant code.. - CheckUninitVar checkuninitvar(&tokenizer, &settings1, this); + CheckUninitVarImpl checkuninitvar(&tokenizer, settings1, *this); checkuninitvar.check(); } @@ -137,7 +137,7 @@ class TestUninitVar : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check for redundant code.. - CheckUninitVar checkuninitvar(&tokenizer, &settings, this); + CheckUninitVarImpl checkuninitvar(&tokenizer, settings, *this); checkuninitvar.check(); } @@ -3673,7 +3673,7 @@ class TestUninitVar : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check for redundant code.. - CheckUninitVar checkuninitvar(&tokenizer, &settings, this); + CheckUninitVarImpl checkuninitvar(&tokenizer, settings, *this); (checkuninitvar.valueFlowUninit)(); } @@ -4265,7 +4265,7 @@ class TestUninitVar : public TestFixture { " else {}\n" " return y;\n" "}"); - TODO_ASSERT_EQUALS("", "[test.cpp:5:9] -> [test.cpp:7:12]: (warning) Uninitialized variable: y [uninitvar]\n", errout_str()); + ASSERT_EQUALS("", errout_str()); // #4560: escaping else keeps x known, so x is true and y is initialized valueFlowUninit("int f(int a) {\n" // #6583 " int x;\n" @@ -4284,7 +4284,8 @@ class TestUninitVar : public TestFixture { " else y = 123;\n" // <- y is always initialized " return y;\n" "}"); - TODO_ASSERT_EQUALS("", "[test.cpp:5:9] -> [test.cpp:7:12]: (warning) Uninitialized variable: y [uninitvar]\n", errout_str()); + ASSERT_EQUALS("", + errout_str()); // #4560: fork-based condition analysis tracks x==0 -> else branch -> y initialized valueFlowUninit("void f(int x) {\n" // #3948 " int value;\n" @@ -5576,11 +5577,12 @@ class TestUninitVar : public TestFixture { SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - CTU::FileInfo *ctu = CTU::getFileInfo(tokenizer); + const CTU::FileInfo *ctu = CTU::getFileInfo(tokenizer); // Check code.. - std::list fileInfo; - Check& c = getCheck(); + std::list fileInfo; + CheckUninitVar check; + Check& c = getCheck(check); fileInfo.push_back(c.getFileInfo(tokenizer, settings, "")); c.analyseWholeProgram(*ctu, fileInfo, settings, *this); // TODO: check result while (!fileInfo.empty()) { @@ -5613,6 +5615,47 @@ class TestUninitVar : public TestFixture { "}"); ASSERT_EQUALS("[test.cpp:18:9] -> [test.cpp:12:13] -> [test.cpp:8:15]: (warning) Uninitialized variable: s->flag [uninitvar]\n", errout_str()); + // A value narrowed by a nested condition (dimensions < 1 here) must survive the enclosing + // 'if' so a later correlated condition can be resolved: dimensions == 1 is then false, the + // function does not return, and the uninitialized read is reached. + valueFlowUninit("unsigned int g();\n" + "void f(bool a) {\n" + " unsigned int dimensions = 0;\n" + " bool mightBeLarger;\n" + " if (a) {\n" + " dimensions = g();\n" + " if (dimensions >= 1)\n" + " mightBeLarger = false;\n" + " } else {\n" + " mightBeLarger = false;\n" + " }\n" + " if (dimensions == 1)\n" + " return;\n" + " if (!mightBeLarger) {}\n" + "}"); + ASSERT_EQUALS( + "[test.cpp:5:9] -> [test.cpp:7:24] -> [test.cpp:14:10]: (warning) Uninitialized variable: mightBeLarger [uninitvar]\n", + errout_str()); + + // Same shape, but the later condition (dimensions == 0) is implied by the narrowing, so the + // early return fires on the uninitialized path and there must be no warning. + valueFlowUninit("unsigned int g();\n" + "void f(bool a) {\n" + " unsigned int dimensions = 0;\n" + " bool mightBeLarger;\n" + " if (a) {\n" + " dimensions = g();\n" + " if (dimensions >= 1)\n" + " mightBeLarger = false;\n" + " } else {\n" + " mightBeLarger = false;\n" + " }\n" + " if (dimensions == 0)\n" + " return;\n" + " if (!mightBeLarger) {}\n" + "}"); + ASSERT_EQUALS("", errout_str()); + // Ticket #2207 - False negative valueFlowUninit("void foo() {\n" " int a;\n" diff --git a/test/testunusedfunctions.cpp b/test/testunusedfunctions.cpp index b3b8a298650..938a1394394 100644 --- a/test/testunusedfunctions.cpp +++ b/test/testunusedfunctions.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 @@ -111,8 +111,8 @@ class TestUnusedFunctions : public TestFixture { // Check for unused functions.. CheckUnusedFunctions checkUnusedFunctions; - checkUnusedFunctions.parseTokens(tokenizer, settings1); - (checkUnusedFunctions.check)(settings1, *this); // TODO: check result + checkUnusedFunctions.parseTokens(tokenizer, settings1.library); + (checkUnusedFunctions.check)(settings1.library, *this); // TODO: check result } // TODO: get rid of this @@ -123,8 +123,8 @@ class TestUnusedFunctions : public TestFixture { // Check for unused functions.. CheckUnusedFunctions checkUnusedFunctions; - checkUnusedFunctions.parseTokens(tokenizer, settings); - (checkUnusedFunctions.check)(settings, *this); // TODO: check result + checkUnusedFunctions.parseTokens(tokenizer, settings.library); + (checkUnusedFunctions.check)(settings.library, *this); // TODO: check result } void incondition() { @@ -602,11 +602,11 @@ class TestUnusedFunctions : public TestFixture { SimpleTokenizer tokenizer{settings, *this, fname}; ASSERT(tokenizer.tokenize(code)); - c.parseTokens(tokenizer, settings); + c.parseTokens(tokenizer, settings.library); } // Check for unused functions.. - (c.check)(settings, *this); // TODO: check result + (c.check)(settings.library, *this); // TODO: check result ASSERT_EQUALS("[test1.cpp:1:13]: (style) The function 'f' is never used. [unusedFunction]\n", errout_str()); } diff --git a/test/testunusedprivfunc.cpp b/test/testunusedprivfunc.cpp index 5a364347163..09f8c21d102 100644 --- a/test/testunusedprivfunc.cpp +++ b/test/testunusedprivfunc.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 @@ -58,7 +58,6 @@ class TestUnusedPrivateFunction : public TestFixture { TEST_CASE(classInClass); TEST_CASE(sameFunctionNames); - TEST_CASE(incompleteImplementation); TEST_CASE(derivedClass); // skip warning for derived classes. It might be a virtual function. @@ -76,7 +75,6 @@ class TestUnusedPrivateFunction : public TestFixture { TEST_CASE(testDoesNotIdentifyMethodAsMiddleFunctionArgument); TEST_CASE(testDoesNotIdentifyMethodAsLastFunctionArgument); - TEST_CASE(multiFile); TEST_CASE(unknownBaseTemplate); // ticket #2580 TEST_CASE(hierarchy_loop); // ticket 5590 @@ -104,7 +102,7 @@ class TestUnusedPrivateFunction : public TestFixture { ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); // Check for unused private functions.. - CheckClass checkClass(&tokenizer, &settings1, this); + CheckClassImpl checkClass(&tokenizer, settings1, *this); checkClass.privateFunctions(); } @@ -482,24 +480,6 @@ class TestUnusedPrivateFunction : public TestFixture { ASSERT_EQUALS("", errout_str()); } - void incompleteImplementation() { - // The implementation for "A::a" is missing - so don't check if - // "A::b" is used or not - check("#file \"test.h\"\n" - "class A\n" - "{\n" - "public:\n" - " A();\n" - " void a();\n" - "private:\n" - " void b();\n" - "};\n" - "#endfile\n" - "A::A() { }\n" - "void A::b() { }"); - ASSERT_EQUALS("", errout_str()); - } - void derivedClass() { // skip warning in derived classes in case the base class is invisible check("class derived : public base\n" @@ -780,25 +760,6 @@ class TestUnusedPrivateFunction : public TestFixture { ASSERT_EQUALS("", errout_str()); } - void multiFile() { // ticket #2567 - check("#file \"test.h\"\n" - "struct Fred\n" - "{\n" - " Fred()\n" - " {\n" - " Init();\n" - " }\n" - "private:\n" - " void Init();\n" - "};\n" - "#endfile\n" - "void Fred::Init()\n" - "{\n" - "}"); - - ASSERT_EQUALS("", errout_str()); - } - void unknownBaseTemplate() { // ticket #2580 check("class Bla : public Base2 {\n" "public:\n" diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 13d288a3fdd..849d34b49b0 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -79,6 +79,7 @@ class TestUnusedVar : public TestFixture { TEST_CASE(structmember31); // #14130 TEST_CASE(structmember32); // #14483 TEST_CASE(structmember33); + TEST_CASE(structmember34); TEST_CASE(structmember_macro); TEST_CASE(structmember_template_argument); // #13887 - do not report that member used in template argument is unused TEST_CASE(classmember); @@ -155,6 +156,7 @@ class TestUnusedVar : public TestFixture { TEST_CASE(localvar70); TEST_CASE(localvar71); TEST_CASE(localvar72); + TEST_CASE(localvar73); TEST_CASE(localvarloops); // loops TEST_CASE(localvaralias1); TEST_CASE(localvaralias2); // ticket #1637 @@ -290,7 +292,7 @@ class TestUnusedVar : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check for unused variables.. - CheckUnusedVar checkUnusedVar(&tokenizer, &settings, this); + CheckUnusedVarImpl checkUnusedVar(&tokenizer, settings, *this); checkUnusedVar.checkFunctionVariableUsage(); } @@ -310,7 +312,7 @@ class TestUnusedVar : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check for unused variables.. - CheckUnusedVar checkUnusedVar(&tokenizer, &settings, this); + CheckUnusedVarImpl checkUnusedVar(&tokenizer, settings, *this); (checkUnusedVar.checkStructMemberUsage)(); } @@ -323,7 +325,7 @@ class TestUnusedVar : public TestFixture { ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); // Check for unused variables.. - CheckUnusedVar checkUnusedVar(&tokenizer, &settings, this); + CheckUnusedVarImpl checkUnusedVar(&tokenizer, settings, *this); (checkUnusedVar.checkStructMemberUsage)(); } @@ -336,7 +338,7 @@ class TestUnusedVar : public TestFixture { ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); // Check for unused variables.. - CheckUnusedVar checkUnusedVar(&tokenizer, &settings, this); + CheckUnusedVarImpl checkUnusedVar(&tokenizer, settings, *this); (checkUnusedVar.checkFunctionVariableUsage)(); } @@ -2088,6 +2090,18 @@ class TestUnusedVar : public TestFixture { ASSERT_EQUALS("[test.cpp:2:23]: (style) struct member 'S::mp' is never used. [unusedStructMember]\n", errout_str()); } + void structmember34() { + checkStructMemberUsage("struct S {\n" // #14785 + " std::int32_t i;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:16]: (style) struct member 'S::i' is never used. [unusedStructMember]\n", errout_str()); + + checkStructMemberUsage("struct S {\n" // #14786 + " std::unique_ptr p;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:24]: (style) struct member 'S::p' is never used. [unusedStructMember]\n", errout_str()); + } + void structmember_macro() { checkStructMemberUsageP("#define S(n) struct n { int a, b, c; };\n" "S(unused);\n"); @@ -4061,6 +4075,16 @@ class TestUnusedVar : public TestFixture { ASSERT_EQUALS("[test.cpp:4:12]: (style) Unused variable: mp [unusedVariable]\n", errout_str()); } + void localvar73() { + functionVariableUsage("struct S { S(); ~S(); };\n" + "void f() {\n" + " auto a{ S() };\n" + " auto const &b{ S() };\n" + " const auto &&c{ S() };\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void localvarloops() { // loops functionVariableUsage("void fun(int c) {\n" @@ -7070,6 +7094,24 @@ class TestUnusedVar : public TestFixture { " S<0> s;\n" "}\n"); ASSERT_EQUALS("[test.cpp:6:10]: (style) Unused variable: s [unusedVariable]\n", errout_str()); + + functionVariableUsage("template \n" // #14783 + "struct A {\n" + " A() = default;\n" + "};\n" + "void f() {\n" + " A a;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6:12]: (style) Unused variable: a [unusedVariable]\n", errout_str()); + + functionVariableUsage("template \n" // #14784 + "struct A {\n" + " A() {}\n" + "};\n" + "void f() {\n" + " A a;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6:12]: (style) Unused variable: a [unusedVariable]\n", errout_str()); } void localvarFuncPtr() { @@ -7158,6 +7200,7 @@ class TestUnusedVar : public TestFixture { "void f() {\n" " Y y;\n" "}"); // #4695 + ASSERT_EQUALS("[test.cpp:6:7]: (style) Unused variable: y [unusedVariable]\n", errout_str()); } void crash3() { diff --git a/test/testvaarg.cpp b/test/testvaarg.cpp index 36e1d2cb038..826438fe355 100644 --- a/test/testvaarg.cpp +++ b/test/testvaarg.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 @@ -38,8 +38,8 @@ class TestVaarg : public TestFixture { SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check.. - runChecks(tokenizer, this); + CheckVaarg check; + runChecks(check, tokenizer, *this); } void run() override { diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index dc5345ab3e3..abeb603b660 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -137,6 +137,7 @@ class TestValueFlow : public TestFixture { TEST_CASE(valueFlowConditionExpressions); TEST_CASE(valueFlowContainerSize); + TEST_CASE(valueFlowContainerSizeIterator); TEST_CASE(valueFlowContainerElement); TEST_CASE(valueFlowDynamicBufferSize); @@ -908,6 +909,19 @@ class TestValueFlow : public TestFixture { ASSERT_EQUALS(true, lifetimes.size() == 1); ASSERT_EQUALS(true, lifetimes.front() == "a"); } + { + const char code[] = "void f(const char *s, size_t len) {\n" + " char buf[10];\n" + " {\n" + " char *tmp = buf;\n" + " s = strcpy(tmp, s);\n" + " }\n" + " if (s[len] == '\0') {}\n" + "}\n"; + lifetimes = lifetimeValues(code, "s ["); + ASSERT_EQUALS(true, lifetimes.size() == 1); + ASSERT_EQUALS(true, lifetimes.front() == "buf"); + } } void valueFlowArrayElement() { @@ -1077,6 +1091,14 @@ class TestValueFlow : public TestFixture { " }\n" "}\n"; ASSERT_EQUALS(false, testValueOfX(code, 13U, ValueFlow::Value::MoveKind::MovedVariable)); + + code = "struct S { int f(int); };\n" // #11751 + "S g(S);\n" + "void h() {\n" + " S x;\n" + " g(std::move(x)).f(1);\n" + "}\n"; + ASSERT_EQUALS(false, testValueOfX(code, 5U, ValueFlow::Value::MoveKind::MovedVariable)); } void valueFlowCalculations() { @@ -1248,6 +1270,12 @@ class TestValueFlow : public TestFixture { ASSERT_EQUALS(1U, values.size()); ASSERT_EQUALS(-10, values.back().intvalue); + code = "bool f(unsigned a) {\n" // #14848 + " bool x = -a < 1;\n" + " return x;\n" + "}"; + ASSERT_EQUALS(false, testValueOfXKnown(code, 3U, 1)); + // Logical and code = "void f(bool b) {\n" " bool x = false && b;\n" @@ -1396,6 +1424,30 @@ class TestValueFlow : public TestFixture { ASSERT_EQUALS(1U, values.size()); ASSERT_EQUALS(4, values.back().intvalue); + code = "char& r = i;\n" + "sizeof(r);"; + values = tokenValues(code, "( r"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(1, values.back().intvalue); + + code = "char* p;\n" + "sizeof(p);"; + values = tokenValues(code, "( p"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(settings.platform.sizeof_pointer, values.back().intvalue); + + code = "char*& pr = p;\n" + "sizeof(pr);"; + values = tokenValues(code, "( pr"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(settings.platform.sizeof_pointer, values.back().intvalue); + + code = "struct { char& r; char* p; } s{ x, y };\n" + "sizeof(s);\n"; + values = tokenValues(code, "( s"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(2 * settings.platform.sizeof_pointer, values.back().intvalue); + #define CHECK3(A, B, C) \ do { \ code = "void f() {\n" \ @@ -1761,6 +1813,20 @@ class TestValueFlow : public TestFixture { ASSERT_EQUALS(1U, values.size()); ASSERT_EQUALS(2 * settings.platform.sizeof_pointer, values.back().intvalue); ASSERT_EQUALS_ENUM(ValueFlow::Value::ValueKind::Known, values.back().valueKind); + + code = "struct S { std::array a; };\n" + "x = sizeof(S);\n"; + values = tokenValues(code, "( S"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(3 * settings.platform.sizeof_int, values.back().intvalue); + ASSERT_EQUALS_ENUM(ValueFlow::Value::ValueKind::Known, values.back().valueKind); + + code = "std::array a;\n" + "x = sizeof(a);\n"; + values = tokenValues(code, "( a"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(3 * settings.platform.sizeof_int, values.back().intvalue); + ASSERT_EQUALS_ENUM(ValueFlow::Value::ValueKind::Known, values.back().valueKind); } void valueFlowComma() @@ -3137,6 +3203,50 @@ class TestValueFlow : public TestFixture { " return x;\n" "}\n"; ASSERT_EQUALS(true, testValueOfXKnown(code, 3U, -1)); + + code = "A* f() {\n" // #14864 + " A* x{};\n" + " return x;\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfXKnown(code, 3U, 0)); + + code = "A* f() {\n" + " A* x{ nullptr };\n" + " return x;\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfXKnown(code, 3U, 0)); + + code = "bool f();\n" // a modification after a conditional escape must still be seen + "void g() {\n" + " bool x = false;\n" + " if (f()) {\n" + " if (f()) return;\n" + " if (f()) x = true;\n" + " }\n" + " if (x) {}\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfX(code, 8U, 0)); + ASSERT_EQUALS(false, testValueOfXKnown(code, 8U, 0)); + + code = "bool f();\n" + "void g() {\n" + " bool x = false;\n" + " if (f()) {\n" + " if (f()) return;\n" + " x = true;\n" + " }\n" + " if (x) {}\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfX(code, 8U, 0)); + ASSERT_EQUALS(false, testValueOfXKnown(code, 8U, 0)); + + code = "bool f();\n" // the branch always escapes - keep the known value + "void g() {\n" + " bool x = false;\n" + " if (f()) { x = true; return; }\n" + " if (x) {}\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfXKnown(code, 5U, 0)); } void valueFlowAfterSwap() @@ -3757,6 +3867,44 @@ class TestValueFlow : public TestFixture { " return x;\n" "}\n"; ASSERT_EQUALS(true, testValueOfX(code, 4U, 0)); + + // if the guarded block calls an unknown, possibly noreturn function + // then the condition value is lowered to inconclusive after the block + code = "int f(int x) {\n" + " if (x == 0)\n" + " g();\n" + " return x;\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfXInconclusive(code, 4U, 0)); + + // .. also when the guard is in the else branch + code = "int f(int x) {\n" + " if (x != 0)\n" + " ;\n" + " else\n" + " g();\n" + " return x;\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfXInconclusive(code, 6U, 0)); + + // a declared function is assumed to return + code = "void g();\n" + "int f(int x) {\n" + " if (x == 0)\n" + " g();\n" + " return x;\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfX(code, 5U, 0)); + ASSERT_EQUALS(false, testValueOfXInconclusive(code, 5U, 0)); + + // a noreturn function conclusively escapes + code = "int f(int x) {\n" + " if (x == 0)\n" + " abort();\n" + " return x;\n" + "}\n"; + ASSERT_EQUALS(false, testValueOfX(code, 4U, 0)); + ASSERT_EQUALS(true, testValueOfXImpossible(code, 4U, 0)); } void valueFlowAfterConditionTernary() @@ -6046,9 +6194,9 @@ class TestValueFlow : public TestFixture { " c++;\n" "}\n"; values = tokenValues(code, "c ++ ; }"); - TODO_ASSERT_EQUALS(true, false, values.size() == 2); - // ASSERT_EQUALS(true, values.front().isUninitValue() || values.back().isUninitValue()); - // ASSERT_EQUALS(true, values.front().isPossible() || values.back().isPossible()); + ASSERT_EQUALS(true, values.size() == 2); + ASSERT_EQUALS(true, values.front().isUninitValue() || values.back().isUninitValue()); + ASSERT_EQUALS(true, values.front().isPossible() || values.back().isPossible()); // ASSERT_EQUALS(true, values.front().intvalue == 0 || values.back().intvalue == 0); code = "void b(bool d, bool e) {\n" @@ -6290,6 +6438,14 @@ class TestValueFlow : public TestFixture { "}\n"; values = tokenValues(code, "x > 5", ValueFlow::Value::ValueType::UNINIT); ASSERT_EQUALS(0, values.size()); + + code = "void f() {\n" // #11152 + " char b[10];\n" + " sprintf(b, \"abc\");\n" + " printf(\"%s\", b);\n" + "}\n"; + values = tokenValues(code, "b )", ValueFlow::Value::ValueType::UNINIT); + ASSERT_EQUALS(0, values.size()); } void valueFlowConditionExpressions() { @@ -7507,6 +7663,47 @@ class TestValueFlow : public TestFixture { ASSERT(!isKnownContainerSizeValue(tokenValues(code, "m ."), 0).empty()); } + void valueFlowContainerSizeIterator() { + const char* code; + + // valueFlowForwardConst: the container size is added to iterators of a const container + code = "void f() {\n" + " const std::vector v{1, 2, 3};\n" + " auto it = v.begin();\n" + " if (it != v.end()) {}\n" + "}"; + ASSERT_EQUALS( + "", + isKnownContainerSizeValue(tokenValues(code, "it !=", ValueFlow::Value::ValueType::CONTAINER_SIZE), 3)); + + // ..also to iterators created in place + code = "void f() {\n" + " const std::deque d{1, 2, 3, 4, 5, 6};\n" + " if (std::equal(d.cbegin(), d.cend(), d.cbegin())) {}\n" + "}"; + ASSERT_EQUALS( + "", + isKnownContainerSizeValue(tokenValues(code, "( ) ,", ValueFlow::Value::ValueType::CONTAINER_SIZE), 6)); + + // ..and to iterators of containers with a static size + code = "void f() {\n" + " std::array a;\n" + " auto it = a.begin();\n" + " if (it != a.end()) {}\n" + "}"; + ASSERT_EQUALS( + "", + isKnownContainerSizeValue(tokenValues(code, "it !=", ValueFlow::Value::ValueType::CONTAINER_SIZE), 5)); + + // the size of another container is not added to the iterator + code = "void f(std::vector& w) {\n" + " const std::vector v{1, 2, 3};\n" + " auto it = w.begin();\n" + " if (it != w.end()) {}\n" + "}"; + ASSERT(tokenValues(code, "it !=", ValueFlow::Value::ValueType::CONTAINER_SIZE).empty()); + } + void valueFlowContainerElement() { const char* code; @@ -8361,6 +8558,75 @@ class TestValueFlow : public TestFixture { " static T f[64];\n" "};\n"; (void)valueOfTok(code, "("); + + // fork explosion on many opaque conditions; bounded by maxForwardConditionForks + code = "int g(int);\n" + "bool h(int);\n" + "void f() {\n" + " int x = 0;\n" + " if (h(0)) g(x);\n" + " if (h(1)) g(x);\n" + " if (h(2)) g(x);\n" + " if (h(3)) g(x);\n" + " if (h(4)) g(x);\n" + " if (h(5)) g(x);\n" + " if (h(6)) g(x);\n" + " if (h(7)) g(x);\n" + " if (h(8)) g(x);\n" + " if (h(9)) g(x);\n" + " if (h(10)) g(x);\n" + " if (h(11)) g(x);\n" + " if (h(12)) g(x);\n" + " if (h(13)) g(x);\n" + " if (h(14)) g(x);\n" + " if (h(15)) g(x);\n" + " if (h(16)) g(x);\n" + " if (h(17)) g(x);\n" + " if (h(18)) g(x);\n" + " if (h(19)) g(x);\n" + " if (h(20)) g(x);\n" + " if (h(21)) g(x);\n" + " if (h(22)) g(x);\n" + " if (h(23)) g(x);\n" + " if (h(24)) g(x);\n" + " if (h(25)) g(x);\n" + " if (h(26)) g(x);\n" + " if (h(27)) g(x);\n" + " if (h(28)) g(x);\n" + " if (h(29)) g(x);\n" + " if (h(30)) g(x);\n" + " if (h(31)) g(x);\n" + " if (h(32)) g(x);\n" + " if (h(33)) g(x);\n" + " if (h(34)) g(x);\n" + " if (h(35)) g(x);\n" + " if (h(36)) g(x);\n" + " if (h(37)) g(x);\n" + " if (h(38)) g(x);\n" + " if (h(39)) g(x);\n" + " if (h(40)) g(x);\n" + " if (h(41)) g(x);\n" + " if (h(42)) g(x);\n" + " if (h(43)) g(x);\n" + " if (h(44)) g(x);\n" + " if (h(45)) g(x);\n" + " if (h(46)) g(x);\n" + " if (h(47)) g(x);\n" + " if (h(48)) g(x);\n" + " if (h(49)) g(x);\n" + " if (h(50)) g(x);\n" + " if (h(51)) g(x);\n" + " if (h(52)) g(x);\n" + " if (h(53)) g(x);\n" + " if (h(54)) g(x);\n" + " if (h(55)) g(x);\n" + " if (h(56)) g(x);\n" + " if (h(57)) g(x);\n" + " if (h(58)) g(x);\n" + " if (h(59)) g(x);\n" + " (void)x;\n" + "}\n"; + (void)valueOfTok(code, "x"); } void valueFlowCrashConstructorInitialization() { // #9577 @@ -9217,6 +9483,19 @@ class TestValueFlow : public TestFixture { "}\n"; ASSERT_EQUALS(false, testValueOfX(code, 5U, 1)); ASSERT_EQUALS(false, testValueOfX(code, 5U, 0)); + + code = "bool f() {\n" + " std::string s1, s2;\n" + " bool x = (s1 == s2);\n" + " return x;\n" + "}\n" + "bool g() {\n" + " std::string s1, s2;\n" + " bool x = (s1 != s2);\n" + " return x;\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfXKnown(code, 4U, 1)); + ASSERT_EQUALS(true, testValueOfXKnown(code, 9U, 0)); } void valueFlowBailoutIncompleteVar() { diff --git a/test/testvarid.cpp b/test/testvarid.cpp index 941b5812678..c8d16bc89a5 100644 --- a/test/testvarid.cpp +++ b/test/testvarid.cpp @@ -2841,7 +2841,7 @@ class TestVarID : public TestFixture { void varid_using() { // #3648 const char code[] = "using std::size_t;"; - const char expected[] = "1: using unsigned long ;\n"; + const char expected[] = "1: ;\n"; ASSERT_EQUALS(expected, tokenize(code)); } diff --git a/test/tools/donate_cpu_lib_test.py b/test/tools/donate_cpu_lib_test.py index e00a3d296a0..141781192aa 100644 --- a/test/tools/donate_cpu_lib_test.py +++ b/test/tools/donate_cpu_lib_test.py @@ -58,6 +58,7 @@ def test_library_includes(tmpdir): _test_library_includes(tmpdir, ['posix', 'gnu', 'bsd', 'opengl'], '#include\t ') _test_library_includes(tmpdir, ['posix', 'gnu', 'bsd', 'nspr'], '#include\t"prtypes.h"') _test_library_includes(tmpdir, ['posix', 'gnu', 'bsd', 'lua'], '#include \t') + _test_library_includes(tmpdir, ['posix', 'gnu', 'bsd', 'microsoft_gsl'], '#include ') def test_match_multiple_time(tmpdir): libinc = LibraryIncludes() diff --git a/tools/dmake/dmake.cpp b/tools/dmake/dmake.cpp index 80f3aa35b83..eaf0a727646 100644 --- a/tools/dmake/dmake.cpp +++ b/tools/dmake/dmake.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 @@ -297,6 +297,7 @@ static std::vector prioritizelib(const std::vector& li std::map priorities; std::size_t prio = libfiles.size(); for (const auto &l : libfiles) { + // cppcheck-suppress useStlAlgorithm - std::transform is cumbersome priorities.emplace(l, prio--); } priorities["lib/valueflow.cpp"] = 1000; @@ -495,12 +496,14 @@ int main(int argc, char **argv) } libfiles_h.emplace("analyzer.h"); libfiles_h.emplace("calculate.h"); + libfiles_h.emplace("check.h"); libfiles_h.emplace("config.h"); libfiles_h.emplace("filesettings.h"); libfiles_h.emplace("findtoken.h"); libfiles_h.emplace("json.h"); libfiles_h.emplace("matchcompiler.h"); libfiles_h.emplace("precompiled.h"); + libfiles_h.emplace("rule.h"); libfiles_h.emplace("smallvector.h"); libfiles_h.emplace("sourcelocation.h"); libfiles_h.emplace("tokenrange.h"); @@ -559,7 +562,7 @@ int main(int argc, char **argv) for (const std::string &libfile: libfiles_prio) { const std::string l = libfile.substr(4); - outstr += make_vcxproj_cl_entry(l, l == "check.cpp" ? Precompile : Compile); + outstr += make_vcxproj_cl_entry(l, l == "checkimpl.cpp" ? Precompile : Compile); } }, [&](std::string &outstr){ outstr += make_vcxproj_cl_entry(R"(..\externals\simplecpp\simplecpp.h)", Include); diff --git a/tools/donate-cpu-server.py b/tools/donate-cpu-server.py index 6f44ea679a7..63a55f5b338 100755 --- a/tools/donate-cpu-server.py +++ b/tools/donate-cpu-server.py @@ -26,10 +26,10 @@ # Version scheme (MAJOR.MINOR.PATCH) should orientate on "Semantic Versioning" https://semver.org/ # Every change in this script should result in increasing the version number accordingly (exceptions may be cosmetic # changes) -SERVER_VERSION = "1.3.68" +SERVER_VERSION = "1.3.69" # TODO: fetch from GitHub tags -OLD_VERSION = '2.20.0' +OLD_VERSION = '2.21.0' HEAD_MARKER = 'head results:' INFO_MARKER = 'info messages:' diff --git a/tools/donate_cpu_lib.py b/tools/donate_cpu_lib.py index c292d2b9a13..ed345cb10c9 100644 --- a/tools/donate_cpu_lib.py +++ b/tools/donate_cpu_lib.py @@ -723,6 +723,7 @@ def __init__(self): 'wxwidgets': [''], + 'microsoft_gsl': [''], } self.__library_includes_re = {} diff --git a/tools/get_checkers.py b/tools/get_checkers.py index 4594b773dc2..48455200fb5 100644 --- a/tools/get_checkers.py +++ b/tools/get_checkers.py @@ -2,8 +2,18 @@ import glob import os import re +import sys import requests +try: + from tqdm import tqdm +except ImportError: + # Fallback: passthrough iterator if tqdm is not installed + def tqdm(iterable, total=None, desc=None, **kwargs): + if desc: + print(desc, file=sys.stderr) + return iterable + def print_checkers(glob_pattern:str): checkers = {} for filename in glob.glob(glob_pattern): @@ -908,44 +918,65 @@ def print_checkers(glob_pattern:str): }; """) +# SEI CERT is available as markdown files at +# https://github.com/cmu-sei/secure-coding-standards +CERT_REPO = 'cmu-sei/secure-coding-standards' +CERT_BRANCH = 'main' + +# Cache git tree +_cert_tree = None + +def listCertFiles(content_subdir:str): + """Lists the rules and recommendation files for one part of the standard.""" + global _cert_tree + if _cert_tree is None: + url = 'https://api.github.com/repos/%s/git/trees/%s?recursive=1' % (CERT_REPO, CERT_BRANCH) + _cert_tree = requests.get(url, timeout=50).json()['tree'] + prefix = 'content/' + content_subdir + files = [] + for entry in _cert_tree: + path = entry['path'] + if entry['type'] != 'blob' or not path.startswith(prefix) or not path.endswith('.md'): + continue + if 'index' in path.rsplit('/', 1)[-1].lower(): + continue + files.append(path) + return sorted(files) -def getCertCInfo(main_url:str): +def printCertCInfo(content_subdir:str): """Fetches CERT C rules information.""" - # Fetching the CERT C rules page - r = requests.get(main_url, timeout=30) - mainpage = r.text - for line in mainpage.split('\n'): - res = re.search(r'(Rule|Rec.) \d\d[.] [A-Za-z ]+ [(][A-Z][A-Z][A-Z][)]', line) + paths = listCertFiles(content_subdir) + rules = {} + for path in tqdm(paths, total=len(paths), desc=f'Fetching {content_subdir}', file=sys.stderr): + raw = 'https://raw.githubusercontent.com/%s/%s/%s' % (CERT_REPO, CERT_BRANCH, path) + text = requests.get(raw, timeout=30).text + res = re.search(r'^#\s+([A-Z]{3}\d{2}-C(?:PP)?)\b', text, re.MULTILINE) if res is None: continue - r = requests.get('https://wiki.sei.cmu.edu' + res.group(1), timeout=30) - text = r.text.replace('\n', '').replace('', '\n').replace('', '\n') - rules = [] - for line in text.split('\n'): - if not line.startswith(']+>([A-Z][A-Z][A-Z][0-9][0-9]-CP*)<.*>(L[1-3])<.+', line) - if res: - if res.group(1) == 'EXP40-C' and 'EXP39-C' not in rules: - print(' {"EXP39-C", "L2"},') - print(' {"%s", "%s"},' % (res.group(1), res.group(2))) - rules.append(res.group(1)) - if 'EXP45-C' in rules: - if 'EXP46-C' not in rules: - print(' {"EXP46-C", "L2"},') - if 'EXP47-C' not in rules: - print(' {"EXP47-C", "L2"},') + head = re.search(r'^#{0,4}\s*Risk Assessments?\s*$', text, re.MULTILINE) + if head is None: + continue + section = text[head.end():] + nexthead = re.search(r'^#{1,4}\s+\S', section, re.MULTILINE) + if nexthead: + section = section[:nexthead.start()] + level = re.search(r'\bL[1-3]\b', section) + if level is None: + continue + rules[res.group(1)] = level.group(0) + for rule_id, level in dict(sorted(rules.items())).items(): + print(' {"%s", "%s"},' % (rule_id, level)) + print('std::vector checkers::certCInfo{') -getCertCInfo('https://wiki.sei.cmu.edu/confluence/display/c/2+Rules') +printCertCInfo('4.sei-cert-c-coding-standard/03.rules/') print(' // Recommendations') -getCertCInfo('https://wiki.sei.cmu.edu/confluence/display/c/3+Recommendations') +printCertCInfo('4.sei-cert-c-coding-standard/08.recommendations/') print('};') print('') print('std::vector checkers::certCppInfo{') -getCertCInfo('https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=88046682') +printCertCInfo('5.sei-cert-cpp-coding-standard/3.rules/') print('};') print('') diff --git a/tools/triage/mainwindow.cpp b/tools/triage/mainwindow.cpp index e8a15f87f3b..18b6bb09533 100644 --- a/tools/triage/mainwindow.cpp +++ b/tools/triage/mainwindow.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2021 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/tools/triage/mainwindow.h b/tools/triage/mainwindow.h index 38afcaf9553..263d9953e60 100644 --- a/tools/triage/mainwindow.h +++ b/tools/triage/mainwindow.h @@ -1,6 +1,6 @@ /* -*- C++ -*- * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2021 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/win_installer/config.wxi b/win_installer/config.wxi index 7bc613d1669..ae7fc8329f3 100644 --- a/win_installer/config.wxi +++ b/win_installer/config.wxi @@ -9,6 +9,6 @@ - + diff --git a/win_installer/cppcheck.wxs b/win_installer/cppcheck.wxs index e7b597e2046..91d08c1c946 100644 --- a/win_installer/cppcheck.wxs +++ b/win_installer/cppcheck.wxs @@ -107,6 +107,7 @@ + diff --git a/win_installer/productInfo.wxi b/win_installer/productInfo.wxi index f89e956dbb8..85e73ea3ca2 100644 --- a/win_installer/productInfo.wxi +++ b/win_installer/productInfo.wxi @@ -1,8 +1,8 @@ - + - +