diff --git a/.clang-tidy b/.clang-tidy index e1032aaa5f3..b83436861bd 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -18,18 +18,19 @@ Checks: > -objc-*, -openmp-*, -zircon-*, - cert-err34-c, cppcoreguidelines-pro-type-static-cast-downcast, cppcoreguidelines-rvalue-reference-param-not-moved, google-explicit-constructor, -bugprone-assignment-in-if-condition, -bugprone-branch-clone, + -bugprone-command-processor, -bugprone-easily-swappable-parameters, -bugprone-empty-catch, -bugprone-macro-parentheses, -bugprone-narrowing-conversions, -bugprone-signed-char-misuse, -bugprone-switch-missing-default-case, + -bugprone-throwing-static-initialization, -bugprone-unchecked-optional-access, -clang-analyzer-*, -concurrency-mt-unsafe, @@ -41,7 +42,9 @@ Checks: > -modernize-avoid-c-arrays, -modernize-deprecated-ios-base-aliases, -misc-include-cleaner, + -misc-multiple-inheritance, -misc-unused-using-decls, + -modernize-avoid-c-style-cast, -modernize-loop-convert, -modernize-macro-to-enum, -modernize-raw-string-literal, @@ -67,11 +70,14 @@ Checks: > -readability-identifier-length, -readability-identifier-naming, -readability-implicit-bool-conversion, + -readability-inconsistent-ifelse-braces, -readability-isolate-declaration, -readability-magic-numbers, + -readability-redundant-parentheses, -readability-suspicious-call-argument, -readability-uppercase-literal-suffix, - -readability-use-concise-preprocessor-directives + -readability-use-concise-preprocessor-directives, + -misc-unconventional-assign-operator WarningsAsErrors: '*' HeaderFilterRegex: '(cli|gui|frontend|lib|oss-fuzz|test|triage)\/[a-z_]+\.h' ExcludeHeaderFilterRegex: 'ui_.*.h' @@ -82,3 +88,7 @@ CheckOptions: value: '0' - key: modernize-use-trailing-return-type.TransformFunctions value: false + - key: misc-override-with-different-visibility.DisallowedVisibilityChange + value: widening + - key: misc-use-internal-linkage.AnalyzeTypes + value: false diff --git a/.github/workflows/CI-cygwin.yml b/.github/workflows/CI-cygwin.yml index 93a77d70c33..6b0ad2cc5bd 100644 --- a/.github/workflows/CI-cygwin.yml +++ b/.github/workflows/CI-cygwin.yml @@ -37,20 +37,21 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false - name: Set up Cygwin - uses: cygwin/cygwin-install-action@master + uses: cygwin/cygwin-install-action@v6 with: + site: https://mirrors.cicku.me/cygwin/ platform: ${{ matrix.platform }} packages: ${{ matrix.packages }} # Cygwin will always link the binaries even if they already exist. The linking is also extremely slow. So just run the "check" target which includes all the binaries. - name: Build all and run test run: | - C:\cygwin\bin\bash.exe -l -c cd %GITHUB_WORKSPACE% && make VERBOSE=1 -j%NUMBER_OF_PROCESSORS% check + C:\cygwin\bin\bash.exe -l -c cd %GITHUB_WORKSPACE% && make VERBOSE=1 -j%NUMBER_OF_PROCESSORS% CXXOPTS="-Werror" test - name: Extra test for misra run: | diff --git a/.github/workflows/CI-mingw.yml b/.github/workflows/CI-mingw.yml index fa7cfb1cfe5..f308cfa5110 100644 --- a/.github/workflows/CI-mingw.yml +++ b/.github/workflows/CI-mingw.yml @@ -33,7 +33,7 @@ jobs: timeout-minutes: 19 # max + 3*std of the last 7K runs steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -53,24 +53,23 @@ jobs: with: key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }} - # TODO: bail out on warning - name: Build cppcheck run: | export PATH="/mingw64/lib/ccache/bin:$PATH" # set RDYNAMIC to work around broken MinGW detection # use lld for faster linking - make VERBOSE=1 RDYNAMIC=-lshlwapi LDOPTS=-fuse-ld=lld -j$(nproc) cppcheck + make VERBOSE=1 RDYNAMIC=-lshlwapi LDOPTS=-fuse-ld=lld -j$(nproc) CXXOPTS="-Werror" cppcheck - name: Build test run: | export PATH="/mingw64/lib/ccache/bin:$PATH" # set RDYNAMIC to work around broken MinGW detection # use lld for faster linking - make VERBOSE=1 RDYNAMIC=-lshlwapi LDOPTS=-fuse-ld=lld -j$(nproc) testrunner + make VERBOSE=1 RDYNAMIC=-lshlwapi LDOPTS=-fuse-ld=lld -j$(nproc) CXXOPTS="-Werror" testrunner - name: Run test run: | export PATH="/mingw64/lib/ccache/bin:$PATH" # set RDYNAMIC to work around broken MinGW detection # use lld for faster linking - make VERBOSE=1 RDYNAMIC=-lshlwapi LDOPTS=-fuse-ld=lld -j$(nproc) check + make VERBOSE=1 RDYNAMIC=-lshlwapi LDOPTS=-fuse-ld=lld -j$(nproc) CXXOPTS="-Werror" test diff --git a/.github/workflows/CI-unixish-docker.yml b/.github/workflows/CI-unixish-docker.yml index a2013b439f9..adf4a74c81b 100644 --- a/.github/workflows/CI-unixish-docker.yml +++ b/.github/workflows/CI-unixish-docker.yml @@ -20,11 +20,16 @@ jobs: strategy: matrix: - image: ["ubuntu:24.04"] include: - - build_gui: false - image: "ubuntu:24.04" - build_gui: true + with_gui: true + full_build: true + - image: "ubuntu:25.10" + with_gui: true + full_build: true + - image: "alpine:3.23" + with_gui: false # it appears FindQt6.cmake is not provided by any package + full_build: false # FIXME: test-signalhandler.cpp fails to build since feenableexcept() is missing fail-fast: false # Prefer quick result runs-on: ubuntu-22.04 @@ -38,7 +43,7 @@ jobs: image: ${{ matrix.image }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -49,10 +54,15 @@ jobs: apt-get install -y cmake g++ make libxml2-utils libpcre3-dev - name: Install missing software (gui) on latest ubuntu - if: matrix.build_gui + if: contains(matrix.image, 'ubuntu') run: | apt-get install -y qt6-base-dev qt6-charts-dev qt6-tools-dev + - name: Install missing software on Alpine + if: contains(matrix.image, 'alpine') + run: | + apk add cmake make g++ pcre-dev + # needs to be called after the package installation since # - it doesn't call "apt-get update" - name: ccache @@ -60,18 +70,13 @@ jobs: with: key: ${{ github.workflow }}-${{ matrix.image }} - - name: CMake build - if: ${{ !matrix.build_gui }} + - name: Run CMake run: | - mkdir cmake.output - cd cmake.output - cmake -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache .. - cmake --build . -- -j$(nproc) + 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 (with GUI) - if: matrix.build_gui + - name: CMake build + if: matrix.full_build run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache cmake --build cmake.output -- -j$(nproc) - name: Run CMake test @@ -82,7 +87,7 @@ jobs: strategy: matrix: - image: ["ubuntu:24.04"] + image: ["ubuntu:24.04", "ubuntu:25.10", "alpine:3.23"] fail-fast: false # Prefer quick result runs-on: ubuntu-22.04 @@ -91,7 +96,7 @@ jobs: image: ${{ matrix.image }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -101,6 +106,11 @@ jobs: apt-get update apt-get install -y g++ make python3 libxml2-utils libpcre3-dev + - name: Install missing software on Alpine + if: contains(matrix.image, 'alpine') + run: | + apk add make g++ pcre-dev bash python3 libxml2-utils + # needs to be called after the package installation since # - it doesn't call "apt-get update" - name: ccache @@ -108,19 +118,21 @@ jobs: with: key: ${{ github.workflow }}-${{ matrix.image }} + # /usr/lib/ccache/bin - Alpine Linux + - name: Build cppcheck run: | - export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" - make -j$(nproc) HAVE_RULES=yes CXXOPTS="-w" + export PATH="/usr/lib/ccache/bin:/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + make -j$(nproc) HAVE_RULES=yes CXXOPTS="-Werror" - name: Build test run: | - export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" - make -j$(nproc) HAVE_RULES=yes CXXOPTS="-w" testrunner + export PATH="/usr/lib/ccache/bin:/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + make -j$(nproc) HAVE_RULES=yes CXXOPTS="-Werror" testrunner - name: Run test run: | - make -j$(nproc) HAVE_RULES=yes check + make -j$(nproc) HAVE_RULES=yes test # requires python3 - name: Run extra tests diff --git a/.github/workflows/CI-unixish.yml b/.github/workflows/CI-unixish.yml index 93b1ed4a04e..9bac980c853 100644 --- a/.github/workflows/CI-unixish.yml +++ b/.github/workflows/CI-unixish.yml @@ -30,7 +30,7 @@ jobs: CCACHE_SLOPPINESS: pch_defines,time_macros steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -58,13 +58,13 @@ jobs: - name: CMake build on ubuntu (with GUI / system tinyxml2) if: contains(matrix.os, 'ubuntu') run: | - cmake -S . -B cmake.output.tinyxml2 -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_BUNDLED_TINYXML2=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_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 -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_BUNDLED_TINYXML2=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_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) @@ -85,7 +85,7 @@ jobs: CCACHE_SLOPPINESS: pch_defines,time_macros steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -97,7 +97,7 @@ jobs: # TODO: move latest compiler to separate step # TODO: bail out on warnings with latest GCC - name: Set up GCC - uses: egor-tensin/setup-gcc@v1 + uses: egor-tensin/setup-gcc@v2 if: false # matrix.os == 'ubuntu-22.04' with: version: 13 @@ -127,12 +127,12 @@ jobs: - name: Run CMake on ubuntu (with GUI) if: contains(matrix.os, 'ubuntu') run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_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 -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=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 -G "Unix Makefiles" -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 -G "Unix Makefiles" -DBUILD_TESTS=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 -G "Unix Makefiles" -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 -G "Unix Makefiles" -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 -G "Unix Makefiles" -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,70 @@ jobs: - name: Run CMake on ubuntu (no CLI / no GUI) if: matrix.os == 'ubuntu-22.04' run: | - cmake -S . -B cmake.output_nocli_nogui -G "Unix Makefiles" -DBUILD_GUI=Off + cmake -S . -B cmake.output_nocli_nogui -Werror=dev --warn-uninitialized -DBUILD_TESTING=Off -DBUILD_GUI=Off + + build_cmake_cxxstd: + + strategy: + matrix: + os: [ubuntu-22.04, macos-15] + cxxstd: [14, 17, 20] + # FIXME: macos-15 fails to compile with C++20 + # + # /Users/runner/work/cppcheck/cppcheck/cmake.output/gui/test/projectfile/moc_testprojectfile.cpp:84:1: error: 'constinit' specifier is incompatible with C++ standards before C++20 [-Werror,-Wc++20-compat] + # 84 | Q_CONSTINIT const QMetaObject TestProjectFile::staticMetaObject = { { + # | ^ + # /opt/homebrew/opt/qt/lib/QtCore.framework/Headers/qcompilerdetection.h:1409:23: note: expanded from macro 'Q_CONSTINIT' + exclude: + - os: macos-15 + cxxstd: 20 + fail-fast: false # Prefer quick result + + runs-on: ${{ matrix.os }} + + env: + # TODO: figure out why there are cache misses with PCH enabled + CCACHE_SLOPPINESS: pch_defines,time_macros + + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }}-${{ matrix.cxxstd }} + + - name: Install missing software on ubuntu + if: contains(matrix.os, 'ubuntu') + run: | + sudo apt-get update + sudo apt-get install libxml2-utils + # qt6-tools-dev-tools for lprodump + # qt6-l10n-tools for lupdate + sudo apt-get install qt6-base-dev libqt6charts6-dev qt6-tools-dev qt6-tools-dev-tools qt6-l10n-tools libglx-dev libgl1-mesa-dev + + # coreutils contains "nproc" + - name: Install missing software on macos + if: contains(matrix.os, 'macos') + run: | + # pcre was removed from runner images in November 2022 + brew install coreutils qt@6 pcre + + - name: Run CMake on ubuntu (with GUI) + if: contains(matrix.os, 'ubuntu') + run: | + 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 --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: | + cmake --build cmake.output -- -j$(nproc) build_uchar: @@ -201,7 +265,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -219,7 +283,7 @@ jobs: - name: Build with Unsigned char run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" - make -j$(nproc) CXXOPTS=-funsigned-char testrunner + make -j$(nproc) CXXOPTS="-Werror -funsigned-char" testrunner - name: Test with Unsigned char run: | @@ -235,7 +299,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -253,11 +317,11 @@ jobs: - name: Build with TEST_MATHLIB_VALUE run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" - make -j$(nproc) CPPOPTS=-DTEST_MATHLIB_VALUE all + make -j$(nproc) CXXOPTS="-Werror" CPPOPTS=-DTEST_MATHLIB_VALUE all - name: Test with TEST_MATHLIB_VALUE run: | - make -j$(nproc) CPPOPTS=-DTEST_MATHLIB_VALUE check + make -j$(nproc) test check_nonneg: @@ -269,7 +333,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -281,7 +345,7 @@ jobs: - name: Check syntax with NONNEG run: | - make check-nonneg + make check-nonneg CXXOPTS="-Werror" build_cmake_boost: @@ -297,7 +361,7 @@ jobs: CCACHE_SLOPPINESS: pch_defines,time_macros steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -310,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 -G "Unix Makefiles" -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 @@ -323,12 +387,12 @@ jobs: - name: Run CMake on macOS (force Boost) run: | - cmake -S . -B cmake.output.boost-force -G "Unix Makefiles" -DUSE_BOOST=On + cmake -S . -B cmake.output.boost-force -Werror=dev --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 -G "Unix Makefiles" -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 @@ -337,13 +401,51 @@ jobs: - name: Run CMake on macOS (with Boost) run: | - cmake -S . -B cmake.output.boost -G "Unix Makefiles" -DBUILD_TESTS=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_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) run: | cmake --build cmake.output.boost -- -j$(nproc) + build_cmake_minimum: # TODO: move to docker workflow? + + runs-on: ubuntu-22.04 # use the oldest available runner + + env: + CMAKE_VERSION: 3.22 + CMAKE_VERSION_FULL: 3.22.6 + + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + + - name: Install missing software + run: | + sudo apt-get update + sudo apt-get install libxml2-utils + # qt6-tools-dev-tools for lprodump + # qt6-l10n-tools for lupdate + sudo apt-get install qt6-base-dev libqt6charts6-dev qt6-tools-dev qt6-tools-dev-tools qt6-l10n-tools libglx-dev libgl1-mesa-dev + + - name: Install CMake + run: | + wget https://cmake.org/files/v${{ env.CMAKE_VERSION }}/cmake-${{ env.CMAKE_VERSION_FULL }}-linux-x86_64.tar.gz + tar xf cmake-${{ env.CMAKE_VERSION_FULL }}-linux-x86_64.tar.gz + + - name: Run CMake (without GUI) + run: | + export PATH=cmake-${{ env.CMAKE_VERSION_FULL }}-linux-x86_64/bin:$PATH + # 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: strategy: @@ -359,7 +461,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -412,16 +514,16 @@ jobs: - name: Build cppcheck run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" - make -j$(nproc) HAVE_RULES=yes + make -j$(nproc) CXXOPTS="-Werror" HAVE_RULES=yes - name: Build test run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" - make -j$(nproc) HAVE_RULES=yes testrunner + make -j$(nproc) CXXOPTS="-Werror" HAVE_RULES=yes testrunner - name: Run test run: | - make -j$(nproc) HAVE_RULES=yes check + make -j$(nproc) HAVE_RULES=yes test # requires "gnu-sed" installed on macos - name: Run extra tests @@ -497,7 +599,7 @@ jobs: - name: Test Signalhandler run: | - cmake -S . -B build.cmake.signal -G "Unix Makefiles" -DBUILD_TESTS=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* . @@ -508,7 +610,7 @@ jobs: - name: Test Stacktrace if: contains(matrix.os, 'ubuntu') run: | - cmake -S . -B build.cmake.stack -G "Unix Makefiles" -DBUILD_TESTS=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* . @@ -571,6 +673,28 @@ jobs: warnings="-pedantic -Wall -Wextra -Wcast-qual -Wno-deprecated-declarations -Wfloat-equal -Wmissing-declarations -Wmissing-format-attribute -Wno-long-long -Wpacked -Wredundant-decls -Wundef -Wno-shadow -Wno-missing-field-initializers -Wno-missing-braces -Wno-sign-compare -Wno-multichar" g++ $warnings -c -Ilib -Iexternals/tinyxml2 democlient/democlient.cpp + - name: Test disabled executors + if: matrix.os == 'ubuntu-22.04' + run: | + g++ -Ilib -c cli/threadexecutor.cpp -DDISALLOW_THREAD_EXECUTOR + test -z "$(nm threadexecutor.o)" + g++ -Ilib -c cli/processexecutor.cpp -DDISALLOW_PROCESS_EXECUTOR + test -z "$(nm processexecutor.o)" + # TODO: test NO_* defines + + - name: Test execinfo.h detection + run: | + make clean + make cli/stacktrace.o | grep HAVE_EXECINFO_H=1 + test -n "$(nm cli/stacktrace.o)" + + - name: Test testrunner inclusion/exclusion + run: | + ! ./testrunner -d TestUtils | grep -v TestUtils > /dev/null + ! ./testrunner -d TestUtils::trim | grep -v TestUtils::trim > /dev/null + ! ./testrunner -d -x TestUtils | grep TestUtils > /dev/null + ! ./testrunner -d -x TestUtils:trim | grep TestUtils:trim > /dev/null + - name: Show all ignored files if: false # TODO: currently lists all the contents of ignored folders - we only need what actually matched run: | @@ -588,7 +712,7 @@ jobs: runs-on: ubuntu-22.04 # run on the latest image only steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -609,11 +733,11 @@ jobs: run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" # compile with verification and ast matchers - make -j$(nproc) CXXOPTS="-g -O2 -w" CPPOPTS="-DCHECK_INTERNAL -DHAVE_BOOST" MATCHCOMPILER=yes VERIFY=1 + make -j$(nproc) CXXOPTS="-Werror -g -O2" CPPOPTS="-DCHECK_INTERNAL -DHAVE_BOOST" MATCHCOMPILER=yes VERIFY=1 - name: CMake run: | - cmake -S . -B cmake.output -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_MATCHCOMPILER=Verify -DENABLE_CHECK_INTERNAL=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On + cmake -S . -B cmake.output -Werror=dev --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: | @@ -623,30 +747,4 @@ jobs: - name: Self check run: | - selfcheck_options="-q -j$(nproc) --std=c++11 --template=selfcheck --showtime=file-total -D__GNUC__ --error-exitcode=1 --inline-suppr --suppressions-list=.selfcheck_suppressions --library=gnu --inconclusive --enable=style,performance,portability,warning,missingInclude --exception-handling --debug-warnings --check-level=exhaustive" - cppcheck_options="-D__CPPCHECK__ -DCHECK_INTERNAL -DHAVE_RULES --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2" - ec=0 - - # TODO: add --check-config - - # early exit - if [ $ec -eq 1 ]; then - exit $ec - fi - - # self check externals - ./cppcheck $selfcheck_options externals || ec=1 - # self check lib/cli - mkdir b1 - ./cppcheck $selfcheck_options $cppcheck_options --cppcheck-build-dir=b1 --addon=naming.json frontend || ec=1 - ./cppcheck $selfcheck_options $cppcheck_options --cppcheck-build-dir=b1 --addon=naming.json -Ifrontend cli || ec=1 - ./cppcheck $selfcheck_options $cppcheck_options --cppcheck-build-dir=b1 --addon=naming.json --enable=internal lib || ec=1 - # check gui with qt settings - mkdir b2 - ./cppcheck $selfcheck_options $cppcheck_options --cppcheck-build-dir=b2 -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB --library=qt --addon=naming.json -Icmake.output/gui -Ifrontend -Igui gui/*.cpp cmake.output/gui || ec=1 - # self check test and tools - ./cppcheck $selfcheck_options $cppcheck_options -Ifrontend -Icli test/*.cpp || ec=1 - ./cppcheck $selfcheck_options $cppcheck_options -Icli tools/dmake/*.cpp || ec=1 - # triage - ./cppcheck $selfcheck_options $cppcheck_options -DQ_MOC_OUTPUT_REVISION=68 -DQT_CHARTS_LIB --library=qt -Icmake.output/tools/triage -Igui tools/triage/*.cpp cmake.output/tools/triage || ec=1 - exit $ec + ./selfcheck.sh diff --git a/.github/workflows/CI-windows.yml b/.github/workflows/CI-windows.yml index 3cf7d66a8fc..66858c7afbe 100644 --- a/.github/workflows/CI-windows.yml +++ b/.github/workflows/CI-windows.yml @@ -19,21 +19,19 @@ defaults: run: shell: cmd -# TODO: choose/add a step to bail out on compiler warnings (maybe even the release build) - jobs: build_qt: strategy: matrix: os: [windows-2022, windows-2025] - qt_ver: [6.9.1] + qt_ver: [6.10.0] fail-fast: false runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -49,29 +47,98 @@ 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 -DCMAKE_BUILD_TYPE=Release -DCMAKE_COMPILE_WARNING_AS_ERROR=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DBUILD_ONLINE_HELP=On -DCMAKE_INSTALL_PREFIX=cppcheck-cmake-install || 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: + matrix: + os: [windows-2022, windows-2025] + cxxstd: [14, 17, 20] + fail-fast: false + + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + + - name: Set up Visual Studio environment + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64 + + - name: Run CMake + run: | + 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: | + cmake --build build.cxxstd --config Debug || exit /b !errorlevel! + + build_cmake_minimum: + + runs-on: windows-2022 # use the oldest available runner + + env: + CMAKE_VERSION: 3.22 + CMAKE_VERSION_FULL: 3.22.6 + + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + + - name: Install CMake + run: | + curl -fsSL https://cmake.org/files/v${{ env.CMAKE_VERSION }}/cmake-${{ env.CMAKE_VERSION_FULL }}-windows-x86_64.zip -o cmake.zip || exit /b !errorlevel! + 7z x cmake.zip || exit /b !errorlevel! + + - name: Set up Visual Studio environment + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64 + + - name: Install Qt + uses: jurplel/install-qt-action@v4 + with: + version: 6.10.0 + modules: 'qtcharts' + setup-python: 'false' + cache: true + + - name: Run CMake (without GUI) + run: | + :: TODO: enable DHAVE_RULES? + cmake-${{ env.CMAKE_VERSION_FULL }}-windows-x86_64\bin\cmake.exe -S . -B cmake.output -A x64 -DHAVE_RULES=Off -DBUILD_TESTING=On + + - name: Run CMake (with GUI) + run: | + :: TODO: enable DHAVE_RULES? + cmake-${{ env.CMAKE_VERSION_FULL }}-windows-x86_64\bin\cmake.exe -S . -B cmake.output.gui -A x64 -DHAVE_RULES=Off -DBUILD_TESTING=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On build: strategy: @@ -87,15 +154,15 @@ jobs: PCRE_VERSION: 8.45 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false - - name: Set up Python 3.13 + - name: Set up Python if: matrix.config == 'release' - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: - python-version: '3.13' + python-version: '3.14' check-latest: true - name: Set up Visual Studio environment @@ -105,7 +172,7 @@ jobs: - name: Cache PCRE id: cache-pcre - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | externals\pcre.h @@ -125,7 +192,7 @@ jobs: 7z x pcre-%PCRE_VERSION%.zip || exit /b !errorlevel! cd pcre-%PCRE_VERSION% || exit /b !errorlevel! git apply --ignore-space-change ..\externals\pcre.patch || exit /b !errorlevel! - cmake . -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DPCRE_BUILD_PCRECPP=Off -DPCRE_BUILD_TESTS=Off -DPCRE_BUILD_PCREGREP=Off -DCMAKE_POLICY_VERSION_MINIMUM=3.5 || exit /b !errorlevel! + cmake . -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DPCRE_BUILD_PCRECPP=Off -DPCRE_BUILD_TESTS=Off -DPCRE_BUILD_PCREGREP=Off -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_COMPILE_WARNING_AS_ERROR=On || exit /b !errorlevel! nmake || exit /b !errorlevel! copy pcre.h ..\externals || exit /b !errorlevel! copy pcre.lib ..\externals\pcre64.lib || exit /b !errorlevel! @@ -142,8 +209,6 @@ jobs: python -m pip install pytest-xdist || exit /b !errorlevel! python -m pip install psutil || exit /b !errorlevel! - # TODO: build with CMake - - name: Build CLI debug configuration using MSBuild if: matrix.config == 'debug' run: | @@ -154,7 +219,7 @@ jobs: - name: Run Debug test if: matrix.config == 'debug' - run: .\bin\debug\testrunner.exe || exit /b !errorlevel! + run: .\bin\debug\testrunner.exe -t || exit /b !errorlevel! - name: Build CLI release configuration using MSBuild if: matrix.config == 'release' @@ -207,7 +272,7 @@ jobs: - name: Test SEH wrapper if: matrix.config == 'release' run: | - cmake -S . -B build.cmake.seh -DBUILD_TESTS=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/asan.yml b/.github/workflows/asan.yml deleted file mode 100644 index 439ebddf372..00000000000 --- a/.github/workflows/asan.yml +++ /dev/null @@ -1,155 +0,0 @@ -# Syntax reference https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions -# Environment reference https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners -name: address sanitizer - -on: - push: - branches: - - 'main' - - 'releases/**' - - '2.*' - tags: - - '2.*' - pull_request: - -permissions: - contents: read - -jobs: - build: - - runs-on: ubuntu-22.04 - - env: - QT_VERSION: 6.9.1 - ASAN_OPTIONS: detect_stack_use_after_return=1 - # TODO: figure out why there are cache misses with PCH enabled - CCACHE_SLOPPINESS: pch_defines,time_macros - - steps: - - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }} - - - name: Set up Python 3.13 - uses: actions/setup-python@v5 - with: - python-version: '3.13' - check-latest: true - - - name: Install missing software on ubuntu - run: | - sudo apt-get update - sudo apt-get install -y cmake make libpcre3-dev libboost-container-dev libxml2-utils - sudo apt-get install -y libcups2-dev # required for Qt6PrintSupport in CMake since Qt 6.7.3 - - - name: Install clang - run: | - sudo apt-get purge --auto-remove llvm python3-lldb-14 llvm-14 - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - sudo ./llvm.sh 21 - - - name: Install Qt ${{ env.QT_VERSION }} - uses: jurplel/install-qt-action@v4 - with: - version: ${{ env.QT_VERSION }} - modules: 'qtcharts' - setup-python: 'false' - cache: true - - - name: Install missing Python packages - run: | - python3 -m pip install pip --upgrade - python3 -m pip install pytest - python3 -m pip install pytest-timeout - python3 -m pip install pytest-xdist - python3 -m pip install psutil - - # TODO: disable all warnings - - name: CMake - run: | - cmake -S . -B cmake.output -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_MATCHCOMPILER=Verify -DANALYZE_ADDRESS=On -DENABLE_CHECK_INTERNAL=On -DUSE_BOOST=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DFILESDIR= -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - env: - CC: clang-21 - CXX: clang++-21 - - - name: Build cppcheck - run: | - cmake --build cmake.output --target cppcheck -- -j $(nproc) - - - name: Build test - run: | - cmake --build cmake.output --target testrunner -- -j $(nproc) - - - name: Build GUI tests - run: | - cmake --build cmake.output --target gui-tests -- -j $(nproc) - - - name: Run tests - run: ./cmake.output/bin/testrunner - - - name: Run cfg tests - run: | - cmake --build cmake.output --target checkcfg -- -j $(nproc) - - - name: Run CTest - run: | - ctest --test-dir cmake.output --output-on-failure -j$(nproc) - - - name: Run test/cli - run: | - pwd=$(pwd) - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv -n auto test/cli - - - name: Run test/cli (-j2) - run: | - pwd=$(pwd) - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv -n auto test/cli - env: - TEST_CPPCHECK_INJECT_J: 2 - - - name: Run test/cli (--clang) - if: false - run: | - pwd=$(pwd) - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv -n auto test/cli - env: - TEST_CPPCHECK_INJECT_CLANG: clang - - - name: Run test/cli (--cppcheck-build-dir) - run: | - pwd=$(pwd) - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv -n auto test/cli - env: - TEST_CPPCHECK_INJECT_BUILDDIR: injected - - - name: Generate dependencies - if: false - run: | - # make sure auto-generated GUI files exist - make -C cmake.output autogen - make -C cmake.output gui-build-deps triage-build-ui-deps - - # TODO: this is currently way too slow (~60 minutes) to enable it - # TODO: only fail the step on sanitizer issues - since we use processes it will only fail the underlying process which will result in an cppcheckError - - name: Self check - if: false - run: | - selfcheck_options="-q -j$(nproc) --std=c++11 --template=selfcheck --showtime=file-total -D__GNUC__ --error-exitcode=1 --inline-suppr --suppressions-list=.selfcheck_suppressions --library=gnu --inconclusive --enable=style,performance,portability,warning,missingInclude --exception-handling --debug-warnings --check-level=exhaustive" - cppcheck_options="-D__CPPCHECK__ -DCHECK_INTERNAL -DHAVE_RULES --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2" - ec=0 - ./cmake.output/bin/cppcheck $selfcheck_options externals || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json frontend || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json -Ifrontend cli || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json --enable=internal lib || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --library=qt --addon=naming.json -Icmake.output/gui -Ifrontend -Igui gui/*.cpp cmake.output/gui/*.cpp || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -Icli -Ifrontend test/*.cpp || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -Icli tools/dmake/*.cpp || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --library=qt -Icmake.output/tools/triage -Igui tools/triage/*.cpp cmake.output/tools/triage/*.cpp || ec=1 - exit $ec diff --git a/.github/workflows/buildman.yml b/.github/workflows/buildman.yml index b0b399dd851..e84cf4bffd9 100644 --- a/.github/workflows/buildman.yml +++ b/.github/workflows/buildman.yml @@ -19,7 +19,7 @@ jobs: convert_via_pandoc: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -38,7 +38,7 @@ jobs: with: args: --output=output/manual-premium.pdf man/manual-premium.md - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: output path: output @@ -46,7 +46,7 @@ jobs: manpage: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -59,7 +59,7 @@ jobs: run: | make man - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: cppcheck.1 path: cppcheck.1 diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index 7b462c688f0..400fb929786 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -10,7 +10,7 @@ permissions: jobs: Fuzzing: runs-on: ubuntu-latest - if: ${{ github.repository_owner == 'danmar' }} + if: ${{ github.repository_owner == 'cppcheck-opensource' }} steps: - name: Build Fuzzers id: build @@ -27,7 +27,7 @@ jobs: dry-run: false language: c++ - name: Upload Crash - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: failure() && steps.build.outcome == 'success' with: name: artifacts diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index 574939e29eb..4f2db4ab113 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -24,10 +24,10 @@ jobs: runs-on: ubuntu-22.04 env: - QT_VERSION: 6.9.1 + QT_VERSION: 6.10.0 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -43,8 +43,8 @@ jobs: sudo apt-get purge --auto-remove llvm python3-lldb-14 llvm-14 wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh - sudo ./llvm.sh 21 - sudo apt-get install -y clang-tidy-21 + sudo ./llvm.sh 22 + sudo apt-get install -y clang-tidy-22 - name: Install Qt ${{ env.QT_VERSION }} uses: jurplel/install-qt-action@v4 @@ -57,14 +57,14 @@ jobs: - name: Verify clang-tidy configuration run: | - clang-tidy-21 --verify-config + clang-tidy-22 --verify-config - name: Prepare CMake run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCPPCHK_GLIBCXX_DEBUG=Off -DWARNINGS_ARE_ERRORS=On + cmake -S . -B cmake.output -Werror=dev --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-21 - CXX: clang++-21 + CC: clang-22 + CXX: clang++-22 - name: Prepare CMake dependencies run: | @@ -86,7 +86,7 @@ jobs: run: | cmake --build cmake.output --target run-clang-tidy-csa 2> /dev/null - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: success() || failure() with: name: Compilation Database diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 185ebe139c6..84d37423d2e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -33,20 +33,20 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: persist-credentials: false # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} - name: Build cppcheck if: matrix.language == 'cpp' run: | - make -j$(nproc) HAVE_RULES=yes cppcheck + make -j$(nproc) CXXOPTS="-Werror" HAVE_RULES=yes CPPCHK_GLIBCXX_DEBUG= cppcheck - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/corpus.yml b/.github/workflows/corpus.yml new file mode 100644 index 00000000000..2d9f1424fad --- /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@v6 + 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@v7 + if: success() + with: + name: corpus + path: ./store diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index c515157cde5..b5e496adcf6 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -43,7 +43,7 @@ jobs: - name: Compile instrumented run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" - make -j$(nproc) CXXOPTS="-g -fprofile-arcs -ftest-coverage" HAVE_RULES=yes all + make -j$(nproc) CXXOPTS="-Werror -g -fprofile-arcs -ftest-coverage" HAVE_RULES=yes CPPCHK_GLIBCXX_DEBUG= all - name: Run instrumented tests run: | @@ -57,12 +57,12 @@ jobs: lcov --extract lcov_tmp.info "$(pwd)/*" --output-file lcov.info genhtml lcov.info -o coverage_report --frame --legend --demangle-cpp - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: Coverage results path: coverage_report - - uses: codecov/codecov-action@v4 + - uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} # file: ./coverage.xml # optional diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index 3c07b61d7c7..4c62971e4c4 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -12,9 +12,9 @@ permissions: jobs: scan: runs-on: ubuntu-latest - if: ${{ github.repository_owner == 'danmar' }} + if: ${{ github.repository_owner == 'cppcheck-opensource' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false - name: Install missing software on ubuntu diff --git a/.github/workflows/cppcheck-premium.yml b/.github/workflows/cppcheck-premium.yml index 546858e5de3..b99cccd69da 100644 --- a/.github/workflows/cppcheck-premium.yml +++ b/.github/workflows/cppcheck-premium.yml @@ -25,16 +25,15 @@ jobs: build: runs-on: ubuntu-24.04 # run on the latest image only steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false - name: Download cppcheckpremium release - if: false run: | premium_version=${{ inputs.premium_version }} if [ -z $premium_version ]; then - premium_version=24.11.0 + premium_version=26.3.0 #wget https://files.cppchecksolutions.com/devdrop/cppcheckpremium-$premium_version-amd64.tar.gz -O cppcheckpremium.tar.gz wget https://files.cppchecksolutions.com/$premium_version/ubuntu-24.04/cppcheckpremium-$premium_version-amd64.tar.gz -O cppcheckpremium.tar.gz else @@ -43,21 +42,12 @@ jobs: tar xzf cppcheckpremium.tar.gz mv cppcheckpremium-$premium_version cppcheckpremium - - name: Download cppcheckpremium devdrop - run: | - wget https://files.cppchecksolutions.com/devdrop/cppcheckpremium-devdrop-20250713-amd64.tar.gz -O cppcheckpremium.tar.gz - tar xzvf cppcheckpremium.tar.gz - mv cppcheckpremium-devdrop-20250713 cppcheckpremium - # Overwrite cppcheck binary - make -j$(nproc) CXXOPTS=-O2 MATCHCOMPILER=yes - cp cppcheck cppcheckpremium/ - - name: Generate a license file run: | echo cppcheck > cppcheck.lic - echo 251231 >> cppcheck.lic + echo 261231 >> cppcheck.lic echo 80000 >> cppcheck.lic - echo 4f8dc8e7c8bb288f >> cppcheck.lic + echo 4b64673f03fb6230 >> cppcheck.lic echo path:lib >> cppcheck.lic - name: Check @@ -70,13 +60,13 @@ jobs: #sed -i 's|"security-severity":.*||' results.sarif cat results.sarif - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: results path: results.sarif - name: Upload report - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@v4 with: sarif_file: results.sarif category: cppcheckpremium diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index fd491c0ec0e..4ec72f935fd 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -24,12 +24,12 @@ jobs: UNCRUSTIFY_VERSION: 0.80.1 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false - name: Cache uncrustify - uses: actions/cache@v4 + uses: actions/cache@v5 id: cache-uncrustify with: path: | diff --git a/.github/workflows/gcc-versions.yml b/.github/workflows/gcc-versions.yml new file mode 100644 index 00000000000..3402bade743 --- /dev/null +++ b/.github/workflows/gcc-versions.yml @@ -0,0 +1,39 @@ +# the purpose of this github action is to test that cppcheck source code can be compiled using old gcc versions. +# the gcc images we use here are copied from the official gcc images on docker hub + +name: gcc-versions + +on: + push: + branches: + - 'main' + - 'releases/**' + - '2.*' + tags: + - '2.*' + pull_request: + +permissions: + contents: read + +jobs: + build: + + strategy: + matrix: + #image: ["ghcr.io/cppcheck-opensource/gcc:5.4", "ghcr.io/cppcheck-opensource/gcc:6.5", "ghcr.io/cppcheck-opensource/gcc:7.5", "ghcr.io/cppcheck-opensource/gcc:8.5", "ghcr.io/cppcheck-opensource/gcc:9.5"] + image: ["ghcr.io/cppcheck-opensource/gcc:5.4"] + fail-fast: false + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Build cppcheck + run: | + # FIXME: simplecpp-1.8.0 can't be compiled with gcc 5.4, so we can't run 'make test' now + #docker run --rm -v ${{ github.workspace }}:/cppcheck -w /cppcheck ${{ matrix.image }} make -j$(nproc) CXXOPTS="-Werror" test + docker run --rm -v ${{ github.workspace }}:/cppcheck -w /cppcheck ${{ matrix.image }} g++ -fsyntax-only -Iexternals -Iexternals/picojson -Iexternals/simplecpp -Iexternals/tinyxml2 -std=c++11 -Wno-multichar lib/*.cpp diff --git a/.github/workflows/iwyu.yml b/.github/workflows/iwyu.yml index 847f1f734dd..2e54b92541e 100644 --- a/.github/workflows/iwyu.yml +++ b/.github/workflows/iwyu.yml @@ -15,34 +15,31 @@ jobs: strategy: matrix: - # "opensuse/tumbleweed:latest" / "fedora:latest" / "debian:unstable" / "archlinux:latest" + # "opensuse/tumbleweed:latest" / "fedora:rawhide" / "debian:unstable" / "archlinux:latest" include: - os: ubuntu-22.04 - image: "fedora:latest" + image: "fedora:rawhide" stdlib: libstdc++ - clang_inc: '-isystem/usr/lib/clang/20/include' - # TODO: disable because it currently fails with "error: tried including but didn't find libc++'s header." - #- os: ubuntu-22.04 - # image: "fedora:latest" - # stdlib: libc++ - # clang_inc: '-isystem/usr/lib/clang/20/include' - - os: macos-13 + - os: ubuntu-22.04 + image: "fedora:rawhide" + stdlib: libc++ + - os: macos-26 image: "" stdlib: libc++ # no libstdc++ on macOS mapping_file_opt: '-Xiwyu --mapping_file=$(realpath ./macos.imp)' fail-fast: false runs-on: ${{ matrix.os }} - if: ${{ github.repository_owner == 'danmar' }} + if: ${{ github.repository_owner == 'cppcheck-opensource' }} container: image: ${{ matrix.image }} env: - QT_VERSION: 6.9.1 + QT_VERSION: 6.10.0 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -74,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 @@ -100,18 +97,21 @@ jobs: if: contains(matrix.os, 'macos') run: | brew install include-what-you-use pcre coreutils - ln -s iwyu_tool.py /usr/local/bin/iwyu_tool + # on Apple Silicon files are symlinked under /opt/homebrew/bin + ln -s /opt/homebrew/bin/iwyu_tool.py /usr/local/bin/iwyu_tool # Fails on OpenSUSE: # Warning: Failed to restore: Tar failed with error: Unable to locate executable file: tar. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also check the file mode to verify the file is executable. # Also the shell is broken afterwards: # OCI runtime exec failed: exec failed: unable to start container process: exec: "sh": executable file not found in $PATH: unknown + # + # On macos-26 we need to perform the Python setup because the default installation is managed externally managed - name: Install Qt ${{ env.QT_VERSION }} uses: jurplel/install-qt-action@v4 with: version: ${{ env.QT_VERSION }} modules: 'qtcharts' - setup-python: 'false' + setup-python: ${{ contains(matrix.os, 'macos') }} install-deps: false cache: true @@ -125,7 +125,8 @@ jobs: - name: Prepare CMake run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off -DEXTERNALS_AS_SYSTEM=On -DUSE_LIBCXX=${{ matrix.stdlib == 'libc++' }} + # 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++ @@ -147,8 +148,7 @@ jobs: - name: iwyu_tool run: | - # TODO: remove -stdlib= - it should have been taken from the compilation database - iwyu_tool -p cmake.output -j $(nproc) -- -w -Xiwyu --max_line_length=1024 -Xiwyu --comment_style=long -Xiwyu --quoted_includes_first -Xiwyu --update_comments -stdlib=${{ matrix.stdlib }} ${{ matrix.mapping_file_opt }} ${{ matrix.clang_inc }} > iwyu.log + iwyu_tool -p cmake.output -j $(nproc) -- -w -Xiwyu --max_line_length=1024 -Xiwyu --comment_style=long -Xiwyu --quoted_includes_first -Xiwyu --update_comments ${{ matrix.mapping_file_opt }} ${{ matrix.clang_inc }} > iwyu.log # TODO: run with all configurations - name: test/cfg @@ -160,13 +160,13 @@ jobs: IWYU: include-what-you-use IWYU_CLANG_INC: ${{ matrix.clang_inc }} - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: success() || failure() with: name: Compilation Database (include-what-you-use - ${{ matrix.os }} ${{ matrix.stdlib }}) path: ./cmake.output/compile_commands.json - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: ${{ contains(matrix.os, 'macos') && (success() || failure()) }} with: name: macOS Mappings @@ -174,7 +174,7 @@ jobs: ./iwyu-mapgen-apple-libc.py ./macos.imp - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: success() || failure() with: name: Logs (include-what-you-use - ${{ matrix.os }} ${{ matrix.stdlib }}) @@ -193,13 +193,13 @@ jobs: fail-fast: false runs-on: ubuntu-22.04 - if: ${{ github.repository_owner == 'danmar' }} + if: ${{ github.repository_owner == 'cppcheck-opensource' }} env: - QT_VERSION: 6.9.1 + QT_VERSION: 6.10.0 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -214,13 +214,13 @@ jobs: sudo apt-get purge --auto-remove llvm python3-lldb-14 llvm-14 wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh - sudo ./llvm.sh 21 - sudo apt-get install -y clang-tools-21 + sudo ./llvm.sh 22 + sudo apt-get install -y clang-tools-22 - name: Install libc++ if: matrix.stdlib == 'libc++' run: | - sudo apt-get install -y libc++-21-dev + sudo apt-get install -y libc++-22-dev - name: Install Qt ${{ env.QT_VERSION }} uses: jurplel/install-qt-action@v4 @@ -233,10 +233,11 @@ jobs: - name: Prepare CMake run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off -DEXTERNALS_AS_SYSTEM=On -DUSE_LIBCXX=${{ matrix.use_libcxx }} + # 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-21 - CXX: clang++-21 + CC: clang-22 + CXX: clang++-22 - name: Prepare CMake dependencies run: | @@ -253,15 +254,15 @@ jobs: - name: clang-include-cleaner run: | # TODO: run multi-threaded - find $PWD/cli $PWD/lib $PWD/test $PWD/gui -maxdepth 1 -name "*.cpp" | xargs -t -n 1 clang-include-cleaner-21 --print=changes --extra-arg=-w --extra-arg=-stdlib=${{ matrix.stdlib }} -p cmake.output > clang-include-cleaner.log 2>&1 + find $PWD/cli $PWD/lib $PWD/test $PWD/gui -maxdepth 1 -name "*.cpp" | xargs -t -n 1 clang-include-cleaner-22 --print=changes --extra-arg=-w --extra-arg=-stdlib=${{ matrix.stdlib }} -p cmake.output > clang-include-cleaner.log 2>&1 - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: success() || failure() with: name: Compilation Database (clang-include-cleaner - ${{ matrix.stdlib }}) path: ./cmake.output/compile_commands.json - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: success() || failure() with: name: Logs (clang-include-cleaner - ${{ matrix.stdlib }}) diff --git a/.github/workflows/release-windows-mingw.yml b/.github/workflows/release-windows-mingw.yml new file mode 100644 index 00000000000..8085990e39d --- /dev/null +++ b/.github/workflows/release-windows-mingw.yml @@ -0,0 +1,69 @@ +# 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: release-windows-mingw + +on: + push: + branches: + - 'main' + - 'releases/**' + - '2.*' + tags: + - '2.*' + pull_request: + +permissions: + contents: read + +defaults: + run: + shell: msys2 {0} + +jobs: + # TODO: add CMake build + build_mingw: + strategy: + matrix: + # only use the latest windows-* as the installed toolchain is identical + os: [windows-2025] + fail-fast: false + + runs-on: ${{ matrix.os }} + + timeout-minutes: 19 # max + 3*std of the last 7K runs + + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + + - name: Set up MSYS2 + uses: msys2/setup-msys2@v2 + with: + release: false # use pre-installed + # TODO: install mingw-w64-x86_64-make and use mingw32.make instead - currently fails with "Windows Subsystem for Linux has no installed distributions." + install: >- + mingw-w64-x86_64-lld + make + mingw-w64-x86_64-gcc + python + + - name: Build cppcheck + run: | + export PATH="/mingw64/lib/ccache/bin:$PATH" + # set RDYNAMIC to work around broken MinGW detection + make VERBOSE=1 RDYNAMIC=-lshlwapi -j$(nproc) CXXFLAGS=-O2 MATCHCOMPILER=yes cppcheck + + - name: Package + run: | + mkdir cppcheck-mingw + cp cppcheck.exe cppcheck-mingw/ + cp -R cfg platforms cppcheck-mingw/ + cp /mingw64/bin/libgcc_s_seh-1.dll cppcheck-mingw/ + cp /mingw64/bin/libstdc*.dll cppcheck-mingw/ + cp /mingw64/bin/libwinpthread-1.dll cppcheck-mingw/ + + - uses: actions/upload-artifact@v7 + with: + name: cppcheck-mingw + path: cppcheck-mingw diff --git a/.github/workflows/release-windows.yml b/.github/workflows/release-windows.yml index 4c901d8d42a..aa467d7b875 100644 --- a/.github/workflows/release-windows.yml +++ b/.github/workflows/release-windows.yml @@ -22,18 +22,26 @@ jobs: build: runs-on: windows-2025 - if: ${{ github.repository_owner == 'danmar' }} + if: ${{ github.repository_owner == 'cppcheck-opensource' }} env: + PYTHON_VERSION: 3.14 # see https://www.pcre.org/original/changelog.txt PCRE_VERSION: 8.45 - QT_VERSION: 6.9.1 + QT_VERSION: 6.10.0 + BOOST_MINOR_VERSION: 89 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + check-latest: true + - name: Set up Visual Studio environment uses: ilammy/msvc-dev-cmd@v1 @@ -47,28 +55,37 @@ jobs: 7z x pcre-%PCRE_VERSION%.zip || exit /b !errorlevel! cd pcre-%PCRE_VERSION% || exit /b !errorlevel! git apply --ignore-space-change ..\externals\pcre.patch || exit /b !errorlevel! - cmake . -G "Visual Studio 17 2022" -A x64 -DPCRE_BUILD_PCRECPP=OFF -DPCRE_BUILD_PCREGREP=OFF -DPCRE_BUILD_TESTS=OFF -DCMAKE_POLICY_VERSION_MINIMUM=3.5 || exit /b !errorlevel! - msbuild -m PCRE.sln -p:Configuration=Release -p:Platform=x64 || 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.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! + - name: Download Boost + run: | + curl -fsSL https://archives.boost.io/release/1.%BOOST_MINOR_VERSION%.0/source/boost_1_%BOOST_MINOR_VERSION%_0.7z -o boost.zip || exit /b !errorlevel! + + - name: Install Boost + run: | + @echo on + 7z x boost.zip boost_1_%BOOST_MINOR_VERSION%_0/boost || exit /b !errorlevel! + ren boost_1_%BOOST_MINOR_VERSION%_0 boost || exit /b !errorlevel! + # available modules: https://github.com/miurahr/aqtinstall/blob/master/docs/getting_started.rst#installing-modules # available tools: https://github.com/miurahr/aqtinstall/blob/master/docs/getting_started.rst#installing-tools - - name: Install Qt ${{ env.QT_VERSION }} + - name: Install Qt uses: jurplel/install-qt-action@v4 with: version: ${{ env.QT_VERSION }} modules: 'qtcharts' setup-python: 'false' tools: 'tools_opensslv3_x64' - aqtversion: '==3.1.*' # TODO: remove when aqtinstall 3.2.2 is available # TODO: build with multiple threads - name: Build x64 release GUI run: | :: TODO: enable rules? :: specify Release build so matchcompiler is used - cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_ONLINE_HELP=On || 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 @@ -78,7 +95,7 @@ jobs: del build\bin\Release\cppcheck-gui.ilk || exit /b !errorlevel! del build\bin\Release\cppcheck-gui.pdb || exit /b !errorlevel! - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: deploy path: build\bin\Release @@ -87,11 +104,12 @@ jobs: run: python tools\matchcompiler.py --write-dir lib || exit /b !errorlevel! # TODO: build with multiple threads - # TODO: build with boost enabled - name: Build CLI x64 release configuration using MSBuild - run: msbuild -m cppcheck.sln -t:cli -p:Configuration=Release-PCRE -p:Platform=x64 || exit /b !errorlevel! + run: msbuild -m cppcheck.sln -t:cli -p:Configuration=Release-PCRE -p:Platform=x64 -p:HaveBoost=HAVE_BOOST -p:BoostInclude=%GITHUB_WORKSPACE%\boost || exit /b !errorlevel! + env: + _CL_: /WX - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: bin path: bin @@ -140,7 +158,7 @@ jobs: :: copy libcrypto-3-x64.dll and libssl-3-x64.dll copy %RUNNER_WORKSPACE%\Qt\Tools\OpenSSLv3\Win_x64\bin\lib*.dll win_installer\files || exit /b !errorlevel! - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: collect path: win_installer\files @@ -155,7 +173,7 @@ jobs: @echo ProductVersion="%PRODUCTVER%" || exit /b !errorlevel! msbuild -m cppcheck.wixproj -p:Platform=x64,ProductVersion=%PRODUCTVER%.${{ github.run_number }} || exit /b !errorlevel! - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: installer path: win_installer/Build/ @@ -191,7 +209,7 @@ jobs: del win_installer\files\Qt6Svg.dll || exit /b !errorlevel! del win_installer\files\vc_redist.x64.exe || exit /b !errorlevel! - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: portable path: win_installer\files diff --git a/.github/workflows/ubsan.yml b/.github/workflows/sanitizers.yml similarity index 60% rename from .github/workflows/ubsan.yml rename to .github/workflows/sanitizers.yml index 31016204950..6021d1237d2 100644 --- a/.github/workflows/ubsan.yml +++ b/.github/workflows/sanitizers.yml @@ -1,6 +1,6 @@ # Syntax reference https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions # Environment reference https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners -name: undefined behaviour sanitizers +name: sanitizers on: push: @@ -18,28 +18,51 @@ permissions: jobs: build: + strategy: + matrix: + include: + - sanitizer: 'asan' + cmake_opts: '-DANALYZE_ADDRESS=On' + run_ctest: true + inject_executor: 'process' + run_selfcheck: false # TODO: this is currently way too slow (~60 minutes) to enable it + - sanitizer: 'tsan' + cmake_opts: '-DANALYZE_THREAD=On' + run_ctest: false # TODO: test-filelist fails with data race in pthread_cond_destroy + inject_executor: 'thread' + run_selfcheck: false # TODO: disabled for now as it takes around 40 minutes to finish + selfcheck_opts: '--executor=thread --error-exitcode=0' # set --error-exitcode=0 so we only fail on sanitizer issues - since it uses threads for execution it will exit the whole process on the first issue + - sanitizer: 'ubsan' + cmake_opts: '-DANALYZE_UNDEFINED=On' + run_ctest: true + inject_executor: 'process' + run_selfcheck: true + fail-fast: false + runs-on: ubuntu-22.04 env: - QT_VERSION: 6.9.1 + QT_VERSION: 6.10.0 + ASAN_OPTIONS: detect_stack_use_after_return=1 + TSAN_OPTIONS: halt_on_error=1 UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1:report_error_type=1 # TODO: figure out why there are cache misses with PCH enabled CCACHE_SLOPPINESS: pch_defines,time_macros steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false - name: ccache uses: hendrikmuhs/ccache-action@v1.2 with: - key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }} + key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }}-${{ matrix.sanitizer }} - - name: Set up Python 3.13 - uses: actions/setup-python@v5 + - name: Set up Python + uses: actions/setup-python@v6 with: - python-version: '3.13' + python-version: '3.14' check-latest: true - name: Install missing software on ubuntu @@ -53,7 +76,7 @@ jobs: sudo apt-get purge --auto-remove llvm python3-lldb-14 llvm-14 wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh - sudo ./llvm.sh 21 + sudo ./llvm.sh 22 - name: Install Qt ${{ env.QT_VERSION }} uses: jurplel/install-qt-action@v4 @@ -71,13 +94,12 @@ jobs: python3 -m pip install pytest-xdist python3 -m pip install psutil - # TODO: disable warnings - name: CMake run: | - cmake -S . -B cmake.output -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_MATCHCOMPILER=Verify -DANALYZE_UNDEFINED=On -DENABLE_CHECK_INTERNAL=On -DUSE_BOOST=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DFILESDIR= -DCMAKE_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-21 - CXX: clang++-21 + CC: clang-22 + CXX: clang++-22 - name: Build cppcheck run: | @@ -92,13 +114,14 @@ jobs: cmake --build cmake.output --target gui-tests -- -j $(nproc) - name: Run tests - run: ./cmake.output/bin/testrunner + run: ./cmake.output/bin/testrunner -t - name: Run cfg tests run: | cmake --build cmake.output --target checkcfg -- -j $(nproc) - name: Run CTest + if: matrix.run_ctest run: | ctest --test-dir cmake.output --output-on-failure -j$(nproc) @@ -106,6 +129,8 @@ jobs: run: | pwd=$(pwd) TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv -n auto test/cli + env: + TEST_CPPCHECK_INJECT_EXECUTOR: ${{ matrix.inject_executor }} - name: Run test/cli (-j2) run: | @@ -130,6 +155,7 @@ jobs: TEST_CPPCHECK_INJECT_BUILDDIR: injected - name: Generate dependencies + if: matrix.run_selfcheck run: | # make sure auto-generated GUI files exist make -C cmake.output autogen @@ -137,16 +163,6 @@ jobs: # TODO: only fail the step on sanitizer issues - since we use processes it will only fail the underlying process which will result in an cppcheckError - name: Self check + if: matrix.run_selfcheck run: | - selfcheck_options="-q -j$(nproc) --std=c++11 --template=selfcheck --showtime=file-total -D__GNUC__ --error-exitcode=1 --inline-suppr --suppressions-list=.selfcheck_suppressions --library=gnu --inconclusive --enable=style,performance,portability,warning,missingInclude --exception-handling --debug-warnings --check-level=exhaustive" - cppcheck_options="-D__CPPCHECK__ -DCHECK_INTERNAL -DHAVE_RULES --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2" - ec=0 - ./cmake.output/bin/cppcheck $selfcheck_options externals || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json frontend || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json -Ifrontend cli || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json --enable=internal lib || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --library=qt --addon=naming.json -Icmake.output/gui -Ifrontend -Igui gui/*.cpp cmake.output/gui/*.cpp || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -Icli -Ifrontend test/*.cpp || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -Icli tools/dmake/*.cpp || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --library=qt -Icmake.output/tools/triage -Igui tools/triage/*.cpp cmake.output/tools/triage/*.cpp || ec=1 - exit $ec + ./selfcheck_san.sh ./cmake.output ${{ matrix.selfcheck_opts }} diff --git a/.github/workflows/scriptcheck.yml b/.github/workflows/scriptcheck.yml index a900020f49a..8cee3c5a5b4 100644 --- a/.github/workflows/scriptcheck.yml +++ b/.github/workflows/scriptcheck.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -31,7 +31,7 @@ jobs: key: ${{ github.workflow }}-${{ runner.os }} - name: Cache Cppcheck - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: cppcheck key: ${{ runner.os }}-scriptcheck-cppcheck-${{ github.sha }} @@ -39,7 +39,7 @@ jobs: - name: build cppcheck run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" - make -j$(nproc) CXXOPTS="-w" + make -j$(nproc) CXXOPTS="-Werror" strip -s ./cppcheck scriptcheck: @@ -48,27 +48,27 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - python-version: [3.7, 3.8, 3.9, '3.10', '3.11', '3.12', '3.13'] + python-version: [3.7, 3.8, 3.9, '3.10', '3.11', '3.12', '3.13', '3.14'] include: - - python-version: '3.13' + - python-version: '3.14' python-latest: true fail-fast: false steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false # TODO: bailout on error - name: Restore Cppcheck - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: cppcheck key: ${{ runner.os }}-scriptcheck-cppcheck-${{ github.sha }} - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} check-latest: true @@ -87,7 +87,7 @@ jobs: python -m pip install pip --upgrade python -m pip install natsort python -m pip install pexpect - python -m pip install 'pylint<=3.3.0' + python -m pip install 'pylint<4.1.0' python -m pip install unittest2 python -m pip install pytest python -m pip install pytest-xdist @@ -209,13 +209,13 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false - name: run dmake run: | - make -j3 CXXOPTS="-w" run-dmake + make -j3 CXXOPTS="-Werror" run-dmake - name: check diff run: | diff --git a/.github/workflows/selfcheck.yml b/.github/workflows/selfcheck.yml index ea242514f72..f16ce8d8332 100644 --- a/.github/workflows/selfcheck.yml +++ b/.github/workflows/selfcheck.yml @@ -21,10 +21,10 @@ jobs: runs-on: ubuntu-22.04 env: - QT_VERSION: 6.9.1 + QT_VERSION: 6.10.0 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -56,7 +56,7 @@ jobs: export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" # valgrind cannot handle DWARF 5 yet so force version 4 # work around performance regression with -inline-deferral - make -j$(nproc) CXXOPTS="-O2 -w -gdwarf-4" CPPOPTS="-DHAVE_BOOST -mllvm -inline-deferral" MATCHCOMPILER=yes + make -j$(nproc) CXXOPTS="-Werror -O2 -gdwarf-4" CPPOPTS="-DHAVE_BOOST -mllvm -inline-deferral" MATCHCOMPILER=yes CPPCHK_GLIBCXX_DEBUG= env: CC: clang-14 CXX: clang++-14 @@ -64,7 +64,7 @@ jobs: # unusedFunction - start - name: CMake run: | - cmake -S . -B cmake.output -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=ON -DWITH_QCHART=ON -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On + 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: | @@ -76,11 +76,10 @@ jobs: # make sure the auto-generated GUI dependencies exist make -C cmake.output gui-build-deps - # TODO: find a way to report unmatched suppressions without need to add information checks - name: Self check (unusedFunction) if: false # TODO: fails with preprocessorErrorDirective - see #10667 run: | - ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib --library=qt -D__CPPCHECK__ -D__GNUC__ -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --enable=unusedFunction --exception-handling -rp=. --project=cmake.output/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr + ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib --library=qt -D__CPPCHECK__ -D__GNUC__ -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --enable=unusedFunction,information --exception-handling -rp=. --project=cmake.output/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr env: DISABLE_VALUEFLOW: 1 UNUSEDFUNCTION_ONLY: 1 @@ -91,7 +90,7 @@ jobs: # unusedFunction notest - start - name: CMake (no test) run: | - cmake -S . -B cmake.output.notest -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=Off -DBUILD_GUI=ON -DBUILD_TRIAGE=On -DWITH_QCHART=ON -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On + 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: | @@ -102,10 +101,9 @@ jobs: # make sure the auto-generated GUI dependencies exist make -C cmake.output.notest gui-build-deps - # TODO: find a way to report unmatched suppressions without need to add information checks - name: Self check (unusedFunction / no test) run: | - ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib --library=qt -D__CPPCHECK__ -D__GNUC__ -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --enable=unusedFunction --exception-handling -rp=. --project=cmake.output.notest/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr + ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib --library=qt -D__CPPCHECK__ -D__GNUC__ -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --enable=unusedFunction,information --exception-handling -rp=. --project=cmake.output.notest/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr env: DISABLE_VALUEFLOW: 1 UNUSEDFUNCTION_ONLY: 1 @@ -114,17 +112,34 @@ jobs: # unusedFunction notest nogui - start - name: CMake (no test / no gui) run: | - cmake -S . -B cmake.output.notest_nogui -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=Off -DENABLE_CHECK_INTERNAL=On + 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: | # make sure the precompiled headers exist make -C cmake.output.notest_nogui lib/CMakeFiles/cppcheck-core.dir/cmake_pch.hxx.cxx - # TODO: find a way to report unmatched suppressions without need to add information checks - name: Self check (unusedFunction / no test / no gui) run: | - ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib -D__CPPCHECK__ -D__GNUC__ --enable=unusedFunction --exception-handling -rp=. --project=cmake.output.notest_nogui/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr + 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 @@ -133,7 +148,7 @@ jobs: # unusedFunction notest nocli - start - name: CMake (no test / no cli) run: | - cmake -S . -B cmake.output.notest_nocli -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=Off -DBUILD_CLI=Off -DBUILD_GUI=ON -DWITH_QCHART=ON -DBUILD_TRIAGE=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On + 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: | @@ -144,11 +159,10 @@ jobs: # make sure the auto-generated GUI dependencies exist make -C cmake.output.notest_nocli gui-build-deps - # TODO: find a way to report unmatched suppressions without need to add information checks - name: Self check (unusedFunction / no test / no cli) if: false # TODO: the findings are currently too intrusive run: | - ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib --library=qt -D__CPPCHECK__ -D__GNUC__ -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --enable=unusedFunction --exception-handling -rp=. --project=cmake.output.notest_nocli/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr + ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib --library=qt -D__CPPCHECK__ -D__GNUC__ -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --enable=unusedFunction,information --exception-handling -rp=. --project=cmake.output.notest_nocli/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr env: DISABLE_VALUEFLOW: 1 UNUSEDFUNCTION_ONLY: 1 @@ -157,18 +171,17 @@ jobs: # unusedFunction notest nocli nogui - start - name: CMake (no test / no cli / no gui) run: | - cmake -S . -B cmake.output.notest_nocli_nogui -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=Off -DBUILD_CLI=Off -DBUILD_GUI=Off -DENABLE_CHECK_INTERNAL=On + 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: | # make sure the precompiled headers exist make -C cmake.output.notest_nocli_nogui lib/CMakeFiles/cppcheck-core.dir/cmake_pch.hxx.cxx - # TODO: find a way to report unmatched suppressions without need to add information checks - name: Self check (unusedFunction / no test / no cli / no gui) if: false # TODO: the findings are currently too intrusive run: | - ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib --library=qt -D__CPPCHECK__ -D__GNUC__ --enable=unusedFunction --exception-handling -rp=. --project=cmake.output.notest_nocli_nogui/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr + ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib --library=qt -D__CPPCHECK__ -D__GNUC__ --enable=unusedFunction,information --exception-handling -rp=. --project=cmake.output.notest_nocli_nogui/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr env: DISABLE_VALUEFLOW: 1 UNUSEDFUNCTION_ONLY: 1 @@ -176,12 +189,12 @@ jobs: - name: Fetch corpus run: | - wget https://github.com/danmar/cppcheck/archive/refs/tags/2.8.tar.gz + wget https://github.com/cppcheck-opensource/cppcheck/archive/refs/tags/2.8.tar.gz tar xvf 2.8.tar.gz - name: CMake (corpus / no test) run: | - cmake -S cppcheck-2.8 -B cmake.output.corpus -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=Off -DBUILD_GUI=ON -DUSE_QT6=On -DWITH_QCHART=ON -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCMAKE_POLICY_VERSION_MINIMUM=3.5 + cmake -S cppcheck-2.8 -B cmake.output.corpus -DHAVE_RULES=On -DBUILD_TESTING=Off -DBUILD_GUI=ON -DUSE_QT6=On -DWITH_QCHART=ON -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DDISABLE_DMAKE=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_POLICY_VERSION_MINIMUM=3.5 - name: Generate dependencies (corpus) run: | @@ -192,18 +205,30 @@ jobs: # make sure the auto-generated GUI dependencies exist make -C cmake.output.corpus gui-build-deps - # TODO: find a way to report unmatched suppressions without need to add information checks - name: Self check (unusedFunction / corpus / no test / callgrind) run: | # TODO: fix -rp so the suppressions actually work - valgrind --tool=callgrind ./cppcheck --template=selfcheck --error-exitcode=0 --library=cppcheck-lib --library=qt -D__GNUC__ -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --enable=unusedFunction --exception-handling -rp=. --project=cmake.output.corpus/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr 2>callgrind.log || (cat callgrind.log && false) + valgrind --tool=callgrind ./cppcheck --template=selfcheck --error-exitcode=0 --library=cppcheck-lib --library=qt -D__GNUC__ -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --enable=unusedFunction,information --exception-handling -rp=. --project=cmake.output.corpus/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr 2>callgrind.log || (cat callgrind.log && false) cat callgrind.log callgrind_annotate --auto=no > callgrind.annotated.log head -50 callgrind.annotated.log env: DISABLE_VALUEFLOW: 1 - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: Callgrind Output path: ./callgrind.* + + - name: Self check (unusedFunction / corpus / no test / memcheck) + run: | + # TODO: fix -rp so the suppressions actually work + valgrind --error-limit=yes --leak-check=full --num-callers=50 --show-reachable=yes --track-origins=yes --gen-suppressions=all --log-fd=9 --error-exitcode=42 ./cppcheck --template=selfcheck --error-exitcode=0 --library=cppcheck-lib --library=qt -D__GNUC__ -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --enable=unusedFunction,information --exception-handling -rp=. --project=cmake.output.corpus/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr 9>memcheck.log || (cat memcheck.log && false) + cat memcheck.log + env: + DISABLE_VALUEFLOW: 1 + + - uses: actions/upload-artifact@v7 + with: + name: Memcheck Output + path: ./memcheck.* diff --git a/.github/workflows/tsan.yml b/.github/workflows/tsan.yml deleted file mode 100644 index 692dfb48785..00000000000 --- a/.github/workflows/tsan.yml +++ /dev/null @@ -1,158 +0,0 @@ -# Syntax reference https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions -# Environment reference https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners -name: thread sanitizer - -on: - push: - branches: - - 'main' - - 'releases/**' - - '2.*' - tags: - - '2.*' - pull_request: - -permissions: - contents: read - -jobs: - build: - - runs-on: ubuntu-22.04 - - env: - QT_VERSION: 6.9.1 - TSAN_OPTIONS: halt_on_error=1 - # TODO: figure out why there are cache misses with PCH enabled - CCACHE_SLOPPINESS: pch_defines,time_macros - - steps: - - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }} - - - name: Set up Python 3.13 - uses: actions/setup-python@v5 - with: - python-version: '3.13' - check-latest: true - - - name: Install missing software on ubuntu - run: | - sudo apt-get update - sudo apt-get install -y cmake make libpcre3-dev libboost-container-dev libxml2-utils - sudo apt-get install -y libcups2-dev # required for Qt6PrintSupport in CMake since Qt 6.7.3 - - - name: Install clang - run: | - sudo apt-get purge --auto-remove llvm python3-lldb-14 llvm-14 - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - sudo ./llvm.sh 21 - - - name: Install Qt ${{ env.QT_VERSION }} - uses: jurplel/install-qt-action@v4 - with: - version: ${{ env.QT_VERSION }} - modules: 'qtcharts' - setup-python: 'false' - cache: true - - - name: Install missing Python packages - run: | - python3 -m pip install pip --upgrade - python3 -m pip install pytest - python3 -m pip install pytest-timeout - python3 -m pip install pytest-xdist - python3 -m pip install psutil - - - name: CMake - run: | - cmake -S . -B cmake.output -DCMAKE_BUILD_TYPE=RelWithDebInfo -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DBUILD_TRIAGE=On -DUSE_MATCHCOMPILER=Verify -DANALYZE_THREAD=On -DENABLE_CHECK_INTERNAL=On -DUSE_BOOST=On -DCPPCHK_GLIBCXX_DEBUG=Off -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=Off -DDISABLE_DMAKE=On -DFILESDIR= -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - env: - CC: clang-21 - CXX: clang++-21 - - - name: Build cppcheck - run: | - cmake --build cmake.output --target cppcheck -- -j $(nproc) - - - name: Build test - run: | - cmake --build cmake.output --target testrunner -- -j $(nproc) - - - name: Build GUI tests - run: | - cmake --build cmake.output --target gui-tests -- -j $(nproc) - - - name: Run tests - run: ./cmake.output/bin/testrunner - - - name: Run cfg tests - run: | - cmake --build cmake.output --target checkcfg -- -j $(nproc) - - - name: Run CTest - if: false # TODO: test-filelist fails with data race in pthread_cond_destroy - run: | - ctest --test-dir cmake.output --output-on-failure -j$(nproc) - - - name: Run test/cli - run: | - pwd=$(pwd) - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv -n auto test/cli - env: - TEST_CPPCHECK_INJECT_EXECUTOR: thread - - - name: Run test/cli (-j2) - run: | - pwd=$(pwd) - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv -n auto test/cli - env: - TEST_CPPCHECK_INJECT_J: 2 - - - name: Run test/cli (--clang) - if: false - run: | - pwd=$(pwd) - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv -n auto test/cli - env: - TEST_CPPCHECK_INJECT_CLANG: clang - - - name: Run test/cli (--cppcheck-build-dir) - run: | - pwd=$(pwd) - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv -n auto test/cli - env: - TEST_CPPCHECK_INJECT_BUILDDIR: injected - - - name: Generate dependencies - if: false - run: | - # make sure auto-generated GUI files exist - make -C cmake.output autogen - make -C cmake.output gui-build-deps triage-build-ui-deps - - # TODO: disabled for now as it takes around 40 minutes to finish - # set --error-exitcode=0 so we only fail on sanitizer issues - since it uses threads for execution it will exit the whole process on the first issue - - name: Self check - if: false - run: | - selfcheck_options="-q -j$(nproc) --std=c++11 --template=selfcheck --showtime=file-total -D__GNUC__ --error-exitcode=0 --inline-suppr --suppressions-list=.selfcheck_suppressions --library=gnu --inconclusive --enable=style,performance,portability,warning,missingInclude --exception-handling --debug-warnings --check-level=exhaustive" - selfcheck_options="$selfcheck_options --executor=thread" - cppcheck_options="-D__CPPCHECK__ -DCHECK_INTERNAL -DHAVE_RULES --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2" - ec=0 - ./cmake.output/bin/cppcheck $selfcheck_options externals || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json frontend || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json -Ifrontend cli || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options --addon=naming.json --enable=internal lib || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -DQT_VERSION=0x060000 -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --library=qt --addon=naming.json -Icmake.output/gui -Ifrontend -Igui gui/*.cpp cmake.output/gui/*.cpp || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -Icli -Ifrontend test/*.cpp || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -Icli tools/dmake/*.cpp || ec=1 - ./cmake.output/bin/cppcheck $selfcheck_options $cppcheck_options -DQ_MOC_OUTPUT_REVISION=69 -DQT_CHARTS_LIB -DQT_MOC_HAS_STRINGDATA --library=qt -Icmake.output/tools/triage -Igui tools/triage/*.cpp cmake.output/tools/triage/*.cpp || ec=1 - exit $ec diff --git a/.github/workflows/valgrind.yml b/.github/workflows/valgrind.yml index 4c2d51acb38..25ef4dd63a2 100644 --- a/.github/workflows/valgrind.yml +++ b/.github/workflows/valgrind.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false @@ -41,24 +41,30 @@ jobs: - name: Build cppcheck run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" - CXXOPTS="-O1 -g -w" CPPOPTS="-DHAVE_BOOST" make -j$(nproc) HAVE_RULES=yes MATCHCOMPILER=yes + make -j$(nproc) CXXOPTS="-Werror -O1 -g" CPPOPTS="-DHAVE_BOOST" HAVE_RULES=yes MATCHCOMPILER=yes CPPCHK_GLIBCXX_DEBUG= - name: Build test run: | export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" - make -j$(nproc) CXXOPTS="-O1 -g -w" CPPOPTS="-DHAVE_BOOST" HAVE_RULES=yes MATCHCOMPILER=yes testrunner + make -j$(nproc) CXXOPTS="-Werror -O1 -g" CPPOPTS="-DHAVE_BOOST" HAVE_RULES=yes MATCHCOMPILER=yes CPPCHK_GLIBCXX_DEBUG= testrunner - name: Run valgrind run: | ec=0 - valgrind --error-limit=yes --leak-check=full --num-callers=50 --show-reachable=yes --track-origins=yes --suppressions=valgrind/testrunner.supp --gen-suppressions=all --log-fd=9 --error-exitcode=42 ./testrunner TestGarbage TestOther TestSimplifyTemplate 9>memcheck.log || ec=1 + # disabled all tests invoking processes because the child processes fail with still reachable memory. + # some of the TestProcessExecutor* tests are also extremely slow. + excluded_tests="TestProcessExecutorFS \ + TestProcessExecutorFiles \ + TestSuppressions::suppressionsSettingsProcessesFiles \ + TestSuppressions::suppressionsSettingsProcessesFS" + valgrind --error-limit=yes --leak-check=full --num-callers=50 --show-reachable=yes --track-origins=yes --suppressions=valgrind/testrunner.supp --gen-suppressions=all -s --log-fd=9 --error-exitcode=42 ./testrunner -t -x $excluded_tests 9>memcheck.log || ec=1 cat memcheck.log exit $ec # TODO: debuginfod.ubuntu.com is currently not responding to any requests causing it to run into a 40(!) minute timeout #env: # DEBUGINFOD_URLS: https://debuginfod.ubuntu.com - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 if: success() || failure() with: name: Logs diff --git a/.gitignore b/.gitignore index 9a2c61ded12..a821204bf2d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ *.bak *.gcno +*.gch *.o +*.a *.pyc /cppcheck /cppcheck.exe diff --git a/.pylintrc b/.pylintrc index 9b14fa2d00e..0ca3480c06f 100644 --- a/.pylintrc +++ b/.pylintrc @@ -63,4 +63,3 @@ reports=no ignored-classes=SQLObject,_socketobject [MASTER] init-hook='import sys; sys.path.append("./addons")' -suggestion-mode=yes diff --git a/.selfcheck_suppressions b/.selfcheck_suppressions index 6a00f33655f..63d33fd2704 100644 --- a/.selfcheck_suppressions +++ b/.selfcheck_suppressions @@ -1,28 +1,69 @@ missingIncludeSystem - -# temporary suppressions - fix the warnings! -simplifyUsing:lib/valueptr.h -varid0:gui/projectfile.cpp -naming-privateMemberVariable:gui/test/cppchecklibrarydata/testcppchecklibrarydata.h -symbolDatabaseWarning:*/moc_*.cpp -simplifyUsing:*/moc_*.cpp +# should not be reported - see #13387 +checkersReport # warnings in Qt generated code we cannot fix -funcArgNamesDifferent:*/moc_*.cpp -naming-varname:*/ui_*.h -functionStatic:*/ui_fileview.h +funcArgNamesDifferentUnnamed:*/moc_aboutdialog.cpp +funcArgNamesDifferentUnnamed:*/moc_applicationdialog.cpp +funcArgNamesDifferentUnnamed:*/moc_applicationlist.cpp +funcArgNamesDifferent:*/moc_checkthread.cpp +funcArgNamesDifferentUnnamed:*/moc_checkthread.cpp +funcArgNamesDifferentUnnamed:*/moc_codeeditor.cpp +funcArgNamesDifferent:*/moc_codeeditstylecontrols.cpp +funcArgNamesDifferentUnnamed:*/moc_codeeditstylecontrols.cpp +funcArgNamesDifferentUnnamed:*/moc_compliancereportdialog.cpp +funcArgNamesDifferentUnnamed:*/moc_codeeditstyledialog.cpp +funcArgNamesDifferentUnnamed:*/moc_fileviewdialog.cpp +funcArgNamesDifferentUnnamed:*/moc_helpdialog.cpp +funcArgNamesDifferentUnnamed:*/moc_libraryaddfunctiondialog.cpp +funcArgNamesDifferentUnnamed:*/moc_librarydialog.cpp +funcArgNamesDifferentUnnamed:*/moc_libraryeditargdialog.cpp +funcArgNamesDifferentUnnamed:*/moc_mainwindow.cpp +funcArgNamesDifferentUnnamed:*/moc_newsuppressiondialog.cpp +funcArgNamesDifferentUnnamed:*/moc_platforms.cpp +funcArgNamesDifferentUnnamed:*/moc_projectfile.cpp +funcArgNamesDifferentUnnamed:*/moc_projectfiledialog.cpp +funcArgNamesDifferent:*/moc_resultstree.cpp +funcArgNamesDifferentUnnamed:*/moc_resultstree.cpp +funcArgNamesDifferent:*/moc_resultsview.cpp +funcArgNamesDifferentUnnamed:*/moc_resultsview.cpp +funcArgNamesDifferentUnnamed:*/moc_scratchpad.cpp +funcArgNamesDifferentUnnamed:*/moc_settingsdialog.cpp +funcArgNamesDifferentUnnamed:*/moc_statsdialog.cpp +funcArgNamesDifferentUnnamed:*/moc_testcppchecklibrarydata.cpp +funcArgNamesDifferentUnnamed:*/moc_testfilelist.cpp +funcArgNamesDifferentUnnamed:*/moc_testprojectfile.cpp +funcArgNamesDifferentUnnamed:*/moc_testresultstree.cpp +funcArgNamesDifferentUnnamed:*/moc_testtranslationhandler.cpp +funcArgNamesDifferentUnnamed:*/moc_testxmlreportv2.cpp +funcArgNamesDifferentUnnamed:*/moc_threaddetails.cpp +funcArgNamesDifferent:*/moc_threadhandler.cpp +funcArgNamesDifferentUnnamed:*/moc_threadhandler.cpp +funcArgNamesDifferent:*/moc_threadresult.cpp +funcArgNamesDifferentUnnamed:*/moc_threadresult.cpp +funcArgNamesDifferentUnnamed:*/moc_translationhandler.cpp +funcArgNamesDifferentUnnamed:*/moc_txtreport.cpp +naming-varname:*/gui/ui_*.h +functionStatic:*/gui/ui_*.h # --debug-warnings suppressions valueFlowBailout valueFlowBailoutIncompleteVar -autoNoType +valueFlowMaxIterations:gui/resultstree.cpp +autoNoType:externals/simplecpp/simplecpp.cpp +autoNoType:cli/*.cpp +autoNoType:lib/*.cpp +autoNoType:lib/library.h +autoNoType:gui/*.cpp +autoNoType:test/*.cpp +autoNoType:tools/triage/mainwindow.cpp # ticket 11631 templateInstantiation:test/testutils.cpp naming-varname:externals/simplecpp/simplecpp.h naming-privateMemberVariable:externals/simplecpp/simplecpp.h - -valueFlowMaxIterations:externals/tinyxml2/tinyxml2.cpp +# 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 @@ -31,8 +72,12 @@ missingOverride:externals/tinyxml2/tinyxml2.h invalidPrintfArgType_sint:externals/tinyxml2/tinyxml2.h naming-privateMemberVariable:externals/tinyxml2/tinyxml2.h functionStatic:externals/tinyxml2/tinyxml2.cpp -invalidPrintfArgType_uint:externals/tinyxml2/tinyxml2.cpp funcArgNamesDifferent:externals/tinyxml2/tinyxml2.cpp +funcArgNamesDifferentUnnamed:externals/tinyxml2/tinyxml2.cpp +funcArgNamesDifferentUnnamed:externals/tinyxml2/tinyxml2.h nullPointerRedundantCheck:externals/tinyxml2/tinyxml2.cpp knownConditionTrueFalse:externals/tinyxml2/tinyxml2.cpp useStlAlgorithm:externals/simplecpp/simplecpp.cpp +funcArgNamesDifferentUnnamed:externals/simplecpp/simplecpp.h +missingMemberCopy:externals/simplecpp/simplecpp.h +shadowFunction:externals/simplecpp/simplecpp.h diff --git a/.selfcheck_unused_suppressions b/.selfcheck_unused_suppressions index ce685d8ab10..5da7c225dfa 100644 --- a/.selfcheck_unused_suppressions +++ b/.selfcheck_unused_suppressions @@ -1,8 +1,8 @@ +# should not be reported - see #13387 +checkersReport + # we are not using all methods of their interfaces unusedFunction:externals/*/* -# usage is disabled -unusedFunction:lib/symboldatabase.cpp - # Q_OBJECT functions which are not called in our code unusedFunction:cmake.output.notest/gui/cppcheck-gui_autogen/*/moc_aboutdialog.cpp diff --git a/AUTHORS b/AUTHORS index 6c72fe81730..e804ab53e16 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,6 +1,7 @@ The cppcheck team, in alphabetical order: 0x41head +Aaron Danen Abhijit Sawant Abhishek Bharadwaj Abigail Buccaneer @@ -22,6 +23,7 @@ Alexey Eryomenko Alexey Zhikhartsev Alfi Maulana Ali Can Demiralp +Alvin Che-Chia Chang Allen Winter Alon Alexander Alon Liberman @@ -33,6 +35,7 @@ Andreas Lutsch Andreas Pokorny Andreas Rönnquist Andreas Vollenweider +Andreas Wilhelm Andrei Karas Andrew C Aitchison Andrew C. Martin @@ -98,6 +101,7 @@ daisuke-chiba Daniel Friedrich David Korczynski Daniel Marjamäki +Daschle Newberry David Hallas David Korth Dávid Slivka @@ -105,6 +109,7 @@ Debrard Sebastien Deepak Gupta Degen's Regens dencat +Devansh Varshney Diego de las Heras Dirk Jagdmann Dirk Mueller @@ -130,14 +135,18 @@ Felipe Pena Felix Faber Felix Geyer Felix Passenberg +Felix Patschkowski Felix Wolff +Florian Mueller Florin Iucha +flovent Francesc Elies François Berder Frank Winklmeier Frank Zingsheim Frederik Schwarzer fu7mu4 +Gaël Bonithon Galimov Albert Garrett Bodily Gary Leutheuser @@ -150,7 +159,9 @@ Gerhard Zlabinger Gerik Rhoden Gianfranco Costamagna Gianluca Scacco +Gilmar Santos Jr Gleydson Soares +Goncalo Mao-Cheia Goran Džaferi Graham Whitted Greg Hewgill @@ -190,6 +201,7 @@ Jim Zhou jlguardi Joel Johnson Johan Bertrand +Johan Crone Johan Samuelson John Marshall John-Paul Ore @@ -198,6 +210,7 @@ Jonathan Clohessy Jonathan Haehne Jonathan Neuschäfer Jonathan Thackray +Jonny Paton José Martins Jose Roquette Joshua Beck @@ -241,6 +254,7 @@ Ludvig Gunne Lindström Luis Díaz Más Luís Pereira Lukas Grützmacher +Lukas Hiesmayr Lukasz Czajczyk Łukasz Jankowski Luxon Jean-Pierre @@ -248,6 +262,7 @@ Maarten van der Schrieck Maksim Derbasov Malcolm Parsons Marc-Antoine Perennou +Marcel Petrick Marcel Raad Marco Trevisan Marek Zmysłowski @@ -274,6 +289,7 @@ Matthias Schmieder Matt Johnson Maurice Gilden Mavik +Melroy van den Berg Michael Drake Michael Løiten Miika-Petteri Matikainen @@ -296,6 +312,7 @@ Nicolás Alvarez Nicolas Le Cam Nilesh Kumar Ogawa KenIchi +Ola Söder Oleksandr Labetskyi Oleksandr Redko Oliver Schode @@ -318,6 +335,7 @@ Philip Chimento Philipp Kloke Pierre Schweitzer Pieter Duchi +Piotr Idzik Pino Toscano Pranav Khanna Radek Jarecki @@ -326,6 +344,7 @@ Ramzan Bekbulatov Raphael Geissert Razvan Ioan Alexe Reijo Tomperi +Reshma V Kumar Rainer Wiesenfarth Riccardo Ghetta Richard A. Smith @@ -337,6 +356,7 @@ Robert Habrich Robert Morin Roberto Martelloni Robert Reif +Robin Getz rofl0r Roman Zaytsev Borisovich Ronald Hiemstra @@ -352,6 +372,7 @@ Samuel Degrande Samuel Poláček Sandeep Dutta Savvas Etairidis +Sayed Kaif Scott Ehlert Scott Furry Seafarix Ltd. @@ -409,6 +430,7 @@ Tommy Bergman Toralf Förster Troshin V.S. Tyson Nottingham +Usman Majid Valentin Batz Valerii Lashmanov Vasily Maslyukov @@ -417,10 +439,12 @@ Vesa Pikki Ville-Pekka Vahteala Ville Skyttä Vincent Le Garrec +Vít Kučera Vladimir Petrigo Wang Haoyu Wang Yang WenChung Chiu +William Jakobsson Wolfgang Stöggl x29a XhmikosR diff --git a/CMakeLists.txt b/CMakeLists.txt index cfe46dc26a3..b5857a8413a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ -cmake_minimum_required(VERSION 3.13) -project(Cppcheck VERSION 2.18.99 LANGUAGES CXX) +cmake_minimum_required(VERSION 3.22) +project(Cppcheck VERSION 2.21.99 LANGUAGES CXX) include(cmake/options.cmake) @@ -11,11 +11,13 @@ set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) include(GNUInstallDirs) +include(CTest) include(cmake/compilerCheck.cmake) include(cmake/versions.cmake) include(cmake/findDependencies.cmake) include(cmake/compileroptions.cmake) +include(cmake/includechecks.cmake) include(cmake/compilerDefinitions.cmake) include(cmake/buildFiles.cmake) if(BUILD_GUI) @@ -77,10 +79,6 @@ endif() # - Cygwin handling # - MinGW handling -if(BUILD_TESTS) - enable_testing() -endif() - add_custom_target(copy_cfg ALL ${CMAKE_COMMAND} -E copy_directory "${PROJECT_SOURCE_DIR}/cfg" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/cfg" @@ -92,9 +90,16 @@ add_custom_target(copy_addons ALL "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/addons" COMMENT "Copying addons files to ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}") +add_custom_target(remove_unsigned_platforms ALL + ${CMAKE_COMMAND} -E remove -f + "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/platforms/unix32-unsigned.xml" + "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/platforms/unix64-unsigned.xml" + COMMENT "Removing unsigned platforms files from ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}") + add_custom_target(copy_platforms ALL ${CMAKE_COMMAND} -E copy_directory "${PROJECT_SOURCE_DIR}/platforms" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/platforms" + DEPENDS remove_unsigned_platforms COMMENT "Copying platforms files to ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}") if(USE_BUNDLED_TINYXML2) @@ -102,6 +107,7 @@ if(USE_BUNDLED_TINYXML2) add_subdirectory(externals/tinyxml2) endif() add_subdirectory(externals/simplecpp) +add_subdirectory(externals/picojson) add_subdirectory(lib) # CppCheck Library add_subdirectory(frontend) add_subdirectory(cli) # Client application diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 715a913b6fc..09e88f021e2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ These are some guidelines *any* contributor should follow. They will help to mak ## Code Changes -Code contributions are handled via GitHub pull requests: https://github.com/danmar/cppcheck/pulls. +Code contributions are handled via GitHub pull requests: https://github.com/cppcheck-opensource/cppcheck/pulls. If you file a pull request you might not get a reply immediately. We are a very small team and it might not fit in the current scope or time. @@ -18,7 +18,7 @@ Also after you filed a pull request please be ready to reply to questions and fe Please do not be discouraged if your change was rejected or if the review process might not have been as smooth as it could have been. -Each change should be accompanied with a unit ([C++](https://github.com/danmar/cppcheck/tree/main/test)) or integration ([Python](https://github.com/danmar/cppcheck/tree/main/test/cli)) test to ensure that it doesn't regress with future changes. Negative tests (testing the opposite behavior) would be favorable but might not be required or might already exist depending on the change. Tests which introduce `TODO_ASSERT_` or `@pytest.mark.skip`/`@pytest.mark.xfail` should have tickets filed. +Each change should be accompanied with a unit ([C++](https://github.com/cppcheck-opensource/cppcheck/tree/main/test)) or integration ([Python](https://github.com/cppcheck-opensource/cppcheck/tree/main/test/cli)) test to ensure that it doesn't regress with future changes. Negative tests (testing the opposite behavior) would be favorable but might not be required or might already exist depending on the change. Tests which introduce `TODO_ASSERT_` or `@pytest.mark.skip`/`@pytest.mark.xfail` should have tickets filed. If the change is modifying existing behavior (i.e. adding a feature or fixing a bug) it should be accompanied by an issue in the [tracker](https://trac.cppcheck.net) (if you do not have access we can assist with that). Depending on the change it might also warrant an entry in `releasenotes.txt`. @@ -56,7 +56,7 @@ So if you start spending a lot of time on these, you might want to get into touc ## simplecpp -At its core Cppcheck is relying on the `simplecpp` library which is a preprocessor implementation which was spun off into its [separate project](https://github.com/danmar/simplecpp) with its own [bug tracker](https://github.com/danmar/simplecpp/issues). This is also maintained by the Cppcheck developers and contributions to it are also welcome. +At its core Cppcheck is relying on the `simplecpp` library which is a preprocessor implementation which was spun off into its [separate project](https://github.com/cppcheck-opensource/simplecpp) with its own [bug tracker](https://github.com/cppcheck-opensource/simplecpp/issues). This is also maintained by the Cppcheck developers and contributions to it are also welcome. ## Translations diff --git a/Makefile b/Makefile index 8dda00a2096..a7f3feefba6 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ ifdef FILESDIR override CPPFLAGS+=-DFILESDIR=\"$(FILESDIR)\" endif -RDYNAMIC=-rdynamic +RDYNAMIC?=-rdynamic # Set the CPPCHK_GLIBCXX_DEBUG flag. This flag is not used in release Makefiles. # The _GLIBCXX_DEBUG define doesn't work in Cygwin or other Win32 systems. ifndef COMSPEC @@ -155,6 +155,15 @@ else ifneq ($(HAVE_RULES),) $(error invalid HAVE_RULES value '$(HAVE_RULES)') endif +# older make versions do not support # in $(shell) and newer ones handle the escape sequence literally +REQUIRE_ESCAPE=$(shell echo "\#define DEF" | $(CXX) -c -xc - 2> /dev/null && echo "1" || echo "0") +ifeq ($(REQUIRE_ESCAPE),1) + HAVE_EXECINFO_H=$(shell echo "\#include " | $(CXX) -c -xc - 2> /dev/null && echo "1" || echo "0") +else + HAVE_EXECINFO_H=$(shell echo "#include " | $(CXX) -c -xc - 2> /dev/null && echo "1" || echo "0") +endif +override CPPFLAGS += -DHAVE_EXECINFO_H=$(HAVE_EXECINFO_H) + override CXXFLAGS += $(CXXOPTS) override CPPFLAGS += $(CPPOPTS) override LDFLAGS += $(LDOPTS) @@ -176,7 +185,7 @@ ifndef INCLUDE_FOR_CLI endif ifndef INCLUDE_FOR_TEST - INCLUDE_FOR_TEST=-Ilib -Ifrontend -Icli -isystem externals/simplecpp -isystem externals/tinyxml2 + INCLUDE_FOR_TEST=-Ilib -Ifrontend -Icli -isystem externals/picojson -isystem externals/simplecpp -isystem externals/tinyxml2 endif ifndef CFLAGS_FOR_TEST @@ -199,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 \ @@ -212,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 \ @@ -219,6 +228,7 @@ LIBOBJ = $(libcppdir)/valueflow.o \ $(libcppdir)/checknullpointer.o \ $(libcppdir)/checkother.o \ $(libcppdir)/checkpostfixoperator.o \ + $(libcppdir)/checks.o \ $(libcppdir)/checksizeof.o \ $(libcppdir)/checkstl.o \ $(libcppdir)/checkstring.o \ @@ -247,7 +257,9 @@ LIBOBJ = $(libcppdir)/valueflow.o \ $(libcppdir)/platform.o \ $(libcppdir)/preprocessor.o \ $(libcppdir)/programmemory.o \ + $(libcppdir)/regex.o \ $(libcppdir)/reverseanalyzer.o \ + $(libcppdir)/sarifreport.o \ $(libcppdir)/settings.o \ $(libcppdir)/standards.o \ $(libcppdir)/summaries.o \ @@ -292,6 +304,7 @@ TESTOBJ = test/fixture.o \ test/testbufferoverrun.o \ test/testcharvar.o \ test/testcheck.o \ + test/testcheckersreport.o \ test/testclangimport.o \ test/testclass.o \ test/testcmdlineparser.o \ @@ -325,6 +338,8 @@ TESTOBJ = test/fixture.o \ test/testpreprocessor.o \ test/testprocessexecutor.o \ test/testprogrammemory.o \ + test/testregex.o \ + test/testsarifreport.o \ test/testsettings.o \ test/testsimplifytemplate.o \ test/testsimplifytokens.o \ @@ -468,13 +483,13 @@ check-nonneg: ###### Build -$(libcppdir)/valueflow.o: lib/valueflow.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/calculate.h lib/check.h lib/checkers.h lib/checkuninitvar.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/findtoken.h lib/forwardanalyzer.h lib/infer.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/reverseanalyzer.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vf_analyzers.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h +$(libcppdir)/valueflow.o: lib/valueflow.cpp lib/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/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/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 @@ -483,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/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/settings.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h - $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/check.cpp - -$(libcppdir)/check64bit.o: lib/check64bit.cpp lib/addoninfo.h lib/check.h lib/check64bit.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/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/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/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/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/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h lib/xml.h +$(libcppdir)/checkbufferoverrun.o: lib/checkbufferoverrun.cpp externals/tinyxml2/tinyxml2.h lib/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/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h lib/xml.h +$(libcppdir)/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/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 @@ -516,73 +528,79 @@ $(libcppdir)/checkers.o: lib/checkers.cpp lib/checkers.h lib/config.h $(libcppdir)/checkersidmapping.o: lib/checkersidmapping.cpp lib/checkers.h lib/config.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkersidmapping.cpp -$(libcppdir)/checkersreport.o: lib/checkersreport.cpp lib/addoninfo.h lib/checkers.h lib/checkersreport.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h +$(libcppdir)/checkersreport.o: lib/checkersreport.cpp lib/addoninfo.h lib/checkers.h lib/checkersreport.h lib/config.h lib/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/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/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/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/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/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/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/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/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/settings.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/settings.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/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/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/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/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/astutils.h lib/checkers.h lib/checkunusedfunctions.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h +$(libcppdir)/checkunusedfunctions.o: lib/checkunusedfunctions.cpp externals/tinyxml2/tinyxml2.h lib/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/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/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/addoninfo.h lib/checkers.h lib/clangimport.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h +$(libcppdir)/clangimport.o: lib/clangimport.cpp lib/clangimport.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/clangimport.cpp $(libcppdir)/color.o: lib/color.cpp lib/color.h lib/config.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/color.cpp -$(libcppdir)/cppcheck.o: lib/cppcheck.cpp externals/picojson/picojson.h externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.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/settings.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 lib/xml.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/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h +$(libcppdir)/ctu.o: lib/ctu.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/ctu.cpp -$(libcppdir)/errorlogger.o: lib/errorlogger.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/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/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.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 @@ -591,16 +609,16 @@ $(libcppdir)/errortypes.o: lib/errortypes.cpp lib/config.h lib/errortypes.h lib/ $(libcppdir)/findtoken.o: lib/findtoken.cpp lib/astutils.h lib/config.h lib/errortypes.h lib/findtoken.h lib/library.h lib/mathlib.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/findtoken.cpp -$(libcppdir)/forwardanalyzer.o: lib/forwardanalyzer.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/forwardanalyzer.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueptr.h lib/vfvalue.h +$(libcppdir)/forwardanalyzer.o: lib/forwardanalyzer.cpp lib/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/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/settings.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/templatesimplifier.h lib/token.h lib/utils.h lib/valueptr.h lib/vfvalue.h +$(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 $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/infer.cpp $(libcppdir)/keywords.o: lib/keywords.cpp lib/config.h lib/keywords.h lib/standards.h lib/utils.h @@ -609,7 +627,7 @@ $(libcppdir)/keywords.o: lib/keywords.cpp lib/config.h lib/keywords.h lib/standa $(libcppdir)/library.o: lib/library.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/config.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/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/library.cpp -$(libcppdir)/mathlib.o: lib/mathlib.cpp externals/simplecpp/simplecpp.h lib/config.h lib/errortypes.h lib/mathlib.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vfvalue.h +$(libcppdir)/mathlib.o: lib/mathlib.cpp externals/simplecpp/simplecpp.h 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)/mathlib.cpp $(libcppdir)/path.o: lib/path.cpp externals/simplecpp/simplecpp.h lib/config.h lib/path.h lib/standards.h lib/utils.h @@ -621,316 +639,331 @@ $(libcppdir)/pathanalysis.o: lib/pathanalysis.cpp lib/astutils.h lib/config.h li $(libcppdir)/pathmatch.o: lib/pathmatch.cpp lib/config.h lib/path.h lib/pathmatch.h lib/standards.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/pathmatch.cpp -$(libcppdir)/platform.o: lib/platform.cpp externals/tinyxml2/tinyxml2.h lib/config.h lib/mathlib.h lib/path.h lib/platform.h lib/standards.h lib/xml.h +$(libcppdir)/platform.o: lib/platform.cpp externals/tinyxml2/tinyxml2.h lib/config.h lib/mathlib.h lib/path.h lib/platform.h lib/standards.h lib/utils.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/platform.cpp -$(libcppdir)/preprocessor.o: lib/preprocessor.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h +$(libcppdir)/preprocessor.o: lib/preprocessor.cpp externals/simplecpp/simplecpp.h lib/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/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)/reverseanalyzer.o: lib/reverseanalyzer.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/forwardanalyzer.h lib/library.h lib/mathlib.h lib/platform.h lib/reverseanalyzer.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueptr.h lib/vfvalue.h +$(libcppdir)/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/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)/settings.o: lib/settings.cpp externals/picojson/picojson.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/summaries.h lib/suppressions.h lib/utils.h lib/vfvalue.h +$(libcppdir)/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/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/platform.h lib/settings.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/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h +$(libcppdir)/suppressions.o: lib/suppressions.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/suppressions.cpp -$(libcppdir)/templatesimplifier.o: lib/templatesimplifier.cpp lib/addoninfo.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/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 lib/utils.h +$(libcppdir)/timer.o: lib/timer.cpp lib/config.h lib/timer.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/timer.cpp -$(libcppdir)/token.o: lib/token.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/tokenrange.h lib/utils.h lib/valueflow.h lib/vfvalue.h +$(libcppdir)/token.o: lib/token.cpp externals/simplecpp/simplecpp.h lib/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/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/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/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_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/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/templatesimplifier.h lib/token.h lib/utils.h lib/vfvalue.h +$(libcppdir)/vfvalue.o: lib/vfvalue.cpp lib/config.h lib/errortypes.h lib/mathlib.h lib/smallvector.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vfvalue.cpp -frontend/frontend.o: frontend/frontend.cpp frontend/frontend.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h +frontend/frontend.o: frontend/frontend.cpp frontend/frontend.h lib/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/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h lib/xml.h +cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/filelister.h externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/checks.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/regex.h lib/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/settings.h lib/standards.h lib/suppressions.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/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 $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/filelister.cpp -cli/main.o: cli/main.cpp cli/cppcheckexecutor.h lib/config.h lib/errortypes.h lib/filesettings.h lib/mathlib.h lib/path.h lib/platform.h lib/standards.h +cli/main.o: cli/main.cpp cli/cppcheckexecutor.h lib/config.h lib/filesettings.h lib/mathlib.h lib/path.h lib/platform.h lib/standards.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/main.cpp -cli/processexecutor.o: cli/processexecutor.cpp cli/executor.h cli/processexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h +cli/processexecutor.o: cli/processexecutor.cpp cli/executor.h cli/processexecutor.h lib/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 $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/sehwrapper.cpp -cli/signalhandler.o: cli/signalhandler.cpp cli/signalhandler.h cli/stacktrace.h lib/config.h lib/utils.h +cli/signalhandler.o: cli/signalhandler.cpp cli/signalhandler.h cli/stacktrace.h lib/config.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/signalhandler.cpp -cli/singleexecutor.o: cli/singleexecutor.cpp cli/executor.h cli/singleexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/config.h lib/cppcheck.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/timer.h lib/utils.h +cli/singleexecutor.o: cli/singleexecutor.cpp cli/executor.h cli/singleexecutor.h lib/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/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/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/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/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/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 test/options.h +test/options.o: test/options.cpp lib/config.h lib/timer.h test/options.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/options.cpp -test/test64bit.o: test/test64bit.cpp lib/addoninfo.h lib/check.h lib/check64bit.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/test64bit.o: test/test64bit.cpp lib/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/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/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/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/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/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/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/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/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/testclangimport.o: test/testclangimport.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/clangimport.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h +test/testcheckersreport.o: test/testcheckersreport.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkersreport.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/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/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/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/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h +test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h lib/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/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/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/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/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcppcheck.cpp -test/testerrorlogger.o: test/testerrorlogger.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/xml.h test/fixture.h test/helpers.h +test/testerrorlogger.o: test/testerrorlogger.cpp externals/tinyxml2/tinyxml2.h lib/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/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/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/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/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/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/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/settings.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/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/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/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/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/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/settings.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/settings.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/settings.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/settings.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/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/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/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/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/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/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/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/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/settings.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/testsettings.o: test/testsettings.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/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/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/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/settings.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/settings.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/settings.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/settings.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/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/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/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/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/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/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/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsuppressions.cpp -test/testsymboldatabase.o: test/testsymboldatabase.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/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/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/settings.h lib/standards.h lib/timer.h lib/utils.h test/fixture.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/settings.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/settings.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/settings.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/settings.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/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/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/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/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/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/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/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/settings.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/settings.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/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/TUNING.md b/TUNING.md index 76ba9383293..ba1f7f49738 100644 --- a/TUNING.md +++ b/TUNING.md @@ -28,7 +28,7 @@ Boost.Container (https://www.boost.org/doc/libs/release/libs/container) is being As the used library is header-only implementation you only need to install the package on the system you build the binary on but not on the system you run the analysis on. -The official Windows binary is currently not using this - see https://trac.cppcheck.net/ticket/13823 for details. +The official Windows binary is always using this. This will be used by default if Boost is detected in CMake. If you want to enforce the usage, you can use the CMake option `-DUSE_BOOST=On` which will cause the build to fail if no Boost was detected. @@ -36,7 +36,7 @@ Using Visual Studio you need to provide a full Boost release (i.e. including bin If you are using `make` instead you need to specify `-DHAVE_BOOST` in the flags. -(TODO: document how to use with provided Visual Studio project) +If you are using the Visual Studio project you need to specify the properties `HaveBoost` (always needs to be set to `HAVE_BOOST`) and `BoostInclude` (set to the Boost folder). On the command-line you would need to add `-p:HaveBoost=HAVE_BOOST -p:BoostInclude=`. ### Use A Different Compiler @@ -46,7 +46,7 @@ In our case Clang is mostly faster than GCC. See https://trac.cppcheck.net/ticke ### Use More Advanced Optimizations -By default we enforce the `-O2` optimization level. Even when using the `Release` build type in CMake which defaults to `-O3`. It might be possible that building with `-O3` might yield a perfomance increase. +By default we enforce the `-O2` optimization level. Even when using the `Release` build type in CMake which defaults to `-O3`. It might be possible that building with `-O3` might yield a performance increase. There are also no additional code generation flags provided so the resulting binary can run on any system. You might be able to tune this and apply more optimization which is tailored to the system you will be running the binary on. diff --git a/addons/README.md b/addons/README.md index 563c0c793f6..05502f547b6 100644 --- a/addons/README.md +++ b/addons/README.md @@ -4,19 +4,19 @@ Addons are scripts that analyses Cppcheck dump files to check compatibility with ## Supported addons -+ [misra.py](https://github.com/danmar/cppcheck/blob/main/addons/misra.py) - Used to verify compliance with MISRA C 2012 - a proprietary set of guidelines to avoid such questionable code, developed for embedded systems. Since this standard is proprietary, cppcheck does not display error text by specifying only the number of violated rules (for example, [c2012-21.3]). If you want to display full texts for violated rules, you will need to create a text file containing MISRA rules, which you will have to pass when calling the script with `--rule-texts` key. Some examples of rule texts files available in [tests directory](https://github.com/danmar/cppcheck/blob/main/addons/test/misra/). -+ [y2038.py](https://github.com/danmar/cppcheck/blob/main/addons/y2038.py) - Checks Linux system for [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) safety. This required [modified environment](https://github.com/3adev/y2038). See complete description [here](https://github.com/danmar/cppcheck/blob/main/addons/doc/y2038.txt). -+ [threadsafety.py](https://github.com/danmar/cppcheck/blob/main/addons/threadsafety.py) ++ [misra.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/misra.py) + Used to verify compliance with MISRA C 2012 - a proprietary set of guidelines to avoid such questionable code, developed for embedded systems. Since this standard is proprietary, cppcheck does not display error text by specifying only the number of violated rules (for example, [c2012-21.3]). If you want to display full texts for violated rules, you will need to create a text file containing MISRA rules, which you will have to pass when calling the script with `--rule-texts` key. Some examples of rule texts files available in [tests directory](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/test/misra/). ++ [y2038.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/y2038.py) + Checks code for [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) safety. See complete description [here](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/doc/y2038.md). ++ [threadsafety.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/threadsafety.py) Analyse Cppcheck dump files to locate threadsafety issues like static local objects used by multiple threads. -+ [naming.py](https://github.com/danmar/cppcheck/blob/main/addons/naming.py) ++ [naming.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/naming.py) Enforces naming conventions across the code. -+ [namingng.py](https://github.com/danmar/cppcheck/blob/main/addons/namingng.py) ++ [namingng.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/namingng.py) Enforces naming conventions across the code. Enhanced version with support for type prefixes in variable and function names. -+ [findcasts.py](https://github.com/danmar/cppcheck/blob/main/addons/findcasts.py) ++ [findcasts.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/findcasts.py) Locates casts in the code. -+ [misc.py](https://github.com/danmar/cppcheck/blob/main/addons/misc.py) ++ [misc.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/misc.py) Performs miscellaneous checks. ### Other files @@ -50,6 +50,11 @@ Addons are scripts that analyses Cppcheck dump files to check compatibility with cppcheck --addon=misc src/test.c ``` +For project-wide analysis with compile_commands.json: +```bash +cppcheck --project=build/compile_commands.json --addon=y2038 +``` + It is also possible to call scripts as follows: ```bash cppcheck --dump --quiet src/test.c @@ -63,5 +68,5 @@ This allows you to add additional parameters when calling the script (for exampl When using the graphical interface `cppcheck-gui`, the selection and configuration of addons is carried out on the tab `Addons and tools` in the project settings (`Edit Project File`): -![Screenshot](https://raw.githubusercontent.com/danmar/cppcheck/main/addons/doc/img/cppcheck-gui-addons.png) +![Screenshot](https://raw.githubusercontent.com/cppcheck-opensource/cppcheck/main/addons/doc/img/cppcheck-gui-addons.png) diff --git a/addons/cppcheckdata.py b/addons/cppcheckdata.py index b0e53161f3a..06028e2005c 100755 --- a/addons/cppcheckdata.py +++ b/addons/cppcheckdata.py @@ -274,7 +274,7 @@ class Token: astParent ast parent astOperand1 ast operand1 astOperand2 ast operand2 - orriginalName orriginal name of the token + orriginalName original name of the token valueType type information: container/.. file file name linenr line number @@ -1003,7 +1003,7 @@ def isMatch(self, file, line, message, errorId): and (self.symbolName is None or fnmatch(message, '*'+self.symbolName+'*')) and fnmatch(errorId, self.errorId)): return True - # Other Suppression (Globaly set via suppression file or cli command) + # Other Suppression (Globally set via suppression file or cli command) if ((self.fileName is None or fnmatch(file, self.fileName)) and (self.suppressionType is None) and (self.symbolName is None or fnmatch(message, '*'+self.symbolName+'*')) @@ -1341,7 +1341,7 @@ def iterconfigurations(self): # Parse tokens elif node.tag == 'tokenlist' and event == 'start': continue - elif node.tag == 'token' and event == 'start' and not iter_directive: + elif node.tag == 'token' and event == 'start' and not iter_directive and not iter_typedef_info: cfg.tokenlist.append(Token(node)) # Parse scopes diff --git a/addons/doc/y2038.md b/addons/doc/y2038.md new file mode 100644 index 00000000000..5566c3936ba --- /dev/null +++ b/addons/doc/y2038.md @@ -0,0 +1,166 @@ +# README of the Y2038 cppcheck addon + +## Contents + +- [README of the Y2038 cppcheck addon](#readme-of-the-y2038-cppcheck-addon) + - [Contents](#contents) + - [What is Y2038?](#what-is-y2038) + - [What is the Y2038 cppcheck addon?](#what-is-the-y2038-cppcheck-addon) + - [How does the Y2038 cppcheck addon work?](#how-does-the-y2038-cppcheck-addon-work) + - [Primary Usage: Cppcheck Addon Integration (`y2038.py`)](#primary-usage-cppcheck-addon-integration-y2038py) + - [Implementation Details](#implementation-details) + - [Requirements](#requirements) + - [How to use the Y2038 cppcheck addon](#how-to-use-the-y2038-cppcheck-addon) + - [**Auditing Your Project for Y2038 Compliance**](#auditing-your-project-for-y2038-compliance) + - [**CI/CD Integration**](#cicd-integration) + - [Testing](#testing) + - [Running Y2038 Addon Tests](#running-y2038-addon-tests) + - [Test Coverage](#test-coverage) + - [Test Structure](#test-structure) + +--- + +## What is Y2038? + +In a few words: + +Most operating systems and programming environments represent the current time as the number of seconds since the Unix epoch. In C and C++ this is exposed by time() and std::time(), with the Unix epoch defined as 00:00:00 UTC on 1 January 1970. + +Typically this representation is stored as a 64-bit signed quantity. +Some systems, mainly embedded systems and older systems, still use a 32-bit signed +time_t representation. + +On January 19th, 2038 at 03:14:07 GMT, such 32-bit representations will reach +their maximum positive value. + +What happens then is unpredictable: system time might roll back to December +13th, 1901 at 19:55:13, or it might keep running on until February 7th, 2106 +at 06:28:15 GMT, or the computer may freeze, or just about anything you can +think of, plus a few ones you can't. + +The workaround for this is to switch to a 64-bit signed representation of time +as seconds from the Unix epoch. This representation will work for more than 250 +billion years. + +Working around Y2038 requires fixing the Linux kernel, the C libraries, and +any user code around which uses 32-bit epoch representations. + +There is Y2038-proofing work in progress on the Linux and GNU glibc front. + +## What is the Y2038 cppcheck addon? + +The Y2038 cppcheck addon is a tool to help detect code which might need fixing +because it is Y2038-unsafe. This may be because it uses types or functions from +GNU libc or from the Linux kernel which are known not to be Y2038-proof. + +## How does the Y2038 cppcheck addon work? + +The Y2038 addon is a comprehensive tool designed to audit your project for Y2038 compliance. It provides a streamlined, intelligent approach to Y2038 analysis. + +### Primary Usage: Cppcheck Integration with Project Files + +The Y2038 addon integrates seamlessly with cppcheck's core project parsing infrastructure. For optimal analysis, use the addon with project files: + +```bash +cppcheck --project=build/compile_commands.json --addon=y2038 +``` + +For single files, you can also use: +```bash +cppcheck --addon=y2038 source_file.c +``` + +#### Implementation Details + +The addon leverages cppcheck's built-in project parsing capabilities: + +- **Core Integration**: Y2038-related compiler flags are extracted by cppcheck core during project parsing and passed through dump file configuration +- **Automatic Flag Detection**: Cppcheck automatically detects Y2038-relevant flags (`-D_TIME_BITS=64`, `-D_FILE_OFFSET_BITS=64`, `-D_USE_TIME_BITS64`) from compilation commands +- **Clean Architecture**: No redundant file parsing - cppcheck handles project files once, addon focuses on analysis +- **Priority Logic**: Dump file configuration (from cppcheck's project parsing) takes precedence over source code `#define` statements +- **Source Fallback**: When no project configuration is available, the addon analyzes source code `#define` statements + +This architecture ensures optimal performance and maintains clean separation of concerns between cppcheck core (project parsing) and addon (analysis logic). + +The output is the standard Cppcheck analysis report, focused on Y2038-related issues. + +## Requirements + +The Y2038 addon works with any cppcheck installation and requires no additional dependencies beyond cppcheck itself. + +For optimal Y2038 analysis, ensure your project uses a supported build system that generates `compile_commands.json`: + +- **CMake**: Use `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON` +- **Bear**: For Make/Autotools projects, use `bear` to generate compile commands +- **Ninja**: Use `ninja -t compdb` to generate compile commands +- **Bazel**: Use `bazel aquery` with appropriate flags + +If using `bear` for Make-based projects, install it via your package manager: + +```bash +# On Debian/Ubuntu +sudo apt-get install bear + +# On Fedora +sudo dnf install bear + +# On macOS (using Homebrew) +brew install bear +``` + +## How to use the Y2038 cppcheck addon + +### **Auditing Your Project for Y2038 Compliance** + +The Y2038 addon seamlessly integrates with your existing cppcheck workflow. + +**For projects with compile_commands.json (recommended):** + +```bash +cppcheck --project=build/compile_commands.json --addon=y2038 +``` + +**For single file analysis:** + +```bash +cppcheck --addon=y2038 source_file.c +``` + +**For project-wide analysis without compile_commands.json:** + +```bash +cppcheck --addon=y2038 src/ +``` + +The integration automatically: + +1. **Extracts Y2038 flags** from your project's compilation commands via cppcheck's project parsing +2. **Passes flag information** through dump file configuration to the addon +3. **Analyzes source code** with proper Y2038 context from both build system and source directives +4. **Reports Y2038 issues** using cppcheck's standard error reporting format + +### **CI/CD Integration** + +For CI/CD integration, use the Y2038 addon with your project's build configuration: + +```sh +# Example CI script with compile_commands.json +#!/bin/bash +# Generate compile_commands.json (if not already available) +cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -B build +# or: bear -- make + +# Run Y2038 analysis +cppcheck --project=build/compile_commands.json --addon=y2038 --error-exitcode=1 + +# The addon will return a non-zero exit code if Y2038 issues are found. +# The output is the standard Cppcheck report. +``` + +**For projects without compile_commands.json:** + +```sh +# Example CI script for source-only analysis +#!/bin/bash +cppcheck --addon=y2038 --error-exitcode=1 src/ +``` diff --git a/addons/doc/y2038.txt b/addons/doc/y2038.txt deleted file mode 100644 index 990b24bd483..00000000000 --- a/addons/doc/y2038.txt +++ /dev/null @@ -1,151 +0,0 @@ -README of the Y2038 cppcheck addon -================================== - -Contents - -1. What is Y2038? -2. What is the Y2038 cppcheck addon? -3. How does the Y2038 cppcheck addon work? -4. How to use the Y2038 cppcheck addon - ---- - -1. What is Y2038? - -In a few words: - -In Linux, the current date and time is kept as the number of seconds elapsed -since the Unix epoch, that is, since January 1st, 1970 at 00:00:00 GMT. - -Most of the time, this representation is stored as a 32-bit signed quantity. - -On January 19th, 2038 at 03:14:07 GMT, such 32-bit representations will reach -their maximum positive value. - -What happens then is unpredictable: system time might roll back to December -13th, 1901 at 19:55:13, or it might keep running on until February 7th, 2106 -at 06:28:15 GMT, or the computer may freeze, or just about anything you can -think of, plus a few ones you can't. - -The workaround for this is to switch to a 64-bit signed representation of time -as seconds from the Unix epoch. This representation will work for more than 250 -billion years. - -Working around Y2038 requires fixing the Linux kernel, the C libraries, and -any user code around which uses 32-bit epoch representations. - -There is Y2038-proofing work in progress on the Linux and GNU glibc front. - -2. What is the Y2038 cppcheck addon? - -The Y2038 cppcheck addon is a tool to help detect code which might need fixing -because it is Y2038-unsafe. This may be because it uses types or functions from -GNU libc or from the Linux kernel which are known not to be Y2038-proof. - -3. How does the Y2038 cppcheck addon work? - -The Y2038 cppcheck addon takes XML dumps produced by cppcheck from source code -files and looks for the names of types or functions which are known to be Y2038- -unsafe, and emits diagnostics whenever it finds one. - -Of course, this is of little use if your code uses a Y2038-proof glibc and -correctly configured Y2038-proof time support. - -This is why y2038.py takes into account two preprocessor directives: -_TIME_BITS and __USE_TIME_BITS64. - -_TIME_BITS is defined equal to 64 by user code when it wants 64-bit time -support from the GNU glibc. Code which does not define _TIME_BITS equal to 64 -(or defines it to something else than 64) runs a risk of not being Y2038-proof. - -__USE_TIME_BITS64 is defined by the GNU glibc when it actually provides 64-bit -time support. When this is defined, then all glibc symbols, barring bugs, are -Y2038-proof (but your code might have its own Y2038 bugs, if it handles signed -32-bit Unix epoch values). - -The Y2038 cppcheck performs the following checks: - - 1. Upon meeting a definition for _TIME_BITS, if that definition does not - set it equal to 64, this error diagnostic is emitted: - - Error: _TIME_BITS must be defined equal to 64 - - This case is very unlikely but might result from a typo, so pointing - it out is quite useful. Note that definitions of _TIME_BITS as an - expression evaluating to 64 will be flagged too. - - 2. Upon meeting a definition for _USE_TIME_BITS64, if _TIME_BITS is not - defined equal to 64, this information diagnostic is emitted: - - Warning: _USE_TIME_BITS64 is defined but _TIME_BITS was not - - This reflects the fact that even though the glibc checked default to - 64-bit time support, this was not requested by the user code, and - therefore the user code might fail Y2038 if built against a glibc - which defaults to 32-bit time support. - - 3. Upon meeting a symbol (type or function) which is known to be Y2038- - unsafe, if _USE_TIME_BITS64 is undefined or _TIME_BITS not properly - defined, this warning diagnostic is emitted: - - Warning: is Y2038-unsafe - - This reflects the fact that the user code is referring to a symbol - which, when glibc defaults to 32-bit time support, might fail Y2038. - -General note: y2038.py will handle multiple configurations, and will -emit diagnostics for each configuration in turn. - -4. How to use the Y2038 cppcheck addon - -The Y2038 cppcheck addon is used like any other cppcheck addon: - - cppcheck --dump file1.c [ file2.c [...]]] - y2038.py file1.c [ file2.c [...]]] - -Sample test C file is provided: - - test/y2038-test-1-bad-time-bits.c - test/y2038-test-2-no-time-bits.c - test/y2038-test-3-no-use-time-bits.c - test/y2038-test-4-good.c - -These cover the cases described above. You can run them through cppcheck -and y2038.py to see for yourself how the addon diagnostics look like. If -this README is not outdated (and if it is, feel free to submit a patch), -you can run cppcheck on these files as on any others: - - cppcheck --dump addons/y2038/test/y2038-*.c - y2038.py addons/y2038/test/y2038-*.dump - -If you have not installed cppcheck yet, you will have to run these -commands from the root of the cppcheck repository: - - make - sudo make install - ./cppcheck --dump addons/y2038/test/y2038-*.c - PYTHONPATH=addons python addons/y2038/y2038.py addons/y2038/test/y2038-*.c.dump - -In both cases, y2038.py execution should result in the following: - -Checking addons/y2038/test/y2038-test-1-bad-time-bits.c.dump... -Checking addons/y2038/test/y2038-test-1-bad-time-bits.c.dump, config ""... -Checking addons/y2038/test/y2038-test-2-no-time-bits.c.dump... -Checking addons/y2038/test/y2038-test-2-no-time-bits.c.dump, config ""... -Checking addons/y2038/test/y2038-test-3-no-use-time-bits.c.dump... -Checking addons/y2038/test/y2038-test-3-no-use-time-bits.c.dump, config ""... -Checking addons/y2038/test/y2038-test-4-good.c.dump... -Checking addons/y2038/test/y2038-test-4-good.c.dump, config ""... -# Configuration "": -# Configuration "": -[addons/y2038/test/y2038-test-1-bad-time-bits.c:8]: (error) _TIME_BITS must be defined equal to 64 -[addons/y2038/test/y2038-inc.h:9]: (warning) _USE_TIME_BITS64 is defined but _TIME_BITS was not -[addons/y2038/test/y2038-test-1-bad-time-bits.c:10]: (information) addons/y2038/test/y2038-inc.h was included from here -[addons/y2038/test/y2038-inc.h:9]: (warning) _USE_TIME_BITS64 is defined but _TIME_BITS was not -[addons/y2038/test/y2038-test-2-no-time-bits.c:8]: (information) addons/y2038/test/y2038-inc.h was included from here -[addons/y2038/test/y2038-test-3-no-use-time-bits.c:13]: (warning) timespec is Y2038-unsafe -[addons/y2038/test/y2038-test-3-no-use-time-bits.c:15]: (warning) clock_gettime is Y2038-unsafe - -Note: y2038.py recognizes option --template as cppcheck does, including -pre-defined templates 'gcc', 'vs' and 'edit'. The short form -t is also -recognized. diff --git a/addons/misra.py b/addons/misra.py index ca8eb2bfb69..933ef4c2025 100755 --- a/addons/misra.py +++ b/addons/misra.py @@ -22,7 +22,6 @@ import re import os import argparse -import codecs import string import copy @@ -804,8 +803,7 @@ def get_function_pointer_type(tok): ret += '(' tok = tok.next.next while tok and (tok.str not in '()'): - if tok.varId is None: - ret += ' ' + tok.str + ret += ' ' + tok.str tok = tok.next if (tok is None) or tok.str != ')': return None @@ -2461,20 +2459,38 @@ def get_category(essential_type): if essential_type.split(' ')[0] in ('unsigned', 'signed'): return essential_type.split(' ')[0] return None + for tok in cfg.tokenlist: - if tok.isAssignmentOp: - lhs = getEssentialType(tok.astOperand1) - rhs = getEssentialType(tok.astOperand2) - #print(lhs) - #print(rhs) - if lhs is None or rhs is None: + if not tok.isAssignmentOp: + continue + + lhs = getEssentialType(tok.astOperand1) + rhs = getEssentialType(tok.astOperand2) + if lhs is None or rhs is None: + continue + + find_std = cfg.standards.c if cfg.standards and cfg.standards.c else self.stdversion + + rhs_tok = tok.astOperand2 + rhs_macro_name = rhs_tok.macroName if rhs_tok else None + rhs_spelling = rhs_macro_name if rhs_macro_name in ('true', 'false') else rhs_tok.str + + rhs_is_source_bool_literal = rhs_spelling in ('true', 'false') + rhs_is_source_int_literal_0_1 = rhs_spelling in ('0', '1') + + if lhs == 'bool': + if rhs_is_source_bool_literal: continue - lhs_category = get_category(lhs) - rhs_category = get_category(rhs) - if lhs_category and rhs_category and lhs_category != rhs_category and rhs_category not in ('signed','unsigned'): - self.reportError(tok, 10, 3) - if bitsOfEssentialType(lhs) < bitsOfEssentialType(rhs) and (lhs != "bool" or tok.astOperand2.str not in ('0','1')): - self.reportError(tok, 10, 3) + if find_std == 'c89' and rhs_is_source_int_literal_0_1: + continue + + lhs_category = get_category(lhs) + rhs_category = get_category(rhs) + if lhs_category and rhs_category and lhs_category != rhs_category and rhs_category not in ('signed', 'unsigned'): + self.reportError(tok, 10, 3) + + if bitsOfEssentialType(lhs) < bitsOfEssentialType(rhs): + self.reportError(tok, 10, 3) def misra_10_4(self, data): op = {'+', '-', '*', '/', '%', '&', '|', '^', '+=', '-=', ':'} @@ -4525,7 +4541,7 @@ def loadRuleTexts(self, filename): encodings = ['ascii', 'utf-8', 'windows-1250', 'windows-1252'] for e in encodings: try: - file_stream = codecs.open(filename, 'r', encoding=e) + file_stream = open(filename, 'r', encoding=e) file_stream.readlines() file_stream.seek(0) except UnicodeDecodeError: diff --git a/addons/test/misra/crash10.c b/addons/test/misra/crash10.c index 455d86e57ec..65e3a14ac96 100644 --- a/addons/test/misra/crash10.c +++ b/addons/test/misra/crash10.c @@ -2,7 +2,7 @@ extern uint32_t end; -//#define KEEP // if uncomment this then wont crash +//#define KEEP // if uncomment this then won't crash KEEP static const int32_t ptr_to_end = &end; diff --git a/addons/test/misra/misra-test-c11.c b/addons/test/misra/misra-test-c11.c index 031bc361e5f..aa00b2f0b42 100644 --- a/addons/test/misra/misra-test-c11.c +++ b/addons/test/misra/misra-test-c11.c @@ -2,6 +2,7 @@ // ~/cppcheck/cppcheck --dump misra/misra-test-c11.c --std=c11 // ~/cppcheck/cppcheck --dump -DDUMMY --suppress=uninitvar --inline-suppr misra/misra-test-c11.c --std=c11 --platform=unix64 && python3 ../misra.py -verify misra/misra-test-c11.c.dump +#include #include typedef unsigned int UINT_TYPEDEF; @@ -23,3 +24,15 @@ static void misra6_1_fn(void) { struct_with_bitfields s; s.h = 61; } + +static void misra_10_3_c11(void) { + bool b = false; + bool b0 = 0; // 10.3 + bool b1 = 1; // 10.3 + bool bf = false; // no-warning + bool bt = true; // no-warning + b = 0; // 10.3 + b = 1; // 10.3 + b = false; // no-warning + b = true; // no-warning +} diff --git a/addons/test/misra/misra-test.c b/addons/test/misra/misra-test.c index 2435dcf253a..6b6f52342aa 100644 --- a/addons/test/misra/misra-test.c +++ b/addons/test/misra/misra-test.c @@ -725,7 +725,11 @@ static void misra_10_3(uint32_t u32a, uint32_t u32b) { res = 0.1f; // 10.3 const char c = '0'; // no-warning bool b = true; // no-warning - uint32_t u = UINT32_C(10); // 17.3 no-warning + uint32_t u = UINT32_C(10); // no-warning + bool b0 = 0; // no-warning + bool b1 = 1; // no-warning + b = 0; // no-warning + b = 1; // no-warning } static void misra_10_4(u32 x, s32 y) { diff --git a/addons/test/y2038/y2038-test-compiler-flags.c b/addons/test/y2038/y2038-test-compiler-flags.c new file mode 100644 index 00000000000..99baa0e1582 --- /dev/null +++ b/addons/test/y2038/y2038-test-compiler-flags.c @@ -0,0 +1,25 @@ +/* + * Shared test case for Y2038 addon compiler flag testing + * + * This file tests various compiler flag scenarios: + * - Proper Y2038 configuration: -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64 -D_USE_TIME_BITS64 + * - Incorrect _TIME_BITS value: -D_TIME_BITS=32 + * - Incomplete configuration: -D_USE_TIME_BITS64 (without _TIME_BITS) + * + * The same source code is used for all scenarios - differentiation happens + * through the compiler flags passed to cppcheck during dump creation. + */ + +#include + +int main(int argc, char **argv) +{ + time_t current_time; + struct timespec ts; + + current_time = time(NULL); + clock_gettime(CLOCK_REALTIME, &ts); + + return 0; +} + diff --git a/addons/test/y2038_test.py b/addons/test/y2038_test.py index 282e55650d7..861b006d8bf 100644 --- a/addons/test/y2038_test.py +++ b/addons/test/y2038_test.py @@ -21,18 +21,28 @@ './addons/test/y2038/y2038-test-4-good.c', './addons/test/y2038/y2038-test-5-good-no-time-used.c'] +# Build system test file (for testing build system integration) +BUILD_SYSTEM_TEST_FILE = './addons/test/y2038/y2038-test-buildsystem.c' + def setup_module(module): sys.argv.append("--cli") + + # Create dumps for regular test files for f in TEST_SOURCE_FILES: dump_create(f) + # For build system tests, we'll create dumps on-demand in each test + # to avoid conflicts from multiple dump_create calls on the same file + def teardown_module(module): sys.argv.remove("--cli") for f in TEST_SOURCE_FILES: dump_remove(f) + # Build system test dumps are cleaned up individually in each test method + def test_1_bad_time_bits(capsys): is_safe = check_y2038_safe('./addons/test/y2038/y2038-test-1-bad-time-bits.c.dump', quiet=True) @@ -107,6 +117,31 @@ def test_5_good(capsys): assert(len([c for c in unsafe_calls if c['file'].endswith('.c')]) == 0) +def test_build_system_integration(): + """Test that Y2038 flags are properly parsed from cppcheck dump file configuration""" + from addons.y2038 import parse_dump_config + + # Test Y2038-safe configuration string (as cppcheck would generate it) + config_string = "_TIME_BITS=64;_FILE_OFFSET_BITS=64;_USE_TIME_BITS64" + result = parse_dump_config(config_string) + # Y2038-safe flags should be detected + assert result['time_bits_defined'] is True + assert result['time_bits_value'] == 64 + assert result['use_time_bits64_defined'] is True + assert result['file_offset_bits_defined'] is True + assert result['file_offset_bits_value'] == 64 + + # Test partial Y2038 configuration + partial_config = "_TIME_BITS=32;_FILE_OFFSET_BITS=64" + result = parse_dump_config(partial_config) + # Should detect the flags with their actual values + assert result['time_bits_defined'] is True + assert result['time_bits_value'] == 32 # Not Y2038-safe value + assert result['use_time_bits64_defined'] is False + assert result['file_offset_bits_defined'] is True + assert result['file_offset_bits_value'] == 64 + + def test_arguments_regression(): args_ok = ["-t=foo", "--template=foo", "-q", "--quiet", @@ -137,4 +172,35 @@ def test_arguments_regression(): pytest.fail("Unexpected SystemExit with '%s'" % arg) sys.argv.remove(arg) finally: - sys.argv = sys_argv_old \ No newline at end of file + sys.argv = sys_argv_old + + +def test_parse_dump_config(): + """Test the parse_dump_config function for cppcheck dump file integration""" + from addons.y2038 import parse_dump_config + + # Test comprehensive Y2038 configuration + full_config = "_TIME_BITS=64;_FILE_OFFSET_BITS=64;_USE_TIME_BITS64;OTHER_FLAG=1" + result = parse_dump_config(full_config) + + assert result['time_bits_defined'] is True + assert result['time_bits_value'] == 64 + assert result['use_time_bits64_defined'] is True + assert result['file_offset_bits_defined'] is True + assert result['file_offset_bits_value'] == 64 + + # Test empty configuration + result = parse_dump_config("") + assert result['time_bits_defined'] is False + assert result['time_bits_value'] is None + assert result['use_time_bits64_defined'] is False + assert result['file_offset_bits_defined'] is False + assert result['file_offset_bits_value'] is None + # Test Y2038-unsafe configuration + unsafe_config = "_TIME_BITS=32;_FILE_OFFSET_BITS=32" + result = parse_dump_config(unsafe_config) + assert result['time_bits_defined'] is True + assert result['time_bits_value'] == 32 + assert result['use_time_bits64_defined'] is False + assert result['file_offset_bits_defined'] is True + assert result['file_offset_bits_value'] == 32 \ No newline at end of file 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/addons/y2038.py b/addons/y2038.py index 93d237afd06..b17d41dd330 100755 --- a/addons/y2038.py +++ b/addons/y2038.py @@ -2,14 +2,33 @@ # # cppcheck addon for Y2038 safeness detection # +# This addon provides comprehensive Y2038 (Year 2038 Problem) detection for C/C++ code. +# It extracts compiler flags from cppcheck dump file configuration to determine +# Y2038 safety, suppressing warnings when proper configuration is detected. +# +# Key Features: +# - Extraction of Y2038-related flags from cppcheck dump file configuration +# - Compiler flag parsing and validation from cppcheck's project parsing +# - Warning suppression when proper Y2038 configuration is found +# - Support for both _TIME_BITS=64 and _FILE_OFFSET_BITS=64 requirements +# - Priority-based flag resolution (dump file configuration > source code directives) +# # Detects: # # 1. _TIME_BITS being defined to something else than 64 bits -# 2. _USE_TIME_BITS64 being defined when _TIME_BITS is not -# 3. Any Y2038-unsafe symbol when _USE_TIME_BITS64 is not defined. +# 2. _FILE_OFFSET_BITS being defined to something else than 64 bits +# 3. _USE_TIME_BITS64 being defined when _TIME_BITS is not +# 4. Any Y2038-unsafe symbol when proper Y2038 configuration is not present +# 5. Dump file configurations that affect Y2038 safety +# +# Warning Suppression: +# When both _TIME_BITS=64 AND _FILE_OFFSET_BITS=64 are detected (prioritizing dump file +# configuration over source code directives), Y2038 warnings are suppressed and an +# informational message is displayed instead. # # Example usage: # $ cppcheck --addon=y2038 path-to-src/test.c +# $ cppcheck --dump file.c && python3 y2038.py file.c.dump # from __future__ import print_function @@ -18,13 +37,23 @@ import sys import re +# Y2038 flags are extracted by cppcheck core during project parsing +# and passed through dump file configuration - no redundant parsing needed + +# -------------------------------- +# Y2038 safety constants +# -------------------------------- + +# Y2038-safe bit values +Y2038_SAFE_TIME_BITS = 64 +Y2038_SAFE_FILE_OFFSET_BITS = 64 # -------------------------------------------- # #define/#undef detection regular expressions # -------------------------------------------- # test for '#define _TIME_BITS 64' -re_define_time_bits_64 = re.compile(r'^\s*#\s*define\s+_TIME_BITS\s+64\s*$') +re_define_time_bits_64 = re.compile(rf'^\s*#\s*define\s+_TIME_BITS\s+{Y2038_SAFE_TIME_BITS}\s*$') # test for '#define _TIME_BITS ...' (combine w/ above to test for 'not 64') re_define_time_bits = re.compile(r'^\s*#\s*define\s+_TIME_BITS\s+.*$') @@ -38,6 +67,34 @@ # test for '#undef _USE_TIME_BITS64' (if it ever happens) re_undef_use_time_bits64 = re.compile(r'^\s*#\s*undef\s+_USE_TIME_BITS64\s*$') +# test for '#define _FILE_OFFSET_BITS 64' +re_define_file_offset_bits_64 = re.compile(rf'^\s*#\s*define\s+_FILE_OFFSET_BITS\s+{Y2038_SAFE_FILE_OFFSET_BITS}\s*$') + +# test for '#define _FILE_OFFSET_BITS ...' (combine w/ above to test for 'not 64') +re_define_file_offset_bits = re.compile(r'^\s*#\s*define\s+_FILE_OFFSET_BITS\s+.*$') + +# test for '#undef _FILE_OFFSET_BITS' (if it ever happens) +re_undef_file_offset_bits = re.compile(r'^\s*#\s*undef\s+_FILE_OFFSET_BITS\s*$') + +# -------------------------------------------- +# Compiler flag parsing regular expressions +# -------------------------------------------- + +# test for '_TIME_BITS=64' in compiler flags +re_flag_time_bits_64 = re.compile(rf'_TIME_BITS={Y2038_SAFE_TIME_BITS}(?:\s|$|;)') + +# test for '_TIME_BITS=...' in compiler flags (combine w/ above to test for 'not 64') +re_flag_time_bits = re.compile(r'_TIME_BITS=(\d+)') + +# test for '_USE_TIME_BITS64' in compiler flags +re_flag_use_time_bits64 = re.compile(r'_USE_TIME_BITS64(?:\s|$|=|;)') + +# test for '_FILE_OFFSET_BITS=64' in compiler flags +re_flag_file_offset_bits_64 = re.compile(rf'_FILE_OFFSET_BITS={Y2038_SAFE_FILE_OFFSET_BITS}(?:\s|$|;)') + +# test for '_FILE_OFFSET_BITS=...' in compiler flags +re_flag_file_offset_bits = re.compile(r'_FILE_OFFSET_BITS=(\d+)') + # -------------------------------- # List of Y2038-unsafe identifiers # -------------------------------- @@ -147,13 +204,142 @@ } + + + + + + + +def parse_dump_config(config_name): + """ + Parse Y2038-related flags from cppcheck dump file configuration name. + + This function analyzes the cppcheck dump file configuration name (which contains + preprocessor definitions extracted by cppcheck from project files like compile_commands.json) + to extract Y2038-related definitions. It looks for _TIME_BITS, _USE_TIME_BITS64, and + _FILE_OFFSET_BITS definitions and validates their values. + + Args: + config_name (str): The cppcheck configuration name from dump file + (e.g., "_TIME_BITS=64;_FILE_OFFSET_BITS=64") + + Returns: + dict: Dictionary containing Y2038-related flag information with keys: + - 'time_bits_defined' (bool): Whether _TIME_BITS is defined + - 'time_bits_value' (int|None): Value of _TIME_BITS (None if not defined) + - 'use_time_bits64_defined' (bool): Whether _USE_TIME_BITS64 is defined + - 'file_offset_bits_defined' (bool): Whether _FILE_OFFSET_BITS is defined + - 'file_offset_bits_value' (int|None): Value of _FILE_OFFSET_BITS (None if not defined) + + Example: + >>> parse_dump_config("_TIME_BITS=64;_FILE_OFFSET_BITS=64") + { + 'time_bits_defined': True, + 'time_bits_value': 64, + 'use_time_bits64_defined': False, + 'file_offset_bits_defined': True, + 'file_offset_bits_value': 64 + } + """ + result = { + 'time_bits_defined': False, + 'time_bits_value': None, + 'use_time_bits64_defined': False, + 'file_offset_bits_defined': False, + 'file_offset_bits_value': None + } + + if not config_name: + return result + + try: + # Check for _TIME_BITS=64 (correct value) + if re_flag_time_bits_64.search(config_name): + result['time_bits_defined'] = True + result['time_bits_value'] = Y2038_SAFE_TIME_BITS + else: + # Check for _TIME_BITS=other_value + match = re_flag_time_bits.search(config_name) + if match: + result['time_bits_defined'] = True + try: + result['time_bits_value'] = int(match.group(1)) + except (ValueError, IndexError): + # Malformed _TIME_BITS value, treat as undefined + result['time_bits_defined'] = False + result['time_bits_value'] = None + + # Check for _USE_TIME_BITS64 + if re_flag_use_time_bits64.search(config_name): + result['use_time_bits64_defined'] = True + + # Check for _FILE_OFFSET_BITS=64 (correct value) + if re_flag_file_offset_bits_64.search(config_name): + result['file_offset_bits_defined'] = True + result['file_offset_bits_value'] = Y2038_SAFE_FILE_OFFSET_BITS + else: + # Check for _FILE_OFFSET_BITS=other_value + match = re_flag_file_offset_bits.search(config_name) + if match: + result['file_offset_bits_defined'] = True + try: + result['file_offset_bits_value'] = int(match.group(1)) + except (ValueError, IndexError): + # Malformed _FILE_OFFSET_BITS value, treat as undefined + result['file_offset_bits_defined'] = False + result['file_offset_bits_value'] = None + + except (AttributeError, TypeError, ValueError): + # If any unexpected error occurs during parsing, return empty result + # This ensures the addon continues to work even with malformed configurations + # Note: We catch specific exceptions rather than broad Exception for better debugging + pass + + return result + + def check_y2038_safe(dumpfile, quiet=False): + """ + Main function to check Y2038 safety of C/C++ code from cppcheck dump files. + + This function performs comprehensive Y2038 analysis including: + 1. Extraction of Y2038-related compiler flags from cppcheck dump file configuration + 2. Analysis of source code preprocessor directives + 3. Warning suppression when proper Y2038 configuration is detected + 4. Reporting of Y2038-unsafe symbols and configurations + + The function implements a priority-based approach for Y2038 flag detection: + - Dump file configuration (from cppcheck's project parsing - highest priority) + - Source code #define directives (fallback) + + Warning suppression occurs when both _TIME_BITS=64 AND _FILE_OFFSET_BITS=64 + are detected from any source. When warnings are suppressed, an informational + message is displayed indicating the configuration source and suppression count. + + Args: + dumpfile (str): Path to the cppcheck XML dump file (.dump extension) + quiet (bool, optional): If True, suppress informational messages. Defaults to False. + + Returns: + bool: True if code is Y2038-safe, False if Y2038 issues were detected + + Raises: + Exception: May raise exceptions from cppcheckdata parsing or file I/O operations + + Example: + >>> check_y2038_safe("test.c.dump") # Normal operation + True + >>> check_y2038_safe("test.c.dump", quiet=True) # Suppress info messages + False + """ # Assume that the code is Y2038 safe until proven otherwise y2038safe = True # load XML from .dump file data = cppcheckdata.CppcheckData(dumpfile) srcfile = data.files[0] + for cfg in data.iterconfigurations(): if not quiet: print('Checking %s, config %s...' % (srcfile, cfg.name)) @@ -162,56 +348,231 @@ def check_y2038_safe(dumpfile, quiet=False): time_bits_defined = False srclinenr = 0 + # Priority-based flag detection: dump file configuration > source code directives + # 1. Check dump file configuration (from cppcheck's project parsing - highest priority) + dump_config_flags = parse_dump_config(cfg.name) + # Initialize effective flags with dump file configuration + effective_flags = { + 'time_bits_defined': dump_config_flags['time_bits_defined'], + 'time_bits_value': dump_config_flags['time_bits_value'], + 'use_time_bits64_defined': dump_config_flags['use_time_bits64_defined'], + 'file_offset_bits_defined': dump_config_flags['file_offset_bits_defined'], + 'file_offset_bits_value': dump_config_flags['file_offset_bits_value'] + } + + # Determine configuration source for reporting + config_source = None + has_dump_config = (dump_config_flags['time_bits_defined'] or + dump_config_flags['file_offset_bits_defined'] or + dump_config_flags['use_time_bits64_defined']) + if has_dump_config: + config_source = "cppcheck configuration" + + # Track time_bits_defined for _USE_TIME_BITS64 validation + time_bits_defined = effective_flags['time_bits_defined'] + + # Check effective _TIME_BITS value (from dump file configuration) + if effective_flags['time_bits_defined']: + if effective_flags['time_bits_value'] != Y2038_SAFE_TIME_BITS: + fake_directive = type('FakeDirective', (), { + 'file': srcfile, 'linenr': 0, 'column': 0, + 'str': 'cppcheck configuration: _TIME_BITS=%s' % effective_flags['time_bits_value'] + })() + cppcheckdata.reportError(fake_directive, 'error', + '_TIME_BITS must be defined equal to 64 (found in cppcheck configuration: _TIME_BITS=%s)' % effective_flags['time_bits_value'], + 'y2038', + 'type-bits-not-64') + y2038safe = False + + # Check effective _FILE_OFFSET_BITS value (from dump file configuration) + if effective_flags['file_offset_bits_defined']: + if effective_flags['file_offset_bits_value'] != Y2038_SAFE_FILE_OFFSET_BITS: + fake_directive = type('FakeDirective', (), { + 'file': srcfile, 'linenr': 0, 'column': 0, + 'str': 'cppcheck configuration: _FILE_OFFSET_BITS=%s' % effective_flags['file_offset_bits_value'] + })() + cppcheckdata.reportError(fake_directive, 'error', + '_FILE_OFFSET_BITS must be defined equal to 64 (found in cppcheck configuration: _FILE_OFFSET_BITS=%s)' % effective_flags['file_offset_bits_value'], + 'y2038', + 'file-offset-bits-not-64') + y2038safe = False + + # Check effective _USE_TIME_BITS64 (from dump file configuration) + if effective_flags['use_time_bits64_defined']: + if not time_bits_defined: + # _USE_TIME_BITS64 defined without _TIME_BITS is problematic + fake_directive = type('FakeDirective', (), { + 'file': srcfile, 'linenr': 0, 'column': 0, + 'str': 'cppcheck configuration: _USE_TIME_BITS64' + })() + cppcheckdata.reportError(fake_directive, 'warning', + '_USE_TIME_BITS64 is defined in cppcheck configuration but _TIME_BITS was not', + 'y2038', + 'type-bits-undef') + y2038safe = False + else: + # _USE_TIME_BITS64 defined WITH _TIME_BITS - this is correct + safe = 0 # Start of file is safe + + # 2. Fallback to source code directives when dump file configuration is not available + source_time_bits_defined = False # pylint: disable=unused-variable + source_file_offset_bits_defined = False # pylint: disable=unused-variable + source_file_offset_bits_value = None # pylint: disable=unused-variable + source_use_time_bits64_defined = False # pylint: disable=unused-variable + + # Track which flags came from source code for mixed scenario reporting + source_flags_used = { + 'time_bits': False, + 'file_offset_bits': False, + 'use_time_bits64': False + } for directive in cfg.directives: # track source line number if directive.file == srcfile: srclinenr = directive.linenr + + # Process source code directives as fallback when dump config is not available # check for correct _TIME_BITS if present if re_define_time_bits_64.match(directive.str): - time_bits_defined = True + source_time_bits_defined = True + # Only use source directive if dump config doesn't define _TIME_BITS + if not effective_flags['time_bits_defined']: + effective_flags['time_bits_defined'] = True + effective_flags['time_bits_value'] = Y2038_SAFE_TIME_BITS + time_bits_defined = True + source_flags_used['time_bits'] = True elif re_define_time_bits.match(directive.str): - cppcheckdata.reportError(directive, 'error', - '_TIME_BITS must be defined equal to 64', - 'y2038', - 'type-bits-not-64') - time_bits_defined = False - y2038safe = False + source_time_bits_defined = False + # Only use source directive if dump config doesn't define _TIME_BITS + if not effective_flags['time_bits_defined']: + source_flags_used['time_bits'] = True + cppcheckdata.reportError(directive, 'error', + '_TIME_BITS must be defined equal to 64', + 'y2038', + 'type-bits-not-64') + y2038safe = False elif re_undef_time_bits.match(directive.str): - time_bits_defined = False + source_time_bits_defined = False + # Only use source directive if dump config doesn't define _TIME_BITS + if not effective_flags['time_bits_defined']: + time_bits_defined = False + source_flags_used['time_bits'] = True + # check for correct _FILE_OFFSET_BITS if present + if re_define_file_offset_bits_64.match(directive.str): + source_file_offset_bits_defined = True + source_file_offset_bits_value = Y2038_SAFE_FILE_OFFSET_BITS + # Only use source directive if dump config doesn't define _FILE_OFFSET_BITS + if not effective_flags['file_offset_bits_defined']: + effective_flags['file_offset_bits_defined'] = True + effective_flags['file_offset_bits_value'] = Y2038_SAFE_FILE_OFFSET_BITS + source_flags_used['file_offset_bits'] = True + elif re_define_file_offset_bits.match(directive.str): + source_file_offset_bits_defined = False + # Only use source directive if dump config doesn't define _FILE_OFFSET_BITS + if not effective_flags['file_offset_bits_defined']: + source_flags_used['file_offset_bits'] = True + cppcheckdata.reportError(directive, 'error', + '_FILE_OFFSET_BITS must be defined equal to 64', + 'y2038', + 'file-offset-bits-not-64') + y2038safe = False + elif re_undef_file_offset_bits.match(directive.str): + source_file_offset_bits_defined = False + source_file_offset_bits_value = None + # Only use source directive if dump config doesn't define _FILE_OFFSET_BITS + if not effective_flags['file_offset_bits_defined']: + effective_flags['file_offset_bits_defined'] = False + effective_flags['file_offset_bits_value'] = None + source_flags_used['file_offset_bits'] = True + # check for _USE_TIME_BITS64 (un)definition if re_define_use_time_bits64.match(directive.str): safe = int(srclinenr) - # warn about _TIME_BITS not being defined - if not time_bits_defined: - cppcheckdata.reportError(directive, 'warning', - '_USE_TIME_BITS64 is defined but _TIME_BITS was not', - 'y2038', - 'type-bits-undef') + source_use_time_bits64_defined = True + # Only use source directive if dump config doesn't define _USE_TIME_BITS64 + if not effective_flags['use_time_bits64_defined']: + effective_flags['use_time_bits64_defined'] = True + source_flags_used['use_time_bits64'] = True + # warn about _TIME_BITS not being defined (check effective flags) + if not time_bits_defined: + cppcheckdata.reportError(directive, 'warning', + '_USE_TIME_BITS64 is defined but _TIME_BITS was not', + 'y2038', + 'type-bits-undef') elif re_undef_use_time_bits64.match(directive.str): unsafe = int(srclinenr) + source_use_time_bits64_defined = False + # Only use source directive if dump config doesn't define _USE_TIME_BITS64 + if not effective_flags['use_time_bits64_defined']: + source_flags_used['use_time_bits64'] = True # do we have a safe..unsafe area? - if unsafe > safe > 0: + if unsafe > safe >= 0: safe_ranges.append((safe, unsafe)) safe = -1 # check end of source beyond last directive if len(cfg.tokenlist) > 0: unsafe = int(cfg.tokenlist[-1].linenr) - if unsafe > safe > 0: + if unsafe > safe >= 0: safe_ranges.append((safe, unsafe)) + # Determine if Y2038 warnings should be suppressed + # Require BOTH _TIME_BITS=64 AND _FILE_OFFSET_BITS=64 for complete Y2038 safety + y2038_safe_config = ( + effective_flags['time_bits_defined'] and + effective_flags['time_bits_value'] == Y2038_SAFE_TIME_BITS and + effective_flags['file_offset_bits_defined'] and + effective_flags['file_offset_bits_value'] == Y2038_SAFE_FILE_OFFSET_BITS + ) + + # Update config_source for suppression reporting based on mixed scenarios + if y2038_safe_config: + # Determine configuration source for mixed scenarios + dump_flags_count = sum([ + dump_config_flags['time_bits_defined'], + dump_config_flags['file_offset_bits_defined'], + dump_config_flags['use_time_bits64_defined'] + ]) + source_flags_count = sum(source_flags_used.values()) + + if dump_flags_count > 0 and source_flags_count > 0: + # Mixed scenario: both dump config and source directives used + config_source = "mixed configuration (cppcheck configuration and source code directives)" + elif dump_flags_count > 0: + # Only dump config used + config_source = "cppcheck configuration" + elif source_flags_count > 0: + # Only source directives used + config_source = "source code directives" + else: + # Fallback (shouldn't happen if y2038_safe_config is True) + config_source = "configuration" + # go through all tokens + warnings_suppressed = 0 for token in cfg.tokenlist: if token.str in id_Y2038: - if not any(lower <= int(token.linenr) <= upper - for (lower, upper) in safe_ranges): - cppcheckdata.reportError(token, 'warning', - token.str + ' is Y2038-unsafe', - 'y2038', - 'unsafe-call') - y2038safe = False + is_in_safe_range = any(lower <= int(token.linenr) <= upper + for (lower, upper) in safe_ranges) + + if not is_in_safe_range: + if y2038_safe_config: + # Count suppressed warnings but don't report them + warnings_suppressed += 1 + else: + # Report the warning as before + cppcheckdata.reportError(token, 'warning', + token.str + ' is Y2038-unsafe', + 'y2038', + 'unsafe-call') + y2038safe = False token = token.next + # Print suppression message if warnings were suppressed + if warnings_suppressed > 0 and config_source and not quiet: + print('Y2038 warnings suppressed: Found proper Y2038 configuration in %s (_TIME_BITS=%d and _FILE_OFFSET_BITS=%d)' % (config_source, Y2038_SAFE_TIME_BITS, Y2038_SAFE_FILE_OFFSET_BITS)) + print('Suppressed %d Y2038-unsafe function warning(s)' % warnings_suppressed) + return y2038safe diff --git a/cfg/boost.cfg b/cfg/boost.cfg index d181860f0bc..b09d9ccd9e5 100644 --- a/cfg/boost.cfg +++ b/cfg/boost.cfg @@ -83,12 +83,12 @@ - + - - + + diff --git a/cfg/cairo.cfg b/cfg/cairo.cfg index e077c2fc40d..d766abffc2e 100644 --- a/cfg/cairo.cfg +++ b/cfg/cairo.cfg @@ -21,6 +21,7 @@ + diff --git a/cfg/googletest.cfg b/cfg/googletest.cfg index 36dd8a40669..c32eef7274b 100644 --- a/cfg/googletest.cfg +++ b/cfg/googletest.cfg @@ -29,11 +29,11 @@ - - - - - + + + + + diff --git a/cfg/gtk.cfg b/cfg/gtk.cfg index 722efb6b76b..a1d7763670e 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 @@ -807,7 +903,6 @@ g_app_info_get_default_for_uri_scheme g_application_new g_application_get_dbus_connection - g_application_get_default g_buffered_input_stream_new g_buffered_output_stream_new g_cancellable_new @@ -910,7 +1005,6 @@ g_zlib_decompressor_new g_object_ref g_object_unref - gtk_widget_destroy g_tree_new @@ -926,6 +1020,17 @@ g_file_attribute_matcher_ref g_file_attribute_matcher_unref + + gtk_window_new + gtk_widget_destroy + gtk_window_destroy + + + + false + + + true @@ -2148,6 +2253,7 @@ + false @@ -6483,6 +6589,7 @@ + false @@ -8761,7 +8868,7 @@ false - + @@ -9688,6 +9795,14 @@ false + + + false + + + + false @@ -21130,10 +21245,6 @@ false - - - false - false @@ -21790,6 +21901,13 @@ false + + false + + + + + false @@ -22967,6 +23085,13 @@ + + + + + + + @@ -23079,4 +23204,8 @@ + + + + diff --git a/cfg/libcurl.cfg b/cfg/libcurl.cfg index 381fbb237d7..949b6de0282 100644 --- a/cfg/libcurl.cfg +++ b/cfg/libcurl.cfg @@ -167,7 +167,7 @@ - + diff --git a/cfg/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 00cb66c1909..95dc022cf57 100644 --- a/cfg/qt.cfg +++ b/cfg/qt.cfg @@ -410,7 +410,6 @@ - @@ -2319,10 +2318,28 @@ + + + + + false + + + + + + + + + + false + + + - + false @@ -2338,6 +2355,68 @@ + + + false + + + + + + + + + + + false + + + + + + + + + + + false + + + + + + + + + + + false + + + + + + + + false + + + + + + + + + + + false + + + + + + + false @@ -2346,8 +2425,9 @@ - + false + @@ -2356,17 +2436,11 @@ - - - false - - - - false + @@ -2375,6 +2449,34 @@ + + + false + + + + + + + false + + + + + + + false + + + + + + + false + + + + @@ -5418,7 +5520,7 @@ - + diff --git a/cfg/selinux.cfg b/cfg/selinux.cfg index e2d7ac34dc3..31a48c6da5e 100644 --- a/cfg/selinux.cfg +++ b/cfg/selinux.cfg @@ -219,7 +219,7 @@ false - + diff --git a/cfg/std.cfg b/cfg/std.cfg index 84cffb79828..6c434b8715c 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -3,16 +3,16 @@ - - + + - - - + + + - - + + @@ -1665,7 +1665,7 @@ false - + @@ -1929,7 +1929,7 @@ false - + @@ -2255,7 +2255,7 @@ false - + @@ -3989,11 +3989,11 @@ 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 @@ -4100,7 +4100,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false - + @@ -4118,10 +4118,10 @@ 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 - + @@ -4911,7 +4911,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 - + @@ -7130,6 +7130,16 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false + + + + + + + + + false + @@ -7137,6 +7147,13 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun false + + + + + + false + @@ -8326,9 +8343,7 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init - - - + false @@ -8734,7 +8749,7 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init false - + @@ -8742,7 +8757,7 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init false - + @@ -8797,6 +8812,12 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init + + + + true + + malloc,std::malloc calloc,std::calloc @@ -9009,6 +9030,16 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init + + + + + + + + + + diff --git a/cfg/windows.cfg b/cfg/windows.cfg index 343e12b3906..b2251900d42 100644 --- a/cfg/windows.cfg +++ b/cfg/windows.cfg @@ -1331,6 +1331,11 @@ AllocateAndInitializeSid FreeSid + + _create_locale + _wcreate_locale + _free_locale + + + + false + + + + + + + + + + + false + + + + + + + + + + false + + + + + arg1 false - + @@ -5963,7 +6000,7 @@ HFONT CreateFont( - + @@ -6009,7 +6046,7 @@ HFONT CreateFont( - + @@ -7191,7 +7228,7 @@ HFONT CreateFont( - + @@ -13345,9 +13382,9 @@ HFONT CreateFont( - - - + + + diff --git a/cfg/wxwidgets.cfg b/cfg/wxwidgets.cfg index e09b19e15af..9dea60761d1 100644 --- a/cfg/wxwidgets.cfg +++ b/cfg/wxwidgets.cfg @@ -7253,6 +7253,15 @@ This function is deprecated, use 'wxPGProperty::GetValueAsString()' instead. + + + + false + + + + + @@ -10352,6 +10361,14 @@ + + + false + + + + + false @@ -11384,6 +11401,12 @@ + + + false + + + @@ -11680,7 +11703,8 @@ - + + false @@ -12503,7 +12527,8 @@ - + + false @@ -15807,7 +15832,8 @@ wxItemKind kind = wxITEM_NORMAL) --> - + + false @@ -16097,6 +16123,30 @@ wxItemKind kind = wxITEM_NORMAL) --> + + + + false + + + + + + + + false + + + + + + + + false + + + + false @@ -16115,7 +16165,9 @@ wxItemKind kind = wxITEM_NORMAL) --> - + + + false @@ -17023,12 +17075,28 @@ wxItemKind kind = wxITEM_NORMAL) --> + - + + false + + + + false + + + + + + + + false + + diff --git a/clang-tidy.md b/clang-tidy.md index 72df0375ca1..f00a39cde12 100644 --- a/clang-tidy.md +++ b/clang-tidy.md @@ -130,6 +130,10 @@ Does not improve the readability. `modernize-use-designated-initializers`
`readability-enum-initial-value`
`modernize-use-trailing-return-type`
+`misc-unconventional-assign-operator`
+`bugprone-throwing-static-initialization`
+`bugprone-command-processor`
+`misc-multiple-inheritance`
To be evaluated (need to remove exclusion). @@ -156,6 +160,22 @@ These apply to codebases which use later standards then C++11 (C++17 is used whe We are not interested in this. +`readability-redundant-parentheses`
+ +Reports false positives - see https://github.com/llvm/llvm-project/issues/164125. + +`readability-inconsistent-ifelse-braces`
+ +The suggestions are too intrusive. + +`modernize-avoid-c-style-cast`
+ +Currently flags functional casts - see https://github.com/llvm/llvm-project/issues/186784. + +`misc-use-internal-linkage.AnalyzeTypes`
+ +Adding anonymous namespaces requires identation which is too instrusive right now. Would require changes to our fomatting configuration. + ### Disabled for performance reasons `portability-std-allocator-const`
@@ -180,7 +200,7 @@ We are currently using our own `naming.json` to enforce naming schemes. Also dis `portability-simd-intrinsics`
-We are not using SIMD instructions and it suggests to use `std::experiemental::` features which might not be commonly available. Also disabled for performance reasons - see https://github.com/llvm/llvm-project/issues/57527#issuecomment-1237935132. +We are not using SIMD instructions and it suggests to use `std::experimental::` features which might not be commonly available. Also disabled for performance reasons - see https://github.com/llvm/llvm-project/issues/57527#issuecomment-1237935132. `modernize-macro-to-enum`
diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index 8ea47196350..52103bdb8ec 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -1,54 +1,28 @@ -if (BUILD_CLI) - - file(GLOB hdrs "*.h") - file(GLOB srcs "*.cpp") - file(GLOB mainfile "main.cpp") - list(REMOVE_ITEM srcs ${mainfile}) +file(GLOB hdrs "*.h") +file(GLOB srcs "*.cpp") +file(GLOB mainfile "main.cpp") +list(REMOVE_ITEM srcs ${mainfile}) - add_library(cli_objs OBJECT ${hdrs} ${srcs}) - target_include_directories(cli_objs PRIVATE ${PROJECT_SOURCE_DIR}/lib/ ${PROJECT_SOURCE_DIR}/frontend/) - if(USE_BUNDLED_TINYXML2) - target_externals_include_directories(cli_objs PRIVATE ${PROJECT_SOURCE_DIR}/externals/tinyxml2/) - else() - target_include_directories(cli_objs SYSTEM PRIVATE ${tinyxml2_INCLUDE_DIRS}) - endif() - target_externals_include_directories(cli_objs PRIVATE ${PROJECT_SOURCE_DIR}/externals/picojson/) - target_externals_include_directories(cli_objs PRIVATE ${PROJECT_SOURCE_DIR}/externals/simplecpp/) - if (NOT CMAKE_DISABLE_PRECOMPILE_HEADERS) - target_precompile_headers(cli_objs PRIVATE precompiled.h) - endif() - if (BUILD_CORE_DLL) - target_compile_definitions(cli_objs PRIVATE CPPCHECKLIB_IMPORT TINYXML2_IMPORT) - endif() +add_library(cli ${hdrs} ${srcs}) +target_include_directories(cli PUBLIC .) +target_link_libraries(cli PRIVATE cppcheck-core frontend tinyxml2 simplecpp picojson) +if (NOT CMAKE_DISABLE_PRECOMPILE_HEADERS) + target_precompile_headers(cli PRIVATE precompiled.h) +endif() - if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 13) - # false positive warning in Clang 13 - caused by FD_ZERO macro - set_source_files_properties(processexecutor.cpp PROPERTIES COMPILE_FLAGS -Wno-reserved-identifier) - endif() +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 13) + # false positive warning in Clang 13 - caused by FD_ZERO macro + set_source_files_properties(processexecutor.cpp PROPERTIES COMPILE_FLAGS -Wno-reserved-identifier) +endif() - list(APPEND cppcheck_SOURCES ${hdrs} ${mainfile} $ $) - if (NOT BUILD_CORE_DLL) - list(APPEND cppcheck_SOURCES $) - list(APPEND cppcheck_SOURCES $) - if(USE_BUNDLED_TINYXML2) - list(APPEND cppcheck_SOURCES $) - endif() - endif() +if (BUILD_CLI) + list(APPEND cppcheck_SOURCES ${hdrs} ${mainfile}) if (WIN32) list(APPEND cppcheck_SOURCES version.rc) endif() add_executable(cppcheck ${cppcheck_SOURCES}) - target_include_directories(cppcheck PRIVATE ${PROJECT_SOURCE_DIR}/lib/) - if(USE_BUNDLED_TINYXML2) - target_externals_include_directories(cppcheck PRIVATE ${PROJECT_SOURCE_DIR}/externals/tinyxml2/) - else() - target_include_directories(cppcheck SYSTEM PRIVATE ${tinyxml2_INCLUDE_DIRS}) - endif() - target_externals_include_directories(cppcheck PRIVATE ${PROJECT_SOURCE_DIR}/externals/simplecpp/) - if (HAVE_RULES) - target_link_libraries(cppcheck ${PCRE_LIBRARY}) - endif() + target_link_libraries(cppcheck cppcheck-core cli tinyxml2 simplecpp) if (WIN32 AND NOT BORLAND) if(NOT MINGW) target_link_libraries(cppcheck Shlwapi.lib) @@ -56,13 +30,7 @@ if (BUILD_CLI) target_link_libraries(cppcheck shlwapi) endif() endif() - if(tinyxml2_FOUND AND NOT USE_BUNDLED_TINYXML2) - target_link_libraries(cppcheck ${tinyxml2_LIBRARIES}) - endif() target_link_libraries(cppcheck ${CMAKE_THREAD_LIBS_INIT}) - if (BUILD_CORE_DLL) - target_link_libraries(cppcheck cppcheck-core) - endif() add_dependencies(cppcheck copy_cfg) add_dependencies(cppcheck copy_addons) @@ -72,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/cli.vcxproj b/cli/cli.vcxproj index 5d4ee25b0e3..05d1cf2916d 100644 --- a/cli/cli.vcxproj +++ b/cli/cli.vcxproj @@ -89,7 +89,7 @@ true ProgramDatabase Disabled - CPPCHECKLIB_IMPORT;TINYXML2_IMPORT;WIN32;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;_WIN64;%(PreprocessorDefinitions) + CPPCHECKLIB_IMPORT;TINYXML2_IMPORT;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) MultiThreadedDebugDLL Level4 4018;4127;4146;4244;4251;4267;4389;4701;4706;4800;4805 @@ -118,7 +118,7 @@ true ProgramDatabase Disabled - CPPCHECKLIB_IMPORT;TINYXML2_IMPORT;WIN32;HAVE_RULES;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;_WIN64;%(PreprocessorDefinitions) + CPPCHECKLIB_IMPORT;TINYXML2_IMPORT;HAVE_RULES;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) MultiThreadedDebugDLL Level4 4018;4127;4146;4244;4251;4267;4389;4701;4706;4800;4805 @@ -146,7 +146,7 @@ ..\lib;..\frontend;..\externals;..\externals\picojson;..\externals\simplecpp;..\externals\tinyxml2;%(AdditionalIncludeDirectories) false MaxSpeed - CPPCHECKLIB_IMPORT;TINYXML2_IMPORT;NDEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;_WIN64;%(PreprocessorDefinitions) + CPPCHECKLIB_IMPORT;TINYXML2_IMPORT;NDEBUG;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) MultiThreadedDLL Level4 AnySuitable @@ -184,7 +184,7 @@ ..\lib;..\frontend;..\externals;..\externals\picojson;..\externals\simplecpp;..\externals\tinyxml2;%(AdditionalIncludeDirectories) false MaxSpeed - CPPCHECKLIB_IMPORT;TINYXML2_IMPORT;NDEBUG;WIN32;HAVE_RULES;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;_WIN64;%(PreprocessorDefinitions) + CPPCHECKLIB_IMPORT;TINYXML2_IMPORT;NDEBUG;HAVE_RULES;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) MultiThreadedDLL Level4 AnySuitable diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 2343652fa61..f2d2254f833 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +20,7 @@ #include "addoninfo.h" #include "check.h" +#include "checks.h" #include "checkers.h" #include "color.h" #include "config.h" @@ -36,14 +37,12 @@ #include "settings.h" #include "standards.h" #include "suppressions.h" -#include "timer.h" #include "utils.h" #include "frontend.h" #include #include -#include #include #include // EXIT_FAILURE #include @@ -57,8 +56,13 @@ #include #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) @@ -74,9 +78,7 @@ static bool addFilesToList(const std::string& fileList, std::vector files = &infile; } std::string fileName; - // cppcheck-suppress accessMoved - FP while (std::getline(*files, fileName)) { // next line - // cppcheck-suppress accessMoved - FP if (!fileName.empty()) { pathNames.emplace_back(std::move(fileName)); } @@ -90,7 +92,6 @@ static bool addIncludePathsToList(const std::string& fileList, std::list& ignored = getIgnoredPaths(); + const std::vector& ignored = mIgnoredPaths; const bool warn = std::any_of(ignored.cbegin(), ignored.cend(), [](const std::string& i) { return Path::isHeader(i); }); @@ -197,15 +198,13 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[]) mLogger.printMessage("Please use --suppress for ignoring results from the header files."); } - const std::vector& pathnamesRef = getPathNames(); - const std::list& fileSettingsRef = getFileSettings(); + const std::vector& pathnamesRef = mPathNames; + const std::list& fileSettingsRef = mFileSettings; // the inputs can only be used exclusively - CmdLineParser should already handle this assert(!(!pathnamesRef.empty() && !fileSettingsRef.empty())); if (!fileSettingsRef.empty()) { - // TODO: de-duplicate - std::list fileSettings; if (!mSettings.fileFilters.empty()) { // filter only for the selected filenames from all project files @@ -223,6 +222,8 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[]) fileSettings = fileSettingsRef; } + // TODO: de-duplicate + mFileSettings.clear(); frontend::applyLang(fileSettings, mSettings, mEnforcedLang); @@ -263,19 +264,6 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[]) return false; } - // de-duplicate files - { - auto it = filesResolved.begin(); - while (it != filesResolved.end()) { - const std::string& name = it->path(); - // TODO: log if duplicated files were dropped - filesResolved.erase(std::remove_if(std::next(it), filesResolved.end(), [&](const FileWithDetails& entry) { - return entry.path() == name; - }), filesResolved.end()); - ++it; - } - } - std::list files; if (!mSettings.fileFilters.empty()) { files = filterFiles(mSettings.fileFilters, filesResolved); @@ -289,6 +277,19 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[]) files = std::move(filesResolved); } + // de-duplicate files + { + auto it = files.begin(); + while (it != files.end()) { + const std::string& absname = it->abspath(); + // TODO: log if duplicated files were dropped + files.erase(std::remove_if(std::next(it), files.end(), [&](const FileWithDetails& entry) { + return entry.abspath() == absname; + }), files.end()); + ++it; + } + } + frontend::applyLang(files, mSettings, mEnforcedLang); // sort the markup last @@ -321,6 +322,35 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a // default to --check-level=normal from CLI for now mSettings.setCheckLevel(Settings::CheckLevel::normal); + // read --debug-lookup early so the option is available for the cppcheck.cfg loading + for (int i = 1; i < argc; i++) { + // Show debug warnings for lookup for configuration files + if (std::strcmp(argv[i], "--debug-lookup") == 0) + mSettings.debuglookup = true; + + else if (std::strncmp(argv[i], "--debug-lookup=", 15) == 0) { + const std::string lookup = argv[i] + 15; + if (lookup == "all") + mSettings.debuglookup = true; + else if (lookup == "addon") + mSettings.debuglookupAddon = true; + else if (lookup == "config") + mSettings.debuglookupConfig = true; + else if (lookup == "library") + mSettings.debuglookupLibrary = true; + else if (lookup == "platform") + mSettings.debuglookupPlatform = true; + else + { + mLogger.printError("unknown lookup '" + lookup + "'"); + return Result::Fail; + } + } + } + + if (!loadCppcheckCfg()) + return Result::Fail; + if (argc <= 1) { printHelp(); return Result::Exit; @@ -332,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"; @@ -346,8 +376,6 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a // print all possible error messages.. if (std::strcmp(argv[i], "--errorlist") == 0) { - if (!loadCppcheckCfg()) - return Result::Fail; { XMLErrorMessagesLogger xmlLogger; std::cout << ErrorMessage::getXMLHeader(mSettings.cppcheckCfgProductName, 2); @@ -371,16 +399,12 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a } if (std::strcmp(argv[i], "--version") == 0) { - if (!loadCppcheckCfg()) - return Result::Fail; const std::string version = getVersion(); mLogger.printRaw(version); // TODO: should not include newline return Result::Exit; } } - bool def = false; - bool maxconfigs = false; bool debug = false; bool inputAsFilter = false; // set by: --file-filter=+ @@ -391,7 +415,10 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a std::string platform; char defaultSign = '\0'; - std::vector lookupPaths{argv[0]}; + std::vector lookupPaths{ + Path::getCurrentPath(), // TODO: do we want to look in CWD? + Path::getPathFromFilename(mSettings.exename), + }; bool executorAuto = true; @@ -426,8 +453,6 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a if (!mSettings.userDefines.empty()) mSettings.userDefines += ";"; mSettings.userDefines += define; - - def = true; } // -E @@ -595,6 +620,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a mSettings.cppHeaderProbe = true; } + else if (std::strcmp(argv[i], "--debug-analyzerinfo") == 0) + mSettings.debugainfo = true; + else if (std::strcmp(argv[i], "--debug-ast") == 0) mSettings.debugast = true; @@ -606,33 +634,19 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a else if (std::strcmp(argv[i], "--debug-ignore") == 0) mSettings.debugignore = true; + else if (std::strcmp(argv[i], "--debug-ipc") == 0) + mSettings.debugipc = true; + // Show --debug output after the first simplifications else if (std::strcmp(argv[i], "--debug") == 0 || std::strcmp(argv[i], "--debug-normal") == 0) debug = true; - // Show debug warnings for lookup for configuration files else if (std::strcmp(argv[i], "--debug-lookup") == 0) - mSettings.debuglookup = true; + continue; // already handled above - else if (std::strncmp(argv[i], "--debug-lookup=", 15) == 0) { - const std::string lookup = argv[i] + 15; - if (lookup == "all") - mSettings.debuglookup = true; - else if (lookup == "addon") - mSettings.debuglookupAddon = true; - else if (lookup == "config") - mSettings.debuglookupConfig = true; - else if (lookup == "library") - mSettings.debuglookupLibrary = true; - else if (lookup == "platform") - mSettings.debuglookupPlatform = true; - else - { - mLogger.printError("unknown lookup '" + lookup + "'"); - return Result::Fail; - } - } + else if (std::strncmp(argv[i], "--debug-lookup=", 15) == 0) + continue; // already handled above // Flag used for various purposes during debugging else if (std::strcmp(argv[i], "--debug-simplified") == 0) @@ -744,6 +758,15 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a } } + else if (std::strncmp(argv[i], "--exitcode-suppress=", 20) == 0) { + const std::string suppression = argv[i]+20; + const std::string errmsg(mSuppressions.nofail.addSuppressionLine(suppression)); + if (!errmsg.empty()) { + mLogger.printError(errmsg); + return Result::Fail; + } + } + // Filter errors else if (std::strncmp(argv[i], "--exitcode-suppressions=", 24) == 0) { // exitcode-suppressions=filename.txt @@ -787,8 +810,10 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a } // Force checking of files that have "too many" configurations - else if (std::strcmp(argv[i], "-f") == 0 || std::strcmp(argv[i], "--force") == 0) + else if (std::strcmp(argv[i], "-f") == 0 || std::strcmp(argv[i], "--force") == 0) { mSettings.force = true; + mSettings.maxConfigsOption = Settings::maxConfigsNotAssigned; + } else if (std::strcmp(argv[i], "--fsigned-char") == 0) defaultSign = 's'; @@ -960,9 +985,8 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a return Result::Fail; } - mSettings.maxConfigs = tmp; + mSettings.maxConfigsOption = tmp; mSettings.force = false; - maxconfigs = true; } // max ctu depth @@ -1002,6 +1026,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a mSettings.cppHeaderProbe = false; } + else if (std::strcmp(argv[i], "--no-safety") == 0) + mSettings.safety = false; + // Write results in file else if (std::strncmp(argv[i], "--output-file=", 14) == 0) mSettings.outputFile = Path::simplifyPath(argv[i] + 14); @@ -1084,7 +1111,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a } // Special Cppcheck Premium options - else if ((std::strncmp(argv[i], "--premium=", 10) == 0 || std::strncmp(argv[i], "--premium-", 10) == 0) && isCppcheckPremium()) { + else if ((std::strncmp(argv[i], "--premium=", 10) == 0 || std::strncmp(argv[i], "--premium-", 10) == 0) && mSettings.premium) { // valid options --premium=.. const std::set valid{ "autosar", @@ -1102,7 +1129,8 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a "misra-c++-2023", "misra-cpp-2023", "bughunting", - "safety", + "safety", // TODO: deprecate in favor of the regular --safety/--no-safety + "safety-profiles", "debug-progress"}; // valid options --premium-..= const std::set valid2{ @@ -1120,13 +1148,21 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a mSettings.premiumArgs += " "; const std::string p(argv[i] + 10); const std::string p2(p.find('=') != std::string::npos ? p.substr(0, p.find('=')) : ""); - const bool isCodingStandard = startsWith(p, "autosar") || startsWith(p,"cert-") || startsWith(p,"misra-"); + const bool isCodingStandard = startsWith(p, "autosar") || startsWith(p,"cert-") || startsWith(p,"misra-") || p == "safety-profiles"; const std::string p3(endsWith(p,":all") && isCodingStandard ? p.substr(0,p.rfind(':')) : p); if (!valid.count(p3) && !valid2.count(p2)) { mLogger.printError("invalid --premium option '" + (p2.empty() ? p : p2) + "'."); return Result::Fail; } - mSettings.premiumArgs += "--" + p; + if (p2 == "cert-c-int-precision") { + int tmp; + if (!parseNumberArg(argv[i], 31, tmp, true)) + return Result::Fail; + } + 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. @@ -1143,9 +1179,8 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a return Result::Fail; } - mSettings.checkAllConfigurations = false; // Can be overridden with --max-configs or --force std::string projectFile = argv[i]+10; - projectType = project.import(projectFile, &mSettings, &mSuppressions, isCppcheckPremium()); + projectType = project.import(projectFile, &mSettings, &mSuppressions); if (projectType == ImportProject::Type::CPPCHECK_GUI) { for (const std::string &lib : project.guiProject.libraries) mSettings.libraries.emplace_back(lib); @@ -1157,7 +1192,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a platform = project.guiProject.platform; // look for external files relative to project first - lookupPaths.insert(lookupPaths.cbegin(), projectFile); + lookupPaths.insert(lookupPaths.cbegin(), Path::getPathFromFilename(projectFile)); const auto& projectFileGui = project.guiProject.projectFile; if (!projectFileGui.empty()) { @@ -1170,9 +1205,15 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a } } } - if (projectType == ImportProject::Type::VS_SLN || projectType == ImportProject::Type::VS_VCXPROJ) { + if (projectType == ImportProject::Type::COMPILE_DB) + mSettings.maxConfigsProject = 1; + if (projectType == ImportProject::Type::VS_SLN || + projectType == ImportProject::Type::VS_SLNX || + projectType == ImportProject::Type::VS_VCXPROJ) { mSettings.libraries.emplace_back("windows"); } + for (const auto &error : project.errors) + mLogger.printError(error); if (projectType == ImportProject::Type::MISSING) { mLogger.printError("failed to open project '" + projectFile + "'. The file does not exist."); return Result::Fail; @@ -1194,7 +1235,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a mLogger.printError("--project-configuration parameter is empty."); return Result::Fail; } - if (projectType != ImportProject::Type::VS_SLN && projectType != ImportProject::Type::VS_VCXPROJ) { + if (projectType != ImportProject::Type::VS_SLN && + projectType != ImportProject::Type::VS_SLNX && + projectType != ImportProject::Type::VS_VCXPROJ) { mLogger.printError("--project-configuration has no effect - no Visual Studio project provided."); return Result::Fail; } @@ -1265,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()) { @@ -1273,6 +1316,13 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a return Result::Fail; } + std::string regex_err; + auto regex = Regex::create(rule.pattern, Regex::Engine::Pcre, regex_err); + if (!regex) { + mLogger.printError("failed to compile rule pattern '" + rule.pattern + "' (" + regex_err + ")."); + return Result::Fail; + } + rule.regex = std::move(regex); mSettings.rules.emplace_back(std::move(rule)); #else mLogger.printError("Option --rule cannot be used as Cppcheck has not been built with rules support."); @@ -1294,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(); @@ -1324,6 +1375,16 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a } } } + else if (std::strcmp(subname, "engine") == 0) { + const char * const engine = empty_if_null(subtext); + if (std::strcmp(engine, "pcre") == 0) { + regexEngine = Regex::Engine::Pcre; + } + else { + mLogger.printError(std::string("unknown regex engine '") + engine + "'."); + return Result::Fail; + } + } else { mLogger.printError("unable to load rule-file '" + ruleFile + "' - unknown element '" + subname + "' encountered in 'rule'."); return Result::Fail; @@ -1350,6 +1411,14 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a return Result::Fail; } + std::string 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; + } + rule.regex = std::move(regex); + if (rule.severity == Severity::none) { mLogger.printError("unable to load rule-file '" + ruleFile + "' - a rule has an invalid severity."); return Result::Fail; @@ -1375,17 +1444,17 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a else if (std::strncmp(argv[i], "--showtime=", 11) == 0) { const std::string showtimeMode = argv[i] + 11; if (showtimeMode == "file") - mSettings.showtime = SHOWTIME_MODES::SHOWTIME_FILE; + mSettings.showtime = Settings::ShowTime::FILE; else if (showtimeMode == "file-total") - mSettings.showtime = SHOWTIME_MODES::SHOWTIME_FILE_TOTAL; + mSettings.showtime = Settings::ShowTime::FILE_TOTAL; else if (showtimeMode == "summary") - mSettings.showtime = SHOWTIME_MODES::SHOWTIME_SUMMARY; + mSettings.showtime = Settings::ShowTime::SUMMARY; else if (showtimeMode == "top5_file") - mSettings.showtime = SHOWTIME_MODES::SHOWTIME_TOP5_FILE; + mSettings.showtime = Settings::ShowTime::TOP5_FILE; else if (showtimeMode == "top5_summary") - mSettings.showtime = SHOWTIME_MODES::SHOWTIME_TOP5_SUMMARY; + mSettings.showtime = Settings::ShowTime::TOP5_SUMMARY; else if (showtimeMode == "none") - mSettings.showtime = SHOWTIME_MODES::SHOWTIME_NONE; + mSettings.showtime = Settings::ShowTime::NONE; else if (showtimeMode.empty()) { mLogger.printError("no mode provided for --showtime"); return Result::Fail; @@ -1543,9 +1612,6 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a } } - if (!loadCppcheckCfg()) - return Result::Fail; - // TODO: bail out? if (!executorAuto && mSettings.useSingleJob()) mLogger.printMessage("'--executor' has no effect as only a single job will be used."); @@ -1560,14 +1626,6 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a substituteTemplateFormatStatic(mSettings.templateFormat, !mSettings.outputFile.empty()); substituteTemplateLocationStatic(mSettings.templateLocation, !mSettings.outputFile.empty()); - if (mSettings.force || maxconfigs) - mSettings.checkAllConfigurations = true; - - if (mSettings.force) - mSettings.maxConfigs = INT_MAX; - else if ((def || mSettings.preprocessOnly) && !maxconfigs) - mSettings.maxConfigs = 1U; - if (debug) { mSettings.debugnormal = true; mSettings.debugvalueflow = true; @@ -1580,11 +1638,22 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a if (mSettings.jobs > 1 && mSettings.buildDir.empty()) { // TODO: bail out instead? if (mSettings.checks.isEnabled(Checks::unusedFunction)) + { mLogger.printMessage("unusedFunction check requires --cppcheck-build-dir to be active with -j."); + mSettings.checks.disable(Checks::unusedFunction); + // TODO: is there some later logic to remove? + } // TODO: enable //mLogger.printMessage("whole program analysis requires --cppcheck-build-dir to be active with -j."); } + if (!mSettings.checks.isEnabled(Checks::unusedFunction)) + mSettings.unmatchedSuppressionFilters.emplace_back("unusedFunction"); + if (!mSettings.addons.count("misra")) + mSettings.unmatchedSuppressionFilters.emplace_back("misra-*"); + if (!mSettings.premium) + mSettings.unmatchedSuppressionFilters.emplace_back("premium-*"); + if (inputAsFilter) { mSettings.fileFilters.insert(mSettings.fileFilters.end(), mPathNames.cbegin(), mPathNames.cend()); mPathNames.clear(); @@ -1608,25 +1677,15 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a mLogger.printError(errstr); return Result::Fail; } - - // TODO: remove - // these are loaded via external files and thus have Settings::PlatformFile set instead. - // override the type so they behave like the regular platforms. - if (platform == "unix32-unsigned") { - mSettings.platform.type = Platform::Type::Unix32; - mLogger.printMessage("The platform 'unix32-unsigned' has been deprecated and will be removed in Cppcheck 2.19. Please use '--platform=unix32 --funsigned-char' instead"); - } - else if (platform == "unix64-unsigned") { - mSettings.platform.type = Platform::Type::Unix64; - mLogger.printMessage("The platform 'unix64-unsigned' has been deprecated and will be removed in Cppcheck 2.19. Please use '--platform=unix64 --funsigned-char' instead"); - } } if (defaultSign != '\0') mSettings.platform.defaultSign = defaultSign; if (!mSettings.analyzeAllVsConfigs) { - if (projectType != ImportProject::Type::VS_SLN && projectType != ImportProject::Type::VS_VCXPROJ) { + if (projectType != ImportProject::Type::VS_SLN && + projectType != ImportProject::Type::VS_SLNX && + projectType != ImportProject::Type::VS_VCXPROJ) { if (mAnalyzeAllVsConfigsSetOnCmdLine) { mLogger.printError("--no-analyze-all-vs-configs has no effect - no Visual Studio project provided."); return Result::Fail; @@ -1683,11 +1742,8 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a void CmdLineParser::printHelp() const { - const std::string manualUrl(isCppcheckPremium() ? - "https://cppcheck.sourceforge.io/manual.pdf" : - "https://files.cppchecksolutions.com/manual.pdf"); - std::ostringstream oss; + // TODO: display product name oss << "Cppcheck - A tool for static C/C++ code analysis\n" "\n" "Syntax:\n" @@ -1739,9 +1795,9 @@ void CmdLineParser::printHelp() const " be considered for evaluation.\n" " --config-excludes-file=\n" " A file that contains a list of config-excludes\n" - " --disable= Disable individual checks.\n" - " Please refer to the documentation of --enable=\n" - " for further details.\n" + " --disable= Disable checks with the given severity.\n" + " Please refer to the documentation of --enable for\n" + " further details.\n" " --dump Dump xml data for each translation unit. The dump\n" " files have the extension .dump and contain ast,\n" " tokenlist, symboldatabase, valueflow.\n" @@ -1751,37 +1807,33 @@ void CmdLineParser::printHelp() const " Example: '-DDEBUG=1 -D__cplusplus'.\n" " -E Print preprocessor output on stdout and don't do any\n" " further processing.\n" - " --enable= Enable additional checks. The available ids are:\n" - " * all\n" - " Enable all checks. It is recommended to only\n" - " use --enable=all when the whole program is\n" - " scanned, because this enables unusedFunction.\n" + " --enable= Enable additional checks grouped by severity. The available\n" + " severities are:\n" " * warning\n" - " Enable warning messages\n" - " * style\n" - " Enable all coding style checks. All messages\n" - " with the severities 'style', 'warning',\n" - " 'performance' and 'portability' are enabled.\n" " * performance\n" - " Enable performance messages\n" " * portability\n" - " Enable portability messages\n" " * information\n" - " Enable information messages\n" + " * style\n" + " Enable checks with severities 'style', 'warning',\n" + " 'performance' and 'portability'.\n" " * unusedFunction\n" " Check for unused functions. It is recommended\n" " to only enable this when the whole program is\n" " scanned.\n" " * missingInclude\n" - " Warn if there are missing includes.\n" - " Several ids can be given if you separate them with\n" - " commas. See also --std\n" + " Check for missing include files.\n" + " * all\n" + " Enable all checks.\n" + " Pass multiple severities as a comma-separated list.\n" " --error-exitcode= If errors are found, integer [n] is returned instead of\n" " the default '0'. '" << EXIT_FAILURE << "' is returned\n" " if arguments are not valid or if no input files are\n" " provided. Note that your operating system can modify\n" " this value, e.g. '256' can become '0'.\n" " --errorlist Print a list of all the error messages in XML format.\n" + " --exitcode-suppress=\n" + " Used to specify an error ID which should not result in\n" + " a non-zero exitcode." " --exitcode-suppressions=\n" " Used when certain messages should be displayed but\n" " should not cause a non-zero exitcode.\n" @@ -1812,9 +1864,13 @@ void CmdLineParser::printHelp() const " this is not needed.\n" " --include=\n" " Force inclusion of a file before the checked file.\n" - " -i Exclude source files or directories matching str from\n" - " the check. This applies only to source files so header\n" - " files included by source files are not matched.\n" + " -i Ignore files that match . can be a filename\n" + " or directory and can contain *,**,?. A file that is\n" + " ignored will not be checked directly (the whole\n" + " translation unit is skipped completely). Header files\n" + " are checked indirectly when they are #include'd.\n" + " Note: If you want to prevent warnings in some headers,\n" + " use suppressions instead.\n" " --inconclusive Allow that Cppcheck reports even though the analysis is\n" " inconclusive.\n" " There are false positives with this option. Each result\n" @@ -1888,7 +1944,7 @@ void CmdLineParser::printHelp() const " --plist-output=\n" " Generate Clang-plist output files in folder.\n"; - if (isCppcheckPremium()) { + if (mSettings.premium) { oss << " --premium=
\n" ""; - /*const*/ Settings settings = settingsBuilder().libraryxml(xmldata).severity(Severity::warning).build(); - settings.platform.sizeof_wchar_t = 4; + // use a platform which has wchar_t with a sizeof 4 + const Settings settings = settingsBuilder().libraryxml(xmldata).severity(Severity::warning).platform(Platform::Unix32).build(); + ASSERT_EQUALS(4, settings.platform.sizeof_wchar_t); check("void f() {\n" " char c[10];\n" " mymemset(c, 0, 10);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " char c[10];\n" " mymemset(c, 0, 11);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:3:14]: (error) Buffer is accessed out of bounds: c [bufferAccessOutOfBounds]\n", errout_str()); check("struct S {\n" @@ -4274,13 +4502,13 @@ class TestBufferOverrun : public TestFixture { "void f() {\n" " S s;\n" " mymemset(s.a, 0, 10);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:6:15]: (error) Buffer is accessed out of bounds: s.a [bufferAccessOutOfBounds]\n", errout_str()); check("void foo() {\n" " char s[10];\n" " mymemset(s, 0, '*');\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); TODO_ASSERT_EQUALS("[test.cpp:3]: (warning) The size argument is given as a char constant.\n" "[test.cpp:3:14]: (error) Buffer is accessed out of bounds: s [bufferAccessOutOfBounds]\n", "[test.cpp:3:14]: (error) Buffer is accessed out of bounds: s [bufferAccessOutOfBounds]\n", errout_str()); @@ -4288,65 +4516,65 @@ class TestBufferOverrun : public TestFixture { check("void f(void) {\n" " char a[10];\n" " mymemset(a+5, 0, 10);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); TODO_ASSERT_EQUALS("[test.cpp:3:13]: (error) Buffer is accessed out of bounds: a [bufferAccessOutOfBounds]\n", "", errout_str()); // Ticket #909 check("void f(void) {\n" " char str[] = \"abcd\";\n" " mymemset(str, 0, 6);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:3:14]: (error) Buffer is accessed out of bounds: str [bufferAccessOutOfBounds]\n", errout_str()); check("void f(void) {\n" " char str[] = \"abcd\";\n" " mymemset(str, 0, 5);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("", errout_str()); check("void f(void) {\n" " wchar_t str[] = L\"abcd\";\n" " mymemset(str, 0, 21);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:3:14]: (error) Buffer is accessed out of bounds: str [bufferAccessOutOfBounds]\n", errout_str()); check("void f(void) {\n" " wchar_t str[] = L\"abcd\";\n" " mymemset(str, 0, 20);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("", errout_str()); // ticket #1659 - overflowing variable when using memcpy check("void f(void) {\n" " char c;\n" " mymemset(&c, 0, 4);\n" - "}", dinit(CheckOptions, $.s = &settings)); - TODO_ASSERT_EQUALS("[test.cpp:3:14]: (error) Buffer is accessed out of bounds: c [bufferAccessOutOfBounds]\n", "", errout_str()); + "}\n", settings); + ASSERT_EQUALS("[test.cpp:3:12]: (error) Buffer is accessed out of bounds: &c [bufferAccessOutOfBounds]\n", errout_str()); // ticket #2121 - buffer access out of bounds when using uint32_t check("void f(void) {\n" " unknown_type_t buf[4];\n" " mymemset(buf, 0, 100);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("", errout_str()); // #3124 - multidimensional array check("int main() {\n" " char b[5][6];\n" " mymemset(b, 0, 5 * 6);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("", errout_str()); check("int main() {\n" " char b[5][6];\n" " mymemset(b, 0, 6 * 6);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:3:14]: (error) Buffer is accessed out of bounds: b [bufferAccessOutOfBounds]\n", errout_str()); check("int main() {\n" " char b[5][6];\n" " mymemset(b, 0, 31);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:3:14]: (error) Buffer is accessed out of bounds: b [bufferAccessOutOfBounds]\n", errout_str()); // #4968 - not standard function @@ -4355,26 +4583,26 @@ class TestBufferOverrun : public TestFixture { " foo.mymemset(str, 0, 100);\n" " foo::mymemset(str, 0, 100);\n" " std::mymemset(str, 0, 100);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); TODO_ASSERT_EQUALS("[test.cpp:5:15]: (error) Buffer is accessed out of bounds: str [bufferAccessOutOfBounds]\n", "", errout_str()); // #5257 - check strings check("void f() {\n" " mymemset(\"abc\", 0, 20);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); TODO_ASSERT_EQUALS("[test.cpp:2]: (error) Buffer is accessed out of bounds.\n", "", errout_str()); check("void f() {\n" " mymemset(temp, \"abc\", 4);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("", errout_str()); check("void f() {\n" // #6816 - fp when array has known string value " char c[10] = \"c\";\n" " mymemset(c, 0, 10);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("", errout_str()); } @@ -4396,43 +4624,43 @@ class TestBufferOverrun : public TestFixture { check("void f() {\n" " char c[7];\n" " mystrncpy(c, \"hello\", 7);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " char c[6];\n" " mystrncpy(c,\"hello\",6);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " char c[5];\n" " mystrncpy(c,\"hello\",6);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:3:12]: (error) Buffer is accessed out of bounds: c [bufferAccessOutOfBounds]\n", errout_str()); check("void f() {\n" " char c[6];\n" " mystrncpy(c,\"hello!\",7);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:3:15]: (error) Buffer is accessed out of bounds: c [bufferAccessOutOfBounds]\n", errout_str()); check("void f(unsigned int addr) {\n" " memset((void *)addr, 0, 1000);\n" - "}", dinit(CheckOptions, $.s = &settings0)); + "}\n", settings0); // TODO: use settings? ASSERT_EQUALS("", errout_str()); check("struct AB { char a[10]; };\n" "void foo(AB *ab) {\n" " mystrncpy(x, ab->a, 100);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("", errout_str()); check("void a(char *p) { mystrncpy(p,\"hello world!\",10); }\n" // #3168 "void b() {\n" " char buf[5];\n" " a(buf);" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); TODO_ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:1]: (error) Buffer is accessed out of bounds: buf\n", "", errout_str()); @@ -4458,13 +4686,13 @@ class TestBufferOverrun : public TestFixture { check("void f() {\n" " char str[3];\n" " mysprintf(str, \"test\");\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:3:15]: (error) Buffer is accessed out of bounds: str [bufferAccessOutOfBounds]\n", errout_str()); check("void f() {\n" " char str[5];\n" " mysprintf(str, \"%s\", \"abcde\");\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:3:15]: (error) Buffer is accessed out of bounds: str [bufferAccessOutOfBounds]\n", errout_str()); check("int getnumber();\n" @@ -4472,51 +4700,51 @@ class TestBufferOverrun : public TestFixture { "{\n" " char str[5];\n" " mysprintf(str, \"%d: %s\", getnumber(), \"abcde\");\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:5:15]: (error) Buffer is accessed out of bounds: str [bufferAccessOutOfBounds]\n", errout_str()); check("void f() {\n" " char str[5];\n" " mysprintf(str, \"test%s\", \"\");\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " char *str = new char[5];\n" " mysprintf(str, \"abcde\");\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:3:15]: (error) Buffer is accessed out of bounds: str [bufferAccessOutOfBounds]\n", errout_str()); check("void f(int condition) {\n" " char str[5];\n" " mysprintf(str, \"test%s\", condition ? \"12\" : \"34\");\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("", errout_str()); check("void f(int condition) {\n" " char str[5];\n" " mysprintf(str, \"test%s\", condition ? \"12\" : \"345\");\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); TODO_ASSERT_EQUALS("error", "", errout_str()); check("struct Foo { char a[1]; };\n" "void f() {\n" " struct Foo x;\n" " mysprintf(x.a, \"aa\");\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:4:14]: (error) Buffer is accessed out of bounds: x.a [bufferAccessOutOfBounds]\n", errout_str()); // ticket #900 check("void f() {\n" " char *a = new char(30);\n" " mysprintf(a, \"a\");\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:3:13]: (error) Buffer is accessed out of bounds: a [bufferAccessOutOfBounds]\n", errout_str()); check("void f(char value) {\n" " char *a = new char(value);\n" " mysprintf(a, \"a\");\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:3:13]: (error) Buffer is accessed out of bounds: a [bufferAccessOutOfBounds]\n", errout_str()); // This is out of bounds if 'sizeof(ABC)' is 1 (No padding) @@ -4524,21 +4752,21 @@ class TestBufferOverrun : public TestFixture { "void f() {\n" " struct Foo *x = malloc(sizeof(Foo));\n" " mysprintf(x->a, \"aa\");\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); TODO_ASSERT_EQUALS("[test.cpp:4]: (error, inconclusive) Buffer is accessed out of bounds: x.a\n", "", errout_str()); check("struct Foo { char a[1]; };\n" "void f() {\n" " struct Foo *x = malloc(sizeof(Foo) + 10);\n" " mysprintf(x->a, \"aa\");\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("", errout_str()); check("struct Foo { char a[1]; };\n" "void f() {\n" " struct Foo x;\n" " mysprintf(x.a, \"aa\");\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:4:14]: (error) Buffer is accessed out of bounds: x.a [bufferAccessOutOfBounds]\n", errout_str()); check("struct Foo {\n" // #6668 - unknown size @@ -4547,8 +4775,43 @@ class TestBufferOverrun : public TestFixture { "};" "void Foo::f() {\n" " mysprintf(a, \"abcd\");\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" // #901 + " const char b[] = \"b\";\n" + " char a[1];\n" + " sprintf(a, \"%s\", b);\n" + "}\n" + "void g() {\n" + " const char* b = \"b\";\n" + " char a[1];\n" + " sprintf(a, \"%s\", b);\n" + "}\n" + "void h() {\n" + " const std::string b = \"b\";\n" + " char a[1];\n" + " sprintf(a, \"%s\", b.c_str());\n" + "}\n" + "void i() {\n" + " const char b[] = \"b\";\n" + " char a[2];\n" + " sprintf(a, \"%s\", b);\n" + "}\n" + "void j() {\n" + " const char* b = \"b\";\n" + " char a[2];\n" + " sprintf(a, \"%s\", b);\n" + "}\n" + "void k() {\n" + " const std::string b = \"b\";\n" + " char a[2];\n" + " sprintf(a, \"%s\", b.c_str());\n" + "}\n", settings0); + ASSERT_EQUALS("[test.cpp:4:13]: (error) Buffer is accessed out of bounds: a [bufferAccessOutOfBounds]\n" + "[test.cpp:9:13]: (error) Buffer is accessed out of bounds: a [bufferAccessOutOfBounds]\n" + "[test.cpp:14:13]: (error) Buffer is accessed out of bounds: a [bufferAccessOutOfBounds]\n", + errout_str()); } void minsize_mul() { @@ -4568,13 +4831,13 @@ class TestBufferOverrun : public TestFixture { check("void f() {\n" " char c[5];\n" " myfread(c, 1, 5, stdin);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " char c[5];\n" " myfread(c, 1, 6, stdin);\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:3:13]: (error) Buffer is accessed out of bounds: c [bufferAccessOutOfBounds]\n", errout_str()); } @@ -4584,7 +4847,7 @@ class TestBufferOverrun : public TestFixture { check("void f()\n" "{\n" " UnknownType *a = malloc(4);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } // extracttests.disable @@ -4596,26 +4859,26 @@ class TestBufferOverrun : public TestFixture { " baz[99] = 0;\n" " strncpy(baz, bar, 100);\n" " baz[99] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo ( char *bar ) {\n" " char baz[100];\n" " strncpy(baz, bar, 100);\n" " baz[99] = '\\0';\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo ( char *bar ) {\n" " char baz[100];\n" " strncpy(baz, bar, 100);\n" " baz[x+1] = '\\0';\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Test with invalid code that there is no segfault check("char baz[100];\n" - "strncpy(baz, \"var\", 100)"); + "strncpy(baz, \"var\", 100)\n"); ASSERT_EQUALS("", errout_str()); // Test that there are no duplicate error messages @@ -4624,7 +4887,7 @@ class TestBufferOverrun : public TestFixture { " strncpy(baz, bar, 100);\n" " foo(baz);\n" " foo(baz);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (warning, inconclusive) The buffer 'baz' may not be null-terminated after the call to strncpy(). [terminateStrncpy]\n", errout_str()); } @@ -4634,7 +4897,7 @@ class TestBufferOverrun : public TestFixture { " strncpy(baz, bar, 100);\n" " bar[99] = 0;\n" " return strdup(baz);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (warning, inconclusive) The buffer 'baz' may not be null-terminated after the call to strncpy(). [terminateStrncpy]\n", errout_str()); } @@ -4657,13 +4920,13 @@ class TestBufferOverrun : public TestFixture { check("void bar() {\n" " char buf[4];\n" " strncpy(buf, \"ab\", 4);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void bar() {\n" " char buf[4];\n" " strncpy(buf, \"abcde\", 4);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (warning, inconclusive) The buffer 'buf' may not be null-terminated after the call to strncpy(). [terminateStrncpy]\n", errout_str()); } @@ -4685,6 +4948,20 @@ class TestBufferOverrun : public TestFixture { } // extracttests.enable + void terminateStrncpy_handle_addr_of_var() { // #7570 + check("void foo() {\n" + " char c[6];\n" + " strncpy(&c, \"hello!\", 6);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:3]: (warning, inconclusive) The buffer 'c' may not be null-terminated after the call to strncpy(). [terminateStrncpy]\n", errout_str()); + + check("void foo() {\n" + " char c[6];\n" + " strncpy(&c, \"hello\\0\", 6);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void recursive_long_time() { // Just test that recursive check doesn't take long time check("char *f2 ( char *b )\n" @@ -4709,7 +4986,7 @@ class TestBufferOverrun : public TestFixture { "{\n" " char a[10];\n" " f2(a);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -4725,7 +5002,7 @@ class TestBufferOverrun : public TestFixture { "{\n" " struct A *str;\n" " str = malloc(4);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -4737,12 +5014,12 @@ class TestBufferOverrun : public TestFixture { "void b() {\n" " char arr[64];\n" " a(arr);\n" - "}"); + "}\n"); } void crash3() { check("struct b { unknown v[0]; };\n" - "void d() { struct b *f; f = malloc(108); }"); + "void d() { struct b *f; f = malloc(108); }\n"); } void crash4() { // #8679 @@ -4750,13 +5027,13 @@ class TestBufferOverrun : public TestFixture { "int main() { " " thread_local_var = malloc(1337); " " return 0; " - "}"); + "}\n"); check("thread_local void *thread_local_var; " "int main() { " " thread_local_var = malloc(1337); " " return 0; " - "}"); + "}\n"); } void crash5() { // 8644 - token has varId() but variable() is null @@ -4764,19 +5041,19 @@ class TestBufferOverrun : public TestFixture { " void b(char **dst) {\n" " *dst = malloc(50);\n" " }\n" - "}"); + "}\n"); } void crash6() { check("void start(char* name) {\n" "char snapname[64] = { 0 };\n" "strncpy(snapname, \"snapshot\", arrayLength(snapname));\n" - "}"); + "}\n"); } void crash7() { // 9073 - [ has no astParent check("char x[10];\n" - "void f() { x[10]; }"); + "void f() { x[10]; }\n"); } void insecureCmdLineArgs() { @@ -4790,7 +5067,7 @@ class TestBufferOverrun : public TestFixture { " free(p);\n" " }\n" " return 0;\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:7]: (error) Buffer overrun possible for long command line arguments.\n", "", errout_str()); check("int main(int argc, char *argv[])\n" @@ -4803,112 +5080,112 @@ class TestBufferOverrun : public TestFixture { " free(p);\n" " }\n" " return 0;\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:7]: (error) Buffer overrun possible for long command line arguments.\n", "", errout_str()); check("int main(const int argc, char* argv[])\n" "{\n" " char prog[10];\n" " strcpy(prog, argv[0]);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Buffer overrun possible for long command line arguments.\n", "", errout_str()); check("int main(int argc, const char* argv[])\n" "{\n" " char prog[10];\n" " strcpy(prog, argv[0]);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Buffer overrun possible for long command line arguments.\n", "", errout_str()); check("int main(const int argc, const char* argv[])\n" "{\n" " char prog[10];\n" " strcpy(prog, argv[0]);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Buffer overrun possible for long command line arguments.\n", "", errout_str()); check("int main(int argc, char* argv[])\n" "{\n" " char prog[10] = {'\\0'};\n" " strcat(prog, argv[0]);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Buffer overrun possible for long command line arguments.\n", "", errout_str()); check("int main(int argc, char **argv, char **envp)\n" "{\n" " char prog[10];\n" " strcpy(prog, argv[0]);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Buffer overrun possible for long command line arguments.\n", "", errout_str()); check("int main(int argc, const char *const *const argv, char **envp)\n" "{\n" " char prog[10];\n" " strcpy(prog, argv[0]);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Buffer overrun possible for long command line arguments.\n", "", errout_str()); check("int main(const int argc, const char *const *const argv, const char *const *const envp)\n" "{\n" " char prog[10];\n" " strcpy(prog, argv[0]);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Buffer overrun possible for long command line arguments.\n", "", errout_str()); check("int main(int argc, char **argv, char **envp)\n" "{\n" " char prog[10] = {'\\0'};\n" " strcat(prog, argv[0]);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Buffer overrun possible for long command line arguments.\n", "", errout_str()); check("int main(const int argc, const char **argv, char **envp)\n" "{\n" " char prog[10] = {'\\0'};\n" " strcat(prog, argv[0]);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Buffer overrun possible for long command line arguments.\n", "", errout_str()); check("int main(int argc, const char **argv, char **envp)\n" "{\n" " char prog[10] = {'\\0'};\n" " strcat(prog, argv[0]);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Buffer overrun possible for long command line arguments.\n", "", errout_str()); check("int main(const int argc, char **argv, char **envp)\n" "{\n" " char prog[10] = {'\\0'};\n" " strcat(prog, argv[0]);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Buffer overrun possible for long command line arguments.\n", "", errout_str()); check("int main(int argc, char **options)\n" "{\n" " char prog[10];\n" " strcpy(prog, options[0]);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Buffer overrun possible for long command line arguments.\n", "", errout_str()); check("int main(int argc, char **options)\n" "{\n" " char prog[10] = {'\\0'};\n" " strcat(prog, options[0]);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Buffer overrun possible for long command line arguments.\n", "", errout_str()); check("int main(int argc, char **options)\n" "{\n" " char prog[10];\n" " strcpy(prog, *options);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Buffer overrun possible for long command line arguments.\n", "", errout_str()); check("int main(int argc, char **options)\n" "{\n" " char prog[10];\n" " strcpy(prog+3, *options);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Buffer overrun possible for long command line arguments.\n", "", errout_str()); check("int main(int argc, char **argv, char **envp)\n" @@ -4916,7 +5193,7 @@ class TestBufferOverrun : public TestFixture { " char prog[10];\n" " if (strlen(argv[0]) < 10)\n" " strcpy(prog, argv[0]);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int main(int argc, char **argv, char **envp)\n" @@ -4924,7 +5201,7 @@ class TestBufferOverrun : public TestFixture { " char prog[10] = {'\\0'};\n" " if (10 > strlen(argv[0]))\n" " strcat(prog, argv[0]);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int main(int argc, char **argv, char **envp)\n" @@ -4932,7 +5209,7 @@ class TestBufferOverrun : public TestFixture { " char prog[10];\n" " argv[0][0] = '\\0';\n" " strcpy(prog, argv[0]);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #5835 @@ -4940,18 +5217,18 @@ class TestBufferOverrun : public TestFixture { " char prog[10];\n" " strcpy(prog, argv[0]);\n" " strcpy(prog, argv[0]);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:3]: (error) Buffer overrun possible for long command line arguments.\n" "[test.cpp:4]: (error) Buffer overrun possible for long command line arguments.\n", "", errout_str()); // #7964 check("int main(int argc, char *argv[]) {\n" " char *strcpy();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int main(int argc, char *argv[]) {\n" " char *strcat();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -4959,33 +5236,33 @@ class TestBufferOverrun : public TestFixture { check("void f(char *a) {\n" " char *b = new char[strlen(a)];\n" " strcpy(b, a);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:3]: (error) Buffer is accessed out of bounds.\n", "", errout_str()); check("void f(char *a) {\n" " char *b = new char[strlen(a) + 1];\n" " strcpy(b, a);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(char *a) {\n" " char *b = new char[strlen(a)];\n" " a[0] = '\\0';\n" " strcpy(b, a);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(char *a) {\n" " char *b = (char *)malloc(strlen(a));\n" " b = realloc(b, 10000);\n" " strcpy(b, a);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(char *a) {\n" " char *b = (char *)malloc(strlen(a));\n" " strcpy(b, a);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:3]: (error) Buffer is accessed out of bounds.\n", "", errout_str()); check("void f(char *a) {\n" @@ -4993,31 +5270,31 @@ class TestBufferOverrun : public TestFixture { " {\n" " strcpy(b, a);\n" " }\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Buffer is accessed out of bounds.\n", "", errout_str()); check("void f(char *a) {\n" " char *b = (char *)malloc(strlen(a) + 1);\n" " strcpy(b, a);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(char *a, char *c) {\n" " char *b = (char *)realloc(c, strlen(a));\n" " strcpy(b, a);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:3]: (error) Buffer is accessed out of bounds.\n", "", errout_str()); check("void f(char *a, char *c) {\n" " char *b = (char *)realloc(c, strlen(a) + 1);\n" " strcpy(b, a);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(char *a) {\n" " char *b = (char *)malloc(strlen(a));\n" " strcpy(b, a);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:3]: (error) Buffer is accessed out of bounds.\n", "", errout_str()); } @@ -5031,7 +5308,7 @@ class TestBufferOverrun : public TestFixture { "{\n" " X x;\n" " x.buf[10] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class A {\n" @@ -5043,14 +5320,15 @@ class TestBufferOverrun : public TestFixture { "{\n" " A::X x;\n" " x.buf[10] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:9:10]: (error) Array 'x.buf[10]' accessed at index 10, which is out of bounds. [arrayIndexOutOfBounds]\n", errout_str()); } 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(); } @@ -5061,68 +5339,68 @@ class TestBufferOverrun : public TestFixture { check("void f(const char s[]) {\n" " if (s[i] == 'x' && i < y) {\n" " }" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // No message because i is unknown and thus gets no varid. Avoid an internalError here. check("void f(const char s[], int i) {\n" " if (s[i] == 'x' && i < y) {\n" " }" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:10]: (style) Array index 'i' is used before limits check. [arrayIndexThenCheck]\n", errout_str()); check("void f(const char s[]) {\n" " for (int i = 0; s[i] == 'x' && i < y; ++i) {\n" " }" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:22]: (style) Array index 'i' is used before limits check. [arrayIndexThenCheck]\n", errout_str()); check("void f(const int a[], unsigned i) {\n" " if((a[i] < 2) && (i <= 42)) {\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:10]: (style) Array index 'i' is used before limits check. [arrayIndexThenCheck]\n", errout_str()); check("void f(const int a[], unsigned i) {\n" " if((a[i] < 2) && (42 >= i)) {\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:10]: (style) Array index 'i' is used before limits check. [arrayIndexThenCheck]\n", errout_str()); // extracttests.start: int elen; check("void f(char* e, int y) {\n" " if (e[y] == '/' && elen > y + 1 && e[y + 1] == '?') {\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // extracttests.start: int foo(int); int func(int); check("void f(const int a[], unsigned i) {\n" " if(a[i] < func(i) && i <= 42) {\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) Array index 'i' is used before limits check. [arrayIndexThenCheck]\n", errout_str()); check("void f(const int a[], unsigned i) {\n" " if (i <= 42 && a[i] < func(i)) {\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(const int a[], unsigned i) {\n" " if (foo(a[i] + 3) < func(i) && i <= 42) {\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:14]: (style) Array index 'i' is used before limits check. [arrayIndexThenCheck]\n", errout_str()); check("void f(int i) {\n" // sizeof " sizeof(a)/sizeof(a[i]) && i < 10;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // extracttests.start: extern int buf[]; check("void f(int i) {\n" // ?: " if ((i < 10 ? buf[i] : 1) && (i < 5 ? buf[i] : 5)){}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -5145,19 +5423,19 @@ class TestBufferOverrun : public TestFixture { check("void f() {\n" " char c[6];\n" " strncpy(c,\"hello!\",6);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (warning, inconclusive) The buffer 'c' may not be null-terminated after the call to strncpy(). [terminateStrncpy]\n", errout_str()); check("void f() {\n" " char c[6];\n" " memcpy(c,\"hello!\",6);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:3]: (warning, inconclusive) The buffer 'c' may not be null-terminated after the call to memcpy().\n", "", errout_str()); check("void f() {\n" " char c[6];\n" " memmove(c,\"hello!\",6);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:3]: (warning, inconclusive) The buffer 'c' may not be null-terminated after the call to memmove().\n", "", errout_str()); } @@ -5167,7 +5445,7 @@ class TestBufferOverrun : public TestFixture { " int *a;\n" " a = new int[-1];\n" " delete [] a;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:8]: (error) Memory allocation size is negative. [negativeMemoryAllocationSize]\n", errout_str()); check("void f()\n" @@ -5175,7 +5453,7 @@ class TestBufferOverrun : public TestFixture { " int *a;\n" " a = (int *)malloc( -10 );\n" " free(a);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4:8]: (error) Memory allocation size is negative. [negativeMemoryAllocationSize]\n", "", errout_str()); check("void f()\n" @@ -5183,14 +5461,14 @@ class TestBufferOverrun : public TestFixture { " int *a;\n" " a = (int *)malloc( -10);\n" " free(a);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4:8]: (error) Memory allocation size is negative. [negativeMemoryAllocationSize]\n", "", errout_str()); check("void f()\n" "{\n" " int *a;\n" " a = (int *)alloca( -10 );\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4:8]: (error) Memory allocation size is negative. [negativeMemoryAllocationSize]\n", "", errout_str()); check("int* f(int n) {\n" // #11145 @@ -5207,14 +5485,14 @@ class TestBufferOverrun : public TestFixture { check("void f(int sz) {\n" // #1760 - VLA " int a[sz];\n" "}\n" - "void x() { f(-100); }"); + "void x() { f(-100); }\n"); ASSERT_EQUALS("[test.cpp:2:8]: (error) Declaration of array 'a' with negative size is undefined behaviour [negativeArraySize]\n", errout_str()); // don't warn for constant sizes -> this is a compiler error so this is used for static assertions for instance check("int x, y;\n" "int a[-1];\n" "int b[x?1:-1];\n" - "int c[x?y:-1];"); + "int c[x?y:-1];\n"); ASSERT_EQUALS("", errout_str()); } @@ -5222,29 +5500,29 @@ class TestBufferOverrun : public TestFixture { check("void f() {\n" " char arr[10];\n" " char *p = arr + 20;\n" - "}"); + "}\n", settings0_p); ASSERT_EQUALS("[test.cpp:3:19]: (portability) Undefined behaviour, pointer arithmetic 'arr+20' is out of bounds. [pointerOutOfBounds]\n", errout_str()); check("char(*g())[1];\n" // #7950 "void f() {\n" " int a[2];\n" " int* b = a + sizeof(*g());\n" - "}\n"); + "}\n", settings0_p); ASSERT_EQUALS("", errout_str()); } -#define ctu(code) ctu_(code, __FILE__, __LINE__) +#define ctu(...) ctu_(__FILE__, __LINE__, __VA_ARGS__) template - void ctu_(const char (&code)[size], const char* file, int line) { + void ctu_(const char* file, int line, const char (&code)[size]) { // Tokenize.. 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()) { @@ -5262,7 +5540,7 @@ class TestBufferOverrun : public TestFixture { "int main() {\n" " char *s = malloc(4);\n" " dostuff(s);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:11] -> [test.cpp:7:10] -> [test.cpp:2:3]: (error) Array index out of bounds; buffer 'p' is accessed at offset -3. [ctuArrayIndex]\n", errout_str()); ctu("void dostuff(char *p) {\n" @@ -5272,7 +5550,7 @@ class TestBufferOverrun : public TestFixture { "int main() {\n" " char *s = malloc(4);\n" " dostuff(s);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:11] -> [test.cpp:7:10] -> [test.cpp:2:3]: (error) Array index out of bounds; 'p' buffer size is 4 and it is accessed at offset 4. [ctuArrayIndex]\n", errout_str()); ctu("void f(int* p) {\n" // #10415 @@ -5286,6 +5564,15 @@ class TestBufferOverrun : public TestFixture { " f(a);\n" "}\n"); ASSERT_EQUALS("[test.cpp:7:12] -> [test.cpp:9:6] -> [test.cpp:3:12]: (error) Array index out of bounds; 'p' buffer size is 4 and it is accessed at offset 20. [ctuArrayIndex]\n", errout_str()); + + ctu("void bar(int *p) { p[4] = 42; }\n" // #13403 + "void f() {\n" + " int *p = (int*)malloc(4 * sizeof(int));\n" + " if (!p) return;\n" + " bar(p);\n" + " free(p);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:12] -> [test.cpp:4:9] -> [test.cpp:5:8] -> [test.cpp:1:20]: (error) Array index out of bounds; 'p' buffer size is 16 and it is accessed at offset 16. [ctuArrayIndex]\n", errout_str()); } void ctu_array() { @@ -5295,7 +5582,7 @@ class TestBufferOverrun : public TestFixture { "int main() {\n" " char str[4];\n" " dostuff(str);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:10] -> [test.cpp:2:5]: (error) Array index out of bounds; 'p' buffer size is 4 and it is accessed at offset 10. [ctuArrayIndex]\n", errout_str()); ctu("static void memclr( char *data )\n" @@ -5307,7 +5594,7 @@ class TestBufferOverrun : public TestFixture { "{\n" " char str[5];\n" " memclr( str );\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:9:11] -> [test.cpp:3:5]: (error) Array index out of bounds; 'data' buffer size is 5 and it is accessed at offset 10. [ctuArrayIndex]\n", errout_str()); ctu("static void memclr( int i, char *data )\n" @@ -5319,7 +5606,7 @@ class TestBufferOverrun : public TestFixture { "{\n" " char str[5];\n" " memclr( 0, str );\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:9:11] -> [test.cpp:3:5]: (error) Array index out of bounds; 'data' buffer size is 5 and it is accessed at offset 10. [ctuArrayIndex]\n", errout_str()); ctu("static void memclr( int i, char *data )\n" @@ -5331,7 +5618,7 @@ class TestBufferOverrun : public TestFixture { "{\n" " char str[5];\n" " memclr( 10, str );\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:9] -> [test.cpp:3]: (possible error) Array index out of bounds.\n", "", errout_str()); @@ -5346,7 +5633,7 @@ class TestBufferOverrun : public TestFixture { "{\n" " char str[5];\n" " memclr( str, 5 );\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #2097 @@ -5360,7 +5647,7 @@ class TestBufferOverrun : public TestFixture { "{\n" " int p[3];\n" " foo(p+1);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9112 @@ -5373,7 +5660,7 @@ class TestBufferOverrun : public TestFixture { "{\n" " u8 macstrbuf[17] = { 0 };\n" " get_mac_address(macstrbuf);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9788 @@ -5430,7 +5717,7 @@ class TestBufferOverrun : public TestFixture { "int main() {\n" " int x = 4;\n" " dostuff(&x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:10] -> [test.cpp:2:5]: (error) Array index out of bounds; 'p' buffer size is 4 and it is accessed at offset 40. [ctuArrayIndex]\n", errout_str()); } @@ -5439,7 +5726,7 @@ class TestBufferOverrun : public TestFixture { "int main() {\n" " int x[3];\n" " dostuff(x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:10] -> [test.cpp:1:28]: (error) Pointer arithmetic overflow; 'p' buffer size is 12 [ctuPointerArith]\n", errout_str()); ctu("void f(const char *p) {\n" // #11361 @@ -5450,13 +5737,26 @@ class TestBufferOverrun : public TestFixture { " f(s);\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + setMultiline(); + ctu("void g(char* p) {\n" + " memset(p + 10, 0, 10);\n" + "}\n" + "void f() {\n" + " char a[10] = {};\n" + " g(a);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:12]: error: Pointer arithmetic overflow; 'p' buffer size is 10 [ctuPointerArith]\n" + "[test.cpp:6:6]: note: Calling function g, 1st argument is accessed out of bounds\n" + "[test.cpp:2:12]: note: Using argument p\n", + errout_str()); } void objectIndex() { check("int f() {\n" " int i;\n" " return (&i)[1];\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:3:13] -> [test.cpp:3:16]: (error) The address of variable 'i' is accessed at non-zero index. [objectIndex]\n", errout_str()); @@ -5464,7 +5764,7 @@ class TestBufferOverrun : public TestFixture { check("int f(int j) {\n" " int i;\n" " return (&i)[j];\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:3:13] -> [test.cpp:3:16]: (warning) The address of variable 'i' might be accessed at non-zero index. [objectIndex]\n", errout_str()); @@ -5472,34 +5772,34 @@ class TestBufferOverrun : public TestFixture { check("int f() {\n" " int i;\n" " return (&i)[0];\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f(int * i) {\n" " return i[1];\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f(std::vector i) {\n" " return i[1];\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f(std::vector i) {\n" " return i.data()[1];\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int* f(std::vector& i) {\n" " return &(i[1]);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A { int i; int j; };\n" "int f() {\n" " A x;\n" " return (&x.i)[0];\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A { int i; int j; };\n" @@ -5507,7 +5807,7 @@ class TestBufferOverrun : public TestFixture { " A x;\n" " int * i = &x.i;\n" " return i[0];\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -5515,7 +5815,7 @@ class TestBufferOverrun : public TestFixture { " std::map m;\n" " m[0] = &x;\n" " m[1] = &x;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f() {\n" @@ -5523,7 +5823,7 @@ class TestBufferOverrun : public TestFixture { " std::map m;\n" " m[0] = &x;\n" " return m[0][1];\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:4:10] -> [test.cpp:5:14]: (error) The address of variable 'x' is accessed at non-zero index. [objectIndex]\n", errout_str()); @@ -5533,7 +5833,7 @@ class TestBufferOverrun : public TestFixture { " std::map m;\n" " m[0] = &x;\n" " return m[0][1];\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:4:10] -> [test.cpp:5:14]: (error) The address of variable 'x' is accessed at non-zero index. [objectIndex]\n", errout_str()); @@ -5544,7 +5844,7 @@ class TestBufferOverrun : public TestFixture { " m[0] = &x;\n" " m[1] = y;\n" " return m[1][1];\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void print(char** test);\n" @@ -5614,7 +5914,7 @@ class TestBufferOverrun : public TestFixture { "void h() {\n" " const uint8_t u = 4;\n" " f(&u, N);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("uint32_t f(uint32_t u) {\n" // #10154 @@ -5674,7 +5974,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 @@ -5686,7 +6008,7 @@ class TestBufferOverrun : public TestFixture { "if (pipe(pipefd) == -1) {\n" " return;\n" " }\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:3:10]: (error) Buffer is accessed out of bounds: pipefd [bufferAccessOutOfBounds]\n", errout_str()); check("void f(){\n" @@ -5694,7 +6016,7 @@ class TestBufferOverrun : public TestFixture { "if (pipe(pipefd) == -1) {\n" " return;\n" " }\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("", errout_str()); check("void f(){\n" @@ -5702,7 +6024,7 @@ class TestBufferOverrun : public TestFixture { "if (pipe((int*)pipefd) == -1) {\n" " return;\n" " }\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("[test.cpp:3:10]: (error) Buffer is accessed out of bounds: (int*)pipefd [bufferAccessOutOfBounds]\n", errout_str()); check("void f(){\n" @@ -5710,7 +6032,7 @@ class TestBufferOverrun : public TestFixture { "if (pipe((int*)pipefd) == -1) {\n" " return;\n" " }\n" - "}", dinit(CheckOptions, $.s = &settings)); + "}\n", settings); ASSERT_EQUALS("", errout_str()); } }; diff --git a/test/testcharvar.cpp b/test/testcharvar.cpp index 624efcff539..0c9c8dd4b5b 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(); } @@ -57,7 +57,7 @@ class TestCharVar : public TestFixture { "{\n" " unsigned char ch = 0x80;\n" " buf[ch] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int buf[256];\n" @@ -65,7 +65,7 @@ class TestCharVar : public TestFixture { "{\n" " char ch = 0x80;\n" " buf[ch] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:5]: (portability) 'char' type used as array index. [unknownSignCharArrayIndex]\n", errout_str()); check("int buf[256];\n" @@ -73,7 +73,7 @@ class TestCharVar : public TestFixture { "{\n" " char ch = 0;\n" " buf[ch] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int buf[256];\n" @@ -81,7 +81,7 @@ class TestCharVar : public TestFixture { "{\n" " signed char ch = 0;\n" " buf[ch] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int buf[256];\n" @@ -89,67 +89,67 @@ class TestCharVar : public TestFixture { "{\n" " char ch = 0x80;\n" " buf[ch] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:5]: (portability) 'char' type used as array index. [unknownSignCharArrayIndex]\n", errout_str()); check("int buf[256];\n" "void foo(signed char ch)\n" "{\n" " buf[ch] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int buf[256];\n" "void foo(char ch)\n" "{\n" " buf[ch] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(char* buf)\n" "{\n" " char ch = 0x80;" " buf[ch] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:24]: (portability) 'char' type used as array index. [unknownSignCharArrayIndex]\n", errout_str()); check("void foo(char* buf)\n" "{\n" " char ch = 0;" " buf[ch] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(char* buf)\n" "{\n" " buf['A'] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(char* buf, char ch)\n" "{\n" " buf[ch] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int flags[256];\n" "void foo(const char* str)\n" "{\n" " flags[*str] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int flags[256];\n" "void foo(const char* str)\n" "{\n" " flags[(unsigned char)*str] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(const char str[])\n" "{\n" " map[str] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -159,7 +159,7 @@ class TestCharVar : public TestFixture { "void bar(int i) {\n" " const char *s = \"abcde\";\n" " foo(s[i]);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -167,32 +167,32 @@ class TestCharVar : public TestFixture { check("void foo(int *result) {\n" " signed char ch = -1;\n" " *result = a | ch;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:17]: (warning) When using 'char' variables in bit operations, sign extension can generate unexpected results. [charBitOp]\n", errout_str()); check("void foo(int *result) {\n" " unsigned char ch = -1;\n" " *result = a | ch;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(char *result) {\n" " signed char ch = -1;\n" " *result = a | ch;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // 0x03 & .. check("void foo(int *result) {\n" " signed char ch = -1;\n" " *result = 0x03 | ch;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:20]: (warning) When using 'char' variables in bit operations, sign extension can generate unexpected results. [charBitOp]\n", errout_str()); check("void foo(int *result) {\n" " signed char ch = -1;\n" " *result = 0x03 & ch;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } }; 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 new file mode 100644 index 00000000000..39a6f2a9997 --- /dev/null +++ b/test/testcheckersreport.cpp @@ -0,0 +1,56 @@ +/* + * 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 "addoninfo.h" +#include "checkersreport.h" +#include "fixture.h" +#include "settings.h" + +class TestCheckersReport : public TestFixture { +public: + TestCheckersReport() : TestFixture("TestCheckersReport") {} + +private: + void run() final { + // AddonInfo::checkers + TEST_CASE(addonInfoCheckers); + } + + void addonInfoCheckers() const { + AddonInfo a; + a.name = "test"; + a.checkers["abcdefghijklmnopqrstuvwxyz::abcdefghijklmnopqrstuvwxyz"] = "123"; + Settings s; + s.addonInfos.emplace_back(a); + const std::set activeCheckers; + CheckersReport r(s, activeCheckers); + const std::string report = r.getReport(""); + const auto pos = report.rfind("\n\n"); + ASSERT(pos != std::string::npos); + + const char expected[] = + "test checkers\n" + "-------------\n" + "No abcdefghijklmnopqrstuvwxyz::abcdefghijklmnopqrstuvwxyz require:123\n"; + + ASSERT_EQUALS(expected, report.substr(pos+2)); + } +}; + +REGISTER_TEST(TestCheckersReport) diff --git a/test/testclangimport.cpp b/test/testclangimport.cpp index 89f2c7b907a..6a39b563982 100644 --- a/test/testclangimport.cpp +++ b/test/testclangimport.cpp @@ -1,5 +1,5 @@ // Cppcheck - A tool for static C/C++ code analysis -// Copyright (C) 2007-2025 Cppcheck team. +// Copyright (C) 2007-2026 Cppcheck team. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -16,6 +16,7 @@ #include "clangimport.h" #include "fixture.h" +#include "mathlib.h" #include "platform.h" #include "settings.h" #include "standards.h" @@ -1327,7 +1328,7 @@ class TestClangImport : public TestFixture { const Token *tok = Token::findsimplematch(tokenizer.tokens(), "\"hello\""); ASSERT(!!tok); ASSERT(!!tok->valueType()); - ASSERT_EQUALS("const signed char *", tok->valueType()->str()); + ASSERT_EQUALS("const char *", tok->valueType()->str()); } void stdinLoc() { diff --git a/test/testclass.cpp b/test/testclass.cpp index 2b87cfd842b..451502c2164 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,10 +35,12 @@ class TestClass : public TestFixture { private: const Settings settings0 = settingsBuilder().severity(Severity::style).library("std.cfg").build(); + const Settings settings0_i = settingsBuilder(settings0).certainty(Certainty::inconclusive).build(); const Settings settings1 = settingsBuilder().severity(Severity::warning).library("std.cfg").build(); const Settings settings2 = settingsBuilder().severity(Severity::style).library("std.cfg").certainty(Certainty::inconclusive).build(); - const Settings settings3 = settingsBuilder().severity(Severity::style).library("std.cfg").severity(Severity::warning).build(); + const Settings settings3 = settingsBuilder().severity(Severity::style).library("std.cfg").severity(Severity::warning).library("posix.cfg").build(); const Settings settings3_i = settingsBuilder(settings3).certainty(Certainty::inconclusive).build(); + const Settings settings4 = settingsBuilder().severity(Severity::warning).severity(Severity::portability).library("std.cfg").library("posix.cfg").build(); void run() override { mNewTemplate = true; @@ -60,6 +62,8 @@ class TestClass : public TestFixture { TEST_CASE(copyConstructor4); // base class with private constructor TEST_CASE(copyConstructor5); // multiple inheritance TEST_CASE(copyConstructor6); // array of pointers + TEST_CASE(copyConstructor7); // ticket #14954 + TEST_CASE(copyConstructor8); TEST_CASE(deletedMemberPointer); // deleted member pointer in destructor TEST_CASE(noOperatorEq); // class with memory management should have operator eq TEST_CASE(noDestructor); // class with memory management should have destructor @@ -193,6 +197,8 @@ class TestClass : public TestFixture { TEST_CASE(const98); TEST_CASE(const99); TEST_CASE(const100); + TEST_CASE(const101); + TEST_CASE(const102); TEST_CASE(const_handleDefaultParameters); TEST_CASE(const_passThisToMemberOfOtherClass); @@ -267,7 +273,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)(); } @@ -276,25 +282,25 @@ class TestClass : public TestFixture { "{\n" " A(const A& other) { }\n" " A& operator=(const A& other) { return *this; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkCopyCtorAndEqOperator("class A\n" "{\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkCopyCtorAndEqOperator("class A\n" "{\n" " A(const A& other) { }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkCopyCtorAndEqOperator("class A\n" "{\n" " A& operator=(const A& other) { return *this; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); @@ -302,7 +308,7 @@ class TestClass : public TestFixture { "{\n" " A(const A& other) { }\n" " int x;\n" - "};"); + "};\n"); TODO_ASSERT_EQUALS("[test.cpp:1]: (warning) The class 'A' has 'copy constructor' but lack of 'operator='.\n", "", errout_str()); // TODO the error message should be clarified. It should say something like 'copy constructor is empty and will not assign i and therefore the behaviour is different to the default assignment operator' @@ -310,7 +316,7 @@ class TestClass : public TestFixture { "{\n" " A& operator=(const A& other) { return *this; }\n" " int x;\n" - "};"); + "};\n"); TODO_ASSERT_EQUALS("[test.cpp:1]: (warning) The class 'A' has 'operator=' but lack of 'copy constructor'.\n", "", errout_str()); // TODO the error message should be clarified. It should say something like 'assignment operator does not assign i and therefore the behaviour is different to the default copy constructor' @@ -318,7 +324,7 @@ class TestClass : public TestFixture { "{\n" " A& operator=(const int &x) { this->x = x; return *this; }\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkCopyCtorAndEqOperator("class A {\n" @@ -338,7 +344,7 @@ class TestClass : public TestFixture { " B(const B & b) :A(b) { }\n" "private:\n" " static int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // #7987 - Don't show warning when there is a move constructor @@ -349,14 +355,14 @@ class TestClass : public TestFixture { " test = std::move(s.test);\n" " return *this;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // #8337 - False positive in copy constructor detection checkCopyCtorAndEqOperator("struct StaticListNode {\n" " StaticListNode(StaticListNode*& prev) : m_next(0) {}\n" " StaticListNode* m_next;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -368,7 +374,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)(); } @@ -380,7 +386,7 @@ class TestClass : public TestFixture { " explicit Class(int i) { }\n" " explicit Class(const std::string&) { }\n" " Class(int a, int b) { }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkExplicitConstructors("class Class {\n" @@ -388,7 +394,7 @@ class TestClass : public TestFixture { " explicit Class(const Class& other) { }\n" " explicit Class(Class&& other) { }\n" " virtual int i() = 0;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkExplicitConstructors("class Class {\n" @@ -396,37 +402,37 @@ class TestClass : public TestFixture { " Class(const Class& other) = delete;\n" " Class(Class&& other) = delete;\n" " virtual int i() = 0;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkExplicitConstructors("class Class {\n" " Class(int i) { }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:2:5]: (style) Class 'Class' has a constructor with 1 argument that is not explicit. [noExplicitConstructor]\n", errout_str()); checkExplicitConstructors("class Class {\n" " Class(const Class& other) { }\n" " virtual int i() = 0;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkExplicitConstructors("class Class {\n" " Class(Class&& other) { }\n" " virtual int i() = 0;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // #6585 checkExplicitConstructors("class Class {\n" " private: Class(const Class&);\n" " virtual int i() = 0;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkExplicitConstructors("class Class {\n" " public: Class(const Class&);\n" " virtual int i() = 0;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // #7465: Error properly reported in templates @@ -437,7 +443,7 @@ class TestClass : public TestFixture { "int main() {\n" " Test test;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:3]: (style) Struct 'Test < int >' has a constructor with 1 argument that is not explicit. [noExplicitConstructor]\n", errout_str()); // #7465: No error for copy or move constructors @@ -450,7 +456,7 @@ class TestClass : public TestFixture { "int main() {\n" " Test test;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #8600 @@ -458,12 +464,12 @@ class TestClass : public TestFixture { "struct A::B {\n" " B() = default;\n" " B(const B&) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkExplicitConstructors("struct A{" - " A(int, int y=2) {}" - "};"); + " A(int, int y=2) {}\n" + "};\n"); ASSERT_EQUALS("[test.cpp:1:14]: (style) Struct 'A' has a constructor with 1 argument that is not explicit. [noExplicitConstructor]\n", errout_str()); checkExplicitConstructors("struct Foo {\n" // #10515 @@ -525,7 +531,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)(); } @@ -535,7 +541,7 @@ class TestClass : public TestFixture { "};\n" "struct Derived : Base {\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkDuplInheritedMembers("class Base {\n" @@ -544,7 +550,7 @@ class TestClass : public TestFixture { "};\n" "struct Derived : Base {\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:6:8]: (warning) The struct 'Derived' defines member variable with name 'x' also defined in its parent class 'Base'. [duplInheritedMember]\n", errout_str()); checkDuplInheritedMembers("class Base {\n" @@ -553,7 +559,7 @@ class TestClass : public TestFixture { "};\n" "struct Derived : public Base {\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:6:8]: (warning) The struct 'Derived' defines member variable with name 'x' also defined in its parent class 'Base'. [duplInheritedMember]\n", errout_str()); checkDuplInheritedMembers("class Base0 {\n" @@ -564,7 +570,7 @@ class TestClass : public TestFixture { "};\n" "struct Derived : Base0, Base1 {\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkDuplInheritedMembers("class Base0 {\n" @@ -576,7 +582,7 @@ class TestClass : public TestFixture { "};\n" "struct Derived : Base0, Base1 {\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:9:8]: (warning) The struct 'Derived' defines member variable with name 'x' also defined in its parent class 'Base0'. [duplInheritedMember]\n", errout_str()); checkDuplInheritedMembers("class Base0 {\n" @@ -589,7 +595,7 @@ class TestClass : public TestFixture { "};\n" "struct Derived : Base0, Base1 {\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:10:8]: (warning) The struct 'Derived' defines member variable with name 'x' also defined in its parent class 'Base0'. [duplInheritedMember]\n" "[test.cpp:7:8] -> [test.cpp:10:8]: (warning) The struct 'Derived' defines member variable with name 'x' also defined in its parent class 'Base1'. [duplInheritedMember]\n", errout_str()); @@ -598,7 +604,7 @@ class TestClass : public TestFixture { "};\n" "struct Derived : Base {\n" " int y;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkDuplInheritedMembers("class A {\n" @@ -606,20 +612,20 @@ class TestClass : public TestFixture { "};\n" "struct B {\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // Unknown 'Base' class checkDuplInheritedMembers("class Derived : public UnknownBase {\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkDuplInheritedMembers("class Base {\n" " int x;\n" "};\n" "class Derived : public Base {\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // #6692 @@ -631,7 +637,7 @@ class TestClass : public TestFixture { " struct SWibble : public test1::wibble {\n" " int Value;\n" " };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9957 @@ -645,12 +651,12 @@ class TestClass : public TestFixture { "};\n" "class Derived2 : public Derived1 {\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:13] -> [test.cpp:10:9]: (warning) The class 'Derived2' defines member variable with name 'i' also defined in its parent class 'Base'. [duplInheritedMember]\n", errout_str()); // don't crash on recursive template checkDuplInheritedMembers("template\n" - "struct BitInt : public BitInt { };"); + "struct BitInt : public BitInt { };\n"); ASSERT_EQUALS("", errout_str()); // don't crash on recursive template @@ -665,7 +671,7 @@ class TestClass : public TestFixture { " template \n" " struct fn_traits\n" " : public fn_traits {};\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #10594 @@ -732,6 +738,13 @@ class TestClass : public TestFixture { " void Two() = delete;\n" "};\n"); ASSERT_EQUALS("", errout_str()); + + checkDuplInheritedMembers("struct B { void f(); };\n" // #14583 + "struct D : B {\n" + " template \n" + " void f();\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); } #define checkCopyConstructor(...) checkCopyConstructor_( __FILE__, __LINE__, __VA_ARGS__) @@ -742,7 +755,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(); } @@ -763,7 +776,7 @@ class TestClass : public TestFixture { " }\n" " F&operator=(const F&);\n" " ~F();\n" - "};"); + "};\n"); TODO_ASSERT_EQUALS("[test.cpp:5]: (warning) Value of pointer 'p', which points to allocated memory, is copied in copy constructor instead of allocating new memory.\n", "", errout_str()); checkCopyConstructor("class F {\n" @@ -776,7 +789,7 @@ class TestClass : public TestFixture { " }\n" " ~F();\n" " F& operator=(const F&f);\n" - "};"); + "};\n"); TODO_ASSERT_EQUALS("[test.cpp:4:7]: (warning) Value of pointer 'p', which points to allocated memory, is copied in copy constructor instead of allocating new memory. [copyCtorPointerCopying]\n" "[test.cpp:3] -> [test.cpp:7]: (warning) Copy constructor does not allocate memory for member 'p' although memory has been allocated in other constructors.\n", "[test.cpp:4:7]: (warning) Value of pointer 'p', which points to allocated memory, is copied in copy constructor instead of allocating new memory. [copyCtorPointerCopying]\n" @@ -796,7 +809,7 @@ class TestClass : public TestFixture { " }\n" " ~F();\n" " F& operator=(const F&f);\n" - "};"); + "};\n"); TODO_ASSERT_EQUALS("[test.cpp:5]: (warning) Value of pointer 'p', which points to allocated memory, is copied in copy constructor instead of allocating new memory.\n" "[test.cpp:5] -> [test.cpp:10]: (warning) Copy constructor does not allocate memory for member 'p' although memory has been allocated in other constructors.\n", "" @@ -826,7 +839,7 @@ class TestClass : public TestFixture { " }\n" " ~kalci();\n" " kalci& operator=(const kalci&kalci);\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkCopyConstructor("class F\n" @@ -851,7 +864,7 @@ class TestClass : public TestFixture { " }\n" " ~F();\n" " F& operator=(const F&f);\n" - "};"); + "};\n"); TODO_ASSERT_EQUALS("[test.cpp:14] -> [test.cpp:11]: (warning) Copy constructor does not allocate memory for member 'd' although memory has been allocated in other constructors.\n", "", errout_str()); checkCopyConstructor("class F {\n" @@ -865,7 +878,7 @@ class TestClass : public TestFixture { " }\n" " ~F();\n" " F& operator=(const F&f);\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkCopyConstructor("class F {\n" @@ -879,7 +892,7 @@ class TestClass : public TestFixture { " }\n" " ~F();\n" " F& operator=(const F&f);\n" - "};"); + "};\n"); TODO_ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:4]: (warning) Copy constructor does not allocate memory for member 'd' although memory has been allocated in other constructors.\n", "", errout_str()); checkCopyConstructor("class F\n" @@ -894,7 +907,7 @@ class TestClass : public TestFixture { " }\n" " ~F();\n" " F& operator=(const F&f);\n" - "};"); + "};\n"); TODO_ASSERT_EQUALS("[test.cpp:8]: (warning) Class 'F' does not have a copy constructor which is recommended since it has dynamic memory/resource management.\n", "", errout_str()); checkCopyConstructor("class F\n" @@ -918,7 +931,7 @@ class TestClass : public TestFixture { " }\n" " ~F();\n" " F& operator=(const F&f);\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkCopyConstructor("class F : E\n" @@ -929,7 +942,7 @@ class TestClass : public TestFixture { " }\n" " ~F();\n" " F& operator=(const F&f);\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkCopyConstructor("class E { E(E&); };\n" // non-copyable @@ -941,7 +954,7 @@ class TestClass : public TestFixture { " }\n" " ~F();\n" " F& operator=(const F&f);\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkCopyConstructor("class E {};\n" @@ -952,7 +965,7 @@ class TestClass : public TestFixture { " }\n" " ~F();\n" " F& operator=(const F&f);\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:5:7]: (warning) Class 'F' does not have a copy constructor which is recommended since it has dynamic memory/resource management. [noCopyConstructor]\n", errout_str()); checkCopyConstructor("class F {\n" @@ -963,7 +976,7 @@ class TestClass : public TestFixture { " F(F& f);\n" " ~F();\n" " F& operator=(const F&f);\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkCopyConstructor("class F {\n" @@ -971,7 +984,7 @@ class TestClass : public TestFixture { " F() : p(malloc(100)) {}\n" " ~F();\n" " F& operator=(const F&f);\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:10]: (warning) Class 'F' does not have a copy constructor which is recommended since it has dynamic memory/resource management. [noCopyConstructor]\n", errout_str()); // #7198 @@ -980,7 +993,7 @@ class TestClass : public TestFixture { " F() {\n" " p = malloc(100);\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -997,7 +1010,7 @@ class TestClass : public TestFixture { " ~Vector();\n" " Vector& operator=(const Vector&v);\n" " _Tp* _M_finish;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1008,7 +1021,7 @@ class TestClass : public TestFixture { " F(const F &f) = delete;\n" " F&operator=(const F &f);\n" " ~F();\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkCopyConstructor("struct F {\n" @@ -1017,7 +1030,7 @@ class TestClass : public TestFixture { " F(const F &f) = default;\n" " F&operator=(const F &f);\n" " ~F();\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:10]: (warning) Struct 'F' has dynamic memory/resource allocation(s). The copy constructor is explicitly defaulted but the default copy constructor does not work well. It is recommended to define or delete the copy constructor. [noCopyConstructor]\n", errout_str()); } @@ -1040,7 +1053,7 @@ class TestClass : public TestFixture { " ~Foo() { delete m_ptr; }\n" "private:\n" " int* m_ptr;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1053,7 +1066,7 @@ class TestClass : public TestFixture { " ~Foo() { delete m_ptr; }\n" "private:\n" " int* m_ptr;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkCopyConstructor("class Copyable {};\n" @@ -1064,7 +1077,7 @@ class TestClass : public TestFixture { " ~Foo() { delete m_ptr; }\n" "private:\n" " int* m_ptr;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1083,6 +1096,25 @@ class TestClass : public TestFixture { errout_str()); } + void copyConstructor7() { // ticket #14954 + checkCopyConstructor("struct S {\n" + " explicit S(char *name) { m_fd = mkstemp(name); }\n" + " ~S() { /* close(m_fd); */ }\n" + " S &operator =(const S&);\n" + " int m_fd;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:30]: (warning) Struct 'S' does not have a copy constructor which is recommended since it has dynamic memory/resource management. [noCopyConstructor]\n", errout_str()); + } + + void copyConstructor8() { + checkCopyConstructor("struct S {\n" + " S() : m_ptr(new int) {}\n" + " ~S();\n" + " std::unique_ptr m_ptr;\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); + } + void deletedMemberPointer() { // delete ... @@ -1116,7 +1148,7 @@ class TestClass : public TestFixture { " F() { c = malloc(100); }\n" " F(const F &f);\n" " ~F();\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:10]: (warning) Struct 'F' does not have a operator= which is recommended since it has dynamic memory/resource management. [noOperatorEq]\n", errout_str()); // defaulted operator= @@ -1126,7 +1158,7 @@ class TestClass : public TestFixture { " F(const F &f);\n" " F &operator=(const F &f) = default;\n" " ~F();\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:10]: (warning) Struct 'F' has dynamic memory/resource allocation(s). The operator= is explicitly defaulted but the default operator= does not work well. It is recommended to define or delete the operator=. [noOperatorEq]\n", errout_str()); // deleted operator= @@ -1136,7 +1168,7 @@ class TestClass : public TestFixture { " F(const F &f);\n" " F &operator=(const F &f) = delete;\n" " ~F();\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // base class deletes operator= @@ -1145,8 +1177,17 @@ class TestClass : public TestFixture { " F() { c = malloc(100); }\n" " F(const F &f);\n" " ~F();\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); + + checkCopyConstructor("struct S {\n" + " explicit S(char *name) { m_fd = mkstemp(name); }\n" + " S(const S&);\n" + " ~S() { /* close(m_fd); */ }\n" + " int m_fd;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:30]: (warning) Struct 'S' does not have a operator= which is recommended since it has dynamic memory/resource management. [noOperatorEq]\n", errout_str()); + } void noDestructor() { @@ -1155,7 +1196,7 @@ class TestClass : public TestFixture { " F() { c = malloc(100); }\n" " F(const F &f);\n" " F&operator=(const F&);" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:10]: (warning) Struct 'F' does not have a destructor which is recommended since it has dynamic memory/resource management. [noDestructor]\n", errout_str()); checkCopyConstructor("struct F {\n" @@ -1163,7 +1204,7 @@ class TestClass : public TestFixture { " F() { c = new C; }\n" " F(const F &f);\n" " F&operator=(const F&);" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkCopyConstructor("struct F {\n" @@ -1171,7 +1212,7 @@ class TestClass : public TestFixture { " F() { i = new int(); }\n" " F(const F &f);\n" " F& operator=(const F&);" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:10]: (warning) Struct 'F' does not have a destructor which is recommended since it has dynamic memory/resource management. [noDestructor]\n", errout_str()); checkCopyConstructor("struct Data { int x; int y; };\n" @@ -1180,7 +1221,7 @@ class TestClass : public TestFixture { " F() { c = new Data; }\n" " F(const F &f);\n" " F&operator=(const F&);" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:10]: (warning) Struct 'F' does not have a destructor which is recommended since it has dynamic memory/resource management. [noDestructor]\n", errout_str()); // defaulted destructor @@ -1190,7 +1231,7 @@ class TestClass : public TestFixture { " F(const F &f);\n" " F &operator=(const F &f);\n" " ~F() = default;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:10]: (warning) Struct 'F' has dynamic memory/resource allocation(s). The destructor is explicitly defaulted but the default destructor does not work well. It is recommended to define the destructor. [noDestructor]\n", errout_str()); // deleted destructor @@ -1200,7 +1241,7 @@ class TestClass : public TestFixture { " F(const F &f);\n" " F &operator=(const F &f);\n" " ~F() = delete;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1213,7 +1254,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(); } @@ -1223,7 +1264,7 @@ class TestClass : public TestFixture { "{\n" "public:\n" " A & operator=(const A &a) { return *this; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqRetRefThis( @@ -1231,7 +1272,7 @@ class TestClass : public TestFixture { "{\n" "public:\n" " A & operator=(const A &a) { return a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:9]: (style) 'operator=' should return reference to 'this' instance. [operatorEqRetRefThis]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1240,7 +1281,7 @@ class TestClass : public TestFixture { "public:\n" " A & operator=(const A &);\n" "};\n" - "A & A::operator=(const A &a) { return *this; }"); + "A & A::operator=(const A &a) { return *this; }\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqRetRefThis( @@ -1249,7 +1290,7 @@ class TestClass : public TestFixture { "public:\n" " A & operator=(const A &a);\n" "};\n" - "A & A::operator=(const A &a) { return *this; }"); + "A & A::operator=(const A &a) { return *this; }\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqRetRefThis( @@ -1258,7 +1299,7 @@ class TestClass : public TestFixture { "public:\n" " A & operator=(const A &);\n" "};\n" - "A & A::operator=(const A &a) { return a; }"); + "A & A::operator=(const A &a) { return a; }\n"); ASSERT_EQUALS("[test.cpp:6:8]: (style) 'operator=' should return reference to 'this' instance. [operatorEqRetRefThis]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1267,7 +1308,7 @@ class TestClass : public TestFixture { "public:\n" " A & operator=(const A &a);\n" "};\n" - "A & A::operator=(const A &a) { return a; }"); + "A & A::operator=(const A &a) { return a; }\n"); ASSERT_EQUALS("[test.cpp:6:8]: (style) 'operator=' should return reference to 'this' instance. [operatorEqRetRefThis]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1279,7 +1320,7 @@ class TestClass : public TestFixture { " public:\n" " B & operator=(const B &b) { return *this; }\n" " };\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqRetRefThis( @@ -1291,7 +1332,7 @@ class TestClass : public TestFixture { " public:\n" " B & operator=(const B &b) { return b; }\n" " };\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:7:13]: (style) 'operator=' should return reference to 'this' instance. [operatorEqRetRefThis]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1304,7 +1345,7 @@ class TestClass : public TestFixture { " B & operator=(const B &);\n" " };\n" "};\n" - "A::B & A::B::operator=(const A::B &b) { return *this; }"); + "A::B & A::B::operator=(const A::B &b) { return *this; }\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqRetRefThis( @@ -1317,7 +1358,7 @@ class TestClass : public TestFixture { " B & operator=(const B &);\n" " };\n" "};\n" - "A::B & A::B::operator=(const A::B &b) { return b; }"); + "A::B & A::B::operator=(const A::B &b) { return b; }\n"); ASSERT_EQUALS("[test.cpp:10:14]: (style) 'operator=' should return reference to 'this' instance. [operatorEqRetRefThis]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1327,7 +1368,7 @@ class TestClass : public TestFixture { "class A::B\n" "{\n" " B & operator=(const B & b) { return b; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:7]: (style) 'operator=' should return reference to 'this' instance. [operatorEqRetRefThis]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1338,7 +1379,7 @@ class TestClass : public TestFixture { "{\n" " B & operator=(const B &);\n" "};\n" - "A::B & A::B::operator=(const A::B & b) { return b; }"); + "A::B & A::B::operator=(const A::B & b) { return b; }\n"); ASSERT_EQUALS("[test.cpp:8:14]: (style) 'operator=' should return reference to 'this' instance. [operatorEqRetRefThis]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1348,7 +1389,7 @@ class TestClass : public TestFixture { "class A::B\n" "{\n" " A::B & operator=(const A::B & b) { return b; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:10]: (style) 'operator=' should return reference to 'this' instance. [operatorEqRetRefThis]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1359,7 +1400,7 @@ class TestClass : public TestFixture { "{\n" " A::B & operator=(const A::B &);\n" "};\n" - "A::B & A::B::operator=(const A::B & b) { return b; }"); + "A::B & A::B::operator=(const A::B & b) { return b; }\n"); ASSERT_EQUALS("[test.cpp:8:14]: (style) 'operator=' should return reference to 'this' instance. [operatorEqRetRefThis]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1369,7 +1410,7 @@ class TestClass : public TestFixture { "class A::B\n" "{\n" " B & operator=(const B & b) { return b; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:7]: (style) 'operator=' should return reference to 'this' instance. [operatorEqRetRefThis]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1380,7 +1421,7 @@ class TestClass : public TestFixture { "{\n" " B & operator=(const B &);\n" "};\n" - "A::B & A::B::operator=(const A::B & b) { return b; }"); + "A::B & A::B::operator=(const A::B & b) { return b; }\n"); ASSERT_EQUALS("[test.cpp:8:14]: (style) 'operator=' should return reference to 'this' instance. [operatorEqRetRefThis]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1390,7 +1431,7 @@ class TestClass : public TestFixture { "class A::B\n" "{\n" " A::B & operator=(const A::B & b) { return b; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:10]: (style) 'operator=' should return reference to 'this' instance. [operatorEqRetRefThis]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1401,7 +1442,7 @@ class TestClass : public TestFixture { "{\n" " A::B & operator=(const A::B &);\n" "};\n" - "A::B & A::B::operator=(const A::B & b) { return b; }"); + "A::B & A::B::operator=(const A::B & b) { return b; }\n"); ASSERT_EQUALS("[test.cpp:8:14]: (style) 'operator=' should return reference to 'this' instance. [operatorEqRetRefThis]\n", errout_str()); checkOpertorEqRetRefThis( // #11380 @@ -1421,7 +1462,7 @@ class TestClass : public TestFixture { "class szp\n" "{\n" " szp &operator =(int *other) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:8]: (error) No 'return' statement in non-void function causes undefined behavior. [operatorEqMissingReturnStatement]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1429,7 +1470,7 @@ class TestClass : public TestFixture { "{\n" " szp &operator =(int *other);\n" "};\n" - "szp &szp::operator =(int *other) {}"); + "szp &szp::operator =(int *other) {}\n"); ASSERT_EQUALS("[test.cpp:5:11]: (error) No 'return' statement in non-void function causes undefined behavior. [operatorEqMissingReturnStatement]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1439,7 +1480,7 @@ class TestClass : public TestFixture { "class NS::szp\n" "{\n" " szp &operator =(int *other) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:8]: (error) No 'return' statement in non-void function causes undefined behavior. [operatorEqMissingReturnStatement]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1450,7 +1491,7 @@ class TestClass : public TestFixture { "{\n" " szp &operator =(int *other);\n" "};\n" - "NS::szp &NS::szp::operator =(int *other) {}"); + "NS::szp &NS::szp::operator =(int *other) {}\n"); ASSERT_EQUALS("[test.cpp:8:19]: (error) No 'return' statement in non-void function causes undefined behavior. [operatorEqMissingReturnStatement]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1460,7 +1501,7 @@ class TestClass : public TestFixture { "class NS::szp\n" "{\n" " NS::szp &operator =(int *other) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:12]: (error) No 'return' statement in non-void function causes undefined behavior. [operatorEqMissingReturnStatement]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1471,7 +1512,7 @@ class TestClass : public TestFixture { "{\n" " NS::szp &operator =(int *other);\n" "};\n" - "NS::szp &NS::szp::operator =(int *other) {}"); + "NS::szp &NS::szp::operator =(int *other) {}\n"); ASSERT_EQUALS("[test.cpp:8:19]: (error) No 'return' statement in non-void function causes undefined behavior. [operatorEqMissingReturnStatement]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1481,7 +1522,7 @@ class TestClass : public TestFixture { "class A::szp\n" "{\n" " szp &operator =(int *other) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:8]: (error) No 'return' statement in non-void function causes undefined behavior. [operatorEqMissingReturnStatement]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1492,7 +1533,7 @@ class TestClass : public TestFixture { "{\n" " szp &operator =(int *other);\n" "};\n" - "A::szp &A::szp::operator =(int *other) {}"); + "A::szp &A::szp::operator =(int *other) {}\n"); ASSERT_EQUALS("[test.cpp:8:17]: (error) No 'return' statement in non-void function causes undefined behavior. [operatorEqMissingReturnStatement]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1502,7 +1543,7 @@ class TestClass : public TestFixture { "class A::szp\n" "{\n" " A::szp &operator =(int *other) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:11]: (error) No 'return' statement in non-void function causes undefined behavior. [operatorEqMissingReturnStatement]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1513,7 +1554,7 @@ class TestClass : public TestFixture { "{\n" " A::szp &operator =(int *other);\n" "};\n" - "A::szp &A::szp::operator =(int *other) {}"); + "A::szp &A::szp::operator =(int *other) {}\n"); ASSERT_EQUALS("[test.cpp:8:17]: (error) No 'return' statement in non-void function causes undefined behavior. [operatorEqMissingReturnStatement]\n", errout_str()); } @@ -1524,7 +1565,7 @@ class TestClass : public TestFixture { "public:\n" " inline A &operator =(int *other) { return (*this); };\n" " inline A &operator =(long *other) { return (*this = 0); };\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqRetRefThis( @@ -1534,7 +1575,7 @@ class TestClass : public TestFixture { " A &operator =(long *other);\n" "};\n" "A &A::operator =(int *other) { return (*this); };\n" - "A &A::operator =(long *other) { return (*this = 0); };"); + "A &A::operator =(long *other) { return (*this = 0); };\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqRetRefThis( @@ -1542,7 +1583,7 @@ class TestClass : public TestFixture { "public:\n" " inline A &operator =(int *other) { return (*this); };\n" " inline A &operator =(long *other) { return operator = (*(int *)other); };\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqRetRefThis( @@ -1552,7 +1593,7 @@ class TestClass : public TestFixture { " A &operator =(long *other);\n" "};\n" "A &A::operator =(int *other) { return (*this); };\n" - "A &A::operator =(long *other) { return operator = (*(int *)other); };"); + "A &A::operator =(long *other) { return operator = (*(int *)other); };\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqRetRefThis( @@ -1562,7 +1603,7 @@ class TestClass : public TestFixture { " A &operator =(long *other);\n" "};\n" "A &A::operator =(int *other) { return (*this); };\n" - "A &A::operator =(long *other) { return this->operator = (*(int *)other); };"); + "A &A::operator =(long *other) { return this->operator = (*(int *)other); };\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqRetRefThis( // #9045 @@ -1574,7 +1615,7 @@ class TestClass : public TestFixture { " }\n" " return *this;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1584,7 +1625,7 @@ class TestClass : public TestFixture { "P& P::operator = (const P& pc)\n" "{\n" " return (P&)(*this += pc);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1594,21 +1635,21 @@ class TestClass : public TestFixture { "class A {\n" "public:\n" " A & operator=(const A &a) { }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:9]: (error) No 'return' statement in non-void function causes undefined behavior. [operatorEqMissingReturnStatement]\n", errout_str()); checkOpertorEqRetRefThis( "class A {\n" "protected:\n" " A & operator=(const A &a) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:9]: (style) 'operator=' should return reference to 'this' instance. [operatorEqRetRefThis]\n", errout_str()); checkOpertorEqRetRefThis( "class A {\n" "private:\n" " A & operator=(const A &a) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:9]: (style) 'operator=' should return reference to 'this' instance. [operatorEqRetRefThis]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1618,7 +1659,7 @@ class TestClass : public TestFixture { " rand();\n" " throw std::exception();\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:9]: (style) 'operator=' should either return reference to 'this' instance or be declared private and left unimplemented. [operatorEqShouldBeLeftUnimplemented]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1628,7 +1669,7 @@ class TestClass : public TestFixture { " rand();\n" " abort();\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:9]: (style) 'operator=' should either return reference to 'this' instance or be declared private and left unimplemented. [operatorEqShouldBeLeftUnimplemented]\n", errout_str()); checkOpertorEqRetRefThis( @@ -1636,7 +1677,7 @@ class TestClass : public TestFixture { "public:\n" " A & operator=(const A &a);\n" "};\n" - "A & A :: operator=(const A &a) { }"); + "A & A :: operator=(const A &a) { }\n"); ASSERT_EQUALS("[test.cpp:5:10]: (error) No 'return' statement in non-void function causes undefined behavior. [operatorEqMissingReturnStatement]\n", errout_str()); } @@ -1653,7 +1694,7 @@ class TestClass : public TestFixture { "}\n" "UString& UString::operator=( const UString& s ) {\n" " return assign( s );\n" - "}"); + "}\n"); } void operatorEqRetRefThis7() { // ticket #5782 Endless recursion in CheckClass::checkReturnPtrThis() @@ -1671,7 +1712,7 @@ class TestClass : public TestFixture { " basic_fbstring& replace() {\n" " return replaceImplDiscr();\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1684,7 +1725,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(); } @@ -1695,7 +1736,7 @@ class TestClass : public TestFixture { "{\n" "public:\n" " A & operator=(const A &a) { if (&a != this) { } return *this; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // this test doesn't have an assignment test but it is not needed @@ -1704,7 +1745,7 @@ class TestClass : public TestFixture { "{\n" "public:\n" " A & operator=(const A &a) { return *this; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // this test needs an assignment test and has it @@ -1722,7 +1763,7 @@ class TestClass : public TestFixture { " }\n" " return *this;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // this class needs an assignment test but doesn't have it @@ -1737,7 +1778,7 @@ class TestClass : public TestFixture { " s = strdup(a.s);\n" " return *this;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:5:9]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. [operatorEqToSelf]\n", errout_str()); // this test has an assignment test but doesn't need it @@ -1747,7 +1788,7 @@ class TestClass : public TestFixture { "public:\n" " A & operator=(const A &);\n" "};\n" - "A & A::operator=(const A &a) { if (&a != this) { } return *this; }"); + "A & A::operator=(const A &a) { if (&a != this) { } return *this; }\n"); ASSERT_EQUALS("", errout_str()); // this test doesn't have an assignment test but doesn't need it @@ -1757,7 +1798,7 @@ class TestClass : public TestFixture { "public:\n" " A & operator=(const A &);\n" "};\n" - "A & A::operator=(const A &a) { return *this; }"); + "A & A::operator=(const A &a) { return *this; }\n"); ASSERT_EQUALS("", errout_str()); // this test needs an assignment test and has it @@ -1776,7 +1817,7 @@ class TestClass : public TestFixture { " s = strdup(a.s);\n" " }\n" " return *this;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // this test needs an assignment test and has the inverse test @@ -1795,7 +1836,7 @@ class TestClass : public TestFixture { " s = strdup(a.s);\n" " }\n" " return *this;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:8]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. [operatorEqToSelf]\n", errout_str()); // this test needs an assignment test and has the inverse test @@ -1814,7 +1855,7 @@ class TestClass : public TestFixture { " s = strdup(a.s);\n" " }\n" " return *this;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:8]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. [operatorEqToSelf]\n", errout_str()); // this test needs an assignment test and has the inverse test @@ -1833,7 +1874,7 @@ class TestClass : public TestFixture { " s = strdup(a.s);\n" " }\n" " return *this;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:8]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. [operatorEqToSelf]\n", errout_str()); // this test needs an assignment test and has the inverse test @@ -1852,7 +1893,7 @@ class TestClass : public TestFixture { " s = strdup(a.s);\n" " }\n" " return *this;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:8]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. [operatorEqToSelf]\n", errout_str()); // this test needs an assignment test and has the inverse test @@ -1871,7 +1912,7 @@ class TestClass : public TestFixture { " s = strdup(a.s);\n" " }\n" " return *this;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:8]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. [operatorEqToSelf]\n", errout_str()); // this test needs an assignment test and has the inverse test @@ -1893,7 +1934,7 @@ class TestClass : public TestFixture { " s = strdup(a.s);\n" " }\n" " return *this;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:8]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. [operatorEqToSelf]\n", errout_str()); // this test needs an assignment test and has the inverse test @@ -1914,7 +1955,7 @@ class TestClass : public TestFixture { " s = strdup(a.s);\n" " }\n" " return *this;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:8]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. [operatorEqToSelf]\n", errout_str()); @@ -1931,7 +1972,7 @@ class TestClass : public TestFixture { " free(s);\n" " s = strdup(a.s);\n" " return *this;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:8]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. [operatorEqToSelf]\n", errout_str()); // ticket #1224 @@ -1949,7 +1990,7 @@ class TestClass : public TestFixture { " tree = new CodeTree(b);\n" " delete oldtree;\n" " return *this;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1965,7 +2006,7 @@ class TestClass : public TestFixture { " public:\n" " B & operator=(const B &b) { if (&b != this) { } return *this; }\n" " };\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // this test doesn't have an assignment test but doesn't need it @@ -1978,7 +2019,7 @@ class TestClass : public TestFixture { " public:\n" " B & operator=(const B &b) { return *this; }\n" " };\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // this test needs an assignment test but has it @@ -1998,7 +2039,7 @@ class TestClass : public TestFixture { " return *this;\n" " }\n" " };\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // this test needs an assignment test but doesn't have it @@ -2017,7 +2058,7 @@ class TestClass : public TestFixture { " return *this;\n" " }\n" " };\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:8:13]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. [operatorEqToSelf]\n", errout_str()); // this test has an assignment test but doesn't need it @@ -2031,7 +2072,7 @@ class TestClass : public TestFixture { " B & operator=(const B &);\n" " };\n" "};\n" - "A::B & A::B::operator=(const A::B &b) { if (&b != this) { } return *this; }"); + "A::B & A::B::operator=(const A::B &b) { if (&b != this) { } return *this; }\n"); ASSERT_EQUALS("", errout_str()); // this test doesn't have an assignment test but doesn't need it @@ -2045,7 +2086,7 @@ class TestClass : public TestFixture { " B & operator=(const B &);\n" " };\n" "};\n" - "A::B & A::B::operator=(const A::B &b) { return *this; }"); + "A::B & A::B::operator=(const A::B &b) { return *this; }\n"); ASSERT_EQUALS("", errout_str()); // this test needs an assignment test and has it @@ -2068,7 +2109,7 @@ class TestClass : public TestFixture { " s = strdup(b.s);\n" " }\n" " return *this;\n" - " }"); + " }\n"); ASSERT_EQUALS("", errout_str()); // this test needs an assignment test but doesn't have it @@ -2088,7 +2129,7 @@ class TestClass : public TestFixture { " free(s);\n" " s = strdup(b.s);\n" " return *this;\n" - " }"); + " }\n"); ASSERT_EQUALS("[test.cpp:11:14]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. [operatorEqToSelf]\n", errout_str()); } @@ -2099,7 +2140,7 @@ class TestClass : public TestFixture { "{\n" "public:\n" " A & operator=(const A &a) { return *this; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // this test has multiple inheritance and needs an assignment test but there is no trivial way to test for it @@ -2114,7 +2155,7 @@ class TestClass : public TestFixture { " s = strdup(a.s);\n" " return *this;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // this test has multiple inheritance so there is no trivial way to test for self assignment but doesn't need it @@ -2124,7 +2165,7 @@ class TestClass : public TestFixture { "public:\n" " A & operator=(const A &);\n" "};\n" - "A & A::operator=(const A &a) { return *this; }"); + "A & A::operator=(const A &a) { return *this; }\n"); ASSERT_EQUALS("", errout_str()); // this test has multiple inheritance and needs an assignment test but there is no trivial way to test for it @@ -2140,7 +2181,7 @@ class TestClass : public TestFixture { " free(s);\n" " s = strdup(a.s);\n" " return *this;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2155,7 +2196,7 @@ class TestClass : public TestFixture { " public:\n" " B & operator=(const B &b) { return *this; }\n" " };\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // this test has multiple inheritance and needs an assignment test but there is no trivial way to test for it @@ -2174,7 +2215,7 @@ class TestClass : public TestFixture { " return *this;\n" " }\n" " };\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // this test has multiple inheritance so there is no trivial way to test for self assignment but doesn't need it @@ -2188,7 +2229,7 @@ class TestClass : public TestFixture { " B & operator=(const B &);\n" " };\n" "};\n" - "A::B & A::B::operator=(const A::B &b) { return *this; }"); + "A::B & A::B::operator=(const A::B &b) { return *this; }\n"); ASSERT_EQUALS("", errout_str()); // this test has multiple inheritance and needs an assignment test but there is no trivial way to test for it @@ -2208,7 +2249,7 @@ class TestClass : public TestFixture { " free(s);\n" " s = strdup(b.s);\n" " return *this;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2228,7 +2269,7 @@ class TestClass : public TestFixture { " }\n" " return *this;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqToSelf( @@ -2245,7 +2286,7 @@ class TestClass : public TestFixture { " }\n" " return *this;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqToSelf( @@ -2262,7 +2303,7 @@ class TestClass : public TestFixture { " }\n" " return *this;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqToSelf( @@ -2279,7 +2320,7 @@ class TestClass : public TestFixture { " }\n" " return *this;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqToSelf( @@ -2296,7 +2337,7 @@ class TestClass : public TestFixture { " }\n" " return *this;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqToSelf( @@ -2313,7 +2354,7 @@ class TestClass : public TestFixture { " }\n" " return *this;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqToSelf( @@ -2330,7 +2371,7 @@ class TestClass : public TestFixture { " }\n" " return *this;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqToSelf( @@ -2347,7 +2388,7 @@ class TestClass : public TestFixture { " }\n" " return *this;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqToSelf( @@ -2365,7 +2406,7 @@ class TestClass : public TestFixture { " s = strdup(a.s);\n" " }\n" " return *this;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqToSelf( @@ -2383,7 +2424,7 @@ class TestClass : public TestFixture { " s = strdup(a.s);\n" " }\n" " return *this;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqToSelf( @@ -2401,7 +2442,7 @@ class TestClass : public TestFixture { " s = strdup(a.s);\n" " }\n" " return *this;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqToSelf( @@ -2419,7 +2460,7 @@ class TestClass : public TestFixture { " s = strdup(a.s);\n" " }\n" " return *this;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqToSelf( @@ -2437,7 +2478,7 @@ class TestClass : public TestFixture { " s = strdup(a.s);\n" " }\n" " return *this;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqToSelf( @@ -2455,7 +2496,7 @@ class TestClass : public TestFixture { " s = strdup(a.s);\n" " }\n" " return *this;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqToSelf( @@ -2473,7 +2514,7 @@ class TestClass : public TestFixture { " s = strdup(a.s);\n" " }\n" " return *this;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqToSelf( @@ -2491,7 +2532,7 @@ class TestClass : public TestFixture { " s = strdup(a.s);\n" " }\n" " return *this;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOpertorEqToSelf( @@ -2503,7 +2544,7 @@ class TestClass : public TestFixture { " free(s);\n" " s = strdup(a.s);\n" " return *this;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -2522,7 +2563,7 @@ class TestClass : public TestFixture { " }\n" "private:\n" " char * data;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:9]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. [operatorEqToSelf]\n", errout_str()); checkOpertorEqToSelf( @@ -2539,7 +2580,7 @@ class TestClass : public TestFixture { " data = new char[strlen(a.data) + 1];\n" " strcpy(data, a.data);\n" " return *this;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:8:8]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. [operatorEqToSelf]\n", errout_str()); checkOpertorEqToSelf( @@ -2555,7 +2596,7 @@ class TestClass : public TestFixture { " }\n" "private:\n" " char * data;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:9]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. [operatorEqToSelf]\n", errout_str()); checkOpertorEqToSelf( @@ -2572,7 +2613,7 @@ class TestClass : public TestFixture { " data = new char;\n" " *data = *a.data;\n" " return *this;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:8:8]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. [operatorEqToSelf]\n", errout_str()); } @@ -2589,7 +2630,7 @@ class TestClass : public TestFixture { " {\n" " return assign(a);\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -2608,7 +2649,7 @@ class TestClass : public TestFixture { "FMat& FMat::operator=(const FMat& in)\n" "{\n" " return copy(in);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2627,13 +2668,12 @@ class TestClass : public TestFixture { "Foo& Foo::operator=(Foo& other)\n" "{\n" " return Foo::operator=(&other);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } struct CheckVirtualDestructorOptions { - CheckVirtualDestructorOptions() = default; bool inconclusive = false; }; @@ -2648,7 +2688,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(); } @@ -2657,12 +2697,12 @@ class TestClass : public TestFixture { checkVirtualDestructor("class Derived : public Base { };\n" "Base *base = new Derived;\n" - "delete base;"); + "delete base;\n"); ASSERT_EQUALS("", errout_str()); checkVirtualDestructor("class Derived : Base { };\n" "Base *base = new Derived;\n" - "delete base;"); + "delete base;\n"); ASSERT_EQUALS("", errout_str()); } @@ -2670,27 +2710,27 @@ class TestClass : public TestFixture { // Base class doesn't have a destructor checkVirtualDestructor("class Base { };\n" - "class Derived : public Base { public: ~Derived() { (void)11; } };" + "class Derived : public Base { public: ~Derived() { (void)11; } };\n" "Base *base = new Derived;\n" - "delete base;"); + "delete base;\n"); ASSERT_EQUALS("[test.cpp:1:1]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. [virtualDestructor]\n", errout_str()); checkVirtualDestructor("class Base { };\n" - "class Derived : protected Base { public: ~Derived() { (void)11; } };" + "class Derived : protected Base { public: ~Derived() { (void)11; } };\n" "Base *base = new Derived;\n" - "delete base;"); + "delete base;\n"); ASSERT_EQUALS("[test.cpp:1:1]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. [virtualDestructor]\n", errout_str()); checkVirtualDestructor("class Base { };\n" - "class Derived : private Base { public: ~Derived() { (void)11; } };" + "class Derived : private Base { public: ~Derived() { (void)11; } };\n" "Base *base = new Derived;\n" - "delete base;"); + "delete base;\n"); ASSERT_EQUALS("", errout_str()); checkVirtualDestructor("class Base { };\n" - "class Derived : Base { public: ~Derived() { (void)11; } };" + "class Derived : Base { public: ~Derived() { (void)11; } };\n" "Base *base = new Derived;\n" - "delete base;"); + "delete base;\n"); ASSERT_EQUALS("", errout_str()); // #9104 @@ -2711,7 +2751,7 @@ class TestClass : public TestFixture { "{\n" " Base* p = new Derived();\n" " delete p;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:1]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. [virtualDestructor]\n", errout_str()); checkVirtualDestructor("using namespace std;\n" @@ -2732,7 +2772,7 @@ class TestClass : public TestFixture { "{\n" " Base* p = new Derived();\n" " delete p;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:1]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. [virtualDestructor]\n", errout_str()); } @@ -2740,21 +2780,21 @@ class TestClass : public TestFixture { // Base class has a destructor, but it's not virtual checkVirtualDestructor("class Base { public: ~Base(); };\n" - "class Derived : public Base { public: ~Derived() { (void)11; } };" + "class Derived : public Base { public: ~Derived() { (void)11; } };\n" "Base *base = new Derived;\n" - "delete base;"); + "delete base;\n"); ASSERT_EQUALS("[test.cpp:1:23]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. [virtualDestructor]\n", errout_str()); checkVirtualDestructor("class Base { public: ~Base(); };\n" - "class Derived : protected Base { public: ~Derived() { (void)11; } };" + "class Derived : protected Base { public: ~Derived() { (void)11; } };\n" "Base *base = new Derived;\n" - "delete base;"); + "delete base;\n"); ASSERT_EQUALS("[test.cpp:1:23]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. [virtualDestructor]\n", errout_str()); checkVirtualDestructor("class Base { public: ~Base(); };\n" - "class Derived : private Fred, public Base { public: ~Derived() { (void)11; } };" + "class Derived : private Fred, public Base { public: ~Derived() { (void)11; } };\n" "Base *base = new Derived;\n" - "delete base;"); + "delete base;\n"); ASSERT_EQUALS("[test.cpp:1:23]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. [virtualDestructor]\n", errout_str()); } @@ -2762,15 +2802,15 @@ class TestClass : public TestFixture { // Derived class doesn't have a destructor => undefined behaviour according to paragraph 3 in [expr.delete] checkVirtualDestructor("class Base { public: ~Base(); };\n" - "class Derived : public Base { };" + "class Derived : public Base { };\n" "Base *base = new Derived;\n" - "delete base;"); + "delete base;\n"); ASSERT_EQUALS("[test.cpp:1:23]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. [virtualDestructor]\n", errout_str()); checkVirtualDestructor("class Base { public: ~Base(); };\n" - "class Derived : private Fred, public Base { };" + "class Derived : private Fred, public Base { };\n" "Base *base = new Derived;\n" - "delete base;"); + "delete base;\n"); ASSERT_EQUALS("[test.cpp:1:23]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. [virtualDestructor]\n", errout_str()); } @@ -2778,15 +2818,15 @@ class TestClass : public TestFixture { // Derived class has empty destructor => undefined behaviour according to paragraph 3 in [expr.delete] checkVirtualDestructor("class Base { public: ~Base(); };\n" - "class Derived : public Base { public: ~Derived() {} };" + "class Derived : public Base { public: ~Derived() {} };\n" "Base *base = new Derived;\n" - "delete base;"); + "delete base;\n"); ASSERT_EQUALS("[test.cpp:1:23]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. [virtualDestructor]\n", errout_str()); checkVirtualDestructor("class Base { public: ~Base(); };\n" - "class Derived : public Base { public: ~Derived(); }; Derived::~Derived() {}" + "class Derived : public Base { public: ~Derived(); }; Derived::~Derived() {}\n" "Base *base = new Derived;\n" - "delete base;"); + "delete base;\n"); ASSERT_EQUALS("[test.cpp:1:23]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. [virtualDestructor]\n", errout_str()); } @@ -2795,7 +2835,7 @@ class TestClass : public TestFixture { // points at derived class checkVirtualDestructor("class Base { public: ~Base(); };\n" - "class Derived : public Base { public: ~Derived() { (void)11; } };"); + "class Derived : public Base { public: ~Derived() { (void)11; } };\n"); ASSERT_EQUALS("", errout_str()); } @@ -2812,7 +2852,7 @@ class TestClass : public TestFixture { "{\n" "public:\n" " ~B() { int a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -2833,7 +2873,7 @@ class TestClass : public TestFixture { "{\n" "public:\n" " ~B() { int a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // class A inherits virtual destructor from struct Base -> no error @@ -2851,7 +2891,7 @@ class TestClass : public TestFixture { "{\n" "public:\n" " ~B() { int a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // Unknown Base class -> it could have virtual destructor, so ignore @@ -2865,7 +2905,7 @@ class TestClass : public TestFixture { "{\n" "public:\n" " ~B() { int a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // Virtual destructor is inherited -> no error @@ -2886,7 +2926,7 @@ class TestClass : public TestFixture { "{\n" "public:\n" " ~B() { int a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // class A doesn't inherit virtual destructor from class Base -> error @@ -2905,7 +2945,7 @@ class TestClass : public TestFixture { "{\n" "public:\n" " ~B() { int a; }\n" - "};"); + "};\n"); TODO_ASSERT_EQUALS("[test.cpp:7]: (error) Class 'Base' which is inherited by class 'B' does not have a virtual destructor.\n", "", errout_str()); } @@ -2927,7 +2967,7 @@ class TestClass : public TestFixture { " ~B(){int a;}\n" "};\n" "\n" - "AA *p = new B; delete p;"); + "AA *p = new B; delete p;\n"); ASSERT_EQUALS("[test.cpp:9:3]: (error) Class 'AA < double >' which is inherited by class 'B' does not have a virtual destructor. [virtualDestructor]\n", errout_str()); } @@ -2975,8 +3015,7 @@ class TestClass : public TestFixture { #define checkNoMemset(...) checkNoMemset_(__FILE__, __LINE__, __VA_ARGS__) template void checkNoMemset_(const char* file, int line, const char (&code)[size]) { - const Settings settings = settingsBuilder().severity(Severity::warning).severity(Severity::portability).library("std.cfg").library("posix.cfg").build(); - checkNoMemset_(file, line, code, settings); + checkNoMemset_(file, line, code, settings4); } template @@ -2986,7 +3025,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(); } @@ -2998,7 +3037,7 @@ class TestClass : public TestFixture { "{\n" " Fred fred;\n" " memset(&fred, 0, sizeof(Fred));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkNoMemset("class Fred\n" @@ -3009,7 +3048,7 @@ class TestClass : public TestFixture { "{\n" " Fred fred;\n" " memset(&fred, 0, sizeof(Fred));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkNoMemset("class Fred\n" @@ -3020,7 +3059,7 @@ class TestClass : public TestFixture { "{\n" " Fred fred;\n" " memset(&fred, 0, sizeof(Fred));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkNoMemset("class Fred\n" @@ -3031,7 +3070,7 @@ class TestClass : public TestFixture { "{\n" " Fred fred;\n" " memset(&fred, 0, sizeof(Fred));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:5]: (error) Using 'memset' on class that contains a 'std::string'. [memsetClass]\n", errout_str()); checkNoMemset("class Fred\n" @@ -3042,7 +3081,7 @@ class TestClass : public TestFixture { "{\n" " Fred fred;\n" " memset(&fred, 0, sizeof(Fred));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:5]: (error) Using 'memset' on class that contains a 'std::string'. [memsetClass]\n", errout_str()); checkNoMemset("class Fred {\n" @@ -3051,7 +3090,7 @@ class TestClass : public TestFixture { "};\n" "void Fred::f() {\n" " memset(this, 0, sizeof(*this));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:5]: (error) Using 'memset' on class that contains a 'std::string'. [memsetClass]\n", errout_str()); checkNoMemset("class Fred\n" @@ -3061,7 +3100,7 @@ class TestClass : public TestFixture { "{\n" " Fred fred;\n" " memset(&fred, 0, sizeof(fred));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkNoMemset("class Fred\n" @@ -3072,7 +3111,7 @@ class TestClass : public TestFixture { "{\n" " Fred fred;\n" " memset(&fred, 0, sizeof(fred));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:5]: (error) Using 'memset' on class that contains a 'std::string'. [memsetClass]\n", errout_str()); checkNoMemset("class Fred\n" @@ -3084,7 +3123,7 @@ class TestClass : public TestFixture { "{\n" " Pebbles pebbles;\n" " memset(&pebbles, 0, sizeof(pebbles));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:9:5]: (error) Using 'memset' on class that contains a 'std::string'. [memsetClass]\n", errout_str()); checkNoMemset("class Fred\n" @@ -3095,7 +3134,7 @@ class TestClass : public TestFixture { "{\n" " Fred fred;\n" " memset(&fred, 0, sizeof(fred));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:5]: (error) Using 'memset' on class that contains a virtual function. [memsetClass]\n", errout_str()); checkNoMemset("class Fred\n" @@ -3106,7 +3145,7 @@ class TestClass : public TestFixture { "{\n" " static Fred fred;\n" " memset(&fred, 0, sizeof(fred));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:5]: (error) Using 'memset' on class that contains a virtual function. [memsetClass]\n", errout_str()); checkNoMemset("class Fred\n" @@ -3121,7 +3160,7 @@ class TestClass : public TestFixture { "{\n" " Pebbles pebbles;\n" " memset(&pebbles, 0, sizeof(pebbles));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:12:5]: (error) Using 'memset' on class that contains a virtual function. [memsetClass]\n", errout_str()); // Fred not defined in scope @@ -3135,7 +3174,7 @@ class TestClass : public TestFixture { "{\n" " Fred fred;\n" " memset(&fred, 0, sizeof(Fred));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Fred with namespace qualifier @@ -3149,7 +3188,7 @@ class TestClass : public TestFixture { "{\n" " n1::Fred fred;\n" " memset(&fred, 0, sizeof(n1::Fred));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:10:5]: (error) Using 'memset' on class that contains a 'std::string'. [memsetClass]\n", errout_str()); // Fred with namespace qualifier @@ -3163,7 +3202,7 @@ class TestClass : public TestFixture { "{\n" " n1::Fred fred;\n" " memset(&fred, 0, sizeof(fred));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:10:5]: (error) Using 'memset' on class that contains a 'std::string'. [memsetClass]\n", errout_str()); checkNoMemset("class A {\n" @@ -3174,7 +3213,7 @@ class TestClass : public TestFixture { " const int N = 10;\n" " A** arr = new A*[N];\n" " memset(arr, 0, N * sizeof(A*));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkNoMemset("class A {\n" // #5116 - nested class data is mixed in the SymbolDatabase @@ -3183,7 +3222,7 @@ class TestClass : public TestFixture { "};\n" "void f(A::B *b) {\n" " memset(b,0,4);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #4461 Warn about memset/memcpy on class with references as members @@ -3193,7 +3232,7 @@ class TestClass : public TestFixture { "void f() {\n" " A a;\n" " memset(&a, 0, sizeof(a));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:3]: (error) Using 'memset' on class that contains a reference. [memsetClassReference]\n", errout_str()); checkNoMemset("class A {\n" " const B&b;\n" @@ -3201,7 +3240,7 @@ class TestClass : public TestFixture { "void f() {\n" " A a;\n" " memset(&a, 0, sizeof(a));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:3]: (error) Using 'memset' on class that contains a reference. [memsetClassReference]\n", errout_str()); // #7456 @@ -3215,7 +3254,7 @@ class TestClass : public TestFixture { "void func() {\n" " B b[4];\n" " memset(b, 0, sizeof(b));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #8619 @@ -3270,11 +3309,11 @@ class TestClass : public TestFixture { " } vid;\n" " };\n" " } hdr;\n" - "};" + "};\n" "void parseHeader() {\n" " ASFStreamHeader strhdr;\n" " memset(&strhdr, 0, sizeof(strhdr));\n" - "}"); + "}\n"); } void memsetOnStruct() { @@ -3285,7 +3324,7 @@ class TestClass : public TestFixture { "{\n" " A a;\n" " memset(&a, 0, sizeof(A));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkNoMemset("struct A\n" @@ -3295,7 +3334,7 @@ class TestClass : public TestFixture { "{\n" " struct A a;\n" " memset(&a, 0, sizeof(struct A));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkNoMemset("struct A\n" @@ -3305,14 +3344,14 @@ class TestClass : public TestFixture { "{\n" " struct A a;\n" " memset(&a, 0, sizeof(A));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkNoMemset("void f()\n" "{\n" " struct sockaddr_in6 fail;\n" " memset(&fail, 0, sizeof(struct sockaddr_in6));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkNoMemset("struct A\n" @@ -3325,7 +3364,7 @@ class TestClass : public TestFixture { "{\n" " struct A fail;\n" " memset(&fail, 0, sizeof(struct A));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:10:2]: (error) Using 'memset' on struct that contains a 'std::string'. [memsetClass]\n", errout_str()); checkNoMemset("struct Fred\n" @@ -3336,7 +3375,7 @@ class TestClass : public TestFixture { "{\n" " Fred fred;\n" " memset(&fred, 0, sizeof(fred));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:5]: (error) Using 'memset' on struct that contains a 'std::string'. [memsetClass]\n", errout_str()); checkNoMemset("struct Stringy {\n" @@ -3348,7 +3387,7 @@ class TestClass : public TestFixture { "int main() {\n" " Foo foo;\n" " memset(&foo, 0, sizeof(Foo));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:9:5]: (error) Using 'memset' on struct that contains a 'std::string'. [memsetClass]\n", errout_str()); } @@ -3361,7 +3400,7 @@ class TestClass : public TestFixture { "{\n" " A a;\n" " memset(&a, 0, sizeof(A));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:5]: (error) Using 'memset' on class that contains a 'std::vector'. [memsetClass]\n", errout_str()); checkNoMemset("struct A\n" @@ -3371,7 +3410,7 @@ class TestClass : public TestFixture { "{\n" " A a;\n" " memset(&a, 0, sizeof(A));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:5]: (error) Using 'memset' on struct that contains a 'std::vector'. [memsetClass]\n", errout_str()); checkNoMemset("struct A\n" @@ -3381,7 +3420,7 @@ class TestClass : public TestFixture { "{\n" " A a;\n" " memset(&a, 0, sizeof(struct A));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:5]: (error) Using 'memset' on struct that contains a 'std::vector'. [memsetClass]\n", errout_str()); checkNoMemset("struct A\n" @@ -3391,7 +3430,7 @@ class TestClass : public TestFixture { "{\n" " A a;\n" " memset(&a, 0, sizeof(a));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:5]: (error) Using 'memset' on struct that contains a 'std::vector'. [memsetClass]\n", errout_str()); checkNoMemset("class A\n" @@ -3401,7 +3440,7 @@ class TestClass : public TestFixture { "{\n" " A a;\n" " memset(&a, 0, sizeof(A));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:5]: (error) Using 'memset' on class that contains a 'std::vector'. [memsetClass]\n", errout_str()); checkNoMemset("struct A\n" @@ -3411,7 +3450,7 @@ class TestClass : public TestFixture { "{\n" " A a;\n" " memset(&a, 0, sizeof(A));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:5]: (error) Using 'memset' on struct that contains a 'std::vector'. [memsetClass]\n", errout_str()); checkNoMemset("struct A\n" @@ -3421,7 +3460,7 @@ class TestClass : public TestFixture { "{\n" " A a;\n" " memset(&a, 0, sizeof(a));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:5]: (error) Using 'memset' on struct that contains a 'std::vector'. [memsetClass]\n", errout_str()); checkNoMemset("struct A\n" @@ -3431,7 +3470,7 @@ class TestClass : public TestFixture { "{\n" " A a;\n" " memset(&a, 0, sizeof(A));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:5]: (error) Using 'memset' on struct that contains a 'std::vector'. [memsetClass]\n", errout_str()); checkNoMemset("struct A {\n" @@ -3441,7 +3480,7 @@ class TestClass : public TestFixture { "void f() {\n" " A a;\n" " memset(a, 0, 100);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #4460 checkNoMemset("struct C {\n" @@ -3459,7 +3498,7 @@ class TestClass : public TestFixture { " memset(*c4, 0, 10);\n" " memset(c2, 0, 10);\n" " memset(c3, 0, 10);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:9:5]: (error) Using 'memset' on struct that contains a 'std::string'. [memsetClass]\n" "[test.cpp:11:5]: (error) Using 'memset' on struct that contains a 'std::string'. [memsetClass]\n" "[test.cpp:12:5]: (error) Using 'memset' on struct that contains a 'std::string'. [memsetClass]\n" @@ -3475,7 +3514,7 @@ class TestClass : public TestFixture { " multilevel_data *d = (multilevel_data *) malloc(sizeof(multilevel_data));\n" " memset(d, 0, sizeof(multilevel_data));\n" " return (void*) d;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:3]: (portability) Using memset() on struct which contains a floating point number. [memsetClassFloat]\n", errout_str()); } @@ -3493,7 +3532,7 @@ class TestClass : public TestFixture { "void f() {\n" " A a;\n" " memset(&a, 0, sizeof(A));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // std::array is POD (#5481) checkNoMemset("struct st {\n" @@ -3504,7 +3543,7 @@ class TestClass : public TestFixture { "void f() {\n" " st s;\n" " std::memset(&s, 0, sizeof(st));\n" - "}", settings); + "}\n", settings); ASSERT_EQUALS("", errout_str()); } @@ -3515,7 +3554,7 @@ class TestClass : public TestFixture { "void f() {\n" " A a;\n" " memset(&a, 0, sizeof(A));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:5]: (portability) Using memset() on struct which contains a floating point number. [memsetClassFloat]\n", errout_str()); checkNoMemset("struct A {\n" @@ -3524,7 +3563,7 @@ class TestClass : public TestFixture { "void f() {\n" " A a;\n" " memset(&a, 0, sizeof(A));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:5]: (portability) Using memset() on struct which contains a floating point number. [memsetClassFloat]\n", errout_str()); checkNoMemset("struct A {\n" @@ -3533,7 +3572,7 @@ class TestClass : public TestFixture { "void f(const A& b) {\n" " A a;\n" " memcpy(&a, &b, sizeof(A));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkNoMemset("struct A {\n" @@ -3542,7 +3581,7 @@ class TestClass : public TestFixture { "void f() {\n" " A a;\n" " memset(&a, 0, sizeof(A));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -3550,7 +3589,7 @@ class TestClass : public TestFixture { checkNoMemset("void clang_tokenize(CXToken **Tokens) {\n" " *Tokens = (CXToken *)malloc(sizeof(CXToken) * CXTokens.size());\n" " memmove(*Tokens, CXTokens.data(), sizeof(CXToken) * CXTokens.size());\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -3558,49 +3597,49 @@ class TestClass : public TestFixture { checkNoMemset("class C { C() {} };\n" "void foo(C*& p) {\n" " p = malloc(sizeof(C));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5] -> [test.cpp:1:1]: (warning) Memory for class instance allocated with malloc(), but class provides constructors. [mallocOnClassWarning]\n", errout_str()); checkNoMemset("class C { C(int z, Foo bar) { bar(); } };\n" "void foo(C*& p) {\n" " p = malloc(sizeof(C));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5] -> [test.cpp:1:1]: (warning) Memory for class instance allocated with malloc(), but class provides constructors. [mallocOnClassWarning]\n", errout_str()); checkNoMemset("struct C { C() {} };\n" "void foo(C*& p) {\n" " p = realloc(p, sizeof(C));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5] -> [test.cpp:1:1]: (warning) Memory for class instance allocated with realloc(), but class provides constructors. [mallocOnClassWarning]\n", errout_str()); checkNoMemset("struct C { virtual void bar(); };\n" "void foo(C*& p) {\n" " p = malloc(sizeof(C));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9] -> [test.cpp:1:1]: (error) Memory for class instance allocated with malloc(), but class contains a virtual function. [mallocOnClassError]\n", errout_str()); checkNoMemset("struct C { std::string s; };\n" "void foo(C*& p) {\n" " p = malloc(sizeof(C));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9] -> [test.cpp:1:1]: (error) Memory for class instance allocated with malloc(), but class contains a 'std::string'. [mallocOnClassError]\n", errout_str()); checkNoMemset("class C { };\n" // C-Style class/struct "void foo(C*& p) {\n" " p = malloc(sizeof(C));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkNoMemset("struct C { C() {} };\n" "void foo(C*& p) {\n" " p = new C();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkNoMemset("class C { C() {} };\n" "void foo(D*& p) {\n" // Unknown type " p = malloc(sizeof(C));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkNoMemset("class AutoCloseFD {\n" @@ -3611,7 +3650,7 @@ class TestClass : public TestFixture { "};\n" "void f() {\n" " AutoCloseFD fd = open(\"abc\", O_RDONLY | O_CLOEXEC);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkNoMemset("struct C {\n" // #12313 @@ -3620,7 +3659,7 @@ class TestClass : public TestFixture { "};\n" "void f() {\n" " C c = strdup(\"abc\");\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -3632,45 +3671,47 @@ class TestClass : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check.. - CheckClass checkClass(&tokenizer, &settings1, this); + CheckClassImpl checkClass(&tokenizer, settings1, *this); checkClass.thisSubtraction(); } void this_subtraction() { - checkThisSubtraction("; this-x ;"); + checkThisSubtraction("; this-x ;\n"); ASSERT_EQUALS("[test.cpp:1:3]: (warning) Suspicious pointer subtraction. Did you intend to write '->'? [thisSubtraction]\n", errout_str()); - checkThisSubtraction("; *this = *this-x ;"); + checkThisSubtraction("; *this = *this-x ;\n"); ASSERT_EQUALS("", errout_str()); checkThisSubtraction("; *this = *this-x ;\n" - "this-x ;"); + "this-x ;\n"); ASSERT_EQUALS("[test.cpp:2:1]: (warning) Suspicious pointer subtraction. Did you intend to write '->'? [thisSubtraction]\n", errout_str()); checkThisSubtraction("; *this = *this-x ;\n" "this-x ;\n" - "this-x ;"); + "this-x ;\n"); ASSERT_EQUALS("[test.cpp:2:1]: (warning) Suspicious pointer subtraction. Did you intend to write '->'? [thisSubtraction]\n" "[test.cpp:3:1]: (warning) Suspicious pointer subtraction. Did you intend to write '->'? [thisSubtraction]\n", errout_str()); } struct CheckConstOptions { - CheckConstOptions() = default; - const Settings *s = nullptr; bool inconclusive = true; }; #define checkConst(...) checkConst_(__FILE__, __LINE__, __VA_ARGS__) template void checkConst_(const char* file, int line, const char (&code)[size], const CheckConstOptions& options = make_default_obj()) { - const Settings settings = settingsBuilder(options.s ? *options.s : settings0).certainty(Certainty::inconclusive, options.inconclusive).build(); + const Settings& settings = options.inconclusive ? settings0_i : settings0; - // Tokenize.. + checkConst_(file, line, code, settings); + } + + template + void checkConst_(const char* file, int line, const char (&code)[size], const Settings& settings) { SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - CheckClass checkClass(&tokenizer, &settings, this); + CheckClassImpl checkClass(&tokenizer, settings, *this); (checkClass.checkConst)(); } @@ -3678,33 +3719,33 @@ class TestClass : public TestFixture { checkConst("class Fred {\n" " int a;\n" " int getA() { return a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:9]: (style, inconclusive) Technically the member function 'Fred::getA' can be const. [functionConst]\n", errout_str()); checkConst("class Fred {\n" " const std::string foo() { return \"\"; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:2:23]: (performance, inconclusive) Technically the member function 'Fred::foo' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:2:23]: (style) The member function 'Fred::foo' can be static. [functionStatic]\n", errout_str()); checkConst("class Fred {\n" " std::string s;\n" " const std::string & foo() { return \"\"; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:25]: (performance, inconclusive) Technically the member function 'Fred::foo' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:25]: (style) The member function 'Fred::foo' can be static. [functionStatic]\n", errout_str()); // constructors can't be const.. checkConst("class Fred {\n" " int a;\n" "public:\n" " Fred() { }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // assignment through |=.. checkConst("class Fred {\n" " int a;\n" " int setA() { a |= true; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // functions with a call to a member function can only be const, if that member function is const, too.. (#1305) @@ -3713,7 +3754,7 @@ class TestClass : public TestFixture { " int x;\n" " void a() { x = 1; }\n" " void b() { a(); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" @@ -3721,15 +3762,15 @@ class TestClass : public TestFixture { " int x;\n" " int a() const { return x; }\n" " void b() { a(); }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:5:10]: (style, inconclusive) Technically the member function 'Fred::b' can be const. [functionConst]\n", errout_str()); checkConst("class Fred {\n" "public:\n" " int x;\n" " void b() { a(); }\n" - "};"); - ASSERT_EQUALS("[test.cpp:4:10]: (performance, inconclusive) Technically the member function 'Fred::b' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:4:10]: (style) The member function 'Fred::b' can be static. [functionStatic]\n", errout_str()); // static functions can't be const.. checkConst("class foo\n" @@ -3737,13 +3778,13 @@ class TestClass : public TestFixture { "public:\n" " static unsigned get()\n" " { return 0; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " const std::string foo() const throw() { return \"\"; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:2:23]: (performance, inconclusive) Technically the member function 'Fred::foo' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:2:23]: (style) The member function 'Fred::foo' can be static. [functionStatic]\n", errout_str()); } void const2() { @@ -3752,49 +3793,49 @@ class TestClass : public TestFixture { checkConst("class Fred {\n" " std::string s;\n" " void foo() { s = \"\"; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // assignment to function argument reference can be const checkConst("class Fred {\n" " std::string s;\n" " void foo(std::string & a) { a = s; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:10]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. [functionConst]\n", errout_str()); // assignment to variable can't be const checkConst("class Fred {\n" " std::string s;\n" " void foo(std::string & a) { s = a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // assignment to function argument references can be const checkConst("class Fred {\n" " std::string s;\n" " void foo(std::string & a, std::string & b) { a = s; b = s; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:10]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. [functionConst]\n", errout_str()); // assignment to variable, can't be const checkConst("class Fred {\n" " std::string s;\n" " void foo(std::string & a, std::string & b) { s = a; s = b; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // assignment to variable, can't be const checkConst("class Fred {\n" " std::string s;\n" " void foo(std::string & a, std::string & b) { s = a; b = a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // assignment to variable, can't be const checkConst("class Fred {\n" " std::string s;\n" " void foo(std::string & a, std::string & b) { a = s; s = b; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3803,42 +3844,42 @@ class TestClass : public TestFixture { checkConst("class Fred {\n" " int s;\n" " void foo(int * a) { *a = s; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:10]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. [functionConst]\n", errout_str()); // assignment to variable, can't be const checkConst("class Fred {\n" " int s;\n" " void foo(int * a) { s = *a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // assignment to function argument pointers can be const checkConst("class Fred {\n" " std::string s;\n" " void foo(std::string * a, std::string * b) { *a = s; *b = s; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:10]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. [functionConst]\n", errout_str()); // assignment to variable, can't be const checkConst("class Fred {\n" " std::string s;\n" " void foo(std::string * a, std::string * b) { s = *a; s = *b; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // assignment to variable, can't be const checkConst("class Fred {\n" " std::string s;\n" " void foo(std::string * a, std::string * b) { s = *a; *b = s; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // assignment to variable, can't be const checkConst("class Fred {\n" " std::string s;\n" " void foo(std::string * a, std::string * b) { *a = s; s = b; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3847,15 +3888,15 @@ class TestClass : public TestFixture { " int a;\n" " int getA();\n" "};\n" - "int Fred::getA() { return a; }"); + "int Fred::getA() { return a; }\n"); ASSERT_EQUALS("[test.cpp:3:9] -> [test.cpp:5:11]: (style, inconclusive) Technically the member function 'Fred::getA' can be const. [functionConst]\n", errout_str()); checkConst("class Fred {\n" " std::string s;\n" " const std::string & foo();\n" "};\n" - "const std::string & Fred::foo() { return \"\"; }"); - ASSERT_EQUALS("[test.cpp:3:25] -> [test.cpp:5:27]: (performance, inconclusive) Technically the member function 'Fred::foo' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "const std::string & Fred::foo() { return \"\"; }\n"); + ASSERT_EQUALS("[test.cpp:3:25] -> [test.cpp:5:27]: (style) The member function 'Fred::foo' can be static. [functionStatic]\n", errout_str()); // functions with a function call to a non-const member can't be const.. (#1305) checkConst("class Fred\n" @@ -3865,7 +3906,7 @@ class TestClass : public TestFixture { " void a() { x = 1; }\n" " void b();\n" "};\n" - "void Fred::b() { a(); }"); + "void Fred::b() { a(); }\n"); ASSERT_EQUALS("", errout_str()); // static functions can't be const.. @@ -3874,7 +3915,7 @@ class TestClass : public TestFixture { "public:\n" " static unsigned get();\n" "};\n" - "static unsigned Fred::get() { return 0; }"); + "static unsigned Fred::get() { return 0; }\n"); ASSERT_EQUALS("", errout_str()); // assignment to variable can't be const @@ -3882,7 +3923,7 @@ class TestClass : public TestFixture { " std::string s;\n" " void foo();\n" "};\n" - "void Fred::foo() { s = \"\"; }"); + "void Fred::foo() { s = \"\"; }\n"); ASSERT_EQUALS("", errout_str()); // assignment to function argument reference can be const @@ -3890,7 +3931,7 @@ class TestClass : public TestFixture { " std::string s;\n" " void foo(std::string & a);\n" "};\n" - "void Fred::foo(std::string & a) { a = s; }"); + "void Fred::foo(std::string & a) { a = s; }\n"); ASSERT_EQUALS("[test.cpp:3:10] -> [test.cpp:5:12]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. [functionConst]\n", errout_str()); // assignment to variable can't be const @@ -3898,7 +3939,7 @@ class TestClass : public TestFixture { " std::string s;\n" " void foo(std::string & a);\n" "};\n" - "void Fred::foo(std::string & a) { s = a; }"); + "void Fred::foo(std::string & a) { s = a; }\n"); ASSERT_EQUALS("", errout_str()); // assignment to function argument references can be const @@ -3906,7 +3947,7 @@ class TestClass : public TestFixture { " std::string s;\n" " void foo(std::string & a, std::string & b);\n" "};\n" - "void Fred::foo(std::string & a, std::string & b) { a = s; b = s; }"); + "void Fred::foo(std::string & a, std::string & b) { a = s; b = s; }\n"); ASSERT_EQUALS("[test.cpp:3:10] -> [test.cpp:5:12]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. [functionConst]\n", errout_str()); // assignment to variable, can't be const @@ -3914,7 +3955,7 @@ class TestClass : public TestFixture { " std::string s;\n" " void foo(std::string & a, std::string & b);\n" "};\n" - "void Fred::foo(std::string & a, std::string & b) { s = a; s = b; }"); + "void Fred::foo(std::string & a, std::string & b) { s = a; s = b; }\n"); ASSERT_EQUALS("", errout_str()); // assignment to variable, can't be const @@ -3922,7 +3963,7 @@ class TestClass : public TestFixture { " std::string s;\n" " void foo(std::string & a, std::string & b);\n" "};\n" - "void Fred::foo(std::string & a, std::string & b) { s = a; b = a; }"); + "void Fred::foo(std::string & a, std::string & b) { s = a; b = a; }\n"); ASSERT_EQUALS("", errout_str()); // assignment to variable, can't be const @@ -3930,7 +3971,7 @@ class TestClass : public TestFixture { " std::string s;\n" " void foo(std::string & a, std::string & b);\n" "};\n" - "void Fred::foo(std::string & a, std::string & b) { a = s; s = b; }"); + "void Fred::foo(std::string & a, std::string & b) { a = s; s = b; }\n"); ASSERT_EQUALS("", errout_str()); // assignment to function argument pointer can be const @@ -3938,7 +3979,7 @@ class TestClass : public TestFixture { " int s;\n" " void foo(int * a);\n" "};\n" - "void Fred::foo(int * a) { *a = s; }"); + "void Fred::foo(int * a) { *a = s; }\n"); ASSERT_EQUALS("[test.cpp:3:10] -> [test.cpp:5:12]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. [functionConst]\n", errout_str()); // assignment to variable, can't be const @@ -3946,7 +3987,7 @@ class TestClass : public TestFixture { " int s;\n" " void foo(int * a);\n" "};\n" - "void Fred::foo(int * a) { s = *a; }"); + "void Fred::foo(int * a) { s = *a; }\n"); ASSERT_EQUALS("", errout_str()); // assignment to function argument pointers can be const @@ -3954,7 +3995,7 @@ class TestClass : public TestFixture { " std::string s;\n" " void foo(std::string * a, std::string * b);\n" "};\n" - "void Fred::foo(std::string * a, std::string * b) { *a = s; *b = s; }"); + "void Fred::foo(std::string * a, std::string * b) { *a = s; *b = s; }\n"); ASSERT_EQUALS("[test.cpp:3:10] -> [test.cpp:5:12]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. [functionConst]\n", errout_str()); // assignment to variable, can't be const @@ -3962,7 +4003,7 @@ class TestClass : public TestFixture { " std::string s;\n" " void foo(std::string * a, std::string * b);\n" "};\n" - "void Fred::foo(std::string * a, std::string * b) { s = *a; s = *b; }"); + "void Fred::foo(std::string * a, std::string * b) { s = *a; s = *b; }\n"); ASSERT_EQUALS("", errout_str()); // assignment to variable, can't be const @@ -3970,7 +4011,7 @@ class TestClass : public TestFixture { " std::string s;\n" " void foo(std::string * a, std::string * b);\n" "};\n" - "void Fred::foo(std::string * a, std::string * b) { s = *a; *b = s; }"); + "void Fred::foo(std::string * a, std::string * b) { s = *a; *b = s; }\n"); ASSERT_EQUALS("", errout_str()); // assignment to variable, can't be const @@ -3978,7 +4019,7 @@ class TestClass : public TestFixture { " std::string s;\n" " void foo(std::string * a, std::string * b);\n" "};\n" - "void Fred::foo(std::string * a, std::string * b) { *a = s; s = b; }"); + "void Fred::foo(std::string * a, std::string * b) { *a = s; s = b; }\n"); ASSERT_EQUALS("", errout_str()); // check functions with same name @@ -3988,11 +4029,11 @@ class TestClass : public TestFixture { " void foo(std::string & a);\n" " void foo(const std::string & a);\n" "};\n" - "void Fred::foo() { }" - "void Fred::foo(std::string & a) { a = s; }" - "void Fred::foo(const std::string & a) { s = a; }"); - ASSERT_EQUALS("[test.cpp:3:10] -> [test.cpp:7:12]: (performance, inconclusive) Technically the member function 'Fred::foo' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n" - "[test.cpp:4:10] -> [test.cpp:7:32]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. [functionConst]\n", errout_str()); + "void Fred::foo() { }\n" + "void Fred::foo(std::string & a) { a = s; }\n" + "void Fred::foo(const std::string & a) { s = a; }\n"); + ASSERT_EQUALS("[test.cpp:3:10] -> [test.cpp:7:12]: (style) The member function 'Fred::foo' can be static. [functionStatic]\n" + "[test.cpp:4:10] -> [test.cpp:8:12]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. [functionConst]\n", errout_str()); // check functions with different or missing parameter names checkConst("class Fred {\n" @@ -4007,12 +4048,12 @@ class TestClass : public TestFixture { "void Fred::foo2(int c, int d) { }\n" "void Fred::foo3(int a, int b) { }\n" "void Fred::foo4(int a, int b) { }\n" - "void Fred::foo5(int, int) { }"); - ASSERT_EQUALS("[test.cpp:3:10] -> [test.cpp:9:12]: (performance, inconclusive) Technically the member function 'Fred::foo1' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n" - "[test.cpp:4:10] -> [test.cpp:10:12]: (performance, inconclusive) Technically the member function 'Fred::foo2' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n" - "[test.cpp:5:10] -> [test.cpp:11:12]: (performance, inconclusive) Technically the member function 'Fred::foo3' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n" - "[test.cpp:6:10] -> [test.cpp:12:12]: (performance, inconclusive) Technically the member function 'Fred::foo4' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n" - "[test.cpp:7:10] -> [test.cpp:13:12]: (performance, inconclusive) Technically the member function 'Fred::foo5' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "void Fred::foo5(int, int) { }\n"); + ASSERT_EQUALS("[test.cpp:3:10] -> [test.cpp:9:12]: (style) The member function 'Fred::foo1' can be static. [functionStatic]\n" + "[test.cpp:4:10] -> [test.cpp:10:12]: (style) The member function 'Fred::foo2' can be static. [functionStatic]\n" + "[test.cpp:5:10] -> [test.cpp:11:12]: (style) The member function 'Fred::foo3' can be static. [functionStatic]\n" + "[test.cpp:6:10] -> [test.cpp:12:12]: (style) The member function 'Fred::foo4' can be static. [functionStatic]\n" + "[test.cpp:7:10] -> [test.cpp:13:12]: (style) The member function 'Fred::foo5' can be static. [functionStatic]\n", errout_str()); // check nested classes checkConst("class Fred {\n" @@ -4020,7 +4061,7 @@ class TestClass : public TestFixture { " int a;\n" " int getA() { return a; }\n" " };\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:13]: (style, inconclusive) Technically the member function 'Fred::A::getA' can be const. [functionConst]\n", errout_str()); checkConst("class Fred {\n" @@ -4029,7 +4070,7 @@ class TestClass : public TestFixture { " int getA();\n" " };\n" " int A::getA() { return a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:13] -> [test.cpp:6:12]: (style, inconclusive) Technically the member function 'Fred::A::getA' can be const. [functionConst]\n", errout_str()); checkConst("class Fred {\n" @@ -4038,7 +4079,7 @@ class TestClass : public TestFixture { " int getA();\n" " };\n" "};\n" - "int Fred::A::getA() { return a; }"); + "int Fred::A::getA() { return a; }\n"); ASSERT_EQUALS("[test.cpp:4:13] -> [test.cpp:7:14]: (style, inconclusive) Technically the member function 'Fred::A::getA' can be const. [functionConst]\n", errout_str()); // check deeply nested classes @@ -4051,7 +4092,7 @@ class TestClass : public TestFixture { " int getA() { return a; }\n" " };\n" " };\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:13]: (style, inconclusive) Technically the member function 'Fred::B::getB' can be const. [functionConst]\n" "[test.cpp:7:17]: (style, inconclusive) Technically the member function 'Fred::B::A::getA' can be const. [functionConst]\n" , errout_str()); @@ -4067,7 +4108,7 @@ class TestClass : public TestFixture { " int A::getA() { return a; }\n" " };\n" " int B::getB() { return b; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:13] -> [test.cpp:11:12]: (style, inconclusive) Technically the member function 'Fred::B::getB' can be const. [functionConst]\n" "[test.cpp:7:17] -> [test.cpp:9:16]: (style, inconclusive) Technically the member function 'Fred::B::A::getA' can be const. [functionConst]\n", errout_str()); @@ -4082,7 +4123,7 @@ class TestClass : public TestFixture { " };\n" " int B::A::getA() { return a; }\n" " int B::getB() { return b; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:13] -> [test.cpp:11:12]: (style, inconclusive) Technically the member function 'Fred::B::getB' can be const. [functionConst]\n" "[test.cpp:7:17] -> [test.cpp:10:15]: (style, inconclusive) Technically the member function 'Fred::B::A::getA' can be const. [functionConst]\n", errout_str()); @@ -4097,7 +4138,7 @@ class TestClass : public TestFixture { " };\n" "};\n" "int Fred::B::A::getA() { return a; }\n" - "int Fred::B::getB() { return b; }"); + "int Fred::B::getB() { return b; }\n"); ASSERT_EQUALS("[test.cpp:4:13] -> [test.cpp:12:14]: (style, inconclusive) Technically the member function 'Fred::B::getB' can be const. [functionConst]\n" "[test.cpp:7:17] -> [test.cpp:11:17]: (style, inconclusive) Technically the member function 'Fred::B::A::getA' can be const. [functionConst]\n", errout_str()); } @@ -4107,7 +4148,7 @@ class TestClass : public TestFixture { checkConst("struct Fred {\n" " int a;\n" " bool operator<(const Fred &f) { return a < f.a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:10]: (style, inconclusive) Technically the member function 'Fred::operator<' can be const. [functionConst]\n", errout_str()); } @@ -4122,7 +4163,7 @@ class TestClass : public TestFixture { " {\n" " foo << 123;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("struct Foo {\n" @@ -4134,7 +4175,7 @@ class TestClass : public TestFixture { " {\n" " std::cout << foo << 123;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:10]: (style, inconclusive) Technically the member function 'Fred::x' can be const. [functionConst]\n", errout_str()); } @@ -4143,13 +4184,13 @@ class TestClass : public TestFixture { " int array[10];\n" " int const & operator [] (unsigned int index) const { return array[index]; }\n" " int & operator [] (unsigned int index) { return array[index]; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("struct Fred {\n" " int array[10];\n" " int const & operator [] (unsigned int index) { return array[index]; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:17]: (style, inconclusive) Technically the member function 'Fred::operator[]' can be const. [functionConst]\n", errout_str()); } @@ -4159,14 +4200,14 @@ class TestClass : public TestFixture { " int c;\n" "public:\n" " operator int*() { return &c; };\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class A {\n" " int c;\n" "public:\n" " operator const int*() { return &c; };\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (style, inconclusive) Technically the member function 'A::operatorconstint*' can be const. [functionConst]\n", errout_str()); // #2375 @@ -4174,14 +4215,14 @@ class TestClass : public TestFixture { " int array[10];\n" " typedef int* (Fred::*UnspecifiedBoolType);\n" " operator UnspecifiedBoolType() { };\n" - "};"); + "};\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (style, inconclusive) Technically the member function 'Fred::operatorint**' can be const.\n", "", errout_str()); checkConst("struct Fred {\n" " int array[10];\n" " typedef int* (Fred::*UnspecifiedBoolType);\n" " operator UnspecifiedBoolType() { array[0] = 0; };\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4190,21 +4231,21 @@ class TestClass : public TestFixture { " int c;\n" "public:\n" " operator int& () {return c}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class A {\n" " int c;\n" "public:\n" " operator const int& () {return c}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (style, inconclusive) Technically the member function 'A::operatorconstint&' can be const. [functionConst]\n", errout_str()); checkConst("class A {\n" " int c;\n" "public:\n" " operator int () {return c}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (style, inconclusive) Technically the member function 'A::operatorint' can be const. [functionConst]\n", errout_str()); } @@ -4212,7 +4253,7 @@ class TestClass : public TestFixture { checkConst("class A {\n" " int c;\n" " void f() { os >> *this; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4226,7 +4267,7 @@ class TestClass : public TestFixture { " same = (i == a);\n" " return same;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:10]: (style, inconclusive) Technically the member function 'A::foo' can be const. [functionConst]\n", errout_str()); } @@ -4235,15 +4276,15 @@ class TestClass : public TestFixture { checkConst("class foo {\n" "public:\n" "};\n" - "void bar() {}"); + "void bar() {}\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred\n" "{\n" "public:\n" " void foo() { }\n" - "};"); - ASSERT_EQUALS("[test.cpp:4:10]: (performance, inconclusive) Technically the member function 'Fred::foo' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:4:10]: (style) The member function 'Fred::foo' can be static. [functionStatic]\n", errout_str()); checkConst("struct fast_string\n" "{\n" @@ -4256,7 +4297,7 @@ class TestClass : public TestFixture { "inline void fast_string::set_type(char t)\n" "{\n" " buff[10] = t;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -4267,7 +4308,7 @@ class TestClass : public TestFixture { " void set(int i) { a = i; }\n" " void set(const foo & f) { *this = f; }\n" "};\n" - "void bar() {}"); + "void bar() {}\n"); ASSERT_EQUALS("", errout_str()); } @@ -4279,7 +4320,7 @@ class TestClass : public TestFixture { " std::string strGetString() { return m_strValue; }\n" "private:\n" " std::string m_strValue;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:17]: (style, inconclusive) Technically the member function 'A::strGetString' can be const. [functionConst]\n", errout_str()); } @@ -4290,7 +4331,7 @@ class TestClass : public TestFixture { " void SetExitCode(wxThread::ExitCode exitcode) { m_exitcode = exitcode; }\n" "private:\n" " wxThread::ExitCode m_exitcode;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4301,7 +4342,7 @@ class TestClass : public TestFixture { " int foo() { return x = 0; }\n" "private:\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class A {\n" @@ -4309,7 +4350,7 @@ class TestClass : public TestFixture { " int foo() { return x ? x : x = 0; }\n" "private:\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class A {\n" @@ -4317,7 +4358,7 @@ class TestClass : public TestFixture { " int foo() { return x ? x = 0 : x; }\n" "private:\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4328,7 +4369,7 @@ class TestClass : public TestFixture { " void set(struct tm time) { m_time = time; }\n" "private:\n" " struct tm m_time;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4339,7 +4380,7 @@ class TestClass : public TestFixture { " int foo() { x = 0; }\n" "private:\n" " mutable int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:9]: (style, inconclusive) Technically the member function 'A::foo' can be const. [functionConst]\n", errout_str()); } @@ -4353,7 +4394,7 @@ class TestClass : public TestFixture { "private:\n" " std::vector m_vec;\n" " std::pair m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:22]: (style, inconclusive) Technically the member function 'A::GetVec' can be const. [functionConst]\n" "[test.cpp:5:27]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. [functionConst]\n", errout_str()); @@ -4365,7 +4406,7 @@ class TestClass : public TestFixture { "private:\n" " std::vector m_vec;\n" " std::pair m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:30]: (style, inconclusive) Technically the member function 'A::GetVec' can be const. [functionConst]\n" "[test.cpp:5:35]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. [functionConst]\n", errout_str()); } @@ -4378,7 +4419,7 @@ class TestClass : public TestFixture { " std::pair,double> GetPair() {return m_pair;}\n" "private:\n" " std::pair,double> m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:40]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. [functionConst]\n", errout_str()); checkConst("class A {\n" @@ -4387,7 +4428,7 @@ class TestClass : public TestFixture { " const std::pair,double>& GetPair() {return m_pair;}\n" "private:\n" " std::pair,double> m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:47]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. [functionConst]\n", errout_str()); checkConst("class A {\n" @@ -4396,7 +4437,7 @@ class TestClass : public TestFixture { " std::pair,double>& GetPair() {return m_pair;}\n" "private:\n" " std::pair,double> m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); @@ -4407,7 +4448,7 @@ class TestClass : public TestFixture { " pair GetPair() {return m_pair;}\n" "private:\n" " pair m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:23]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. [functionConst]\n", errout_str()); checkConst("using namespace std;" @@ -4417,7 +4458,7 @@ class TestClass : public TestFixture { " const pair & GetPair() {return m_pair;}\n" "private:\n" " pair m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:31]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. [functionConst]\n", errout_str()); checkConst("using namespace std;" @@ -4427,7 +4468,7 @@ class TestClass : public TestFixture { " pair & GetPair() {return m_pair;}\n" "private:\n" " pair m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); @@ -4437,7 +4478,7 @@ class TestClass : public TestFixture { " std::pair< int,std::vector > GetPair() {return m_pair;}\n" "private:\n" " std::pair< int,std::vector > m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:40]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. [functionConst]\n", errout_str()); checkConst("class A {\n" @@ -4446,7 +4487,7 @@ class TestClass : public TestFixture { " const std::pair< int,std::vector >& GetPair() {return m_pair;}\n" "private:\n" " std::pair< int,std::vector > m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:47]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. [functionConst]\n", errout_str()); checkConst("class A {\n" @@ -4455,7 +4496,7 @@ class TestClass : public TestFixture { " std::pair< int,std::vector >& GetPair() {return m_pair;}\n" "private:\n" " std::pair< int,std::vector > m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); @@ -4466,7 +4507,7 @@ class TestClass : public TestFixture { " pair< vector, int > GetPair() {return m_pair;}\n" "private:\n" " pair< vector, int > m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:31]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. [functionConst]\n", errout_str()); checkConst("using namespace std;" @@ -4476,7 +4517,7 @@ class TestClass : public TestFixture { " const pair< vector, int >& GetPair() {return m_pair;}\n" "private:\n" " pair< vector, int > m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:38]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. [functionConst]\n", errout_str()); checkConst("using namespace std;" @@ -4486,7 +4527,7 @@ class TestClass : public TestFixture { " pair< vector, int >& GetPair() {return m_pair;}\n" "private:\n" " pair< vector, int > m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class A {\n" @@ -4495,7 +4536,7 @@ class TestClass : public TestFixture { " std::pair< std::vector,std::vector > GetPair() {return m_pair;}\n" "private:\n" " std::pair< std::vector,std::vector > m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:53]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. [functionConst]\n", errout_str()); checkConst("class A {\n" @@ -4504,7 +4545,7 @@ class TestClass : public TestFixture { " const std::pair< std::vector,std::vector >& GetPair() {return m_pair;}\n" "private:\n" " std::pair< std::vector,std::vector > m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:60]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. [functionConst]\n", errout_str()); checkConst("class A {\n" @@ -4513,7 +4554,7 @@ class TestClass : public TestFixture { " std::pair< std::vector,std::vector >& GetPair() {return m_pair;}\n" "private:\n" " std::pair< std::vector,std::vector > m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); @@ -4524,7 +4565,7 @@ class TestClass : public TestFixture { " std::pair< std::pair < int, char > , int > GetPair() {return m_pair;}\n" "private:\n" " std::pair< std::pair < int, char > , int > m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:49]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. [functionConst]\n", errout_str()); checkConst("class A {\n" @@ -4533,7 +4574,7 @@ class TestClass : public TestFixture { " const std::pair< std::pair < int, char > , int > & GetPair() {return m_pair;}\n" "private:\n" " std::pair< std::pair < int, char > , int > m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:56]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. [functionConst]\n", errout_str()); checkConst("class A {\n" @@ -4542,7 +4583,7 @@ class TestClass : public TestFixture { " std::pair< std::pair < int, char > , int > & GetPair() {return m_pair;}\n" "private:\n" " std::pair< std::pair < int, char > , int > m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); @@ -4552,7 +4593,7 @@ class TestClass : public TestFixture { " std::pair< int , std::pair < int, char > > GetPair() {return m_pair;}\n" "private:\n" " std::pair< int , std::pair < int, char > > m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:49]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. [functionConst]\n", errout_str()); checkConst("class A {\n" @@ -4561,7 +4602,7 @@ class TestClass : public TestFixture { " const std::pair< int , std::pair < int, char > >& GetPair() {return m_pair;}\n" "private:\n" " std::pair< int , std::pair < int, char > > m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:56]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. [functionConst]\n", errout_str()); checkConst("class A {\n" @@ -4570,7 +4611,7 @@ class TestClass : public TestFixture { " std::pair< int , std::pair < int, char > >& GetPair() {return m_pair;}\n" "private:\n" " std::pair< int , std::pair < int, char > > m_pair;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); @@ -4581,7 +4622,7 @@ class TestClass : public TestFixture { " vector GetVec() {return m_Vec;}\n" "private:\n" " vector m_Vec;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:18]: (style, inconclusive) Technically the member function 'A::GetVec' can be const. [functionConst]\n", errout_str()); checkConst("using namespace std;" @@ -4591,7 +4632,7 @@ class TestClass : public TestFixture { " const vector& GetVec() {return m_Vec;}\n" "private:\n" " vector m_Vec;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:25]: (style, inconclusive) Technically the member function 'A::GetVec' can be const. [functionConst]\n", errout_str()); checkConst("using namespace std;" @@ -4601,7 +4642,7 @@ class TestClass : public TestFixture { " vector& GetVec() {return m_Vec;}\n" "private:\n" " vector m_Vec;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); @@ -4610,7 +4651,7 @@ class TestClass : public TestFixture { " int * * foo() { return &x; }\n" "private:\n" " const int * x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class A {\n" @@ -4618,7 +4659,7 @@ class TestClass : public TestFixture { " const int ** foo() { return &x; }\n" "private:\n" " const int * x;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:18]: (style, inconclusive) Technically the member function 'A::foo' can be const. [functionConst]\n", errout_str()); } @@ -4626,7 +4667,7 @@ class TestClass : public TestFixture { checkConst("class Fred {\n" " unsigned long long int a;\n" " unsigned long long int getA() { return a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:28]: (style, inconclusive) Technically the member function 'Fred::getA' can be const. [functionConst]\n", errout_str()); // constructors can't be const.. @@ -4634,14 +4675,14 @@ class TestClass : public TestFixture { " unsigned long long int a;\n" "public:\n" " Fred() { }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // assignment through |=.. checkConst("class Fred {\n" " unsigned long long int a;\n" " unsigned long long int setA() { a |= true; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // static functions can't be const.. @@ -4650,7 +4691,7 @@ class TestClass : public TestFixture { "public:\n" " static unsigned long long int get()\n" " { return 0; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4659,7 +4700,7 @@ class TestClass : public TestFixture { checkConst("class Fred {\n" " int a;\n" " void set(int i) { Fred::a = i; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4670,7 +4711,7 @@ class TestClass : public TestFixture { " void set(int i, int j) { a[i].k = i; }\n" "private:\n" " struct { int k; } a[4];\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4679,8 +4720,8 @@ class TestClass : public TestFixture { "static int x;\n" "public:\n" " void set(int i) { x = i; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:4:10]: (performance, inconclusive) Technically the member function 'Fred::set' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:4:10]: (style) The member function 'Fred::set' can be static. [functionStatic]\n", errout_str()); } void const19() { @@ -4691,7 +4732,7 @@ class TestClass : public TestFixture { " std::string s;\n" "public:\n" " void set(std::string ss) { s = ss; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4701,35 +4742,35 @@ class TestClass : public TestFixture { " int x : 3;\n" "public:\n" " void set(int i) { x = i; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " list x;\n" "public:\n" " list get() { return x; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " list x;\n" "public:\n" " list get() { return x; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:23]: (style, inconclusive) Technically the member function 'Fred::get' can be const. [functionConst]\n", errout_str()); checkConst("class Fred {\n" " std::list x;\n" "public:\n" " std::list get() { return x; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " std::list x;\n" "public:\n" " std::list get() { return x; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:36]: (style, inconclusive) Technically the member function 'Fred::get' can be const. [functionConst]\n", errout_str()); } @@ -4745,7 +4786,7 @@ class TestClass : public TestFixture { " for (int i = 0 ; i < 10; l1[i] = NULL, i++);\n" " }\n" " void f1() { l1[0] = \"Hello\"; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4756,7 +4797,7 @@ class TestClass : public TestFixture { " B::C * v1;\n" "public:\n" " void f1() { v1 = 0; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class A\n" @@ -4765,7 +4806,7 @@ class TestClass : public TestFixture { " B::C * v1[0];\n" "public:\n" " void f1() { v1[0] = 0; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4777,7 +4818,7 @@ class TestClass : public TestFixture { " void set_member(Type2 m) { _m = m; }\n" "private:\n" " Type2 _m;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4790,7 +4831,7 @@ class TestClass : public TestFixture { "}\n" "private:\n" " std::map *m_pSettings;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4805,7 +4846,7 @@ class TestClass : public TestFixture { "{return m_strVal.c_str();}\n" "private:\n" "std::string m_strVal;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class A{\n" @@ -4815,7 +4856,7 @@ class TestClass : public TestFixture { "{return m_strVal.c_str();}\n" "private:\n" "std::string m_strVal;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:13]: (style, inconclusive) Technically the member function 'A::strGetString' can be const. [functionConst]\n", errout_str()); checkConst("class A{\n" @@ -4825,7 +4866,7 @@ class TestClass : public TestFixture { "{return m_strVal.c_str();}\n" "private:\n" "std::string m_strVal;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:19]: (style, inconclusive) Technically the member function 'A::strGetString1' can be const. [functionConst]\n", errout_str()); checkConst("class A{\n" @@ -4835,7 +4876,7 @@ class TestClass : public TestFixture { "{return m_strVec.size();}\n" "private:\n" "std::vector m_strVec;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:8]: (style, inconclusive) Technically the member function 'A::strGetSize' can be const. [functionConst]\n", errout_str()); checkConst("class A{\n" @@ -4845,7 +4886,7 @@ class TestClass : public TestFixture { "{return m_strVec.empty();}\n" "private:\n" "std::vector m_strVec;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:6]: (style, inconclusive) Technically the member function 'A::strGetEmpty' can be const. [functionConst]\n", errout_str()); } @@ -4856,7 +4897,7 @@ class TestClass : public TestFixture { " std::swap(delays_[index1], delays_[index2]);\n" "}\n" "float delays_[4];\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("struct DelayBase {\n" @@ -4864,7 +4905,7 @@ class TestClass : public TestFixture { " return delays_[index1];\n" " }\n" " float delays_[4];\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style, inconclusive) Technically the member function 'DelayBase::swapSpecificDelays' can be const. [functionConst]\n", errout_str()); } @@ -4882,7 +4923,7 @@ class TestClass : public TestFixture { " if( m_d != 0 )\n" " return m_iRealVal / m_d;\n" " return dRet;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:12] -> [test.cpp:9:12]: (style, inconclusive) Technically the member function 'A::dGetValue' can be const. [functionConst]\n", errout_str()); } @@ -4899,7 +4940,7 @@ class TestClass : public TestFixture { " x=xPos;\n" " y=yPos;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class AA : public P {\n" @@ -4909,7 +4950,7 @@ class TestClass : public TestFixture { " {\n" " UnknownScope::x = x_;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class AA {\n" @@ -4919,8 +4960,8 @@ class TestClass : public TestFixture { " {\n" " UnknownScope::x = x_;\n" " }\n" - "};"); - ASSERT_EQUALS("[test.cpp:4:17]: (performance, inconclusive) Technically the member function 'AA::vSetXPos' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:4:17]: (style) The member function 'AA::vSetXPos' can be static. [functionStatic]\n", errout_str()); } @@ -4944,7 +4985,7 @@ class TestClass : public TestFixture { "char* test::get()\n" "{\n" " return value_;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -4959,7 +5000,7 @@ class TestClass : public TestFixture { " int get() {\n" " return a;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:7:9]: (style, inconclusive) Technically the member function 'Derived::get' can be const. [functionConst]\n", errout_str()); checkConst("class Base1 {\n" @@ -4978,7 +5019,7 @@ class TestClass : public TestFixture { " int getB() {\n" " return b;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:11:9]: (style, inconclusive) Technically the member function 'Derived::getA' can be const. [functionConst]\n" "[test.cpp:14:9]: (style, inconclusive) Technically the member function 'Derived::getB' can be const. [functionConst]\n", errout_str()); @@ -4992,7 +5033,7 @@ class TestClass : public TestFixture { " int get() {\n" " return a;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:8:9]: (style, inconclusive) Technically the member function 'Derived2::get' can be const. [functionConst]\n", errout_str()); checkConst("class Base {\n" @@ -5007,7 +5048,7 @@ class TestClass : public TestFixture { " int get() {\n" " return a;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:10:9]: (style, inconclusive) Technically the member function 'Derived4::get' can be const. [functionConst]\n", errout_str()); // check for false positives @@ -5020,7 +5061,7 @@ class TestClass : public TestFixture { " int get() const {\n" " return a;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Base1 {\n" @@ -5039,7 +5080,7 @@ class TestClass : public TestFixture { " int getB() const {\n" " return b;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Base {\n" @@ -5052,7 +5093,7 @@ class TestClass : public TestFixture { " int get() const {\n" " return a;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Base {\n" @@ -5067,7 +5108,7 @@ class TestClass : public TestFixture { " int get() const {\n" " return a;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -5077,7 +5118,7 @@ class TestClass : public TestFixture { "public:\n" " int a;\n" " int get() { return a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:5:9]: (style, inconclusive) Technically the member function 'Fred::get' can be const. [functionConst]\n", errout_str()); } @@ -5086,7 +5127,7 @@ class TestClass : public TestFixture { "public:\n" " std::string a[10];\n" " void seta() { a[0] = \"\"; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -5094,8 +5135,8 @@ class TestClass : public TestFixture { checkConst("class derived : public base {\n" "public:\n" " void f(){}\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Either there is a missing 'override', or the member function 'derived::f' can be static. [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) Either there is a missing 'override', or the member function 'derived::f' can be static. [functionStatic]\n", errout_str()); } void const34() { // ticket #1964 @@ -5103,7 +5144,7 @@ class TestClass : public TestFixture { " void init(Foo * foo) {\n" " foo.bar = this;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -5122,7 +5163,7 @@ class TestClass : public TestFixture { " int getResourceName() { return var; }\n" " int var;\n" " };\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:12:21]: (style, inconclusive) Technically the member function 'N::Derived::getResourceName' can be const. [functionConst]\n", errout_str()); checkConst("namespace N\n" @@ -5134,7 +5175,7 @@ class TestClass : public TestFixture { " int var;\n" " };\n" "}\n" - "int N::Base::getResourceName() { return var; }"); + "int N::Base::getResourceName() { return var; }\n"); ASSERT_EQUALS("[test.cpp:6:21] -> [test.cpp:10:14]: (style, inconclusive) Technically the member function 'N::Base::getResourceName' can be const. [functionConst]\n", errout_str()); checkConst("namespace N\n" @@ -5149,7 +5190,7 @@ class TestClass : public TestFixture { "namespace N\n" "{\n" " int Base::getResourceName() { return var; }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:21] -> [test.cpp:12:19]: (style, inconclusive) Technically the member function 'N::Base::getResourceName' can be const. [functionConst]\n", errout_str()); checkConst("namespace N\n" @@ -5162,7 +5203,7 @@ class TestClass : public TestFixture { " };\n" "}\n" "using namespace N;\n" - "int Base::getResourceName() { return var; }"); + "int Base::getResourceName() { return var; }\n"); ASSERT_EQUALS("[test.cpp:6:21] -> [test.cpp:11:11]: (style, inconclusive) Technically the member function 'N::Base::getResourceName' can be const. [functionConst]\n", errout_str()); } @@ -5174,7 +5215,7 @@ class TestClass : public TestFixture { " {\n" " m_MaxQueueSize = a_MaxQueueSize;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -5189,7 +5230,7 @@ class TestClass : public TestFixture { " }\n" "private:\n" " std::string m_str;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:5:17]: (style, inconclusive) Technically the member function 'A::operator+' can be const. [functionConst]\n", errout_str()); checkConst("class Fred\n" @@ -5203,7 +5244,7 @@ class TestClass : public TestFixture { " bool isValid() {\n" " return (x == 0x11224488);\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:9:10]: (style, inconclusive) Technically the member function 'Fred::isValid' can be const. [functionConst]\n", errout_str()); } @@ -5219,7 +5260,7 @@ class TestClass : public TestFixture { "void Foo::MyMethod()\n" "{\n" " (*oArq) << \"\";\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -5239,7 +5280,7 @@ class TestClass : public TestFixture { "int * Foo::f()\n" "{\n" " return p;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -5256,7 +5297,7 @@ class TestClass : public TestFixture { " {\n" " pView = aView;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -5270,7 +5311,7 @@ class TestClass : public TestFixture { " {\n" " m_name = name;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); @@ -5282,7 +5323,7 @@ class TestClass : public TestFixture { " {\n" " pNum = apNum;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); @@ -5297,7 +5338,7 @@ class TestClass : public TestFixture { " {\n" " pNum = apNum;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); @@ -5314,7 +5355,7 @@ class TestClass : public TestFixture { " {\n" " pNum = apNum;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); @@ -5332,7 +5373,7 @@ class TestClass : public TestFixture { " {\n" " pNum = apNum;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -5346,9 +5387,9 @@ class TestClass : public TestFixture { "};\n" "bool Fred::f(Fred::AB * ab)\n" "{\n" - "}"); + "}\n"); - ASSERT_EQUALS("[test.cpp:5:10] -> [test.cpp:7:12]: (performance, inconclusive) Technically the member function 'Fred::f' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:5:10] -> [test.cpp:7:12]: (style) The member function 'Fred::f' can be static. [functionStatic]\n", errout_str()); checkConst("class Fred\n" "{\n" @@ -5360,9 +5401,9 @@ class TestClass : public TestFixture { "};\n" "bool Fred::f(Fred::AB::CD * cd)\n" "{\n" - "}"); + "}\n"); - ASSERT_EQUALS("[test.cpp:7:10] -> [test.cpp:9:12]: (performance, inconclusive) Technically the member function 'Fred::f' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:7:10] -> [test.cpp:9:12]: (style) The member function 'Fred::f' can be static. [functionStatic]\n", errout_str()); checkConst("namespace NS {\n" " class Fred\n" @@ -5376,9 +5417,9 @@ class TestClass : public TestFixture { " bool Fred::f(Fred::AB::CD * cd)\n" " {\n" " }\n" - "}"); + "}\n"); - ASSERT_EQUALS("[test.cpp:8:14] -> [test.cpp:10:16]: (performance, inconclusive) Technically the member function 'NS::Fred::f' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:8:14] -> [test.cpp:10:16]: (style) The member function 'NS::Fred::f' can be static. [functionStatic]\n", errout_str()); checkConst("namespace NS {\n" " class Fred\n" @@ -5392,9 +5433,9 @@ class TestClass : public TestFixture { "}\n" "bool NS::Fred::f(NS::Fred::AB::CD * cd)\n" "{\n" - "}"); + "}\n"); - ASSERT_EQUALS("[test.cpp:8:14] -> [test.cpp:11:16]: (performance, inconclusive) Technically the member function 'NS::Fred::f' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:8:14] -> [test.cpp:11:16]: (style) The member function 'NS::Fred::f' can be static. [functionStatic]\n", errout_str()); checkConst("class Foo {\n" " class Fred\n" @@ -5408,9 +5449,9 @@ class TestClass : public TestFixture { "};\n" "bool Foo::Fred::f(Foo::Fred::AB::CD * cd)\n" "{\n" - "}"); + "}\n"); - ASSERT_EQUALS("[test.cpp:8:14] -> [test.cpp:11:17]: (performance, inconclusive) Technically the member function 'Foo::Fred::f' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:8:14] -> [test.cpp:11:17]: (style) The member function 'Foo::Fred::f' can be static. [functionStatic]\n", errout_str()); } void const43() { // ticket 2377 @@ -5423,7 +5464,7 @@ class TestClass : public TestFixture { "void A::foo( AA::BB::CC::DD b )\n" "{\n" " a = b;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); @@ -5447,7 +5488,7 @@ class TestClass : public TestFixture { " {\n" " a = b;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); @@ -5467,7 +5508,7 @@ class TestClass : public TestFixture { " {\n" " a = b;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -5480,7 +5521,7 @@ class TestClass : public TestFixture { " {\n" " return 0 != (bOn = bOn);\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -5497,9 +5538,9 @@ class TestClass : public TestFixture { " {\n" " }\n" " };\n" - "}"); + "}\n"); - ASSERT_EQUALS("[test.cpp:8:13]: (performance, inconclusive) Technically the member function 'tools::WorkspaceControl::toGrid' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:8:13]: (style) The member function 'tools::WorkspaceControl::toGrid' can be static. [functionStatic]\n", errout_str()); } void const46() { // ticket 2663 @@ -5512,10 +5553,10 @@ class TestClass : public TestFixture { " int fun2() {\n" " b++;\n" " }\n" - "};"); + "};\n"); - ASSERT_EQUALS("[test.cpp:3:9]: (performance, inconclusive) Technically the member function 'Altren::fun1' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n" - "[test.cpp:7:9]: (performance, inconclusive) Technically the member function 'Altren::fun2' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:3:9]: (style) The member function 'Altren::fun1' can be static. [functionStatic]\n" + "[test.cpp:7:9]: (style) The member function 'Altren::fun2' can be static. [functionStatic]\n", errout_str()); } void const47() { // ticket 2670 @@ -5524,18 +5565,18 @@ class TestClass : public TestFixture { " void foo() { delete this; }\n" " void foo(int i) const { }\n" " void bar() { foo(); }\n" - "};"); + "};\n"); - ASSERT_EQUALS("[test.cpp:4:8]: (performance, inconclusive) Technically the member function 'Altren::foo' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:4:8]: (style) The member function 'Altren::foo' can be static. [functionStatic]\n", errout_str()); checkConst("class Altren {\n" "public:\n" " void foo() { delete this; }\n" " void foo(int i) const { }\n" " void bar() { foo(1); }\n" - "};"); + "};\n"); - ASSERT_EQUALS("[test.cpp:4:8]: (performance, inconclusive) Technically the member function 'Altren::foo' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n" + ASSERT_EQUALS("[test.cpp:4:8]: (style) The member function 'Altren::foo' can be static. [functionStatic]\n" "[test.cpp:5:8]: (style, inconclusive) Technically the member function 'Altren::bar' can be const. [functionConst]\n", errout_str()); } @@ -5556,7 +5597,7 @@ class TestClass : public TestFixture { "};\n" "bool TextIterator::setTagColour() {\n" " mSave = mCurrent;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -5571,7 +5612,7 @@ class TestClass : public TestFixture { " {\n" " return _hash[key];\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -5586,7 +5627,7 @@ class TestClass : public TestFixture { "{\n" " if (mTileSize.height > 0) return;\n" " if (mEmptyView) return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -5600,7 +5641,7 @@ class TestClass : public TestFixture { " void SetSection(uint num) { pesdata()[6] = num; }\n" "private:\n" " unsigned char *_pesdata;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class PESPacket {\n" @@ -5615,7 +5656,7 @@ class TestClass : public TestFixture { "{\n" "public:\n" " void SetSection(uint num) { pesdata()[6] = num; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -5625,8 +5666,8 @@ class TestClass : public TestFixture { " void DoSomethingElse() { DoSomething(bar); }\n" "private:\n" " int bar;\n" - "};"); - ASSERT_EQUALS("[test.cpp:2:10]: (performance, inconclusive) Technically the member function 'foo::DoSomething' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:2:10]: (style) The member function 'foo::DoSomething' can be static. [functionStatic]\n", errout_str()); } void const53() { // ticket 3049 @@ -5641,7 +5682,7 @@ class TestClass : public TestFixture { " public:\n" " B() {};\n" " bool One(bool b = false) { return false; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -5649,7 +5690,7 @@ class TestClass : public TestFixture { checkConst("class Example {\n" " public:\n" " void Clear(void) { Example tmp; (*this) = tmp; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -5659,7 +5700,7 @@ class TestClass : public TestFixture { " MyObject() : tmp(0) {}\n" "public:\n" " void set(std::stringstream &in) { in >> tmp; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -5669,8 +5710,8 @@ class TestClass : public TestFixture { " void foo(int x) {\n" " switch (x) { }\n" " }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'MyObject::foo' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'MyObject::foo' can be static. [functionStatic]\n", errout_str()); checkConst("class A\n" "{\n" @@ -5709,16 +5750,16 @@ class TestClass : public TestFixture { " }\n" "\n" " return RET_NOK;\n" - "}"); - ASSERT_EQUALS("[test.cpp:4:24] -> [test.cpp:9:19]: (performance, inconclusive) Technically the member function 'A::f' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "}\n"); + ASSERT_EQUALS("[test.cpp:4:24] -> [test.cpp:9:19]: (style) The member function 'A::f' can be static. [functionStatic]\n", errout_str()); checkConst("class MyObject {\n" "public:\n" " void foo(int x) {\n" " for (int i = 0; i < 5; i++) { }\n" " }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'MyObject::foo' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'MyObject::foo' can be static. [functionStatic]\n", errout_str()); } void const57() { // tickets #2669 and #2477 @@ -5742,17 +5783,17 @@ class TestClass : public TestFixture { " }\n" "private:\n" " MyGUI::IntCoord mCoordValue;\n" - "};"); - TODO_ASSERT_EQUALS("[test.cpp:7:13]: (performance, inconclusive) Technically the member function 'MyGUI::types::TCoord::size' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n" + "};\n"); + TODO_ASSERT_EQUALS("[test.cpp:7:13]: (style) The member function 'MyGUI::types::TCoord::size' can be static. [functionStatic]\n" "[test.cpp:15]: (style, inconclusive) Technically the member function 'SelectorControl::getSize' can be const.\n", - "[test.cpp:7:13]: (performance, inconclusive) Technically the member function 'MyGUI::types::TCoord::size' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "[test.cpp:7:13]: (style) The member function 'MyGUI::types::TCoord::size' can be static. [functionStatic]\n", errout_str()); checkConst("struct Foo {\n" " Bar b;\n" " void foo(Foo f) {\n" " b.run();\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("struct Bar {\n" @@ -5764,7 +5805,7 @@ class TestClass : public TestFixture { " void foo(Foo f) {\n" " b.run();\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("struct Bar {\n" @@ -5775,8 +5816,8 @@ class TestClass : public TestFixture { " void foo(Foo f) {\n" " b.run();\n" " }\n" - "};"); - ASSERT_EQUALS("[test.cpp:2:10]: (performance, inconclusive) Technically the member function 'Bar::run' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:10]: (style) The member function 'Bar::run' can be static. [functionStatic]\n" "[test.cpp:6:10]: (style, inconclusive) Technically the member function 'Foo::foo' can be const. [functionConst]\n", errout_str()); } @@ -5785,22 +5826,22 @@ class TestClass : public TestFixture { " void foo(Foo f) {\n" " f.clear();\n" " }\n" - "};"); - ASSERT_EQUALS("[test.cpp:2:10]: (performance, inconclusive) Technically the member function 'MyObject::foo' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:2:10]: (style) The member function 'MyObject::foo' can be static. [functionStatic]\n", errout_str()); checkConst("struct MyObject {\n" " int foo(Foo f) {\n" " return f.length();\n" " }\n" - "};"); - ASSERT_EQUALS("[test.cpp:2:9]: (performance, inconclusive) Technically the member function 'MyObject::foo' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:2:9]: (style) The member function 'MyObject::foo' can be static. [functionStatic]\n", errout_str()); checkConst("struct MyObject {\n" " Foo f;\n" " int foo() {\n" " return f.length();\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("struct MyObject {\n" @@ -5808,7 +5849,7 @@ class TestClass : public TestFixture { " int foo() {\n" " return f.length();\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:9]: (style, inconclusive) Technically the member function 'MyObject::foo' can be const. [functionConst]\n", errout_str()); } @@ -5820,7 +5861,7 @@ class TestClass : public TestFixture { "protected:\n" " int re;\n" " int im;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -5835,7 +5876,7 @@ class TestClass : public TestFixture { " MyString append( const MyString& str )\n" " { return operator+=( str ); }\n" " char *m_ptr;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class MyString {\n" "public:\n" @@ -5844,7 +5885,7 @@ class TestClass : public TestFixture { " MyString append( const MyString& str )\n" " { return operator+=( str ); }\n" " char *m_ptr;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -5855,14 +5896,14 @@ class TestClass : public TestFixture { "};\n" "int MixerParticipant::GetAudioFrame() {\n" " return 0;\n" - "}"); + "}\n"); // this code is invalid so a false negative is OK checkConst("class MixerParticipant : public MixerParticipant {\n" " bool InitializeFileReader() {\n" " printf(\"music\");\n" " }\n" - "};"); + "};\n"); // Based on an example from SVN source code causing an endless recursion within CheckClass::isConstMemberFunc() // A more complete example including a template declaration like @@ -5881,7 +5922,7 @@ class TestClass : public TestFixture { " inherited::set(inherited::Key(key));\n" " }\n" "};\n", dinit(CheckConstOptions, $.inconclusive = false)); - ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:4:23]: (performance, inconclusive) Either there is a missing 'override', or the member function 'MixerParticipant::GetAudioFrame' can be static. [functionStatic]\n", + ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:4:23]: (style) Either there is a missing 'override', or the member function 'MixerParticipant::GetAudioFrame' can be static. [functionStatic]\n", errout_str()); } @@ -5895,7 +5936,7 @@ class TestClass : public TestFixture { " {\n" " return _hash[key];\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -5906,7 +5947,7 @@ class TestClass : public TestFixture { " std::string* p = &s;\n" " p->clear();\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("struct A {\n" @@ -5915,7 +5956,7 @@ class TestClass : public TestFixture { " std::string& r = s;\n" " r.clear();\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("struct A {\n" @@ -5924,7 +5965,7 @@ class TestClass : public TestFixture { " std::string& r = sth; r = s;\n" " r.clear();\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:10]: (style, inconclusive) Technically the member function 'A::clear' can be const. [functionConst]\n", errout_str()); checkConst("struct A {\n" @@ -5933,7 +5974,7 @@ class TestClass : public TestFixture { " const std::string* p = &s;\n" " p->somefunction();\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:10]: (style, inconclusive) Technically the member function 'A::clear' can be const. [functionConst]\n", errout_str()); checkConst("struct A {\n" @@ -5942,7 +5983,7 @@ class TestClass : public TestFixture { " const std::string& r = s;\n" " r.somefunction();\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:10]: (style, inconclusive) Technically the member function 'A::clear' can be const. [functionConst]\n", errout_str()); } @@ -5957,7 +5998,7 @@ class TestClass : public TestFixture { " }\n" " ::B::D::DKIPtr membervariable;\n" " };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -5976,7 +6017,7 @@ class TestClass : public TestFixture { " TemplateClass a;\n" " TemplateClass b;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -5986,7 +6027,7 @@ class TestClass : public TestFixture { " void f(int v) { g((char *) &v); }\n" " void g(char *) { n++; }\n" " int n;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -6000,7 +6041,7 @@ class TestClass : public TestFixture { "public:\n" " const std::list>& get() { return m_test.m_list; }\n" " TestList> m_test;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:8:44]: (style, inconclusive) Technically the member function 'Test::get' can be const. [functionConst]\n", errout_str()); } @@ -6030,7 +6071,7 @@ class TestClass : public TestFixture { " call();\n" " call(1, 2, 3);\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -6043,7 +6084,7 @@ class TestClass : public TestFixture { " void test() {\n" " call(1, 2);\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -6178,7 +6219,7 @@ class TestClass : public TestFixture { " void bar(void) {\n" " for(std::vector::const_iterator it = m_str.begin(); it != m_str.end(); ++it) {;}\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:5:10]: (style, inconclusive) Technically the member function 'A::bar' can be const. [functionConst]\n", errout_str()); // Don't crash @@ -6200,7 +6241,7 @@ class TestClass : public TestFixture { " if (N::i) {}\n" " }\n" "};\n"); - ASSERT_EQUALS("[test.cpp:4:10]: (performance, inconclusive) Technically the member function 'S::f' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:4:10]: (style) The member function 'S::f' can be static. [functionStatic]\n", errout_str()); checkConst("int i = 0;\n" "struct S {\n" @@ -6209,7 +6250,7 @@ class TestClass : public TestFixture { " if (::i) {}\n" " }\n" "};\n"); - ASSERT_EQUALS("[test.cpp:4:10]: (performance, inconclusive) Technically the member function 'S::f' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:4:10]: (style) The member function 'S::f' can be static. [functionStatic]\n", errout_str()); checkConst("namespace N {\n" " struct S {\n" @@ -6232,7 +6273,7 @@ class TestClass : public TestFixture { "void S::f(const T* t) {\n" " const_cast(t)->e();\n" "};\n"); - ASSERT_EQUALS("[test.cpp:3:10] -> [test.cpp:7:9]: (performance, inconclusive) Technically the member function 'S::f' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", + ASSERT_EQUALS("[test.cpp:3:10] -> [test.cpp:7:9]: (style) The member function 'S::f' can be static. [functionStatic]\n", errout_str()); } @@ -6278,7 +6319,7 @@ class TestClass : public TestFixture { " return nullptr;\n" " }\n" "};\n"); - ASSERT_EQUALS("[test.cpp:3:11]: (performance, inconclusive) Technically the member function 'A::f' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", + ASSERT_EQUALS("[test.cpp:3:11]: (style) The member function 'A::f' can be static. [functionStatic]\n", errout_str()); } @@ -6309,10 +6350,10 @@ class TestClass : public TestFixture { "void S::n() {\n" " this->h();\n" "}\n"); - ASSERT_EQUALS("[test.cpp:4:10] -> [test.cpp:11:9]: (performance, inconclusive) Technically the member function 'S::g' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n" - "[test.cpp:5:10] -> [test.cpp:14:9]: (performance, inconclusive) Technically the member function 'S::h' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n" + ASSERT_EQUALS("[test.cpp:4:10] -> [test.cpp:11:9]: (style) The member function 'S::g' can be static. [functionStatic]\n" + "[test.cpp:5:10] -> [test.cpp:14:9]: (style) The member function 'S::h' can be static. [functionStatic]\n" "[test.cpp:6:10] -> [test.cpp:17:9]: (style, inconclusive) Technically the member function 'S::k' can be const. [functionConst]\n" - "[test.cpp:7:10] -> [test.cpp:21:9]: (performance, inconclusive) Technically the member function 'S::m' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", + "[test.cpp:7:10] -> [test.cpp:21:9]: (style) The member function 'S::m' can be static. [functionStatic]\n", errout_str()); } @@ -6672,7 +6713,7 @@ class TestClass : public TestFixture { " }\n" "};\n"); ASSERT_EQUALS("[test.cpp:3:9]: (style, inconclusive) Technically the member function 'S::f' can be const. [functionConst]\n" - "[test.cpp:8:9]: (performance, inconclusive) Technically the member function 'S::g' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", + "[test.cpp:8:9]: (style) The member function 'S::g' can be static. [functionStatic]\n", errout_str()); checkConst("class C {\n" // #11653 @@ -6683,7 +6724,7 @@ class TestClass : public TestFixture { " if (b)\n" " f(false);\n" "}\n"); - ASSERT_EQUALS("[test.cpp:3:10] -> [test.cpp:5:9]: (performance, inconclusive) Technically the member function 'C::f' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", + ASSERT_EQUALS("[test.cpp:3:10] -> [test.cpp:5:9]: (style) The member function 'C::f' can be static. [functionStatic]\n", errout_str()); } @@ -6729,6 +6770,7 @@ class TestClass : public TestFixture { "struct S<0> {};\n" "struct D : S<150> {};\n"); // don't hang + ignore_errout(); } void const93() { // #12162 @@ -6783,6 +6825,52 @@ class TestClass : public TestFixture { " B::g(0);\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + checkConst("struct S {\n" // #14366 + " void f();\n" + "};\n" + "struct T : U {\n" + " void g(S* s) {\n" + " s->f();\n" + " }\n" + " void h() {\n" + " S s;\n" + " s.f();\n" + " }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:5:10]: (style) Either there is a missing 'override', or the member function 'T::g' can be static. [functionStatic]\n" + "[test.cpp:8:10]: (style) Either there is a missing 'override', or the member function 'T::h' can be static. [functionStatic]\n", + errout_str()); + + checkConst("enum E { E0 };\n" + "int f();\n" + "struct S : U {\n" + " E g() {\n" + " return E0;\n" + " }\n" + " int h() {\n" + " return f();\n" + " }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:4:7]: (style) Either there is a missing 'override', or the member function 'S::g' can be static. [functionStatic]\n" + "[test.cpp:7:9]: (style) Either there is a missing 'override', or the member function 'S::h' can be static. [functionStatic]\n", + errout_str()); + + checkConst("namespace N {\n" // #14391 + " void f();\n" + "}\n" + "struct S : U {\n" + " void g() { N::f(); }\n" + " void h() { ::N::f(); }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:5:10]: (style) Either there is a missing 'override', or the member function 'S::g' can be static. [functionStatic]\n" + "[test.cpp:6:10]: (style) Either there is a missing 'override', or the member function 'S::h' can be static. [functionStatic]\n", + errout_str()); + + checkConst("struct S : U {\n" // #14425 + " void f() { this->g(); }\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); } void const97() { // #13301 @@ -6916,6 +7004,47 @@ class TestClass : public TestFixture { ASSERT_EQUALS("", errout_str()); // don't crash } + void const101() { + checkConst("struct error {\n" // #14450 + " error() = default;\n" + "};\n" + "struct S : U {\n" + " int f() { return this->error(); }\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); + + checkConst("struct S {\n" // #14702 + " int i;\n" + " void f() {\n" + " S& r = *this;\n" + " r.i = 0;\n" + " }\n" + "};\n" + "struct T : std::array {\n" + " void g() {\n" + " for (int& r : *this)\n" + " r = 0;\n" + " }\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); + } + + void 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" @@ -6945,9 +7074,9 @@ class TestClass : public TestFixture { " int bar6() {\n" " return foo3();\n" " }\n" - "};"); - ASSERT_EQUALS("[test.cpp:11:9]: (performance, inconclusive) Technically the member function 'Foo::bar3' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n" - "[test.cpp:14:9]: (performance, inconclusive) Technically the member function 'Foo::bar4' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:11:9]: (style) The member function 'Foo::bar3' can be static. [functionStatic]\n" + "[test.cpp:14:9]: (style) The member function 'Foo::bar4' can be static. [functionStatic]\n", errout_str()); } void const_passThisToMemberOfOtherClass() { @@ -6956,7 +7085,7 @@ class TestClass : public TestFixture { " Bar b;\n" " b.takeFoo(this);\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("struct Foo {\n" @@ -6964,8 +7093,8 @@ class TestClass : public TestFixture { " Foo f;\n" " f.foo();\n" " }\n" - "};"); - ASSERT_EQUALS("[test.cpp:2:10]: (performance, inconclusive) Technically the member function 'Foo::foo' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:2:10]: (style) The member function 'Foo::foo' can be static. [functionStatic]\n", errout_str()); checkConst("struct A;\n" // #5839 - operator() "struct B {\n" @@ -6975,7 +7104,7 @@ class TestClass : public TestFixture { " void dostuff() {\n" " B()(this);\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -6987,7 +7116,7 @@ class TestClass : public TestFixture { " {\n" " v = 0;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -6999,7 +7128,7 @@ class TestClass : public TestFixture { " {\n" " v[0] = \"Happy new year!\";\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -7008,50 +7137,50 @@ class TestClass : public TestFixture { checkConst("class Fred {\n" " int a;\n" " void nextA() { return ++a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " int a;\n" " void nextA() { return --a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " int a;\n" " void nextA() { return a++; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " int a;\n" " void nextA() { return a--; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("int a;\n" "class Fred {\n" " void nextA() { return ++a; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("int a;\n" "class Fred {\n" " void nextA() { return --a; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("int a;\n" "class Fred {\n" " void nextA() { return a++; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("int a;\n" "class Fred {\n" " void nextA() { return a--; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("struct S {\n" // #10077 " int i{};\n" @@ -7066,152 +7195,152 @@ class TestClass : public TestFixture { checkConst("class Fred {\n" " int a;\n" " void nextA() { return a=1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " int a;\n" " void nextA() { return a-=1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " int a;\n" " void nextA() { return a+=1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " int a;\n" " void nextA() { return a*=-1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " int a;\n" " void nextA() { return a/=-2; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("int a;\n" "class Fred {\n" " void nextA() { return a=1; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("int a;\n" "class Fred {\n" " void nextA() { return a-=1; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("int a;\n" "class Fred {\n" " void nextA() { return a+=1; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("int a;\n" "class Fred {\n" " void nextA() { return a*=-1; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("int a;\n" "class Fred {\n" " void nextA() { return a/=-2; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); } void constassign2() { checkConst("class Fred {\n" " struct A { int a; } s;\n" " void nextA() { return s.a=1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " struct A { int a; } s;\n" " void nextA() { return s.a-=1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " struct A { int a; } s;\n" " void nextA() { return s.a+=1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " struct A { int a; } s;\n" " void nextA() { return s.a*=-1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("struct A { int a; } s;\n" "class Fred {\n" " void nextA() { return s.a=1; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("struct A { int a; } s;\n" "class Fred {\n" " void nextA() { return s.a-=1; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("struct A { int a; } s;\n" "class Fred {\n" " void nextA() { return s.a+=1; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("struct A { int a; } s;\n" "class Fred {\n" " void nextA() { return s.a*=-1; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("struct A { int a; } s;\n" "class Fred {\n" " void nextA() { return s.a/=-2; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("struct A { int a; };\n" "class Fred {\n" " A s;\n" " void nextA() { return s.a=1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("struct A { int a; };\n" "class Fred {\n" " A s;\n" " void nextA() { return s.a-=1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("struct A { int a; };\n" "class Fred {\n" " A s;\n" " void nextA() { return s.a+=1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("struct A { int a; };\n" "class Fred {\n" " A s;\n" " void nextA() { return s.a*=-1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("struct A { int a; };\n" "class Fred {\n" " A s;\n" " void nextA() { return s.a/=-2; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -7220,112 +7349,112 @@ class TestClass : public TestFixture { checkConst("class Fred {\n" " int a[2];\n" " void nextA() { return ++a[0]; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " int a[2];\n" " void nextA() { return --a[0]; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " int a[2];\n" " void nextA() { return a[0]++; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " int a[2];\n" " void nextA() { return a[0]--; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("int a[2];\n" "class Fred {\n" " void nextA() { return ++a[0]; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("int a[2];\n" "class Fred {\n" " void nextA() { return --a[0]; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("int a[2];\n" "class Fred {\n" " void nextA() { return a[0]++; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("int a[2];\n" "class Fred {\n" " void nextA() { return a[0]--; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); } void constassignarray() { checkConst("class Fred {\n" " int a[2];\n" " void nextA() { return a[0]=1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " int a[2];\n" " void nextA() { return a[0]-=1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " int a[2];\n" " void nextA() { return a[0]+=1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " int a[2];\n" " void nextA() { return a[0]*=-1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class Fred {\n" " int a[2];\n" " void nextA() { return a[0]/=-2; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("int a[2];\n" "class Fred {\n" " void nextA() { return a[0]=1; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("int a[2];\n" "class Fred {\n" " void nextA() { return a[0]-=1; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("int a[2];\n" "class Fred {\n" " void nextA() { return a[0]+=1; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("int a[2];\n" "class Fred {\n" " void nextA() { return a[0]*=-1; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); checkConst("int a[2];\n" "class Fred {\n" " void nextA() { return a[0]/=-2; }\n" - "};"); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + "};\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'Fred::nextA' can be static. [functionStatic]\n", errout_str()); } // return pointer/reference => not const @@ -7333,8 +7462,8 @@ class TestClass : public TestFixture { checkConst("class Fred {\n" " int a;\n" " int &getR() { return a; }\n" - " int *getP() { return &a; }" - "};"); + " int *getP() { return &a; }\n" + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -7343,7 +7472,7 @@ class TestClass : public TestFixture { checkConst("class Fred {\n" " int *a;\n" " void clean() { delete a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -7351,14 +7480,14 @@ class TestClass : public TestFixture { void constLPVOID() { checkConst("class Fred {\n" " UNKNOWN a() { return 0; };\n" - "};"); - TODO_ASSERT_EQUALS("[test.cpp:2]: (performance, inconclusive) Technically the member function 'Fred::a' can be static.\n", "", errout_str()); + "};\n"); + TODO_ASSERT_EQUALS("[test.cpp:2]: (style) The member function 'Fred::a' can be static.\n", "", errout_str()); // #1579 - HDC checkConst("class Fred {\n" " foo bar;\n" " UNKNOWN a() { return b; };\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -7367,8 +7496,8 @@ class TestClass : public TestFixture { checkConst("class Fred {\n" " void f() const { };\n" " void a() { f(); };\n" - "};"); - ASSERT_EQUALS("[test.cpp:2:10]: (performance, inconclusive) Technically the member function 'Fred::f' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:10]: (style) The member function 'Fred::f' can be static. [functionStatic]\n" "[test.cpp:3:10]: (style, inconclusive) Technically the member function 'Fred::a' can be const. [functionConst]\n", errout_str()); // ticket #1593 @@ -7378,7 +7507,7 @@ class TestClass : public TestFixture { "public:\n" " A(){}\n" " unsigned int GetVecSize() {return m_v.size();}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:17]: (style, inconclusive) Technically the member function 'A::GetVecSize' can be const. [functionConst]\n", errout_str()); checkConst("class A\n" @@ -7387,7 +7516,7 @@ class TestClass : public TestFixture { "public:\n" " A(){}\n" " bool GetVecEmpty() {return m_v.empty();}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:9]: (style, inconclusive) Technically the member function 'A::GetVecEmpty' can be const. [functionConst]\n", errout_str()); } @@ -7399,7 +7528,7 @@ class TestClass : public TestFixture { "public:\n" " B() : b(0) { }\n" " int func() { return b; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:8]: (style, inconclusive) Technically the member function 'B::func' can be const. [functionConst]\n", errout_str()); checkConst("class A { };\n" @@ -7409,7 +7538,7 @@ class TestClass : public TestFixture { " B() : b(0) { }\n" " int func();\n" "};\n" - "int B::func() { return b; }"); + "int B::func() { return b; }\n"); ASSERT_EQUALS("[test.cpp:6:8] -> [test.cpp:8:8]: (style, inconclusive) Technically the member function 'B::func' can be const. [functionConst]\n", errout_str()); // base class has no virtual function @@ -7422,7 +7551,7 @@ class TestClass : public TestFixture { "public:\n" " B() : b(0) { }\n" " int func() { return b; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:9:9]: (style, inconclusive) Technically the member function 'B::func' can be const. [functionConst]\n", errout_str()); checkConst("class A {\n" @@ -7435,7 +7564,7 @@ class TestClass : public TestFixture { " B() : b(0) { }\n" " int func();\n" "};\n" - "int B::func() { return b; }"); + "int B::func() { return b; }\n"); ASSERT_EQUALS("[test.cpp:9:9] -> [test.cpp:11:8]: (style, inconclusive) Technically the member function 'B::func' can be const. [functionConst]\n", errout_str()); // base class has virtual function @@ -7448,7 +7577,7 @@ class TestClass : public TestFixture { "public:\n" " B() : b(0) { }\n" " int func() { return b; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class A {\n" @@ -7461,7 +7590,7 @@ class TestClass : public TestFixture { " B() : b(0) { }\n" " int func();\n" "};\n" - "int B::func() { return b; }"); + "int B::func() { return b; }\n"); ASSERT_EQUALS("", errout_str()); checkConst("class A {\n" @@ -7474,7 +7603,7 @@ class TestClass : public TestFixture { " B() : b(0) { }\n" " int func();\n" "};\n" - "int B::func() { return b; }"); + "int B::func() { return b; }\n"); ASSERT_EQUALS("", errout_str()); // base class has no virtual function @@ -7495,7 +7624,7 @@ class TestClass : public TestFixture { "public:\n" " C() : c(0) { }\n" " int func() { return c; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:5:9]: (style, inconclusive) Technically the member function 'A::func' can be const. [functionConst]\n" "[test.cpp:11:9]: (style, inconclusive) Technically the member function 'B::func' can be const. [functionConst]\n" "[test.cpp:17:9]: (style, inconclusive) Technically the member function 'C::func' can be const. [functionConst]\n", errout_str()); @@ -7520,7 +7649,7 @@ class TestClass : public TestFixture { " C() : c(0) { }\n" " int func();\n" "};\n" - "int C::func() { return c; }"); + "int C::func() { return c; }\n"); ASSERT_EQUALS("[test.cpp:5:9] -> [test.cpp:7:8]: (style, inconclusive) Technically the member function 'A::func' can be const. [functionConst]\n" "[test.cpp:12:9] -> [test.cpp:14:8]: (style, inconclusive) Technically the member function 'B::func' can be const. [functionConst]\n" "[test.cpp:19:9] -> [test.cpp:21:8]: (style, inconclusive) Technically the member function 'C::func' can be const. [functionConst]\n", errout_str()); @@ -7543,7 +7672,7 @@ class TestClass : public TestFixture { "public:\n" " C() : c(0) { }\n" " int func() { return c; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkConst("class A {\n" @@ -7566,7 +7695,7 @@ class TestClass : public TestFixture { " C() : c(0) { }\n" " int func();\n" "};\n" - "int C::func() { return c; }"); + "int C::func() { return c; }\n"); ASSERT_EQUALS("", errout_str()); // ticket #1311 @@ -7587,7 +7716,7 @@ class TestClass : public TestFixture { "public:\n" " Z(int x, int y, int z) : Y(x, y), z(z) { }\n" " int getZ() { return z; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:5:9]: (style, inconclusive) Technically the member function 'X::getX' can be const. [functionConst]\n" "[test.cpp:11:9]: (style, inconclusive) Technically the member function 'Y::getY' can be const. [functionConst]\n" "[test.cpp:17:9]: (style, inconclusive) Technically the member function 'Z::getZ' can be const. [functionConst]\n", errout_str()); @@ -7612,7 +7741,7 @@ class TestClass : public TestFixture { " Z(int x, int y, int z) : Y(x, y), z(z) { }\n" " int getZ();\n" "};\n" - "int Z::getZ() { return z; }"); + "int Z::getZ() { return z; }\n"); ASSERT_EQUALS("[test.cpp:5:9] -> [test.cpp:7:8]: (style, inconclusive) Technically the member function 'X::getX' can be const. [functionConst]\n" "[test.cpp:12:9] -> [test.cpp:14:8]: (style, inconclusive) Technically the member function 'Y::getY' can be const. [functionConst]\n" "[test.cpp:19:9] -> [test.cpp:21:8]: (style, inconclusive) Technically the member function 'Z::getZ' can be const. [functionConst]\n", errout_str()); @@ -7626,19 +7755,19 @@ class TestClass : public TestFixture { //" i = 4;\n" //"endif\n" " }\n" - "};"; + "};\n"; - checkConst(code, dinit(CheckConstOptions, $.s = &settings0, $.inconclusive = true)); - ASSERT_EQUALS("[test.cpp:3:10]: (performance, inconclusive) Technically the member function 'foo::f' can be static (but you may consider moving to unnamed namespace). [functionStatic]\n", errout_str()); + checkConst(code); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'foo::f' can be static. [functionStatic]\n", errout_str()); - checkConst(code, dinit(CheckConstOptions, $.s = &settings0, $.inconclusive = false)); // TODO: Set inconclusive to true (preprocess it) - ASSERT_EQUALS("", errout_str()); + checkConst(code, dinit(CheckConstOptions, $.inconclusive = false)); + ASSERT_EQUALS("[test.cpp:3:10]: (style) The member function 'foo::f' can be static. [functionStatic]\n", errout_str()); } void constFriend() { // ticket #1921 const char code[] = "class foo {\n" " friend void f() { }\n" - "};"; + "};\n"; checkConst(code); ASSERT_EQUALS("", errout_str()); } @@ -7653,7 +7782,7 @@ class TestClass : public TestFixture { " void setf(float x) {\n" " d.f = x;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -7670,7 +7799,7 @@ class TestClass : public TestFixture { " T c() {\n" " return y[1][6];\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:10:7]: (style, inconclusive) Technically the member function 'foo::c' can be const. [functionConst]\n", errout_str()); } @@ -7690,8 +7819,21 @@ class TestClass : public TestFixture { " for (decltype(auto) e : array)\n" " foo(e);\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:8:10]: (style, inconclusive) Technically the member function 'Fred::f2' can be const. [functionConst]\n", errout_str()); + + checkConst("struct T {\n" // #14390 + " std::vector v;\n" + " void f() {\n" + " for (const auto& p : v)\n" + " *p = 0;\n" + " }\n" + " void g() {\n" + " for (auto* p : v)\n" + " *p = 0;\n" + " }\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); } void const_shared_ptr() { // #8674 @@ -7702,7 +7844,7 @@ class TestClass : public TestFixture { " std::shared_ptr data;\n" "};\n" "\n" - "std::shared_ptr Fred::getData() { return data; }"); + "std::shared_ptr Fred::getData() { return data; }\n"); ASSERT_EQUALS("", errout_str()); } @@ -7710,7 +7852,7 @@ class TestClass : public TestFixture { checkConst("class Fred {\n" "public:\n" " const char *const *data;\n" - " const char *const *getData() { return data; }\n}"); + " const char *const *getData() { return data; }\n}\n"); ASSERT_EQUALS("[test.cpp:4:24]: (style, inconclusive) Technically the member function 'Fred::getData' can be const. [functionConst]\n", errout_str()); } @@ -7718,7 +7860,7 @@ class TestClass : public TestFixture { checkConst("struct A {\n" " int x = 1;\n" " auto get() -> int & { return x; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -7749,7 +7891,7 @@ class TestClass : public TestFixture { } void qualifiedNameMember() { // #10872 - const Settings s = settingsBuilder().severity(Severity::style).debugwarnings().library("std.cfg").build(); + const Settings s = settingsBuilder().severity(Severity::style).debugwarnings().library("std.cfg").certainty(Certainty::inconclusive).build(); checkConst("struct data {};\n" " struct S {\n" " std::vector std;\n" @@ -7757,7 +7899,7 @@ class TestClass : public TestFixture { "};\n" "void S::f() {\n" " std::vector::const_iterator end = std.end();\n" - "}\n", dinit(CheckConstOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("[test.cpp:4:10] -> [test.cpp:6:9]: (style, inconclusive) Technically the member function 'S::f' can be const. [functionConst]\n", errout_str()); } @@ -7768,7 +7910,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(); } @@ -7777,7 +7919,7 @@ class TestClass : public TestFixture { " int a, b, c;\n" "public:\n" " Fred() : c(0), b(0), a(0) { }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:20] -> [test.cpp:2:12]: (style, inconclusive) Member variable 'Fred::b' is in the wrong place in the initializer list. [initializerList]\n" "[test.cpp:4:26] -> [test.cpp:2:9]: (style, inconclusive) Member variable 'Fred::a' is in the wrong place in the initializer list. [initializerList]\n", errout_str()); @@ -7785,14 +7927,14 @@ class TestClass : public TestFixture { " int a, b, c;\n" "public:\n" " Fred() : c{0}, b{0}, a{0} { }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:20] -> [test.cpp:2:12]: (style, inconclusive) Member variable 'Fred::b' is in the wrong place in the initializer list. [initializerList]\n" "[test.cpp:4:26] -> [test.cpp:2:9]: (style, inconclusive) Member variable 'Fred::a' is in the wrong place in the initializer list. [initializerList]\n", errout_str()); checkInitializerListOrder("struct S {\n" " S() : b(a = 1) {}\n" " int a, b;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializerListOrder("struct S {\n" @@ -7815,7 +7957,7 @@ class TestClass : public TestFixture { " : B(\"abc\", s.nRows(), s.nCols())\n" " , m_i(_i)\n" " {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -7826,41 +7968,41 @@ class TestClass : public TestFixture { " C() : b(&a) {}\n" " B b;\n" " const A a;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:11] -> [test.cpp:5:7]: (style, inconclusive) Member variable 'C::b' uses an uninitialized argument 'a' due to the order of declarations. [initializerList]\n", errout_str()); checkInitializerListOrder("struct S {\n" " S(const std::string& f, std::string i, int b, int c) : a(0), b(b), c(c) {}\n" " int a, b, c;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializerListOrder("struct S {\n" " S() : p(a) {}\n" " int* p;\n" " int a[1];\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializerListOrder("struct S {\n" " S() : p(&i) {}\n" " int* p;\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializerListOrder("struct S {\n" " S() : a(b = 1) {}\n" " int a, b;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializerListOrder("struct S {\n" " S() : r(i) {}\n" " int& r;\n" " int i{};\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializerListOrder("struct B {\n" @@ -7869,7 +8011,7 @@ class TestClass : public TestFixture { "struct D : B {\n" " D() : B(), j(b) {}\n" " int j;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializerListOrder("struct S {\n" @@ -7877,13 +8019,13 @@ class TestClass : public TestFixture { " int a;\n" " static int i;\n" "};\n" - "int S::i = 0;"); + "int S::i = 0;\n"); ASSERT_EQUALS("", errout_str()); checkInitializerListOrder("struct S {\n" " S(int b) : a(b) {}\n" " int a, b{};\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializerListOrder("class Foo {\n" // #3524 @@ -7922,7 +8064,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(); } @@ -7933,113 +8075,113 @@ class TestClass : public TestFixture { " int* b;\n" // No message for pointers: No performance gain " Enum c;\n" // No message for enums: No performance gain " Fred() { a = 0; b = 0; c = C; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializationListUsage("class Fred {\n" " std::string s;\n" " Fred() { a = 0; s = \"foo\"; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:21]: (performance) Variable 's' is assigned in constructor body. Consider performing initialization in initialization list. [useInitializationList]\n", errout_str()); checkInitializationListUsage("class Fred {\n" " std::string& s;\n" // Message is invalid for references, since their initialization in initializer list is required anyway and behaves different from assignment (#5004) " Fred(const std::string& s_) : s(s_) { s = \"foo\"; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializationListUsage("class Fred {\n" " std::vector v;\n" " Fred() { v = unknown; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:14]: (performance) Variable 'v' is assigned in constructor body. Consider performing initialization in initialization list. [useInitializationList]\n", errout_str()); checkInitializationListUsage("class C { std::string s; };\n" "class Fred {\n" " C c;\n" " Fred() { c = unknown; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:14]: (performance) Variable 'c' is assigned in constructor body. Consider performing initialization in initialization list. [useInitializationList]\n", errout_str()); checkInitializationListUsage("class C;\n" "class Fred {\n" " C c;\n" " Fred() { c = unknown; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:14]: (performance) Variable 'c' is assigned in constructor body. Consider performing initialization in initialization list. [useInitializationList]\n", errout_str()); checkInitializationListUsage("class C;\n" "class Fred {\n" " C c;\n" " Fred(Fred const & other) { c = other.c; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:32]: (performance) Variable 'c' is assigned in constructor body. Consider performing initialization in initialization list. [useInitializationList]\n", errout_str()); checkInitializationListUsage("class C;\n" "class Fred {\n" " C c;\n" " Fred(Fred && other) { c = other.c; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:27]: (performance) Variable 'c' is assigned in constructor body. Consider performing initialization in initialization list. [useInitializationList]\n", errout_str()); checkInitializationListUsage("class C;\n" "class Fred {\n" " C a;\n" " Fred() { initB(); a = b; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializationListUsage("class C;\n" "class Fred {\n" " C a;\n" " Fred() : a(0) { if(b) a = 0; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializationListUsage("class C;\n" "class Fred {\n" " C a[5];\n" " Fred() { for(int i = 0; i < 5; i++) a[i] = 0; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializationListUsage("class C;\n" "class Fred {\n" " C a; int b;\n" " Fred() : b(5) { a = b; }\n" // Don't issue a message here: You actually could move it to the initialization list, but it would cause problems if you change the order of the variable declarations. - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializationListUsage("class C;\n" "class Fred {\n" " C a;\n" " Fred() { try { a = new int; } catch(...) {} }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializationListUsage("class Fred {\n" " std::string s;\n" " Fred() { s = toString((size_t)this); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializationListUsage("class Fred {\n" " std::string a;\n" " std::string foo();\n" " Fred() { a = foo(); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializationListUsage("class Fred {\n" " std::string a;\n" " Fred() { a = foo(); }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:14]: (performance) Variable 'a' is assigned in constructor body. Consider performing initialization in initialization list. [useInitializationList]\n", errout_str()); checkInitializationListUsage("class Fred {\n" // #4332 " static std::string s;\n" " Fred() { s = \"foo\"; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializationListUsage("class Fred {\n" // #5640 @@ -8050,7 +8192,7 @@ class TestClass : public TestFixture { " str[1] = 0;\n" " s = str;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializationListUsage("class B {\n" // #5640 @@ -8058,7 +8200,7 @@ class TestClass : public TestFixture { " B(const B& other) : _d(std::make_shared()) {\n" " *_d = *other._d;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializationListUsage("class Bar {\n" // #8466 @@ -8067,7 +8209,7 @@ class TestClass : public TestFixture { " explicit Bar(const char s) : s{s} {}\n" "private:\n" " char s;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializationListUsage("unsigned bar(std::string);\n" // #8291 @@ -8076,7 +8218,7 @@ class TestClass : public TestFixture { " int a_, b_;\n" " Foo(int a, int b) : a_(a), b_(b) {}\n" " Foo(int a, const std::string& b) : Foo(a, bar(b)) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializationListUsage("class Fred {\n" // #8111 @@ -8086,7 +8228,7 @@ class TestClass : public TestFixture { " ostr << x;\n" " a = ostr.str();\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // bailout: multi line lambda in rhs => do not warn @@ -8097,7 +8239,7 @@ class TestClass : public TestFixture { " return 1;\n" " };\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // don't warn if some other instance's members are assigned to @@ -8106,7 +8248,7 @@ class TestClass : public TestFixture { " C(C& c) : m_i(c.m_i) { c.m_i = (Foo)-1; }\n" "private:\n" " Foo m_i;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkInitializationListUsage("class A {\n" // #9821 - delegate constructor @@ -8119,7 +8261,22 @@ class TestClass : public TestFixture { "\n" "private:\n" " std::string st;\n" - "};"); + "};\n"); + ASSERT_EQUALS("", errout_str()); + + checkInitializationListUsage("struct S {\n" // #14189 + " S() {}\n" + " int i{};\n" + "};\n" + "struct T { explicit T(const S&); };\n" + "class C {\n" + " C() {\n" + " S s;\n" + " s.i = 1;\n" + " p = std::make_unique(s);\n" + " }\n" + " std::unique_ptr p;\n" + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -8131,7 +8288,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)(); } @@ -8140,14 +8297,14 @@ class TestClass : public TestFixture { " int i;\n" " Fred() : i(i) {\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:12]: (error) Member variable 'i' is initialized by itself. [selfInitialization]\n", errout_str()); checkSelfInitialization("class Fred {\n" " int i;\n" " Fred() : i{i} {\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:12]: (error) Member variable 'i' is initialized by itself. [selfInitialization]\n", errout_str()); checkSelfInitialization("class Fred {\n" @@ -8155,7 +8312,7 @@ class TestClass : public TestFixture { " Fred();\n" "};\n" "Fred::Fred() : i(i) {\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:14]: (error) Member variable 'i' is initialized by itself. [selfInitialization]\n", errout_str()); checkSelfInitialization("class A {\n" // #10427 @@ -8178,56 +8335,56 @@ class TestClass : public TestFixture { " std::string s;\n" " Fred() : s(s) {\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:12]: (error) Member variable 's' is initialized by itself. [selfInitialization]\n", errout_str()); checkSelfInitialization("class Fred {\n" " int x;\n" " Fred(int x);\n" "};\n" - "Fred::Fred(int x) : x(x) { }"); + "Fred::Fred(int x) : x(x) { }\n"); ASSERT_EQUALS("", errout_str()); checkSelfInitialization("class Fred {\n" " int x;\n" " Fred(int x);\n" "};\n" - "Fred::Fred(int x) : x{x} { }"); + "Fred::Fred(int x) : x{x} { }\n"); ASSERT_EQUALS("", errout_str()); checkSelfInitialization("class Fred {\n" " std::string s;\n" " Fred(const std::string& s) : s(s) {\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkSelfInitialization("class Fred {\n" " std::string s;\n" " Fred(const std::string& s) : s{s} {\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkSelfInitialization("struct Foo : Bar {\n" " int i;\n" " Foo(int i)\n" " : Bar(\"\"), i(i) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkSelfInitialization("struct Foo : std::Bar {\n" // #6073 " int i;\n" " Foo(int i)\n" " : std::Bar(\"\"), i(i) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkSelfInitialization("struct Foo : std::Bar {\n" // #6073 " int i;\n" " Foo(int i)\n" " : std::Bar(\"\"), i{i} {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -8241,7 +8398,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(); } @@ -8252,21 +8409,21 @@ class TestClass : public TestFixture { " A();\n" "};\n" "A::A()\n" - "{f();}"); + "{f();}\n"); ASSERT_EQUALS("[test.cpp:7:2] -> [test.cpp:3:17]: (style) Virtual function 'f' is called from constructor 'A()' at line 7. Dynamic binding is not used. [virtualCallInConstructor]\n", errout_str()); checkVirtualFunctionCall("class A {\n" " virtual int f();\n" " A() {f();}\n" "};\n" - "int A::f() { return 1; }"); + "int A::f() { return 1; }\n"); ASSERT_EQUALS("[test.cpp:3:10] -> [test.cpp:2:17]: (style) Virtual function 'f' is called from constructor 'A()' at line 3. Dynamic binding is not used. [virtualCallInConstructor]\n", errout_str()); checkVirtualFunctionCall("class A : B {\n" " int f() override;\n" " A() {f();}\n" "};\n" - "int A::f() { return 1; }"); + "int A::f() { return 1; }\n"); ASSERT_EQUALS("[test.cpp:3:10] -> [test.cpp:2:9]: (style) Virtual function 'f' is called from constructor 'A()' at line 3. Dynamic binding is not used. [virtualCallInConstructor]\n", errout_str()); checkVirtualFunctionCall("class B {\n" @@ -8276,14 +8433,14 @@ class TestClass : public TestFixture { " int f();\n" // <- not explicitly virtual " A() {f();}\n" "};\n" - "int A::f() { return 1; }"); + "int A::f() { return 1; }\n"); ASSERT_EQUALS("", errout_str()); checkVirtualFunctionCall("class A\n" "{\n" " A() { A::f(); }\n" " virtual void f() {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkVirtualFunctionCall("class A : B {\n" @@ -8369,7 +8526,7 @@ class TestClass : public TestFixture { " A();\n" "};\n" "A::A()\n" - "{pure();}"); + "{pure();}\n"); ASSERT_EQUALS("[test.cpp:7:2] -> [test.cpp:3:18]: (warning) Call of pure virtual function 'pure' in constructor. [pureVirtualCall]\n", errout_str()); checkVirtualFunctionCall("class A\n" @@ -8379,7 +8536,7 @@ class TestClass : public TestFixture { " int m;\n" "};\n" "A::A():m(A::pure())\n" - "{}"); + "{}\n"); ASSERT_EQUALS("[test.cpp:7:13] -> [test.cpp:3:17]: (warning) Call of pure virtual function 'pure' in constructor. [pureVirtualCall]\n", errout_str()); checkVirtualFunctionCall("namespace N {\n" @@ -8400,7 +8557,7 @@ class TestClass : public TestFixture { " int m;\n" "};\n" "A::~A()\n" - "{pure();}"); + "{pure();}\n"); ASSERT_EQUALS("[test.cpp:8:2] -> [test.cpp:3:18]: (warning) Call of pure virtual function 'pure' in destructor. [pureVirtualCall]\n", errout_str()); checkVirtualFunctionCall("class A\n" @@ -8411,7 +8568,7 @@ class TestClass : public TestFixture { " A();\n" "};\n" "A::A()\n" - "{nonpure();}"); + "{nonpure();}\n"); ASSERT_EQUALS("[test.cpp:9:2] -> [test.cpp:5:6] -> [test.cpp:3:18]: (warning) Call of pure virtual function 'pure' in constructor. [pureVirtualCall]\n", errout_str()); checkVirtualFunctionCall("class A\n" @@ -8423,7 +8580,7 @@ class TestClass : public TestFixture { " int m;\n" "};\n" "A::A():m(nonpure())\n" - "{}"); + "{}\n"); TODO_ASSERT_EQUALS("[test.cpp:9:2] -> [test.cpp:5:6] -> [test.cpp:3:18]: (warning) Call of pure virtual function 'pure' in constructor. [pureVirtualCall]\n", "", errout_str()); checkVirtualFunctionCall("class A\n" @@ -8435,7 +8592,7 @@ class TestClass : public TestFixture { " int m;\n" "};\n" "A::~A()\n" - "{nonpure();}"); + "{nonpure();}\n"); ASSERT_EQUALS("[test.cpp:10:2] -> [test.cpp:5:6] -> [test.cpp:3:18]: (warning) Call of pure virtual function 'pure' in destructor. [pureVirtualCall]\n", errout_str()); checkVirtualFunctionCall("class A\n" @@ -8444,7 +8601,7 @@ class TestClass : public TestFixture { " A(bool b);\n" "};\n" "A::A(bool b)\n" - "{if (b) pure();}"); + "{if (b) pure();}\n"); ASSERT_EQUALS("[test.cpp:7:9] -> [test.cpp:3:18]: (warning) Call of pure virtual function 'pure' in constructor. [pureVirtualCall]\n", errout_str()); checkVirtualFunctionCall("class A\n" @@ -8454,7 +8611,7 @@ class TestClass : public TestFixture { " int m;\n" "};\n" "A::~A()\n" - "{if (b) pure();}"); + "{if (b) pure();}\n"); ASSERT_EQUALS("[test.cpp:8:9] -> [test.cpp:3:18]: (warning) Call of pure virtual function 'pure' in destructor. [pureVirtualCall]\n", errout_str()); // #5831 @@ -8462,7 +8619,7 @@ class TestClass : public TestFixture { "public:\n" " virtual ~abc() throw() {}\n" " virtual void def(void* g) throw () = 0;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // #4992 @@ -8473,7 +8630,7 @@ class TestClass : public TestFixture { " m_callback = [this]() { return VirtualMethod(); };\n" " }\n" " virtual void VirtualMethod() = 0;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // #10559 @@ -8492,7 +8649,7 @@ class TestClass : public TestFixture { " A(const A & a);\n" "};\n" "A::A(const A & a)\n" - "{a.pure();}"); + "{a.pure();}\n"); ASSERT_EQUALS("", errout_str()); checkVirtualFunctionCall("class A\n" @@ -8505,7 +8662,7 @@ class TestClass : public TestFixture { " virtual void pure()=0;\n" "};\n" "A::A()\n" - "{B b; b.pure();}"); + "{B b; b.pure();}\n"); ASSERT_EQUALS("", errout_str()); } @@ -8518,7 +8675,7 @@ class TestClass : public TestFixture { "A::A()\n" "{pureWithBody();}\n" "void A::pureWithBody()\n" - "{}"); + "{}\n"); ASSERT_EQUALS("", errout_str()); checkVirtualFunctionCall("class A\n" @@ -8531,7 +8688,7 @@ class TestClass : public TestFixture { "A::A()\n" "{nonpure();}\n" "void A::pureWithBody()\n" - "{}"); + "{}\n"); ASSERT_EQUALS("", errout_str()); } @@ -8545,7 +8702,7 @@ class TestClass : public TestFixture { " A();\n" "};\n" "A::A()\n" - "{nonpure(false);}"); + "{nonpure(false);}\n"); ASSERT_EQUALS("", errout_str()); checkVirtualFunctionCall("class A\n" @@ -8556,7 +8713,7 @@ class TestClass : public TestFixture { " A();\n" "};\n" "A::A()\n" - "{nonpure(false);}"); + "{nonpure(false);}\n"); ASSERT_EQUALS("", errout_str()); checkVirtualFunctionCall("class A\n" @@ -8571,7 +8728,7 @@ class TestClass : public TestFixture { " A();\n" "};\n" "A::A()\n" - "{nonpure(false);}"); + "{nonpure(false);}\n"); ASSERT_EQUALS("", errout_str()); } @@ -8586,21 +8743,21 @@ class TestClass : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check.. - CheckClass checkClass(&tokenizer, &settings, this); + CheckClassImpl checkClass(&tokenizer, settings, *this); (checkClass.checkOverride)(); } void override1() { checkOverride("class Base { virtual void f(); };\n" - "class Derived : Base { virtual void f(); };"); + "class Derived : Base { virtual void f(); };\n"); ASSERT_EQUALS("[test.cpp:1:27] -> [test.cpp:2:37]: (style) The function 'f' overrides a function in a base class but is not marked with a 'override' specifier. [missingOverride]\n", errout_str()); checkOverride("class Base { virtual void f(); };\n" - "class Derived : Base { virtual void f() override; };"); + "class Derived : Base { virtual void f() override; };\n"); ASSERT_EQUALS("", errout_str()); checkOverride("class Base { virtual void f(); };\n" - "class Derived : Base { virtual void f() final; };"); + "class Derived : Base { virtual void f() final; };\n"); ASSERT_EQUALS("", errout_str()); checkOverride("class Base {\n" @@ -8612,7 +8769,7 @@ class TestClass : public TestFixture { "public :\n" " auto foo( ) const -> size_t { return 0; }\n" " auto bar( ) const -> size_t override { return 0; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:18] -> [test.cpp:8:10]: (style) The function 'foo' overrides a function in a base class but is not marked with a 'override' specifier. [missingOverride]\n", errout_str()); checkOverride("namespace Test {\n" @@ -8624,7 +8781,7 @@ class TestClass : public TestFixture { "class C : Test::C {\n" "public:\n" " ~C();\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:18] -> [test.cpp:9:6]: (style) The destructor '~C' overrides a destructor in a base class but is not marked with a 'override' specifier. [missingOverride]\n", errout_str()); checkOverride("struct Base {\n" @@ -8634,7 +8791,7 @@ class TestClass : public TestFixture { "struct Derived: public Base {\n" " void foo() override;\n" " void foo(int);\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOverride("struct B {\n" // #9092 @@ -8758,23 +8915,33 @@ class TestClass : public TestFixture { "};\n"); ASSERT_EQUALS("[test.cpp:2:14] -> [test.cpp:5:6]: (style) The destructor '~D' overrides a destructor in a base class but is not marked with a 'override' specifier. [missingOverride]\n", errout_str()); + + checkOverride("struct B {\n" // #14581 + " virtual void f();\n" + "};\n" + "struct D : B {\n" + " void f() override;\n" + " template \n" + " void f();\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); } void overrideCVRefQualifiers() { checkOverride("class Base { virtual void f(); };\n" - "class Derived : Base { void f() const; }"); + "class Derived : Base { void f() const; }\n"); ASSERT_EQUALS("", errout_str()); checkOverride("class Base { virtual void f(); };\n" - "class Derived : Base { void f() volatile; }"); + "class Derived : Base { void f() volatile; }\n"); ASSERT_EQUALS("", errout_str()); checkOverride("class Base { virtual void f(); };\n" - "class Derived : Base { void f() &; }"); + "class Derived : Base { void f() &; }\n"); ASSERT_EQUALS("", errout_str()); checkOverride("class Base { virtual void f(); };\n" - "class Derived : Base { void f() &&; }"); + "class Derived : Base { void f() &&; }\n"); ASSERT_EQUALS("", errout_str()); } @@ -8788,7 +8955,7 @@ class TestClass : public TestFixture { ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); // Check.. - CheckClass checkClass(&tokenizer, &settings, this); + CheckClassImpl checkClass(&tokenizer, settings, *this); (checkClass.checkUselessOverride)(); } @@ -8796,51 +8963,51 @@ class TestClass : public TestFixture { checkUselessOverride("struct B { virtual int f() { return 5; } };\n" // #11757 "struct D : B {\n" " int f() override { return B::f(); }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:1:24] -> [test.cpp:3:9]: (style) The function 'f' overrides a function in a base class but just delegates back to the base class. [uselessOverride]\n", errout_str()); checkUselessOverride("struct B { virtual void f(); };\n" "struct D : B {\n" " void f() override { B::f(); }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:1:25] -> [test.cpp:3:10]: (style) The function 'f' overrides a function in a base class but just delegates back to the base class. [uselessOverride]\n", errout_str()); checkUselessOverride("struct B { virtual int f() = 0; };\n" "int B::f() { return 5; }\n" "struct D : B {\n" " int f() override { return B::f(); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkUselessOverride("struct B { virtual int f(int i); };\n" "struct D : B {\n" " int f(int i) override { return B::f(i); }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:1:24] -> [test.cpp:3:9]: (style) The function 'f' overrides a function in a base class but just delegates back to the base class. [uselessOverride]\n", errout_str()); checkUselessOverride("struct B { virtual int f(int i); };\n" "struct D : B {\n" " int f(int i) override { return B::f(i + 1); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkUselessOverride("struct B { virtual int f(int i, int j); };\n" "struct D : B {\n" " int f(int i, int j) override { return B::f(j, i); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkUselessOverride("struct B { virtual int f(); };\n" "struct I { virtual int f() = 0; };\n" "struct D : B, I {\n" " int f() override { return B::f(); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkUselessOverride("struct S { virtual void f(); };\n" "struct D : S {\n" " void f() final { S::f(); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkUselessOverride("struct S {\n" @@ -8850,7 +9017,7 @@ class TestClass : public TestFixture { "struct D : S {\n" "public:\n" " void f() override { S::f(); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkUselessOverride("struct B { virtual void f(int, int, int) const; };\n" // #11799 @@ -8860,7 +9027,7 @@ class TestClass : public TestFixture { "};\n" "void D::f(int a, int b, int c) const {\n" " B::f(a, b, m);\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkUselessOverride("struct B {\n" // #11803 @@ -8871,7 +9038,7 @@ class TestClass : public TestFixture { " void f() override { B::f(); }\n" " void f(int i) override;\n" " void g() { f(); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkUselessOverride("struct B { virtual void f(); };\n" // #11808 @@ -8880,7 +9047,7 @@ class TestClass : public TestFixture { " void f() override {\n" " B::f();\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkUselessOverride("struct B {\n" @@ -8894,7 +9061,7 @@ class TestClass : public TestFixture { " int g() override { return 7; }\n" " int h(int j, int i) override { return i + j; }\n" " int j(int i, int j) override { return i + j; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:17] -> [test.cpp:9:9]: (style) The function 'g' overrides a function in a base class but is identical to the overridden function [uselessOverride]\n" "[test.cpp:5:17] -> [test.cpp:11:9]: (style) The function 'j' overrides a function in a base class but is identical to the overridden function [uselessOverride]\n", errout_str()); @@ -8978,12 +9145,12 @@ class TestClass : public TestFixture { ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check.. - CheckClass checkClass(&tokenizer, &settings, this); + CheckClassImpl checkClass(&tokenizer, settings, *this); (checkClass.checkUnsafeClassRefMember)(); } void unsafeClassRefMember() { - checkUnsafeClassRefMember("class C { C(const std::string &s) : s(s) {} const std::string &s; };"); + checkUnsafeClassRefMember("class C { C(const std::string &s) : s(s) {} const std::string &s; };\n"); ASSERT_EQUALS("[test.cpp:1:37]: (warning) Unsafe class: The const reference member 'C::s' is initialized by a const reference constructor argument. You need to be careful about lifetime issues. [unsafeClassRefMember]\n", errout_str()); } @@ -8996,7 +9163,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)(); } @@ -9010,7 +9177,7 @@ class TestClass : public TestFixture { "private:\n" " static C *mInstance;\n" " void hello() {}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:38]: warning: Calling method 'hello()' when 'this' might be invalid [thisUseAfterFree]\n" "[test.cpp:5:13]: note: Assuming 'mInstance' is used as 'this'\n" "[test.cpp:3:20]: note: Delete 'mInstance', invalidating 'this'\n" @@ -9023,7 +9190,7 @@ class TestClass : public TestFixture { "private:\n" " static std::shared_ptr mInstance;\n" " void hello() {}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:39]: warning: Calling method 'hello()' when 'this' might be invalid [thisUseAfterFree]\n" "[test.cpp:5:29]: note: Assuming 'mInstance' is used as 'this'\n" "[test.cpp:3:20]: note: Delete 'mInstance', invalidating 'this'\n" @@ -9037,7 +9204,7 @@ class TestClass : public TestFixture { " static std::shared_ptr mInstance;\n" " void hello();\n" " void reset() { mInstance.reset(); }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:29]: warning: Calling method 'hello()' when 'this' might be invalid [thisUseAfterFree]\n" "[test.cpp:5:29]: note: Assuming 'mInstance' is used as 'this'\n" "[test.cpp:7:18]: note: Delete 'mInstance', invalidating 'this'\n" @@ -9051,7 +9218,7 @@ class TestClass : public TestFixture { "private:\n" " static C *self;\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:33]: warning: Using member 'x' when 'this' might be invalid [thisUseAfterFree]\n" "[test.cpp:5:13]: note: Assuming 'self' is used as 'this'\n" "[test.cpp:3:20]: note: Delete 'self', invalidating 'this'\n" @@ -9064,7 +9231,7 @@ class TestClass : public TestFixture { "private:\n" " static C *self;\n" " std::map x;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:33]: warning: Using member 'x' when 'this' might be invalid [thisUseAfterFree]\n" "[test.cpp:5:13]: note: Assuming 'self' is used as 'this'\n" "[test.cpp:3:20]: note: Delete 'self', invalidating 'this'\n" @@ -9079,7 +9246,7 @@ class TestClass : public TestFixture { "private:\n" " std::shared_ptr mInstance;\n" " void hello() {}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:39]: warning: Calling method 'hello()' when 'this' might be invalid [thisUseAfterFree]\n" "[test.cpp:6:22]: note: Assuming 'mInstance' is used as 'this'\n" "[test.cpp:4:20]: note: Delete 'mInstance', invalidating 'this'\n" @@ -9093,7 +9260,7 @@ class TestClass : public TestFixture { "private:\n" " C *self;\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkThisUseAfterFree("class C {\n" @@ -9103,7 +9270,7 @@ class TestClass : public TestFixture { "private:\n" " std::shared_ptr mInstance;\n" " void hello() {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkThisUseAfterFree("class C\n" @@ -9120,7 +9287,7 @@ class TestClass : public TestFixture { " static C* instanceSingleton;\n" "};\n" "\n" - "C* C::instanceSingleton;"); + "C* C::instanceSingleton;\n"); ASSERT_EQUALS("", errout_str()); // Avoid false positive when pointer is deleted in lambda @@ -9136,7 +9303,7 @@ class TestClass : public TestFixture { " auto done = [this] () { delete p; };\n" " dostuff();\n" " done();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkThisUseAfterFree("class C {\n" // #13311 @@ -9152,16 +9319,17 @@ class TestClass : public TestFixture { " if (self)\n" " delete self;\n" " self = new C();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } 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}; @@ -9180,19 +9348,19 @@ class TestClass : public TestFixture { } void ctuOneDefinitionRule() { - ctu({"class C { C() { std::cout << 0; } };", "class C { C() { std::cout << 1; } };"}); + ctu({"class C { C() { std::cout << 0; } };\n", "class C { C() { std::cout << 1; } };\n"}); ASSERT_EQUALS("[1.cpp:1:1] -> [0.cpp:1:1]: (error) The one definition rule is violated, different classes/structs have the same name 'C' [ctuOneDefinitionRuleViolation]\n", errout_str()); - ctu({"class C { C(); }; C::C() { std::cout << 0; }", "class C { C(); }; C::C() { std::cout << 1; }"}); + ctu({"class C { C(); }; C::C() { std::cout << 0; }\n", "class C { C(); }; C::C() { std::cout << 1; }\n"}); ASSERT_EQUALS("[1.cpp:1:1] -> [0.cpp:1:1]: (error) The one definition rule is violated, different classes/structs have the same name 'C' [ctuOneDefinitionRuleViolation]\n", errout_str()); ctu({"class C { C() {} };\n", "class C { C() {} };\n"}); ASSERT_EQUALS("", errout_str()); - ctu({"class C { C(); }; C::C(){}", "class C { C(); }; C::C(){}"}); + ctu({"class C { C(); }; C::C(){}\n", "class C { C(); }; C::C(){}\n"}); ASSERT_EQUALS("", errout_str()); - ctu({"class A::C { C() { std::cout << 0; } };", "class B::C { C() { std::cout << 1; } };"}); + ctu({"class A::C { C() { std::cout << 0; } };\n", "class B::C { C() { std::cout << 1; } };\n"}); ASSERT_EQUALS("", errout_str()); // 11435 - template specialisations @@ -9210,16 +9378,16 @@ 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; } void testGetFileInfo() { - getFileInfo("void foo() { union { struct { }; }; }"); // don't crash - getFileInfo("struct sometype { sometype(); }; sometype::sometype() = delete;"); // don't crash + getFileInfo("void foo() { union { struct { }; }; }\n"); // don't crash + getFileInfo("struct sometype { sometype(); }; sometype::sometype() = delete;\n"); // don't crash } #define checkReturnByReference(...) checkReturnByReference_(__FILE__, __LINE__, __VA_ARGS__) @@ -9232,7 +9400,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 3527ff6cc76..326b7ad613d 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,9 +31,13 @@ #include "settings.h" #include "standards.h" #include "suppressions.h" -#include "timer.h" #include "utils.h" +#ifdef HAVE_RULES +#include "regex.h" +#include "rule.h" +#endif + #include #include #include @@ -49,7 +53,7 @@ class TestCmdlineParser : public TestFixture { {} private: - class CmdLineLoggerTest : public CmdLineLogger + class CmdLineLoggerTest final : public CmdLineLogger { public: CmdLineLoggerTest() = default; @@ -91,16 +95,25 @@ class TestCmdlineParser : public TestFixture { std::string buf; }; + class CmdLineParserTest final : public CmdLineParser + { + friend class TestCmdlineParser; + public: + CmdLineParserTest(CmdLineLogger &logger, Settings &settings, Suppressions &suppressions) + : CmdLineParser(logger, settings, suppressions) + {} + }; + std::unique_ptr logger; std::unique_ptr settings; std::unique_ptr supprs; - std::unique_ptr parser; + std::unique_ptr parser; void prepareTestInternal() override { logger.reset(new CmdLineLoggerTest()); settings.reset(new Settings()); supprs.reset(new Suppressions()); - parser.reset(new CmdLineParser(*logger, *settings, *supprs)); + parser.reset(new CmdLineParserTest(*logger, *settings, *supprs)); } void teardownTestInternal() override { @@ -124,14 +137,17 @@ class TestCmdlineParser : public TestFixture { void run() override { TEST_CASE(nooptions); + TEST_CASE(nooptionsWithCfg); + TEST_CASE(nooptionsWithInvalidCfg); TEST_CASE(helpshort); TEST_CASE(helpshortExclusive); + TEST_CASE(helpshortWithCfg); TEST_CASE(helplong); TEST_CASE(helplongExclusive); + TEST_CASE(helplongWithCfg); TEST_CASE(version); TEST_CASE(versionWithCfg); TEST_CASE(versionExclusive); - TEST_CASE(versionWithInvalidCfg); TEST_CASE(checkVersionCorrect); TEST_CASE(checkVersionIncorrect); TEST_CASE(onefile); @@ -246,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); @@ -288,10 +305,14 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(suppressionsNoFile1); TEST_CASE(suppressionsNoFile2); TEST_CASE(suppressionsNoFile3); - TEST_CASE(suppressionSingle); - TEST_CASE(suppressionSingleFile); - TEST_CASE(suppressionTwo); - TEST_CASE(suppressionTwoSeparate); + TEST_CASE(suppressSingle); + TEST_CASE(suppressSingleFile); + TEST_CASE(suppressTwo); + TEST_CASE(suppressTwoSeparate); + TEST_CASE(exitcodeSuppressSingle); + TEST_CASE(exitcodeSuppressSingleFile); + TEST_CASE(exitcodeSuppressTwo); + TEST_CASE(exitcodeSuppressTwoSeparate); TEST_CASE(templates); TEST_CASE(templatesGcc); TEST_CASE(templatesVs); @@ -325,7 +346,6 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(errorlist); TEST_CASE(errorlistWithCfg); TEST_CASE(errorlistExclusive); - TEST_CASE(errorlistWithInvalidCfg); TEST_CASE(ignorepathsnopath); #if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING) TEST_CASE(exceptionhandling); @@ -382,6 +402,7 @@ class TestCmdlineParser : public TestFixture { #ifdef HAVE_RULES TEST_CASE(rule); TEST_CASE(ruleMissingPattern); + TEST_CASE(ruleInvalidPattern); #else TEST_CASE(ruleNotSupported); #endif @@ -401,6 +422,8 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(ruleFileMissingId); TEST_CASE(ruleFileInvalidSeverity1); TEST_CASE(ruleFileInvalidSeverity2); + TEST_CASE(ruleFileInvalidPattern); + TEST_CASE(ruleFileInvalidEngine); #else TEST_CASE(ruleFileNotSupported); #endif @@ -476,6 +499,12 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(debugNormalVerbose); TEST_CASE(debug); TEST_CASE(debugVerbose); + TEST_CASE(safety); + TEST_CASE(safetyOverride); + TEST_CASE(noSafety); + TEST_CASE(noSafetyOverride); + TEST_CASE(debugAnalyzerinfo); + TEST_CASE(debugIpc); TEST_CASE(ignorepaths1); TEST_CASE(ignorepaths2); @@ -530,6 +559,31 @@ class TestCmdlineParser : public TestFixture { ASSERT(startsWith(logger->str(), "Cppcheck - A tool for static C/C++ code analysis")); } + void nooptionsWithCfg() { + REDIRECT; + ScopedFile file(Path::join(Path::getPathFromFilename(Path::getCurrentExecutablePath("")), "cppcheck.cfg"), + "{\n" + "\"productName\": \"Cppcheck Premium\"," + "\"manualUrl\": \"https://docs.notcppcheck.com/manual.pdf\"" + "}\n"); + const char * const argv[] = {"cppcheck"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Exit, parseFromArgs(argv)); + ASSERT_EQUALS(1, settings->settingsFiles.size()); + ASSERT_EQUALS(file.path(), *settings->settingsFiles.cbegin()); + const std::string log_str = logger->str(); + ASSERT_MSG(startsWith(log_str, "Cppcheck - A tool for static C/C++ code analysis"), "header"); + ASSERT_MSG(log_str.find("https://docs.notcppcheck.com/manual.pdf") != std::string::npos, "help url"); + } + + void nooptionsWithInvalidCfg() { + REDIRECT; + ScopedFile file(Path::join(Path::getPathFromFilename(Path::getCurrentExecutablePath("")), "cppcheck.cfg"), + "{\n"); + const char * const argv[] = {"cppcheck"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); + ASSERT_EQUALS("cppcheck: error: could not load cppcheck.cfg - not a valid JSON - syntax error at line 2 near: \n", logger->str()); + } + void helpshort() { REDIRECT; const char * const argv[] = {"cppcheck", "-h"}; @@ -544,6 +598,22 @@ class TestCmdlineParser : public TestFixture { ASSERT(startsWith(logger->str(), "Cppcheck - A tool for static C/C++ code analysis")); } + void helpshortWithCfg() { + REDIRECT; + ScopedFile file(Path::join(Path::getPathFromFilename(Path::getCurrentExecutablePath("")), "cppcheck.cfg"), + "{\n" + "\"productName\": \"Cppcheck Premium\"," + "\"manualUrl\": \"https://docs.notcppcheck.com/manual.pdf\"" + "}\n"); + const char * const argv[] = {"cppcheck", "-h"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Exit, parseFromArgs(argv)); + ASSERT_EQUALS(1, settings->settingsFiles.size()); + ASSERT_EQUALS(file.path(), *settings->settingsFiles.cbegin()); + const std::string log_str = logger->str(); + ASSERT_MSG(startsWith(log_str, "Cppcheck - A tool for static C/C++ code analysis"), "header"); + ASSERT_MSG(log_str.find("https://docs.notcppcheck.com/manual.pdf") != std::string::npos, "help url"); + } + void helplong() { REDIRECT; const char * const argv[] = {"cppcheck", "--help"}; @@ -558,6 +628,22 @@ class TestCmdlineParser : public TestFixture { ASSERT(startsWith(logger->str(), "Cppcheck - A tool for static C/C++ code analysis")); } + void helplongWithCfg() { + REDIRECT; + ScopedFile file(Path::join(Path::getPathFromFilename(Path::getCurrentExecutablePath("")), "cppcheck.cfg"), + "{\n" + "\"productName\": \"Cppcheck Premium\"," + "\"manualUrl\": \"https://docs.notcppcheck.com/manual.pdf\"" + "}\n"); + const char * const argv[] = {"cppcheck", "--help"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Exit, parseFromArgs(argv)); + ASSERT_EQUALS(1, settings->settingsFiles.size()); + ASSERT_EQUALS(file.path(), *settings->settingsFiles.cbegin()); + const std::string log_str = logger->str(); + ASSERT_MSG(startsWith(log_str, "Cppcheck - A tool for static C/C++ code analysis"), "header"); + ASSERT_MSG(log_str.find("https://docs.notcppcheck.com/manual.pdf") != std::string::npos, "help url"); + } + void version() { REDIRECT; const char * const argv[] = {"cppcheck", "--version"}; @@ -573,8 +659,9 @@ class TestCmdlineParser : public TestFixture { "}\n"); const char * const argv[] = {"cppcheck", "--version"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Exit, parseFromArgs(argv)); - // TODO: somehow the config is not loaded on some systems - (void)logger->str(); //ASSERT_EQUALS("The Product\n", logger->str()); // TODO: include version? + ASSERT_EQUALS(1, settings->settingsFiles.size()); + ASSERT_EQUALS(file.path(), *settings->settingsFiles.cbegin()); + ASSERT_EQUALS("The Product\n", logger->str()); // TODO: include version? } // TODO: test --version with extraVersion @@ -586,15 +673,6 @@ class TestCmdlineParser : public TestFixture { ASSERT(logger->str().compare(0, 11, "Cppcheck 2.") == 0); } - void versionWithInvalidCfg() { - REDIRECT; - ScopedFile file(Path::join(Path::getPathFromFilename(Path::getCurrentExecutablePath("")), "cppcheck.cfg"), - "{\n"); - const char * const argv[] = {"cppcheck", "--version"}; - ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: could not load cppcheck.cfg - not a valid JSON - syntax error at line 2 near: \n", logger->str()); - } - void checkVersionCorrect() { REDIRECT; const std::string currentVersion = parser->getVersion(); @@ -614,23 +692,23 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT_EQUALS(1, parser->getPathNames().size()); - ASSERT_EQUALS("file.cpp", parser->getPathNames().at(0)); + ASSERT_EQUALS(1, parser->mPathNames.size()); + ASSERT_EQUALS("file.cpp", parser->mPathNames[0]); } void onepath() { REDIRECT; const char * const argv[] = {"cppcheck", "src"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT_EQUALS(1, parser->getPathNames().size()); - ASSERT_EQUALS("src", parser->getPathNames().at(0)); + ASSERT_EQUALS(1, parser->mPathNames.size()); + ASSERT_EQUALS("src", parser->mPathNames[0]); } void optionwithoutfile() { REDIRECT; const char * const argv[] = {"cppcheck", "-v"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS(0, parser->getPathNames().size()); + ASSERT_EQUALS(0, parser->mPathNames.size()); ASSERT_EQUALS("cppcheck: error: no C or C++ source files found.\n", logger->str()); } @@ -1164,7 +1242,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "--error-exitcode=", "file.cpp"}; // Fails since exit code not given ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--error-exitcode=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--error-exitcode=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void errorExitcodeStr() { @@ -1172,7 +1250,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "--error-exitcode=foo", "file.cpp"}; // Fails since invalid exit code ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--error-exitcode=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--error-exitcode=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void exitcodeSuppressionsOld() { @@ -1264,8 +1342,8 @@ class TestCmdlineParser : public TestFixture { "file2.cpp\n"); const char * const argv[] = {"cppcheck", "--file-list=files.txt", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT_EQUALS(3, parser->getPathNames().size()); - auto it = parser->getPathNames().cbegin(); + ASSERT_EQUALS(3, parser->mPathNames.size()); + auto it = parser->mPathNames.cbegin(); ASSERT_EQUALS("file1.c", *it++); ASSERT_EQUALS("file2.cpp", *it++); ASSERT_EQUALS("file.cpp", *it); @@ -1283,8 +1361,8 @@ class TestCmdlineParser : public TestFixture { RedirectInput input("file1.c\nfile2.cpp\n"); const char * const argv[] = {"cppcheck", "--file-list=-", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT_EQUALS(3, parser->getPathNames().size()); - auto it = parser->getPathNames().cbegin(); + ASSERT_EQUALS(3, parser->mPathNames.size()); + auto it = parser->mPathNames.cbegin(); ASSERT_EQUALS("file1.c", *it++); ASSERT_EQUALS("file2.cpp", *it++); ASSERT_EQUALS("file.cpp", *it); @@ -1323,7 +1401,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "-j", "file.cpp"}; // Fails since -j is missing thread count ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '-j' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '-j' is not valid - not an integer (invalid_argument).\n", logger->str()); } void jobsInvalid() { @@ -1331,7 +1409,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "-j", "e", "file.cpp"}; // Fails since invalid count given for -j ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '-j' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '-j' is not valid - not an integer (invalid_argument).\n", logger->str()); } void jobsNoJobs() { @@ -1352,7 +1430,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "-f", "--max-configs=12", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT_EQUALS(12, settings->maxConfigs); + ASSERT_EQUALS(12, settings->maxConfigsOption); ASSERT_EQUALS(false, settings->force); } @@ -1361,7 +1439,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "--max-configs=", "file.cpp"}; // Fails since --max-configs= is missing limit ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--max-configs=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--max-configs=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void maxConfigsInvalid() { @@ -1369,7 +1447,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "--max-configs=e", "file.cpp"}; // Fails since invalid count given for --max-configs= ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--max-configs=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--max-configs=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void maxConfigsTooSmall() { @@ -1549,6 +1627,14 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS("--cert-c-int-precision=12", settings->premiumArgs); } + void premiumOptionsCertCIntPrecisionInvalid() { + REDIRECT; + asPremium(); + const char * const argv[] = {"cppcheck", "--premium-cert-c-int-precision=abc", "file.c"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); + ASSERT_EQUALS("cppcheck: error: argument to '--premium-cert-c-int-precision=' is not valid - not an integer (invalid_argument).\n", logger->str()); + } + void premiumOptionsLicenseFile() { REDIRECT; asPremium(); @@ -1557,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(); @@ -1600,7 +1694,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--report-progress=", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--report-progress=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--report-progress=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void reportProgress3() { @@ -1766,9 +1860,8 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--platform=unix32-unsigned", "file.cpp"}; ASSERT(settings->platform.set(Platform::Type::Unspecified)); - ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT_EQUALS(Platform::Type::Unix32, settings->platform.type); - ASSERT_EQUALS("cppcheck: The platform 'unix32-unsigned' has been deprecated and will be removed in Cppcheck 2.19. Please use '--platform=unix32 --funsigned-char' instead\n", logger->str()); + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); + ASSERT_EQUALS("cppcheck: error: unrecognized platform: 'unix32-unsigned'.\n", logger->str()); } void platformUnix64() { @@ -1783,9 +1876,8 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--platform=unix64-unsigned", "file.cpp"}; ASSERT(settings->platform.set(Platform::Type::Unspecified)); - ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT_EQUALS(Platform::Type::Unix64, settings->platform.type); - ASSERT_EQUALS("cppcheck: The platform 'unix64-unsigned' has been deprecated and will be removed in Cppcheck 2.19. Please use '--platform=unix64 --funsigned-char' instead\n", logger->str()); + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); + ASSERT_EQUALS("cppcheck: error: unrecognized platform: 'unix64-unsigned'.\n", logger->str()); } void platformNative() { @@ -1891,30 +1983,28 @@ class TestCmdlineParser : public TestFixture { return e; } - void suppressionSingle() { + void suppressSingle() { REDIRECT; const char * const argv[] = {"cppcheck", "--suppress=uninitvar", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS(true, supprs->nomsg.isSuppressed(errorMessage("uninitvar", "file.cpp", 1))); } - void suppressionSingleFile() { + void suppressSingleFile() { REDIRECT; const char * const argv[] = {"cppcheck", "--suppress=uninitvar:file.cpp", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS(true, supprs->nomsg.isSuppressed(errorMessage("uninitvar", "file.cpp", 1U))); } - void suppressionTwo() { + void suppressTwo() { REDIRECT; const char * const argv[] = {"cppcheck", "--suppress=uninitvar,noConstructor", "file.cpp"}; - TODO_ASSERT_EQUALS(static_cast(CmdLineParser::Result::Success), static_cast(CmdLineParser::Result::Fail), static_cast(parseFromArgs(argv))); - TODO_ASSERT_EQUALS(true, false, supprs->nomsg.isSuppressed(errorMessage("uninitvar", "file.cpp", 1U))); - TODO_ASSERT_EQUALS(true, false, supprs->nomsg.isSuppressed(errorMessage("noConstructor", "file.cpp", 1U))); - TODO_ASSERT_EQUALS("", "cppcheck: error: Failed to add suppression. Invalid id \"uninitvar,noConstructor\"\n", logger->str()); + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); + ASSERT_EQUALS("cppcheck: error: Failed to add suppression. Invalid id \"uninitvar,noConstructor\"\n", logger->str()); } - void suppressionTwoSeparate() { + void suppressTwoSeparate() { REDIRECT; const char * const argv[] = {"cppcheck", "--suppress=uninitvar", "--suppress=noConstructor", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); @@ -1922,6 +2012,35 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS(true, supprs->nomsg.isSuppressed(errorMessage("noConstructor", "file.cpp", 1U))); } + void exitcodeSuppressSingle() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--exitcode-suppress=uninitvar", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS(true, supprs->nofail.isSuppressed(errorMessage("uninitvar", "file.cpp", 1))); + } + + void exitcodeSuppressSingleFile() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--exitcode-suppress=uninitvar:file.cpp", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS(true, supprs->nofail.isSuppressed(errorMessage("uninitvar", "file.cpp", 1U))); + } + + void exitcodeSuppressTwo() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--exitcode-suppress=uninitvar,noConstructor", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); + ASSERT_EQUALS("cppcheck: error: Failed to add suppression. Invalid id \"uninitvar,noConstructor\"\n", logger->str()); + } + + void exitcodeSuppressTwoSeparate() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--exitcode-suppress=uninitvar", "--exitcode-suppress=noConstructor", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS(true, supprs->nofail.isSuppressed(errorMessage("uninitvar", "file.cpp", 1U))); + ASSERT_EQUALS(true, supprs->nofail.isSuppressed(errorMessage("noConstructor", "file.cpp", 1U))); + } + void templates() { REDIRECT; const char * const argv[] = {"cppcheck", "--template={file}:{line},{severity},{id},{message}", "--template-location={file}:{line}:{column} {info}", "file.cpp"}; @@ -2075,7 +2194,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "--xml", "--xml-version=a", "file.cpp"}; // FAils since unknown XML format version ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--xml-version=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--xml-version=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void doc() { @@ -2096,21 +2215,21 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--showtime=summary", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT(settings->showtime == SHOWTIME_MODES::SHOWTIME_SUMMARY); + ASSERT_EQUALS_ENUM(Settings::ShowTime::SUMMARY, settings->showtime); } void showtimeFile() { REDIRECT; const char * const argv[] = {"cppcheck", "--showtime=file", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT(settings->showtime == SHOWTIME_MODES::SHOWTIME_FILE); + ASSERT_EQUALS_ENUM(Settings::ShowTime::FILE, settings->showtime); } void showtimeFileTotal() { REDIRECT; const char * const argv[] = {"cppcheck", "--showtime=file-total", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT(settings->showtime == SHOWTIME_MODES::SHOWTIME_FILE_TOTAL); + ASSERT_EQUALS_ENUM(Settings::ShowTime::FILE_TOTAL, settings->showtime); } void showtimeTop5() { @@ -2124,21 +2243,21 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--showtime=top5_file", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT(settings->showtime == SHOWTIME_MODES::SHOWTIME_TOP5_FILE); + ASSERT_EQUALS_ENUM(Settings::ShowTime::TOP5_FILE, settings->showtime); } void showtimeTop5Summary() { REDIRECT; const char * const argv[] = {"cppcheck", "--showtime=top5_summary", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT(settings->showtime == SHOWTIME_MODES::SHOWTIME_TOP5_SUMMARY); + ASSERT_EQUALS_ENUM(Settings::ShowTime::TOP5_SUMMARY, settings->showtime); } void showtimeNone() { REDIRECT; const char * const argv[] = {"cppcheck", "--showtime=none", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT(settings->showtime == SHOWTIME_MODES::SHOWTIME_NONE); + ASSERT_EQUALS_ENUM(Settings::ShowTime::NONE, settings->showtime); } void showtimeEmpty() { @@ -2159,8 +2278,8 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--errorlist"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Exit, parseFromArgs(argv)); - ASSERT_EQUALS("", logger->str()); // empty since it is logged via ErrorLogger const std::string errout_s = GET_REDIRECT_OUTPUT; + ASSERT_EQUALS("", logger->str()); // empty since it is logged via ErrorLogger ASSERT(startsWith(errout_s, ErrorMessage::getXMLHeader(""))); ASSERT(endsWith(errout_s, "\n")); } @@ -2171,29 +2290,23 @@ class TestCmdlineParser : public TestFixture { R"({"productName": "The Product"}\n)"); const char * const argv[] = {"cppcheck", "--errorlist"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Exit, parseFromArgs(argv)); + const std::string errout_s = GET_REDIRECT_OUTPUT; + ASSERT_EQUALS(1, settings->settingsFiles.size()); + ASSERT_EQUALS(file.path(), *settings->settingsFiles.cbegin()); ASSERT_EQUALS("", logger->str()); // empty since it is logged via ErrorLogger - ASSERT(startsWith(GET_REDIRECT_OUTPUT, ErrorMessage::getXMLHeader("The Product"))); + ASSERT(startsWith(errout_s, ErrorMessage::getXMLHeader("The Product"))); } void errorlistExclusive() { REDIRECT; const char * const argv[] = {"cppcheck", "--library=missing", "--errorlist"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Exit, parseFromArgs(argv)); - ASSERT_EQUALS("", logger->str()); // empty since it is logged via ErrorLogger const std::string errout_s = GET_REDIRECT_OUTPUT; + ASSERT_EQUALS("", logger->str()); // empty since it is logged via ErrorLogger ASSERT(startsWith(errout_s, ErrorMessage::getXMLHeader(""))); ASSERT(endsWith(errout_s, "\n")); } - void errorlistWithInvalidCfg() { - REDIRECT; - ScopedFile file(Path::join(Path::getPathFromFilename(Path::getCurrentExecutablePath("")), "cppcheck.cfg"), - "{\n"); - const char * const argv[] = {"cppcheck", "--errorlist"}; - ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: could not load cppcheck.cfg - not a valid JSON - syntax error at line 2 near: \n", logger->str()); - } - void ignorepathsnopath() { REDIRECT; const char * const argv[] = {"cppcheck", "-i"}; @@ -2304,7 +2417,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--valueflow-max-iterations=seven"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--valueflow-max-iterations=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--valueflow-max-iterations=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void valueFlowMaxIterationsInvalid3() { @@ -2332,7 +2445,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--checks-max-time=one", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--checks-max-time=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--checks-max-time=' is not valid - not an integer (invalid_argument).\n", logger->str()); } #ifdef HAS_THREADING_MODEL_FORK @@ -2354,7 +2467,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "-l", "one", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '-l' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '-l' is not valid - not an integer (invalid_argument).\n", logger->str()); } #else void loadAverageNotSupported() { @@ -2391,7 +2504,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--max-ctu-depth=one", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--max-ctu-depth=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--max-ctu-depth=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void performanceValueflowMaxTime() { @@ -2405,7 +2518,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--performance-valueflow-max-time=one", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--performance-valueflow-max-time=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--performance-valueflow-max-time=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void performanceValueFlowMaxIfCount() { @@ -2419,7 +2532,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--performance-valueflow-max-if-count=one", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--performance-valueflow-max-if-count=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--performance-valueflow-max-if-count=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void templateMaxTime() { @@ -2433,7 +2546,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--template-max-time=one", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--template-max-time=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--template-max-time=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void templateMaxTimeInvalid2() { @@ -2454,7 +2567,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--typedef-max-time=one", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--typedef-max-time=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--typedef-max-time=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void typedefMaxTimeInvalid2() { @@ -2474,8 +2587,8 @@ class TestCmdlineParser : public TestFixture { ""); const char * const argv[] = {"cppcheck", "--project=project.cppcheck"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT_EQUALS(1, parser->getPathNames().size()); - auto it = parser->getPathNames().cbegin(); + ASSERT_EQUALS(1, parser->mPathNames.size()); + auto it = parser->mPathNames.cbegin(); ASSERT_EQUALS("dir", *it); } @@ -2584,6 +2697,13 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); ASSERT_EQUALS("cppcheck: error: no rule pattern provided.\n", logger->str()); } + + void ruleInvalidPattern() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--rule=.*\\", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("cppcheck: error: failed to compile rule pattern '.*\\' (\\ at end of pattern).\n", logger->str()); + } #else void ruleNotSupported() { REDIRECT; @@ -2599,6 +2719,7 @@ class TestCmdlineParser : public TestFixture { ScopedFile file("rule.xml", "\n" "\n" + "pcre\n" "raw\n" ".+\n" "\n" @@ -2621,12 +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->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->regex->engine()); ASSERT_EQUALS("define", it->tokenlist); ASSERT_EQUALS(".*", it->pattern); ASSERT_EQUALS_ENUM(Severity::warning, it->severity); @@ -2650,6 +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->regex->engine()); ASSERT_EQUALS("define", it->tokenlist); ASSERT_EQUALS(".+", it->pattern); ASSERT_EQUALS_ENUM(Severity::error, it->severity); @@ -2808,6 +2932,29 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); ASSERT_EQUALS("cppcheck: error: unable to load rule-file 'rule.xml' - a rule has an invalid severity.\n", logger->str()); } + + void ruleFileInvalidPattern() { + REDIRECT; + ScopedFile file("rule.xml", + "\n" + ".+\\\n" + "\n"); + const char * const argv[] = {"cppcheck", "--rule-file=rule.xml", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("cppcheck: error: unable to load rule-file 'rule.xml' - pattern '.+\\' failed to compile (\\ at end of pattern).\n", logger->str()); + } + + void ruleFileInvalidEngine() { + REDIRECT; + ScopedFile file("rule.xml", + "\n" + "llvm\n" + ".+\n" + "\n"); + const char * const argv[] = {"cppcheck", "--rule-file=rule.xml", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); + ASSERT_EQUALS("cppcheck: error: unknown regex engine 'llvm'.\n", logger->str()); + } #else void ruleFileNotSupported() { REDIRECT; @@ -3058,16 +3205,16 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--debug-lookup", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT_EQUALS(true, settings->debuglookup); GET_REDIRECT_OUTPUT; // ignore config lookup output + ASSERT_EQUALS(true, settings->debuglookup); } void debugLookupAll() { REDIRECT; const char * const argv[] = {"cppcheck", "--debug-lookup=all", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT_EQUALS(true, settings->debuglookup); GET_REDIRECT_OUTPUT; // ignore config lookup output + ASSERT_EQUALS(true, settings->debuglookup); } void debugLookupAddon() { @@ -3081,8 +3228,8 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--debug-lookup=config", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT_EQUALS(true, settings->debuglookupConfig); GET_REDIRECT_OUTPUT; // ignore config lookup output + ASSERT_EQUALS(true, settings->debuglookupConfig); } void debugLookupLibrary() { @@ -3110,7 +3257,7 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "--max-template-recursion=", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--max-template-recursion=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--max-template-recursion=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void emitDuplicates() { @@ -3151,21 +3298,21 @@ class TestCmdlineParser : public TestFixture { void checkHeaders() { REDIRECT; const char * const argv[] = {"cppcheck", "--check-headers", "file.cpp"}; - ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS(true, settings->checkHeaders); } void noCheckHeaders() { REDIRECT; const char * const argv[] = {"cppcheck", "--no-check-headers", "file.cpp"}; - ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS(false, settings->checkHeaders); } void noCheckHeaders2() { REDIRECT; const char * const argv[] = {"cppcheck", "--check-headers", "--no-check-headers", "file.cpp"}; - ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(4, argv)); + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS(false, settings->checkHeaders); } @@ -3183,28 +3330,28 @@ class TestCmdlineParser : public TestFixture { void checkUnusedTemplates() { REDIRECT; const char * const argv[] = {"cppcheck", "--check-unused-templates", "file.cpp"}; - ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS(true, settings->checkUnusedTemplates); } void noCheckUnusedTemplates() { REDIRECT; const char * const argv[] = {"cppcheck", "--no-check-unused-templates", "file.cpp"}; - ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs( argv)); ASSERT_EQUALS(false, settings->checkUnusedTemplates); } void noCheckUnusedTemplates2() { REDIRECT; const char * const argv[] = {"cppcheck", "--check-unused-templates", "--no-check-unused-templates", "file.cpp"}; - ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(4, argv)); + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS(false, settings->checkUnusedTemplates); } void clangTidy() { REDIRECT; const char * const argv[] = {"cppcheck", "--clang-tidy", "file.cpp"}; - ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT(settings->clangTidy); ASSERT_EQUALS("clang-tidy", settings->clangTidyExecutable); } @@ -3212,7 +3359,7 @@ class TestCmdlineParser : public TestFixture { void clangTidyCustom() { REDIRECT; const char * const argv[] = {"cppcheck", "--clang-tidy=clang-tidy-14", "file.cpp"}; - ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT(settings->clangTidy); ASSERT_EQUALS("clang-tidy-14", settings->clangTidyExecutable); } @@ -3320,86 +3467,128 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS(true, settings->debugsymdb); } + void safety() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--safety", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS(true, settings->safety); + } + + void safetyOverride() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--no-safety", "--safety", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS(true, settings->safety); + } + + void noSafety() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--no-safety", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS(false, settings->safety); + } + + void noSafetyOverride() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--safety", "--no-safety", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS(false, settings->safety); + } + + void debugAnalyzerinfo() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--debug-analyzerinfo", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS(true, settings->debugainfo); + } + + void debugIpc() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--debug-ipc", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS(true, settings->debugipc); + } + void ignorepaths1() { REDIRECT; const char * const argv[] = {"cppcheck", "-isrc", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); - ASSERT_EQUALS("src", parser->getIgnoredPaths()[0]); - ASSERT_EQUALS(1, parser->getPathNames().size()); - ASSERT_EQUALS("file.cpp", parser->getPathNames()[0]); + ASSERT_EQUALS(1, parser->mIgnoredPaths.size()); + ASSERT_EQUALS("src", parser->mIgnoredPaths[0]); + ASSERT_EQUALS(1, parser->mPathNames.size()); + ASSERT_EQUALS("file.cpp", parser->mPathNames[0]); } void ignorepaths2() { REDIRECT; const char * const argv[] = {"cppcheck", "-i", "src", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); - ASSERT_EQUALS("src", parser->getIgnoredPaths()[0]); - ASSERT_EQUALS(1, parser->getPathNames().size()); - ASSERT_EQUALS("file.cpp", parser->getPathNames()[0]); + ASSERT_EQUALS(1, parser->mIgnoredPaths.size()); + ASSERT_EQUALS("src", parser->mIgnoredPaths[0]); + ASSERT_EQUALS(1, parser->mPathNames.size()); + ASSERT_EQUALS("file.cpp", parser->mPathNames[0]); } void ignorepaths3() { REDIRECT; const char * const argv[] = {"cppcheck", "-isrc", "-imodule", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT_EQUALS(2, parser->getIgnoredPaths().size()); - ASSERT_EQUALS("src", parser->getIgnoredPaths()[0]); - ASSERT_EQUALS("module", parser->getIgnoredPaths()[1]); - ASSERT_EQUALS(1, parser->getPathNames().size()); - ASSERT_EQUALS("file.cpp", parser->getPathNames()[0]); + ASSERT_EQUALS(2, parser->mIgnoredPaths.size()); + ASSERT_EQUALS("src", parser->mIgnoredPaths[0]); + ASSERT_EQUALS("module", parser->mIgnoredPaths[1]); + ASSERT_EQUALS(1, parser->mPathNames.size()); + ASSERT_EQUALS("file.cpp", parser->mPathNames[0]); } void ignorepaths4() { REDIRECT; const char * const argv[] = {"cppcheck", "-i", "src", "-i", "module", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT_EQUALS(2, parser->getIgnoredPaths().size()); - ASSERT_EQUALS("src", parser->getIgnoredPaths()[0]); - ASSERT_EQUALS("module", parser->getIgnoredPaths()[1]); - ASSERT_EQUALS(1, parser->getPathNames().size()); - ASSERT_EQUALS("file.cpp", parser->getPathNames()[0]); + ASSERT_EQUALS(2, parser->mIgnoredPaths.size()); + ASSERT_EQUALS("src", parser->mIgnoredPaths[0]); + ASSERT_EQUALS("module", parser->mIgnoredPaths[1]); + ASSERT_EQUALS(1, parser->mPathNames.size()); + ASSERT_EQUALS("file.cpp", parser->mPathNames[0]); } void ignorefilepaths1() { REDIRECT; const char * const argv[] = {"cppcheck", "-ifoo.cpp", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); - ASSERT_EQUALS("foo.cpp", parser->getIgnoredPaths()[0]); - ASSERT_EQUALS(1, parser->getPathNames().size()); - ASSERT_EQUALS("file.cpp", parser->getPathNames()[0]); + ASSERT_EQUALS(1, parser->mIgnoredPaths.size()); + ASSERT_EQUALS("foo.cpp", parser->mIgnoredPaths[0]); + ASSERT_EQUALS(1, parser->mPathNames.size()); + ASSERT_EQUALS("file.cpp", parser->mPathNames[0]); } void ignorefilepaths2() { REDIRECT; const char * const argv[] = {"cppcheck", "-isrc/foo.cpp", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); - ASSERT_EQUALS("src/foo.cpp", parser->getIgnoredPaths()[0]); - ASSERT_EQUALS(1, parser->getPathNames().size()); - ASSERT_EQUALS("file.cpp", parser->getPathNames()[0]); + ASSERT_EQUALS(1, parser->mIgnoredPaths.size()); + ASSERT_EQUALS("src/foo.cpp", parser->mIgnoredPaths[0]); + ASSERT_EQUALS(1, parser->mPathNames.size()); + ASSERT_EQUALS("file.cpp", parser->mPathNames[0]); } void ignorefilepaths3() { REDIRECT; const char * const argv[] = {"cppcheck", "-i", "foo.cpp", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); - ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); - ASSERT_EQUALS("foo.cpp", parser->getIgnoredPaths()[0]); - ASSERT_EQUALS(1, parser->getPathNames().size()); - ASSERT_EQUALS("file.cpp", parser->getPathNames()[0]); + ASSERT_EQUALS(1, parser->mIgnoredPaths.size()); + ASSERT_EQUALS("foo.cpp", parser->mIgnoredPaths[0]); + ASSERT_EQUALS(1, parser->mPathNames.size()); + ASSERT_EQUALS("file.cpp", parser->mPathNames[0]); } void ignorefilepaths4() { REDIRECT; const char * const argv[] = {"cppcheck", "-ifoo.cpp", "file.cpp"}; ASSERT(!fillSettingsFromArgs(argv)); - ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); - ASSERT_EQUALS("foo.cpp", parser->getIgnoredPaths()[0]); - ASSERT_EQUALS(1, parser->getPathNames().size()); - ASSERT_EQUALS("file.cpp", parser->getPathNames()[0]); + ASSERT_EQUALS(1, parser->mIgnoredPaths.size()); + ASSERT_EQUALS("foo.cpp", parser->mIgnoredPaths[0]); + ASSERT_EQUALS(1, parser->mPathNames.size()); + ASSERT_EQUALS("file.cpp", parser->mPathNames[0]); TODO_ASSERT_EQUALS("cppcheck: error: could not find or open any of the paths given.\n", "cppcheck: error: could not find or open any of the paths given.\ncppcheck: Maybe all paths were ignored?\n", logger->str()); } @@ -3407,10 +3596,10 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "-ifile.cpp", "file.cpp"}; ASSERT(!fillSettingsFromArgs(argv)); - ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); - ASSERT_EQUALS("file.cpp", parser->getIgnoredPaths()[0]); - ASSERT_EQUALS(1, parser->getPathNames().size()); - ASSERT_EQUALS("file.cpp", parser->getPathNames()[0]); + ASSERT_EQUALS(1, parser->mIgnoredPaths.size()); + ASSERT_EQUALS("file.cpp", parser->mIgnoredPaths[0]); + ASSERT_EQUALS(1, parser->mPathNames.size()); + ASSERT_EQUALS("file.cpp", parser->mPathNames[0]); ASSERT_EQUALS("cppcheck: error: could not find or open any of the paths given.\ncppcheck: Maybe all paths were ignored?\n", logger->str()); } @@ -3418,10 +3607,10 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "-isrc/file.cpp", "src/file.cpp"}; ASSERT(!fillSettingsFromArgs(argv)); - ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); - ASSERT_EQUALS("src/file.cpp", parser->getIgnoredPaths()[0]); - ASSERT_EQUALS(1, parser->getPathNames().size()); - ASSERT_EQUALS("src/file.cpp", parser->getPathNames()[0]); + ASSERT_EQUALS(1, parser->mIgnoredPaths.size()); + ASSERT_EQUALS("src/file.cpp", parser->mIgnoredPaths[0]); + ASSERT_EQUALS(1, parser->mPathNames.size()); + ASSERT_EQUALS("src/file.cpp", parser->mPathNames[0]); ASSERT_EQUALS("cppcheck: error: could not find or open any of the paths given.\ncppcheck: Maybe all paths were ignored?\n", logger->str()); } @@ -3429,10 +3618,10 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "-isrc\\file.cpp", "src/file.cpp"}; ASSERT(!fillSettingsFromArgs(argv)); - ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); - ASSERT_EQUALS("src/file.cpp", parser->getIgnoredPaths()[0]); - ASSERT_EQUALS(1, parser->getPathNames().size()); - ASSERT_EQUALS("src/file.cpp", parser->getPathNames()[0]); + ASSERT_EQUALS(1, parser->mIgnoredPaths.size()); + ASSERT_EQUALS("src/file.cpp", parser->mIgnoredPaths[0]); + ASSERT_EQUALS(1, parser->mPathNames.size()); + ASSERT_EQUALS("src/file.cpp", parser->mPathNames[0]); ASSERT_EQUALS("cppcheck: error: could not find or open any of the paths given.\ncppcheck: Maybe all paths were ignored?\n", logger->str()); } @@ -3440,10 +3629,10 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "-isrc/file.cpp", "src\\file.cpp"}; ASSERT(!fillSettingsFromArgs(argv)); - ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); - ASSERT_EQUALS("src/file.cpp", parser->getIgnoredPaths()[0]); - ASSERT_EQUALS(1, parser->getPathNames().size()); - ASSERT_EQUALS("src/file.cpp", parser->getPathNames()[0]); + ASSERT_EQUALS(1, parser->mIgnoredPaths.size()); + ASSERT_EQUALS("src/file.cpp", parser->mIgnoredPaths[0]); + ASSERT_EQUALS(1, parser->mPathNames.size()); + ASSERT_EQUALS("src/file.cpp", parser->mPathNames[0]); ASSERT_EQUALS("cppcheck: error: could not find or open any of the paths given.\ncppcheck: Maybe all paths were ignored?\n", logger->str()); } @@ -3451,10 +3640,10 @@ class TestCmdlineParser : public TestFixture { REDIRECT; const char * const argv[] = {"cppcheck", "-isrc\\", "src\\file.cpp"}; ASSERT(!fillSettingsFromArgs(argv)); - ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); - ASSERT_EQUALS("src/", parser->getIgnoredPaths()[0]); - ASSERT_EQUALS(1, parser->getPathNames().size()); - ASSERT_EQUALS("src/file.cpp", parser->getPathNames()[0]); + ASSERT_EQUALS(1, parser->mIgnoredPaths.size()); + ASSERT_EQUALS("src/", parser->mIgnoredPaths[0]); + ASSERT_EQUALS(1, parser->mPathNames.size()); + ASSERT_EQUALS("src/file.cpp", parser->mPathNames[0]); ASSERT_EQUALS("cppcheck: error: could not find or open any of the paths given.\ncppcheck: Maybe all paths were ignored?\n", logger->str()); } diff --git a/test/testcondition.cpp b/test/testcondition.cpp index d1b7137377f..6d62b644043 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,7 +24,6 @@ #include "settings.h" #include -#include #include class TestCondition : public TestFixture { @@ -95,6 +94,8 @@ class TestCondition : public TestFixture { TEST_CASE(identicalConditionAfterEarlyExit); TEST_CASE(innerConditionModified); + TEST_CASE(overlappingInnerCondition); + TEST_CASE(clarifyCondition1); // if (a = b() < 0) TEST_CASE(clarifyCondition2); // if (a & b == c) TEST_CASE(clarifyCondition3); // if (! a & b) @@ -110,6 +111,8 @@ class TestCondition : public TestFixture { TEST_CASE(alwaysTrueContainer); TEST_CASE(alwaysTrueLoop); TEST_CASE(alwaysTrueTryCatch); + TEST_CASE(alwaysTrueSideEffect); + TEST_CASE(alwaysTruePremiumMisra); TEST_CASE(multiConditionAlwaysTrue); TEST_CASE(duplicateCondition); @@ -130,24 +133,24 @@ class TestCondition : public TestFixture { struct CheckOptions { - CheckOptions() = default; - const Settings* s = nullptr; bool cpp = true; - bool inconclusive = false; }; #define check(...) check_(__FILE__, __LINE__, __VA_ARGS__) template void check_(const char* file, int line, const char (&code)[size], const CheckOptions& options = make_default_obj()) { - const Settings settings = settingsBuilder(options.s ? *options.s : settings0).certainty(Certainty::inconclusive, options.inconclusive).build(); + check_(file, line, code, settings0, options.cpp); + } - SimpleTokenizer2 tokenizer(settings, *this, code, options.cpp ? "test.cpp" : "test.c"); + template + void check_(const char* file, int line, const char (&code)[size], const Settings& settings, bool cpp = true) { + SimpleTokenizer2 tokenizer(settings, *this, code, cpp ? "test.cpp" : "test.c"); // Tokenizer.. ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); - // Run checks.. - runChecks(tokenizer, this); + CheckCondition check; + runChecks(check, tokenizer, *this); } #define checkP(...) checkP_(__FILE__, __LINE__, __VA_ARGS__) @@ -159,8 +162,8 @@ class TestCondition : public TestFixture { // Tokenizer.. ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); - // Run checks.. - runChecks(tokenizer, this); + CheckCondition check; + runChecks(check, tokenizer, *this); } void assignAndCompare() { @@ -169,59 +172,59 @@ class TestCondition : public TestFixture { "{\n" " int y = x & 4;\n" " if (y == 3);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:4:8]: (style) Mismatching assignment and comparison, comparison 'y==3' is always false. [assignIfError]\n", errout_str()); check("void foo(int x)\n" "{\n" " int y = x & 4;\n" " if (y != 3);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:4:8]: (style) Mismatching assignment and comparison, comparison 'y!=3' is always true. [assignIfError]\n", errout_str()); // | check("void foo(int x) {\n" " int y = x | 0x14;\n" " if (y == 0x710);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:8]: (style) Mismatching assignment and comparison, comparison 'y==0x710' is always false. [assignIfError]\n", errout_str()); check("void foo(int x) {\n" " int y = x | 0x14;\n" " if (y == 0x71f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // various simple assignments check("void foo(int x) {\n" " int y = (x+1) | 1;\n" " if (y == 2);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:8]: (style) Mismatching assignment and comparison, comparison 'y==2' is always false. [assignIfError]\n", errout_str()); check("void foo() {\n" " int y = 1 | x();\n" " if (y == 2);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:8]: (style) Mismatching assignment and comparison, comparison 'y==2' is always false. [assignIfError]\n", errout_str()); // multiple conditions check("void foo(int x) {\n" " int y = x & 4;\n" " if ((y == 3) && (z == 1));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:9]: (style) Mismatching assignment and comparison, comparison 'y==3' is always false. [assignIfError]\n", errout_str()); check("void foo(int x) {\n" " int y = x & 4;\n" " if ((x==123) || ((y == 3) && (z == 1)));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:22]: (style) Mismatching assignment and comparison, comparison 'y==3' is always false. [assignIfError]\n", errout_str()); check("void f(int x) {\n" " int y = x & 7;\n" " if (setvalue(&y) && y != 8);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // recursive checking into scopes @@ -229,20 +232,20 @@ class TestCondition : public TestFixture { " int y = x & 7;\n" " if (z) y=0;\n" " else { if (y==8); }\n" // always false - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:4:15]: (style) Mismatching assignment and comparison, comparison 'y==8' is always false. [assignIfError]\n", errout_str()); // while check("void f(int x) {\n" " int y = x & 7;\n" " while (y==8);\n" // local variable => always false - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:11]: (style) Mismatching assignment and comparison, comparison 'y==8' is always false. [assignIfError]\n", errout_str()); check("void f(int x) {\n" " extern int y; y = x & 7;\n" " while (y==8);\n" // non-local variable => no error - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" @@ -251,7 +254,7 @@ class TestCondition : public TestFixture { " int y = 16 | a;\n" " while (y != 0) y--;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void g(int x);\n" @@ -261,7 +264,7 @@ class TestCondition : public TestFixture { " int y = 16 | a;\n" " while (y != 0) g(y);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:5:15] -> [test.cpp:6:15]: (style) Mismatching assignment and comparison, comparison 'y!=0' is always true. [assignIfError]\n", errout_str()); @@ -273,7 +276,7 @@ class TestCondition : public TestFixture { " int y = 16 | a;\n" " while (y != 0) g(y);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // calling function @@ -281,14 +284,14 @@ class TestCondition : public TestFixture { " int y = x & 7;\n" " do_something();\n" " if (y==8);\n" // local variable => always false - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:4:8]: (style) Mismatching assignment and comparison, comparison 'y==8' is always false. [assignIfError]\n", errout_str()); check("void f(int x) {\n" " int y = x & 7;\n" " do_something(&y);\n" // passing variable => no error " if (y==8);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void do_something(int);\n" @@ -296,14 +299,14 @@ class TestCondition : public TestFixture { " int y = x & 7;\n" " do_something(y);\n" " if (y==8);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:5:8]: (style) Mismatching assignment and comparison, comparison 'y==8' is always false. [assignIfError]\n", errout_str()); check("void f(int x) {\n" " extern int y; y = x & 7;\n" " do_something();\n" " if (y==8);\n" // non-local variable => no error - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #4434 : false positive: ?: @@ -311,28 +314,28 @@ class TestCondition : public TestFixture { " x = x & 1;\n" " x = x & 1 ? 1 : -1;\n" " if(x != -1) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #4735 check("void f() {\n" " int x = *(char*)&0x12345678;\n" " if (x==18) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // bailout: no variable info check("void foo(int x) {\n" " y = 2 | x;\n" // y not declared => no error " if(y == 1) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // bailout: negative number check("void foo(int x) {\n" " int y = -2 | x;\n" // negative number => no error " if (y==1) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // bailout: pass variable to function @@ -340,7 +343,7 @@ class TestCondition : public TestFixture { " int y = 2 | x;\n" " bar(&y);\n" // pass variable to function => no error " if (y==1) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // no crash on unary operator& (#5643) @@ -348,7 +351,7 @@ class TestCondition : public TestFixture { check("SdrObject* ApplyGraphicToObject() {\n" " if (&rHitObject) {}\n" " else if (rHitObject.IsClosedObj() && !&rHitObject) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) Condition '&rHitObject' is always true [knownConditionTrueFalse]\n" "[test.cpp:3:42]: (style) Condition '!&rHitObject' is always false [knownConditionTrueFalse]\n", errout_str()); @@ -361,7 +364,7 @@ class TestCondition : public TestFixture { " if (c == 4)\n" " c = 0;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int a) {\n" // #6662 @@ -369,7 +372,7 @@ class TestCondition : public TestFixture { " while (x <= 4) {\n" " if (x != 5) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:4:8]: (style) Mismatching assignment and comparison, comparison 'x!=5' is always true. [assignIfError]\n", errout_str()); check("void f(int a) {\n" // #6662 @@ -377,7 +380,7 @@ class TestCondition : public TestFixture { " while ((x += 4) < 10) {\n" " if (x != 5) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -385,7 +388,7 @@ class TestCondition : public TestFixture { " while (x) {\n" " g(x);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void g(int x);\n" @@ -394,7 +397,7 @@ class TestCondition : public TestFixture { " while (x) {\n" " g(x);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:12]: (style) Condition 'x' is always true [knownConditionTrueFalse]\n", errout_str()); check("void g(int & x);\n" @@ -403,7 +406,7 @@ class TestCondition : public TestFixture { " while (x) {\n" " g(x);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -412,13 +415,13 @@ class TestCondition : public TestFixture { check("void f(int a) {\n" " int b = a & 0xf0;\n" " b &= 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:5]: (style) Mismatching bitmasks. Result is always 0 (X = Y & 0xf0; Z = X & 0x1; => Z=0). [mismatchingBitAnd]\n", errout_str()); check("void f(int a) {\n" " int b = a & 0xf0;\n" " int c = b & 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:9]: (style) Mismatching bitmasks. Result is always 0 (X = Y & 0xf0; Z = X & 0x1; => Z=0). [mismatchingBitAnd]\n", errout_str()); check("void f(int a) {\n" @@ -427,67 +430,67 @@ class TestCondition : public TestFixture { " case 1: b &= 1; break;\n" " case 2: b &= 2; break;\n" " };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void comparison() { // CheckCondition::comparison test cases // '==' - check("void f(int a) {\n assert( (a & 0x07) == 8U );\n}"); + check("void f(int a) {\n assert( (a & 0x07) == 8U );\n}\n"); ASSERT_EQUALS("[test.cpp:2:13]: (style) Expression '(X & 0x7) == 0x8' is always false. [comparisonError]\n",errout_str()); - check("void f(int a) {\n assert( (a & b & 4 & c ) == 3 );\n}"); + check("void f(int a) {\n assert( (a & b & 4 & c ) == 3 );\n}\n"); ASSERT_EQUALS("[test.cpp:2:21]: (style) Expression '(X & 0x4) == 0x3' is always false. [comparisonError]\n", errout_str()); - check("void f(int a) {\n assert( (a | 0x07) == 8U );\n}"); + check("void f(int a) {\n assert( (a | 0x07) == 8U );\n}\n"); ASSERT_EQUALS("[test.cpp:2:13]: (style) Expression '(X | 0x7) == 0x8' is always false. [comparisonError]\n",errout_str()); - check("void f(int a) {\n assert( (a & 0x07) == 7U );\n}"); + check("void f(int a) {\n assert( (a & 0x07) == 7U );\n}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(int a) {\n assert( (a | 0x01) == -15 );\n}"); + check("void f(int a) {\n assert( (a | 0x01) == -15 );\n}\n"); ASSERT_EQUALS("", errout_str()); // '!=' - check("void f(int a) {\n assert( (a & 0x07) != 8U );\n}"); + check("void f(int a) {\n assert( (a & 0x07) != 8U );\n}\n"); ASSERT_EQUALS("[test.cpp:2:13]: (style) Expression '(X & 0x7) != 0x8' is always true. [comparisonError]\n",errout_str()); - check("void f(int a) {\n assert( (a | 0x07) != 8U );\n}"); + check("void f(int a) {\n assert( (a | 0x07) != 8U );\n}\n"); ASSERT_EQUALS("[test.cpp:2:13]: (style) Expression '(X | 0x7) != 0x8' is always true. [comparisonError]\n",errout_str()); - check("void f(int a) {\n assert( (a & 0x07) != 7U );\n}"); + check("void f(int a) {\n assert( (a & 0x07) != 7U );\n}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(int a) {\n assert( (a | 0x07) != 7U );\n}"); + check("void f(int a) {\n assert( (a | 0x07) != 7U );\n}\n"); ASSERT_EQUALS("", errout_str()); // '>=' - check("void f(int a) {\n assert( (a & 0x07) >= 8U );\n}"); + check("void f(int a) {\n assert( (a & 0x07) >= 8U );\n}\n"); ASSERT_EQUALS("[test.cpp:2:13]: (style) Expression '(X & 0x7) >= 0x8' is always false. [comparisonError]\n",errout_str()); - check("void f(unsigned int a) {\n assert( (a | 0x7) >= 7U );\n}"); + check("void f(unsigned int a) {\n assert( (a | 0x7) >= 7U );\n}\n"); ASSERT_EQUALS("[test.cpp:2:13]: (style) Expression '(X | 0x7) >= 0x7' is always true. [comparisonError]\n",errout_str()); - check("void f(int a) {\n assert( (a & 0x07) >= 7U );\n}"); + check("void f(int a) {\n assert( (a & 0x07) >= 7U );\n}\n"); ASSERT_EQUALS("",errout_str()); - check("void f(int a) {\n assert( (a | 0x07) >= 8U );\n}"); + check("void f(int a) {\n assert( (a | 0x07) >= 8U );\n}\n"); ASSERT_EQUALS("",errout_str()); //correct for negative 'a' // '>' - check("void f(int a) {\n assert( (a & 0x07) > 7U );\n}"); + check("void f(int a) {\n assert( (a & 0x07) > 7U );\n}\n"); ASSERT_EQUALS("[test.cpp:2:13]: (style) Expression '(X & 0x7) > 0x7' is always false. [comparisonError]\n",errout_str()); - check("void f(unsigned int a) {\n assert( (a | 0x7) > 6U );\n}"); + check("void f(unsigned int a) {\n assert( (a | 0x7) > 6U );\n}\n"); ASSERT_EQUALS("[test.cpp:2:13]: (style) Expression '(X | 0x7) > 0x6' is always true. [comparisonError]\n",errout_str()); - check("void f(int a) {\n assert( (a & 0x07) > 6U );\n}"); + check("void f(int a) {\n assert( (a & 0x07) > 6U );\n}\n"); ASSERT_EQUALS("",errout_str()); - check("void f(int a) {\n assert( (a | 0x07) > 7U );\n}"); + check("void f(int a) {\n assert( (a | 0x07) > 7U );\n}\n"); ASSERT_EQUALS("",errout_str()); //correct for negative 'a' // '<=' - check("void f(int a) {\n assert( (a & 0x07) <= 7U );\n}"); + check("void f(int a) {\n assert( (a & 0x07) <= 7U );\n}\n"); ASSERT_EQUALS("[test.cpp:2:13]: (style) Expression '(X & 0x7) <= 0x7' is always true. [comparisonError]\n",errout_str()); - check("void f(unsigned int a) {\n assert( (a | 0x08) <= 7U );\n}"); + check("void f(unsigned int a) {\n assert( (a | 0x08) <= 7U );\n}\n"); ASSERT_EQUALS("[test.cpp:2:13]: (style) Expression '(X | 0x8) <= 0x7' is always false. [comparisonError]\n",errout_str()); - check("void f(int a) {\n assert( (a & 0x07) <= 6U );\n}"); + check("void f(int a) {\n assert( (a & 0x07) <= 6U );\n}\n"); ASSERT_EQUALS("",errout_str()); - check("void f(int a) {\n assert( (a | 0x08) <= 7U );\n}"); + check("void f(int a) {\n assert( (a | 0x08) <= 7U );\n}\n"); ASSERT_EQUALS("",errout_str()); //correct for negative 'a' // '<' - check("void f(int a) {\n assert( (a & 0x07) < 8U );\n}"); + check("void f(int a) {\n assert( (a & 0x07) < 8U );\n}\n"); ASSERT_EQUALS("[test.cpp:2:13]: (style) Expression '(X & 0x7) < 0x8' is always true. [comparisonError]\n",errout_str()); - check("void f(unsigned int a) {\n assert( (a | 0x07) < 7U );\n}"); + check("void f(unsigned int a) {\n assert( (a | 0x07) < 7U );\n}\n"); ASSERT_EQUALS("[test.cpp:2:13]: (style) Expression '(X | 0x7) < 0x7' is always false. [comparisonError]\n",errout_str()); - check("void f(int a) {\n assert( (a & 0x07) < 3U );\n}"); + check("void f(int a) {\n assert( (a & 0x07) < 3U );\n}\n"); ASSERT_EQUALS("",errout_str()); - check("void f(int a) {\n assert( (a | 0x07) < 7U );\n}"); + check("void f(int a) {\n assert( (a | 0x07) < 7U );\n}\n"); ASSERT_EQUALS("",errout_str()); //correct for negative 'a' check("void f(int i) {\n" // #11998 @@ -517,20 +520,30 @@ class TestCondition : public TestFixture { errout_str()); } -#define checkPureFunction(code) checkPureFunction_(code, __FILE__, __LINE__) +#define checkPureFunction(...) checkPureFunction_(__FILE__, __LINE__, __VA_ARGS__) + template + void checkPureFunction_(const char* file, int line, const char (&code)[size]) { + // Tokenize.. + SimpleTokenizer tokenizer(settings1, *this); + ASSERT_LOC(tokenizer.tokenize(code), file, line); + + CheckCondition check; + runChecks(check, tokenizer, *this); + } + void multicompare() { check("void foo(int x)\n" "{\n" " if (x & 7);\n" " else { if (x == 1); }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:18]: (style) Expression is always false because 'else if' condition matches previous condition at line 3. [multiCondition]\n", errout_str()); check("void foo(int x)\n" "{\n" " if (x & 7);\n" " else { if (x & 1); }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:18]: (style) Expression is always false because 'else if' condition matches previous condition at line 3. [multiCondition]\n", errout_str()); check("extern int bar() __attribute__((pure));\n" @@ -538,7 +551,7 @@ class TestCondition : public TestFixture { "{\n" " if ( bar() >1 && b) {}\n" " else if (bar() >1 && b) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:23]: (style) Expression is always false because 'else if' condition matches previous condition at line 4. [multiCondition]\n", errout_str()); checkPureFunction("extern int bar();\n" @@ -546,14 +559,14 @@ class TestCondition : public TestFixture { "{\n" " if ( bar() >1 && b) {}\n" " else if (bar() >1 && b) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:23]: (style) Expression is always false because 'else if' condition matches previous condition at line 4. [multiCondition]\n", errout_str()); // 7284 check("void foo() {\n" " if (a) {}\n" " else if (!!a) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:14]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str()); // #11059 @@ -576,66 +589,57 @@ class TestCondition : public TestFixture { ASSERT_EQUALS("", errout_str()); } - template - void checkPureFunction_(const char (&code)[size], const char* file, int line) { - // Tokenize.. - SimpleTokenizer tokenizer(settings1, *this); - ASSERT_LOC(tokenizer.tokenize(code), file, line); - - runChecks(tokenizer, this); - } - void overlappingElseIfCondition() { check("void f(int a, int &b) {\n" " if (a) { b = 1; }\n" " else { if (a) { b = 2; } }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:16]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str()); check("void f(int a, int &b) {\n" " if (a) { b = 1; }\n" " else { if (a) { b = 2; } }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:16]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str()); check("void f(int a, int &b) {\n" " if (a == 1) { b = 1; }\n" " else { if (a == 2) { b = 2; }\n" " else { if (a == 1) { b = 3; } } }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:18]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str()); check("void f(int a, int &b) {\n" " if (a == 1) { b = 1; }\n" " else { if (a == 2) { b = 2; }\n" " else { if (a == 2) { b = 3; } } }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:18]: (style) Expression is always false because 'else if' condition matches previous condition at line 3. [multiCondition]\n", errout_str()); check("void f(int a, int &b) {\n" " if (a++) { b = 1; }\n" " else { if (a++) { b = 2; }\n" " else { if (a++) { b = 3; } } }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int a, int &b) {\n" " if (!strtok(NULL, \" \")) { b = 1; }\n" " else { if (!strtok(NULL, \" \")) { b = 2; } }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); { check("void f(Class &c) {\n" " if (c.dostuff() == 3) {}\n" " else { if (c.dostuff() == 3) {} }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(const Class &c) {\n" " if (c.dostuff() == 3) {}\n" " else { if (c.dostuff() == 3) {} }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:28]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str()); } @@ -643,13 +647,13 @@ class TestCondition : public TestFixture { " x = x / 2;\n" " if (x < 100) { b = 1; }\n" " else { x = x / 2; if (x < 100) { b = 2; } }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int64_t i) {\n" " if(i == 0x02e2000000 || i == 0xa0c6000000)\n" " foo(i);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // ticket 3689 ( avoid false positive ) @@ -671,13 +675,13 @@ class TestCondition : public TestFixture { " return -1;\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(WIDGET *widget) {\n" " if (dynamic_cast(widget)){}\n" " else if (dynamic_cast(widget)){}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class B { virtual void v() {} };\n" // #11037 @@ -694,67 +698,67 @@ class TestCondition : public TestFixture { check("void f(int x) {\n" // #6482 " if (x & 1) {}\n" " else if (x == 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" " if (x & 15) {}\n" " else if (x == 40) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:14]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str()); check("void f(int x) {\n" " if (x == sizeof(double)) {}\n" - " else { if (x == sizeof(long double)) {} }" - "}"); + " else { if (x == sizeof(long double)) {} }\n" + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" " if (x & 0x08) {}\n" " else if (x & 0xF8) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" " if (x & 0xF8) {}\n" " else if (x & 0x08) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:14]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str()); check("void f(bool a, bool b) {\n" " if(a && b){}\n" " else if( !!b && !!a){}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:17]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str()); check("void f(bool a, bool b) {\n" " if(a && b){}\n" " else if( !!b && a){}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:17]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str()); check("void f(bool a, bool b) {\n" " if(a && b){}\n" " else if( b && !!a){}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:15]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str()); check("void f(bool a, bool b) {\n" " if(a && b){}\n" " else if( b && !(!a)){}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:15]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str()); check("void f(bool a, bool b) {\n" " if(a && b){}\n" " else if( !!b && !(!a)){}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:17]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str()); check("void f(bool a, bool b) {\n" " if(a && b){}\n" " else if( !!(b) && !!(a+b)){}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #8168 @@ -766,18 +770,18 @@ class TestCondition : public TestFixture { "void TestFunction(int value) {\n" " if ( value & (int)Value1 ) {}\n" " else if ( value & (int)Value2 ) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(size_t x) {\n" " if (x == sizeof(int)) {}\n" - " else { if (x == sizeof(long))} {}\n" + " else { if (x == sizeof(long)) {} }\n" "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(size_t x) {\n" " if (x == sizeof(long)) {}\n" - " else { if (x == sizeof(long long))} {}\n" + " else { if (x == sizeof(long long)) {} }\n" "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -788,7 +792,7 @@ class TestCondition : public TestFixture { check("void f(int x) {\n" " if (x) {}\n" " else if (!x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:14]: style: Expression is always true because 'else if' condition is opposite to previous condition at line 2. [multiCondition]\n" "[test.cpp:2:9]: note: first condition\n" "[test.cpp:3:14]: note: else if condition is opposite to first condition\n", errout_str()); @@ -797,7 +801,7 @@ class TestCondition : public TestFixture { " int y = x;\n" " if (x) {}\n" " else if (!y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:14]: style: Expression is always true because 'else if' condition is opposite to previous condition at line 3. [multiCondition]\n" "[test.cpp:2:13]: note: 'y' is assigned value 'x' here.\n" "[test.cpp:3:9]: note: first condition\n" @@ -808,31 +812,31 @@ class TestCondition : public TestFixture { check("bool f(int x) {\n" " bool b = x | 0x02;\n" " return b;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:16]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str()); check("bool f(int x) {\n" " bool b = 0x02 | x;\n" " return b;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:19]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str()); check("int f(int x) {\n" " int b = x | 0x02;\n" " return b;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("bool f(int x) {\n" " bool b = x & 0x02;\n" " return b;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("bool f(int x) {\n" " if(x | 0x02)\n" " return b;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:10]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str()); check("bool f(int x) {\n" @@ -840,27 +844,27 @@ class TestCondition : public TestFixture { " if(b) y = 0;\n" " if(x | y)\n" " return b;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("bool f(int x) {\n" " foo(a && (x | 0x02));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:17]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str()); check("int f(int x) {\n" " return (x | 0x02) ? 0 : 5;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str()); check("int f(int x) {\n" " return x ? (x | 0x02) : 5;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("bool f(int x) {\n" " return x | 0x02;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:14]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str()); check("bool f(int x) {\n" @@ -868,19 +872,19 @@ class TestCondition : public TestFixture { " return x | 0x02;\n" " }\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:14]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str()); check("const bool f(int x) {\n" " return x | 0x02;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:14]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str()); check("struct F {\n" " static const bool f(int x) {\n" " return x | 0x02;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:16]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str()); check("struct F {\n" @@ -888,12 +892,12 @@ class TestCondition : public TestFixture { "};\n" "F::b_t f(int x) {\n" " return x | 0x02;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:12]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str()); check("int f(int x) {\n" " return x | 0x02;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void create_rop_masks_4( rop_mask_bits *bits) {\n" @@ -901,7 +905,7 @@ class TestCondition : public TestFixture { "BYTE *and_bits = bits->and;\n" "rop_mask *rop_mask;\n" "and_bits[mask_offset] |= (rop_mask->and & 0x0f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(unsigned a, unsigned b) {\n" @@ -909,7 +913,7 @@ class TestCondition : public TestFixture { " if (cmd1 | a) {\n" " if (b == 0x0C) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int i) {\n" // #11082 @@ -937,7 +941,7 @@ class TestCondition : public TestFixture { "#if BAR_ENABLED\n" " FEATURE_BAR |\n" "#endif\n" - " 0;"); + " 0;\n"); ASSERT_EQUALS("", errout_str()); check("enum precedence { PC0, UNARY };\n" @@ -956,84 +960,84 @@ class TestCondition : public TestFixture { check("void f(int x) {\n" " if ((x != 1) || (x != 3))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:18]: (warning) Logical disjunction always evaluates to true: x != 1 || x != 3. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (1 != x || 3 != x)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:16]: (warning) Logical disjunction always evaluates to true: x != 1 || x != 3. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (x<0 && !x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (warning) Logical conjunction always evaluates to false: x < 0 && !x. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (x==0 && x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:12]: (warning) Logical conjunction always evaluates to false: x == 0 && x. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" // ast.. " if (y == 1 && x == 1 && x == 7) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:26]: (warning) Logical conjunction always evaluates to false: x == 1 && x == 7. [incorrectLogicOperator]\n", errout_str()); check("void f(int x, int y) {\n" " if (x != 1 || y != 1)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x, int y) {\n" " if ((y == 1) && (x != 1) || (x != 3))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x, int y) {\n" " if ((x != 1) || (x != 3) && (y == 1))\n" " a++;\n" - "}" + "}\n" ); ASSERT_EQUALS("[test.cpp:2:12] -> [test.cpp:2:24]: (style) Condition 'x!=3' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f(int x) {\n" " if ((x != 1) && (x != 3))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" " if ((x == 1) || (x == 3))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x, int y) {\n" " if ((x != 1) || (y != 3))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x, int y) {\n" " if ((x != hotdog) || (y != hotdog))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x, int y) {\n" " if ((x != 5) || (y != 5))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" " if ((x != 5) || (x != 6))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:18]: (warning) Logical disjunction always evaluates to true: x != 5 || x != 6. [incorrectLogicOperator]\n", errout_str()); check("void f(unsigned int a, unsigned int b, unsigned int c) {\n" @@ -1042,7 +1046,7 @@ class TestCondition : public TestFixture { " return true;\n" " }\n" " return false;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:23] -> [test.cpp:2:35]: (style) Condition 'c!=a' is always false [knownConditionTrueFalse]\n", errout_str()); } @@ -1050,224 +1054,224 @@ class TestCondition : public TestFixture { check("void f(float x) {\n" " if ((x == 1) && (x == 1.0))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" " if ((x == 1) && (x == 0x00000001))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:12] -> [test.cpp:2:24]: (style) Condition 'x==0x00000001' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f(int x) {\n" " if (x == 1 && x == 3)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:16]: (warning) Logical conjunction always evaluates to false: x == 1 && x == 3. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (x == 1.0 && x == 3.0)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // float comparisons with == and != are not checked right now - such comparison is a bad idea check("void f(float x) {\n" " if (x == 1 && x == 1.0)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void bar(float f) {\n" // #5246 " if ((f > 0) && (f < 1)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" " if (x < 1 && x > 1)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Logical conjunction always evaluates to false: x < 1 && x > 1. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (x < 1.0 && x > 1.0)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:17]: (warning) Logical conjunction always evaluates to false: x < 1.0 && x > 1.0. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (x < 1 && x > 1.0)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Logical conjunction always evaluates to false: x < 1 && x > 1.0. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (x >= 1.0 && x <= 1.001)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" " if (x < 1 && x > 3)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Logical conjunction always evaluates to false: x < 1 && x > 3. [incorrectLogicOperator]\n", errout_str()); check("void f(float x) {\n" " if (x < 1.0 && x > 3.0)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:17]: (warning) Logical conjunction always evaluates to false: x < 1.0 && x > 3.0. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (1 > x && 3 < x)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Logical conjunction always evaluates to false: x < 1 && x > 3. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (x < 3 && x > 1)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" " if (x > 3 || x < 10)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Logical disjunction always evaluates to true: x > 3 || x < 10. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (x >= 3 || x <= 10)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:16]: (warning) Logical disjunction always evaluates to true: x >= 3 || x <= 10. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (x >= 3 || x < 10)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:16]: (warning) Logical disjunction always evaluates to true: x >= 3 || x < 10. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (x > 3 || x <= 10)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Logical disjunction always evaluates to true: x > 3 || x <= 10. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (x > 3 || x < 3)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" " if (x >= 3 || x <= 3)\n" " a++;\n" - "}" + "}\n" ); ASSERT_EQUALS("[test.cpp:2:16]: (warning) Logical disjunction always evaluates to true: x >= 3 || x <= 3. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (x >= 3 || x < 3)\n" " a++;\n" - "}" + "}\n" ); ASSERT_EQUALS("[test.cpp:2:16]: (warning) Logical disjunction always evaluates to true: x >= 3 || x < 3. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (x > 3 || x <= 3)\n" " a++;\n" - "}" + "}\n" ); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Logical disjunction always evaluates to true: x > 3 || x <= 3. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if((x==3) && (x!=4))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:14]: (style) Redundant condition: The condition 'x != 4' is redundant since 'x == 3' is sufficient. [redundantCondition]\n", errout_str()); check("void f(const std::string &s) {\n" // #8860 " const std::size_t p = s.find(\"42\");\n" " const std::size_t * const ptr = &p;\n" " if(p != std::string::npos && p == 0 && *ptr != 1){;}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:36] -> [test.cpp:4:49]: (style) Condition '*ptr!=1' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f(int x) {\n" " if ((x!=4) && (x==3))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:16]: (style) Redundant condition: The condition 'x != 4' is redundant since 'x == 3' is sufficient. [redundantCondition]\n", errout_str()); check("void f(int x) {\n" " if ((x==3) || (x!=4))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:16]: (style) Redundant condition: The condition 'x == 3' is redundant since 'x != 4' is sufficient. [redundantCondition]\n", errout_str()); check("void f(int x) {\n" " if ((x!=4) || (x==3))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:16]: (style) Redundant condition: The condition 'x == 3' is redundant since 'x != 4' is sufficient. [redundantCondition]\n", errout_str()); check("void f(int x) {\n" " if ((x==3) && (x!=3))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:16]: (warning) Logical conjunction always evaluates to false: x == 3 && x != 3. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if ((x==6) || (x!=6))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:16]: (warning) Logical disjunction always evaluates to true: x == 6 || x != 6. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (x > 10 || x < 3)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" " if (x > 5 && x == 1)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Logical conjunction always evaluates to false: x > 5 && x == 1. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (x > 5 && x == 6)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (style) Redundant condition: The condition 'x > 5' is redundant since 'x == 6' is sufficient. [redundantCondition]\n", errout_str()); // #3419 check("void f() {\n" " if ( &q != &a && &q != &b ) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #3676 check("void f(int m_x2, int w, int x) {\n" " if (x + w - 1 > m_x2 || m_x2 < 0 )\n" " m_x2 = x + w - 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(float x) {\n" // x+1 => x " if (x <= 1.0e20 && x >= -1.0e20) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(float x) {\n" // x+1 => x " if (x >= 1.0e20 && x <= 1.0e21) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(float x) {\n" // x+1 => x " if (x <= -1.0e20 && x >= -1.0e21) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1277,7 +1281,7 @@ class TestCondition : public TestFixture { " c = x < 1 && x == 3;\n" " d = x >= 5 && x == 1;\n" " e = x <= 1 && x == 3;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Logical conjunction always evaluates to false: x > 5 && x == 1. [incorrectLogicOperator]\n" "[test.cpp:3:15]: (warning) Logical conjunction always evaluates to false: x < 1 && x == 3. [incorrectLogicOperator]\n" "[test.cpp:4:16]: (warning) Logical conjunction always evaluates to false: x >= 5 && x == 1. [incorrectLogicOperator]\n" @@ -1288,7 +1292,7 @@ class TestCondition : public TestFixture { check("#define ZERO 0\n" "void f(int x) {\n" " if (x && x != ZERO) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int N) {\n" // #9789 @@ -1303,58 +1307,59 @@ class TestCondition : public TestFixture { void incorrectLogicOperator5() { // complex expressions check("void f(int x) {\n" " if (x+3 > 2 || x+3 < 10) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Logical disjunction always evaluates to true: x+3 > 2 || x+3 < 10. [incorrectLogicOperator]\n", errout_str()); } void incorrectLogicOperator6() { // char literals + const Settings s = settingsBuilder(settings0).certainty(Certainty::inconclusive).build(); check("void f(char x) {\n" " if (x == '1' || x == '2') {}\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", s); ASSERT_EQUALS("", errout_str()); check("void f(char x) {\n" " if (x == '1' && x == '2') {}\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", s); ASSERT_EQUALS("[test.cpp:2:16]: (warning) Logical conjunction always evaluates to false: x == '1' && x == '2'. [incorrectLogicOperator]\n", errout_str()); check("int f(char c) {\n" " return (c >= 'a' && c <= 'z');\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", s); ASSERT_EQUALS("", errout_str()); check("int f(char c) {\n" " return (c <= 'a' && c >= 'z');\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", s); ASSERT_EQUALS("[test.cpp:2:20]: (warning, inconclusive) Logical conjunction always evaluates to false: c <= 'a' && c >= 'z'. [incorrectLogicOperator]\n", errout_str()); check("int f(char c) {\n" " return (c <= 'a' && c >= 'z');\n" - "}"); + "}\n"); // TODO: use s? ASSERT_EQUALS("[test.cpp:2:13] -> [test.cpp:2:25]: (style) Return value 'c>='z'' is always false [knownConditionTrueFalse]\n", errout_str()); } void incorrectLogicOperator7() { // opposite expressions check("void f(int i) {\n" " if (i || !i) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (warning) Logical disjunction always evaluates to true: i || !(i). [incorrectLogicOperator]\n", errout_str()); check("void f(int a, int b) {\n" " if (a>b || a<=b) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (warning) Logical disjunction always evaluates to true: a > b || a <= b. [incorrectLogicOperator]\n", errout_str()); check("void f(int a, int b) {\n" " if (a>b || a T icdf( const T uniform ) {\n" " if ((0(obj));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1389,21 +1394,21 @@ class TestCondition : public TestFixture { "void f(Type_t t) {\n" " if ((t == A) && (t == B))\n" " {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:18]: (warning) Logical conjunction always evaluates to false: t == 0 && t == 1. [incorrectLogicOperator]\n", errout_str()); } void incorrectLogicOperator11() { - check("void foo(int i, const int n) { if ( i < n && i == n ) {} }"); + check("void foo(int i, const int n) { if ( i < n && i == n ) {} }\n"); ASSERT_EQUALS("[test.cpp:1:43]: (warning) Logical conjunction always evaluates to false: i < n && i == n. [incorrectLogicOperator]\n", errout_str()); - check("void foo(int i, const int n) { if ( i > n && i == n ) {} }"); + check("void foo(int i, const int n) { if ( i > n && i == n ) {} }\n"); ASSERT_EQUALS("[test.cpp:1:43]: (warning) Logical conjunction always evaluates to false: i > n && i == n. [incorrectLogicOperator]\n", errout_str()); - check("void foo(int i, const int n) { if ( i == n && i > n ) {} }"); + check("void foo(int i, const int n) { if ( i == n && i > n ) {} }\n"); ASSERT_EQUALS("[test.cpp:1:44]: (warning) Logical conjunction always evaluates to false: i == n && i > n. [incorrectLogicOperator]\n", errout_str()); - check("void foo(int i, const int n) { if ( i == n && i < n ) {} }"); + check("void foo(int i, const int n) { if ( i == n && i < n ) {} }\n"); ASSERT_EQUALS("[test.cpp:1:44]: (warning) Logical conjunction always evaluates to false: i == n && i < n. [incorrectLogicOperator]\n", errout_str()); } @@ -1417,7 +1422,7 @@ class TestCondition : public TestFixture { " y.f();\n" " if (a > x && a < y)\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:5:9] -> [test.cpp:6:9] -> [test.cpp:8:13]: (warning) Logical conjunction always evaluates to false: a > x && a < y. [incorrectLogicOperator]\n", errout_str()); @@ -1431,7 +1436,7 @@ class TestCondition : public TestFixture { " y.f();\n" " if (a > x && a < y)\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(A a, A b) {\n" @@ -1440,7 +1445,7 @@ class TestCondition : public TestFixture { " y.f();\n" " if (a > x && a < y)\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(A a, A b) {\n" @@ -1449,7 +1454,7 @@ class TestCondition : public TestFixture { " y.f();\n" " if (a > x && a < y)\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:15] -> [test.cpp:3:15] -> [test.cpp:5:13]: (warning) Logical conjunction always evaluates to false: a > x && a < y. [incorrectLogicOperator]\n", errout_str()); @@ -1463,7 +1468,7 @@ class TestCondition : public TestFixture { " y.f();\n" " if (a > x && a < y)\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:9]: (style) Condition 'a>x' is always false [knownConditionTrueFalse]\n" "[test.cpp:8:18]: (style) Condition 'a x && a < y)\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:9]: (style) Condition 'a>x' is always false [knownConditionTrueFalse]\n", errout_str()); check("void foo(A a) {\n" @@ -1486,7 +1491,7 @@ class TestCondition : public TestFixture { " y.f();\n" " if (a > x && a < y)\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:9]: (style) Condition 'a>x' is always false [knownConditionTrueFalse]\n", errout_str()); check("void foo(A a) {\n" @@ -1495,7 +1500,7 @@ class TestCondition : public TestFixture { " y.f();\n" " if (a > x && a < y)\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:9]: (style) Condition 'a>x' is always false [knownConditionTrueFalse]\n" "[test.cpp:5:18]: (style) Condition 'a [test.cpp:3:18]: (warning) Logical conjunction always evaluates to false: v == 1 && x == 2. [incorrectLogicOperator]\n", errout_str()); check("void f2(const int *v) {\n" " const int *x=v;\n" " if ((*v == 1) && (*x == 2)) {;}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:18] -> [test.cpp:3:19]: (warning) Logical conjunction always evaluates to false: *(v) == 1 && *(x) == 2. [incorrectLogicOperator]\n", errout_str()); } @@ -1719,7 +1724,7 @@ class TestCondition : public TestFixture { " if (f && g)\n" " ;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:200:11] -> [test.cpp:200:16]: (style) Condition 'g' is always true [knownConditionTrueFalse]\n", errout_str()); } @@ -1775,31 +1780,31 @@ class TestCondition : public TestFixture { check("void f(void) {\n" // #8892 " const char c[1] = { \'x\' }; \n" " if(c[0] == \'x\'){;}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:13]: (style) Condition 'c[0]=='x'' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f(int x) {\n" " if (x > 5 && x != 1)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (style) Redundant condition: The condition 'x != 1' is redundant since 'x > 5' is sufficient. [redundantCondition]\n", errout_str()); check("void f(int x) {\n" " if (x > 5 && x != 6)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" " if ((x > 5) && (x != 1))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:17]: (style) Redundant condition: The condition 'x != 1' is redundant since 'x > 5' is sufficient. [redundantCondition]\n", errout_str()); check("void f(int x) {\n" " if ((x > 5) && (x != 6))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x, bool& b) {\n" @@ -1807,7 +1812,7 @@ class TestCondition : public TestFixture { " c = x < 5 || x == 4;\n" " d = x >= 3 || x == 4;\n" " e = x <= 5 || x == 4;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (style) Redundant condition: The condition 'x == 4' is redundant since 'x > 3' is sufficient. [redundantCondition]\n" "[test.cpp:3:15]: (style) Redundant condition: The condition 'x == 4' is redundant since 'x < 5' is sufficient. [redundantCondition]\n" "[test.cpp:4:16]: (style) Redundant condition: The condition 'x == 4' is redundant since 'x >= 3' is sufficient. [redundantCondition]\n" @@ -1819,7 +1824,7 @@ class TestCondition : public TestFixture { " c = x < 1 || x != 3;\n" " d = x >= 5 || x != 1;\n" " e = x <= 1 || x != 3;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (style) Redundant condition: The condition 'x > 5' is redundant since 'x != 1' is sufficient. [redundantCondition]\n" "[test.cpp:3:15]: (style) Redundant condition: The condition 'x < 1' is redundant since 'x != 3' is sufficient. [redundantCondition]\n" "[test.cpp:4:16]: (style) Redundant condition: The condition 'x >= 5' is redundant since 'x != 1' is sufficient. [redundantCondition]\n" @@ -1831,7 +1836,7 @@ class TestCondition : public TestFixture { " c = x > 5 || x > 6;\n" " d = x < 6 && x < 5;\n" " e = x < 5 || x < 6;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (style) Redundant condition: The condition 'x > 5' is redundant since 'x > 6' is sufficient. [redundantCondition]\n" "[test.cpp:3:15]: (style) Redundant condition: The condition 'x > 6' is redundant since 'x > 5' is sufficient. [redundantCondition]\n" "[test.cpp:4:15]: (style) Redundant condition: The condition 'x < 6' is redundant since 'x < 5' is sufficient. [redundantCondition]\n" @@ -1843,7 +1848,7 @@ class TestCondition : public TestFixture { " c = x > 5.5 || x > 6.5;\n" " d = x < 6.5 && x < 5.5;\n" " e = x < 5.5 || x < 6.5;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:17]: (style) Redundant condition: The condition 'x > 5.5' is redundant since 'x > 6.5' is sufficient. [redundantCondition]\n" "[test.cpp:3:17]: (style) Redundant condition: The condition 'x > 6.5' is redundant since 'x > 5.5' is sufficient. [redundantCondition]\n" "[test.cpp:4:17]: (style) Redundant condition: The condition 'x < 6.5' is redundant since 'x < 5.5' is sufficient. [redundantCondition]\n" @@ -1861,49 +1866,49 @@ class TestCondition : public TestFixture { check("void f(int x) {\n" " if (x < 1 && x > 3)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Logical conjunction always evaluates to false: x < 1 && x > 3. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (1 > x && x > 3)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Logical conjunction always evaluates to false: x < 1 && x > 3. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (x < 1 && 3 < x)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Logical conjunction always evaluates to false: x < 1 && x > 3. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (1 > x && 3 < x)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Logical conjunction always evaluates to false: x < 1 && x > 3. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (x > 3 && x < 1)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Logical conjunction always evaluates to false: x > 3 && x < 1. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (3 < x && x < 1)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Logical conjunction always evaluates to false: x > 3 && x < 1. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (x > 3 && 1 > x)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Logical conjunction always evaluates to false: x > 3 && x < 1. [incorrectLogicOperator]\n", errout_str()); check("void f(int x) {\n" " if (3 < x && 1 > x)\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Logical conjunction always evaluates to false: x > 3 && x < 1. [incorrectLogicOperator]\n", errout_str()); } @@ -1913,7 +1918,7 @@ class TestCondition : public TestFixture { " b2 = a % c == 100000;\n" " b3 = a % 5 == c;\n" " return a % 5 == 5-p;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("bool f(bool& b1, bool& b2, bool& b3, bool& b4, bool& b5) {\n" @@ -1923,7 +1928,7 @@ class TestCondition : public TestFixture { " b4 = a % 5 != 5;\n" " b5 = a % 5 >= 5;\n" " return a % 5 > 5;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:16]: (warning) Comparison of modulo result is predetermined, because it is always less than 5. [moduloAlwaysTrueFalse]\n" "[test.cpp:3:16]: (warning) Comparison of modulo result is predetermined, because it is always less than 5. [moduloAlwaysTrueFalse]\n" @@ -1937,7 +1942,7 @@ class TestCondition : public TestFixture { " b1 = bar() % 5 < 889;\n" " if(x[593] % 5 <= 5)\n" " b2 = x.a % 5 == 5;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:20]: (warning) Comparison of modulo result is predetermined, because it is always less than 5. [moduloAlwaysTrueFalse]\n" "[test.cpp:3:19]: (warning) Comparison of modulo result is predetermined, because it is always less than 5. [moduloAlwaysTrueFalse]\n" @@ -1947,7 +1952,7 @@ class TestCondition : public TestFixture { check("void f() {\n" " if (a % 2 + b % 2 == 2)\n" " foo();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1956,21 +1961,21 @@ class TestCondition : public TestFixture { " if(a==b)\n" " if(a!=b)\n" " cout << a;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:13]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); check("bool foo(int a, int b) {\n" " if(a==b)\n" " return a!=b;\n" " return false;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:17]: (warning) Opposite inner 'return' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); check("void foo(int a, int b) {\n" " if(a==b)\n" " if(b!=a)\n" " cout << a;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:13]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); check("void foo(int a) {\n" @@ -1980,7 +1985,7 @@ class TestCondition : public TestFixture { " else\n" " cout << 100;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:10] -> [test.cpp:3:14]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); // #4186 @@ -1991,7 +1996,7 @@ class TestCondition : public TestFixture { " else\n" " cout << 100;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // 4170 @@ -2010,7 +2015,7 @@ class TestCondition : public TestFixture { " }\n" " void next();\n" " const char *tok;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int i)\n" @@ -2021,7 +2026,7 @@ class TestCondition : public TestFixture { " cout << a;\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int& i) {\n" @@ -2033,7 +2038,7 @@ class TestCondition : public TestFixture { " if(i<5) {\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int& i);\n" @@ -2044,7 +2049,7 @@ class TestCondition : public TestFixture { " if(i<5) {\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int i);\n" @@ -2054,7 +2059,7 @@ class TestCondition : public TestFixture { " if(i<5) {\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9] -> [test.cpp:5:13]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); check("void foo(const int &i);\n" @@ -2064,7 +2069,7 @@ class TestCondition : public TestFixture { " if(i<5) {\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9] -> [test.cpp:5:13]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); check("void foo(int i);\n" @@ -2075,7 +2080,7 @@ class TestCondition : public TestFixture { " if(i<5) {\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9] -> [test.cpp:6:13]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); check("class C { void f(int &i) const; };\n" // #7028 - variable is changed by const method @@ -2084,7 +2089,7 @@ class TestCondition : public TestFixture { " c.f(i);\n" " if (i != 5) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // see linux revision 1f80c0cc @@ -2098,7 +2103,7 @@ class TestCondition : public TestFixture { " err = rc;\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:11] -> [test.cpp:7:14]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); @@ -2109,7 +2114,7 @@ class TestCondition : public TestFixture { " array[0] += 5;\n" " if (array[0] > 2) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #6227 - FP caused by simplifications of casts and known variables @@ -2118,7 +2123,7 @@ class TestCondition : public TestFixture { " B *b = dynamic_cast(a);\n" " if(!b) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int a) {\n" @@ -2126,7 +2131,7 @@ class TestCondition : public TestFixture { " int b = a;\n" " if(!b) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:16] -> [test.cpp:2:7] -> [test.cpp:4:11]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); check("void foo(unsigned u) {\n" @@ -2136,7 +2141,7 @@ class TestCondition : public TestFixture { " u = x;\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #8186 @@ -2144,7 +2149,7 @@ class TestCondition : public TestFixture { " for (int i=0;i<4;i++) {\n" " if (i==5) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:17] -> [test.cpp:3:10]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); // #8938 @@ -2153,7 +2158,7 @@ class TestCondition : public TestFixture { " GetActiveCell(&(upperleft.Col), &(upperleft.Row));\n" " if (upperleft.Row == -1) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9702 @@ -2166,7 +2171,7 @@ class TestCondition : public TestFixture { " }\n" " bool IsSet() const { return m_value; }\n" " bool m_value = false;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // #12725 @@ -2188,7 +2193,7 @@ class TestCondition : public TestFixture { " err = rc;\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void Fred::f() {\n" // daca: ace @@ -2196,7 +2201,7 @@ class TestCondition : public TestFixture { " this->next_ = n;\n" " if (this->next_ != map_man_->table_) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void test(float *f) {\n" // #7405 @@ -2204,13 +2209,13 @@ class TestCondition : public TestFixture { " (*f) += 0.1f;\n" " if(*f<10) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int * f(int * x, int * y) {\n" " if(!x) return x;\n" " return y;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2222,7 +2227,7 @@ class TestCondition : public TestFixture { " fred.dostuff();\n" " if (!fred.isValid()) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:19] -> [test.cpp:5:9]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); check("class Fred { public: bool isValid() const; void dostuff() const; };\n" @@ -2232,7 +2237,7 @@ class TestCondition : public TestFixture { " fred.dostuff();\n" // <- dostuff() is const, warn " if (!fred.isValid()) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:19] -> [test.cpp:6:9]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); check("void f() {\n" @@ -2241,7 +2246,7 @@ class TestCondition : public TestFixture { " fred.dostuff();\n" " if (!fred.isValid()) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #6385 "crash in Variable::getFlag()" @@ -2252,14 +2257,14 @@ class TestCondition : public TestFixture { " qApp->removeTranslator(mTranslator);\n" " }\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // just don't crash... check("bool f(std::ofstream &CFileStream) {\n" // #8198 " if(!CFileStream.good()) { return; }\n" " CFileStream << \"abc\";\n" " if (!CFileStream.good()) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2270,7 +2275,7 @@ class TestCondition : public TestFixture { " x = do_something();\n" " if (x != -1) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #5750 - another fp when undeclared variable is used @@ -2279,7 +2284,7 @@ class TestCondition : public TestFixture { " r += 3;\n" " if (r > w) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #6574 - another fp when undeclared variable is used @@ -2288,7 +2293,7 @@ class TestCondition : public TestFixture { " i++;\n" " if(!i) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // undeclared array @@ -2297,7 +2302,7 @@ class TestCondition : public TestFixture { " a[x] -= dt;\n" " if (a[x] < 0) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #6313 - false positive: opposite conditions in nested if blocks when condition changed @@ -2307,7 +2312,7 @@ class TestCondition : public TestFixture { " if(!var){}\n" " else {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // daca hyphy @@ -2316,7 +2321,7 @@ class TestCondition : public TestFixture { " rec.Delete(i);\n" " if (rec.lLength!=0) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2330,7 +2335,7 @@ class TestCondition : public TestFixture { " doStuff(&s);\n" " if (hasFailed) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:7]: (style) Condition '!hasFailed' is always true [knownConditionTrueFalse]\n", errout_str()); } @@ -2341,7 +2346,7 @@ class TestCondition : public TestFixture { " if (x<4) {\n" " if (x==5) {}\n" // <- Warning " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:4:10]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); check("void f(int x) {\n" @@ -2349,14 +2354,14 @@ class TestCondition : public TestFixture { " if (x<4) {\n" " if (x!=5) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:4:10]: (style) Condition 'x!=5' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f(int x) {\n" "\n" " if (x<4) {\n" " if (x>5) {}\n" // <- Warning " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:4:10]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); check("void f(int x) {\n" @@ -2364,7 +2369,7 @@ class TestCondition : public TestFixture { " if (x<4) {\n" " if (x>=5) {}\n" // <- Warning " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:4:10]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); check("void f(int x) {\n" @@ -2372,14 +2377,14 @@ class TestCondition : public TestFixture { " if (x<4) {\n" " if (x<5) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:4:10]: (style) Condition 'x<5' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f(int x) {\n" "\n" " if (x<4) {\n" " if (x<=5) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:4:10]: (style) Condition 'x<=5' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f(int x) {\n" @@ -2387,49 +2392,49 @@ class TestCondition : public TestFixture { " if (x<5) {\n" " if (x==4) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" "\n" " if (x<5) {\n" " if (x!=4) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" "\n" " if (x<5) {\n" " if (x!=6) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:4:10]: (style) Condition 'x!=6' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f(int x) {\n" "\n" " if (x<5) {\n" " if (x>4) {}\n" // <- Warning " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:4:10]: (style) Condition 'x>4' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f(int x) {\n" "\n" " if (x<5) {\n" " if (x>=4) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" "\n" " if (x<5) {\n" " if (x<4) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" "\n" " if (x<5) {\n" " if (x<=4) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:4:10]: (style) Condition 'x<=4' is always true [knownConditionTrueFalse]\n", errout_str()); // first comparison: > @@ -2438,35 +2443,35 @@ class TestCondition : public TestFixture { " if (x>4) {\n" " if (x==5) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" "\n" " if (x>4) {\n" " if (x>5) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" "\n" " if (x>4) {\n" " if (x>=5) {}\n" // <- Warning " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:4:10]: (style) Condition 'x>=5' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f(int x) {\n" "\n" " if (x>4) {\n" " if (x<5) {}\n" // <- Warning " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:4:10]: (style) Condition 'x<5' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f(int x) {\n" "\n" " if (x>4) {\n" " if (x<=5) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" @@ -2474,7 +2479,7 @@ class TestCondition : public TestFixture { " if (x>5) {\n" " if (x==4) {}\n" // <- Warning " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:4:10]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); check("void f(int x) {\n" @@ -2482,21 +2487,21 @@ class TestCondition : public TestFixture { " if (x>5) {\n" " if (x>4) {}\n" // <- Warning " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:4:10]: (style) Condition 'x>4' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f(int x) {\n" "\n" " if (x>5) {\n" " if (x>=4) {}\n" // <- Warning " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:4:10]: (style) Condition 'x>=4' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f(int x) {\n" "\n" " if (x>5) {\n" " if (x<4) {}\n" // <- Warning " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:4:10]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); check("void f(int x) {\n" @@ -2504,7 +2509,7 @@ class TestCondition : public TestFixture { " if (x>5) {\n" " if (x<=4) {}\n" // <- Warning " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:4:10]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); @@ -2512,62 +2517,62 @@ class TestCondition : public TestFixture { " if (x < 4) {\n" " if (10 < x) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:12]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); } void oppositeInnerCondition3() { - check("void f3(char c) { if(c=='x') if(c=='y') {}}"); + check("void f3(char c) { if(c=='x') if(c=='y') {}}\n"); ASSERT_EQUALS("[test.cpp:1:23] -> [test.cpp:1:34]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); - check("void f4(char *p) { if(*p=='x') if(*p=='y') {}}"); + check("void f4(char *p) { if(*p=='x') if(*p=='y') {}}\n"); ASSERT_EQUALS("[test.cpp:1:25] -> [test.cpp:1:37]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); - check("void f5(const char * const p) { if(*p=='x') if(*p=='y') {}}"); + check("void f5(const char * const p) { if(*p=='x') if(*p=='y') {}}\n"); ASSERT_EQUALS("[test.cpp:1:38] -> [test.cpp:1:50]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); - check("void f5(const char * const p) { if('x'==*p) if('y'==*p) {}}"); + check("void f5(const char * const p) { if('x'==*p) if('y'==*p) {}}\n"); ASSERT_EQUALS("[test.cpp:1:39] -> [test.cpp:1:51]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); - check("void f6(char * const p) { if(*p=='x') if(*p=='y') {}}"); + check("void f6(char * const p) { if(*p=='x') if(*p=='y') {}}\n"); ASSERT_EQUALS("[test.cpp:1:32] -> [test.cpp:1:44]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); - check("void f7(const char * p) { if(*p=='x') if(*p=='y') {}}"); + check("void f7(const char * p) { if(*p=='x') if(*p=='y') {}}\n"); ASSERT_EQUALS("[test.cpp:1:32] -> [test.cpp:1:44]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); - check("void f8(int i) { if(i==4) if(i==2) {}}"); + check("void f8(int i) { if(i==4) if(i==2) {}}\n"); ASSERT_EQUALS("[test.cpp:1:22] -> [test.cpp:1:31]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); - check("void f9(int *p) { if (*p==4) if(*p==2) {}}"); + check("void f9(int *p) { if (*p==4) if(*p==2) {}}\n"); ASSERT_EQUALS("[test.cpp:1:25] -> [test.cpp:1:35]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); - check("void f10(int * const p) { if (*p==4) if(*p==2) {}}"); + check("void f10(int * const p) { if (*p==4) if(*p==2) {}}\n"); ASSERT_EQUALS("[test.cpp:1:33] -> [test.cpp:1:43]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); - check("void f11(const int *p) { if (*p==4) if(*p==2) {}}"); + check("void f11(const int *p) { if (*p==4) if(*p==2) {}}\n"); ASSERT_EQUALS("[test.cpp:1:32] -> [test.cpp:1:42]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); - check("void f12(const int * const p) { if (*p==4) if(*p==2) {}}"); + check("void f12(const int * const p) { if (*p==4) if(*p==2) {}}\n"); ASSERT_EQUALS("[test.cpp:1:39] -> [test.cpp:1:49]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); check("struct foo {\n" " int a;\n" " int b;\n" "};\n" - "void f(foo x) { if(x.a==4) if(x.b==2) {}}"); + "void f(foo x) { if(x.a==4) if(x.b==2) {}}\n"); ASSERT_EQUALS("", errout_str()); check("struct foo {\n" " int a;\n" " int b;\n" "};\n" - "void f(foo x) { if(x.a==4) if(x.b==4) {}}"); + "void f(foo x) { if(x.a==4) if(x.b==4) {}}\n"); ASSERT_EQUALS("", errout_str()); - check("void f3(char a, char b) { if(a==b) if(a==0) {}}"); + check("void f3(char a, char b) { if(a==b) if(a==0) {}}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(int x) { if (x == 1) if (x != 1) {} }"); + check("void f(int x) { if (x == 1) if (x != 1) {} }\n"); ASSERT_EQUALS("[test.cpp:1:23] -> [test.cpp:1:35]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); } @@ -2575,8 +2580,8 @@ class TestCondition : public TestFixture { check("void f(int x) {\n" " if (a>3 && x > 100) {\n" " if (x < 10) {}\n" - " }" - "}"); + " }\n" + "}\n"); ASSERT_EQUALS("[test.cpp:2:16] -> [test.cpp:3:11]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); check("void f(bool x, const int a, const int b) {\n" @@ -2627,57 +2632,69 @@ class TestCondition : public TestFixture { } void oppositeInnerConditionEmpty() { - check("void f1(const std::string &s) { if(s.size() > 42) if(s.empty()) {}}"); + check("void f1(const std::string &s) { if(s.size() > 42) if(s.empty()) {}}\n"); ASSERT_EQUALS("[test.cpp:1:45] -> [test.cpp:1:61]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); - check("void f1(const std::string &s) { if(s.size() > 0) if(s.empty()) {}}"); + check("void f1(const std::string &s) { if(s.size() > 0) if(s.empty()) {}}\n"); ASSERT_EQUALS("[test.cpp:1:45] -> [test.cpp:1:60]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); - check("void f1(const std::string &s) { if(s.size() < 0) if(s.empty()) {}} "); // <- CheckOther reports: checking if unsigned expression is less than zero + check("void f1(const std::string &s) { if(s.size() < 0) if(s.empty()) {}} \n"); // <- CheckOther reports: checking if unsigned expression is less than zero ASSERT_EQUALS("[test.cpp:1:45] -> [test.cpp:1:60]: (style) Condition 's.empty()' is always false [knownConditionTrueFalse]\n", errout_str()); - check("void f1(const std::string &s) { if(s.empty()) if(s.size() > 42) {}}"); + check("void f1(const std::string &s) { if(s.empty()) if(s.size() > 42) {}}\n"); ASSERT_EQUALS("[test.cpp:1:43] -> [test.cpp:1:59]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); - check("template void f1(const T &s) { if(s.size() > 42) if(s.empty()) {}}"); + check("template void f1(const T &s) { if(s.size() > 42) if(s.empty()) {}}\n"); ASSERT_EQUALS("", errout_str()); //We don't know the type of T so we don't know the relationship between size() and empty(). e.g. s might be a 50 tonne truck with nothing in it. - check("void f2(const std::wstring &s) { if(s.empty()) if(s.size() > 42) {}}"); + check("void f2(const std::wstring &s) { if(s.empty()) if(s.size() > 42) {}}\n"); ASSERT_EQUALS("[test.cpp:1:44] -> [test.cpp:1:60]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); - check("void f1(QString s) { if(s.isEmpty()) if(s.length() > 42) {}}"); + check("void f1(QString s) { if(s.isEmpty()) if(s.length() > 42) {}}\n"); ASSERT_EQUALS("[test.cpp:1:34] -> [test.cpp:1:52]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); - check("void f1(const std::string &s, bool b) { if(s.empty() || ((s.size() == 1) && b)) {}}"); + check("void f1(const std::string &s, bool b) { if(s.empty() || ((s.size() == 1) && b)) {}}\n"); ASSERT_EQUALS("", errout_str()); - check("void f1(const std::string &x, const std::string &y) { if(x.size() > 42) if(y.empty()) {}}"); + check("void f1(const std::string &x, const std::string &y) { if(x.size() > 42) if(y.empty()) {}}\n"); ASSERT_EQUALS("", errout_str()); - check("void f1(const std::string &x, const std::string &y) { if(y.empty()) if(x.size() > 42) {}}"); + check("void f1(const std::string &x, const std::string &y) { if(y.empty()) if(x.size() > 42) {}}\n"); ASSERT_EQUALS("", errout_str()); - check("void f1(const std::string v[10]) { if(v[0].size() > 42) if(v[1].empty()) {}}"); + check("void f1(const std::string v[10]) { if(v[0].size() > 42) if(v[1].empty()) {}}\n"); ASSERT_EQUALS("", errout_str()); - check("void f1(const std::string &s) { if(s.size() <= 1) if(s.empty()) {}}"); + check("void f1(const std::string &s) { if(s.size() <= 1) if(s.empty()) {}}\n"); ASSERT_EQUALS("", errout_str()); - check("void f1(const std::string &s) { if(s.size() <= 2) if(s.empty()) {}}"); + check("void f1(const std::string &s) { if(s.size() <= 2) if(s.empty()) {}}\n"); ASSERT_EQUALS("", errout_str()); - check("void f1(const std::string &s) { if(s.size() < 2) if(s.empty()) {}}"); + check("void f1(const std::string &s) { if(s.size() < 2) if(s.empty()) {}}\n"); ASSERT_EQUALS("", errout_str()); - check("void f1(const std::string &s) { if(s.size() >= 0) if(s.empty()) {}} "); // CheckOther says: Unsigned expression 's.size()' can't be negative so it is unnecessary to test it. [unsignedPositive] + check("void f1(const std::string &s) { if(s.size() >= 0) if(s.empty()) {}} \n"); // CheckOther says: Unsigned expression 's.size()' can't be negative so it is unnecessary to test it. [unsignedPositive] + ASSERT_EQUALS("", errout_str()); + + check("void f1(const std::string &s) { if(42 < s.size()) if(s.empty()) {}}\n"); + ASSERT_EQUALS("[test.cpp:1:39] -> [test.cpp:1:61]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); + + check("void f1(const std::string &s) { if(s.empty()) if(42 < s.size()) {}}\n"); + ASSERT_EQUALS("[test.cpp:1:43] -> [test.cpp:1:53]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); + + check("void f(const std::string& s, int n) {\n" // #14716 + " if (s.size() < n)\n" + " if (s.empty()) {}\n" + "}\n"); ASSERT_EQUALS("", errout_str()); // TODO: These are identical condition since size cannot be negative - check("void f1(const std::string &s) { if(s.size() <= 0) if(s.empty()) {}}"); + check("void f1(const std::string &s) { if(s.size() <= 0) if(s.empty()) {}}\n"); ASSERT_EQUALS("", errout_str()); // TODO: These are identical condition since size cannot be negative - check("void f1(const std::string &s) { if(s.size() < 1) if(s.empty()) {}}"); + check("void f1(const std::string &s) { if(s.size() < 1) if(s.empty()) {}}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2692,7 +2709,7 @@ class TestCondition : public TestFixture { " }\n" " void bar();\n" " int get() const;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct CD {\n" @@ -2720,7 +2737,7 @@ class TestCondition : public TestFixture { " bool b = f();\n" " x += 1;\n" " if (!b && f()) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(double d) {\n" @@ -2749,10 +2766,10 @@ class TestCondition : public TestFixture { } void identicalInnerCondition() { - check("void f1(int a, int b) { if(a==b) if(a==b) {}}"); + check("void f1(int a, int b) { if(a==b) if(a==b) {}}\n"); ASSERT_EQUALS("[test.cpp:1:29] -> [test.cpp:1:38]: (warning) Identical inner 'if' condition is always true. [identicalInnerCondition]\n", errout_str()); - check("void f2(int a, int b) { if(a!=b) if(a!=b) {}}"); + check("void f2(int a, int b) { if(a!=b) if(a!=b) {}}\n"); ASSERT_EQUALS("[test.cpp:1:29] -> [test.cpp:1:38]: (warning) Identical inner 'if' condition is always true. [identicalInnerCondition]\n", errout_str()); // #6645 false negative: condition is always false @@ -2761,38 +2778,38 @@ class TestCondition : public TestFixture { " if(a) {}\n" " else {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:6] -> [test.cpp:3:9]: (warning) Identical inner 'if' condition is always true. [identicalInnerCondition]\n", errout_str()); check("bool f(int a, int b) {\n" " if(a == b) { return a == b; }\n" " return false;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:10] -> [test.cpp:2:27]: (warning) Identical inner 'return' condition is always true. [identicalInnerCondition]\n", errout_str()); check("bool f(bool a) {\n" " if(a) { return a; }\n" " return false;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int* f(int* a, int * b) {\n" " if(a) { return a; }\n" " return b;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int* f(std::shared_ptr a, std::shared_ptr b) {\n" " if(a.get()) { return a.get(); }\n" " return b.get();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A { int * x; };\n" "int* f(A a, int * b) {\n" " if(a.x) { return a.x; }\n" " return b;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -2804,7 +2821,7 @@ class TestCondition : public TestFixture { " get_value (&value);\n" " if ((value >> 28) & 1) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkP("#define TYPE_1 \"a\"\n" // #13202 @@ -2816,61 +2833,85 @@ class TestCondition : public TestFixture { " if (s == TYPE_2) {}\n" " else if (s == TYPE_3) {}\n" " }\n" - "}"); + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f(const int* p, const int* e) {\n" // #14595 + " for (; p;) {\n" + " if (p == e) {}\n" + " if (p) {}\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:12] -> [test.cpp:4:13]: (warning) Identical inner 'if' condition is always true. [identicalInnerCondition]\n", errout_str()); + + check("int f(const int *q, const int *s) {\n" // #14711 + " if (*q && *s)\n" + " return *q;\n" + " return 0;\n" + "}\n"); ASSERT_EQUALS("", errout_str()); + + check("void f(int x, int y) {\n" + " int a[] = { x, y };\n" + " if (a[0] == 1) {\n" + " if (a[0] == 1) {}\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:14] -> [test.cpp:4:18]: (warning) Identical inner 'if' condition is always true. [identicalInnerCondition]\n", + errout_str()); } void identicalConditionAfterEarlyExit() { check("void f(int x) {\n" // #8137 " if (x > 100) { return; }\n" " if (x > 100) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:9]: (warning) Identical condition 'x>100', second condition is always false [identicalConditionAfterEarlyExit]\n", errout_str()); check("bool f(int x) {\n" " if (x > 100) { return false; }\n" " return x > 100;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:12]: (warning) Identical condition and return expression 'x>100', return value is always false [identicalConditionAfterEarlyExit]\n", errout_str()); check("void f(int x) {\n" " if (x > 100) { return; }\n" " if (x > 100 || y > 100) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:9]: (warning) Identical condition 'x>100', second condition is always false [identicalConditionAfterEarlyExit]\n", errout_str()); check("void f(int x) {\n" " if (x > 100) { return; }\n" " if (x > 100 && y > 100) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:9]: (warning) Identical condition 'x>100', second condition is always false [identicalConditionAfterEarlyExit]\n", errout_str()); check("void f(int x) {\n" " if (x > 100) { return; }\n" " if (abc) {}\n" " if (x > 100) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:4:9]: (warning) Identical condition 'x>100', second condition is always false [identicalConditionAfterEarlyExit]\n", errout_str()); check("void f(int x) {\n" " if (x > 100) { return; }\n" " while (abc) { y = x; }\n" " if (x > 100) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:4:9]: (warning) Identical condition 'x>100', second condition is always false [identicalConditionAfterEarlyExit]\n", errout_str()); ASSERT_THROW_INTERNAL(check("void f(int x) {\n" // #8217 - crash for incomplete code " if (x > 100) { return; }\n" " X(do);\n" " if (x > 100) {}\n" - "}"), + "}\n"), SYNTAX); check("void f(const int *i) {\n" " if (!i) return;\n" " if (!num1tok) { *num1 = *num2; }\n" " if (!i) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:7] -> [test.cpp:4:7]: (warning) Identical condition '!i', second condition is always false [identicalConditionAfterEarlyExit]\n", errout_str()); check("void C::f(Tree &coreTree) {\n" // daca @@ -2878,7 +2919,7 @@ class TestCondition : public TestFixture { " return;\n" " coreTree.dostuff();\n" " if(!coreTree.build()) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct C { void f(const Tree &coreTree); };\n" @@ -2887,7 +2928,7 @@ class TestCondition : public TestFixture { " return;\n" " coreTree.dostuff();\n" " if(!coreTree.build()) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:6] -> [test.cpp:6:6]: (warning) Identical condition '!coreTree.build()', second condition is always false [identicalConditionAfterEarlyExit]\n", errout_str()); check("void f(int x) {\n" // daca: labplot @@ -2900,7 +2941,7 @@ class TestCondition : public TestFixture { " else return 4;\n" " }\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("static int failed = 0;\n" @@ -2908,14 +2949,14 @@ class TestCondition : public TestFixture { " if (failed) return;\n" " checkBuffer();\n" " if (failed) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // daca icu check("void f(const uint32_t *section, int32_t start) {\n" " if(10<=section[start]) { return; }\n" " if(++start<100 && 10<=section[start]) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // daca iqtree @@ -2925,7 +2966,7 @@ class TestCondition : public TestFixture { " if (ch != '|') return;\n" " in >> ch;\n" " if (ch != '|') {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #8924 @@ -2936,7 +2977,7 @@ class TestCondition : public TestFixture { " if (this->FileIndex < 0) return;\n" " }\n" " int FileIndex;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:5:29]: (style) Condition 'this->FileIndex<0' is always false [knownConditionTrueFalse]\n", errout_str()); // #8858 - #if @@ -2948,7 +2989,7 @@ class TestCondition : public TestFixture { " ret = bar2();\n" "#endif\n" " return ret;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #10456 @@ -2986,7 +3027,7 @@ class TestCondition : public TestFixture { " x += y;\n" " if (x == 0) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" @@ -2994,7 +3035,7 @@ class TestCondition : public TestFixture { " x += y;\n" " if (x == 1) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int * x, int * y) {\n" @@ -3002,7 +3043,32 @@ class TestCondition : public TestFixture { " (*y)++;\n" " if (x[*y] == 0) {}\n" " }\n" - "}"); + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void g(int[]);\n" // #14724 + "void f(int a[]) {\n" + " if (a[0] == 1) {\n" + " g(a);\n" + " if (a[0] == 1) {}\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + + void overlappingInnerCondition() { + check("void f(int x) {\n" + " if (x == 1) {\n" + " if (x & 7) {}\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:15]: (warning) Overlapping inner 'if' condition is always true. [overlappingInnerCondition]\n", errout_str()); + + check("void f(int x) {\n" + " if (x & 7) {\n" + " if (x == 1) {}\n" + " }\n" + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -3010,102 +3076,102 @@ class TestCondition : public TestFixture { void clarifyCondition1() { check("void f() {\n" " if (x = b() < 0) {}\n" // don't simplify and verify this code - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:8]: (style) Suspicious condition (assignment + comparison); Clarify expression with parentheses. [clarifyCondition]\n", errout_str()); check("void f(int i) {\n" " for (i = 0; i < 10; i++) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " x = a(); if (x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " if (x = b < 0 ? 1 : 2) {}\n" // don't simplify and verify this code - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " int y = rand(), z = rand();\n" " if (y || (!y && z));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11]: (style) Redundant condition: !y. 'y || (!y && z)' is equivalent to 'y || z' [redundantCondition]\n", errout_str()); check("void f() {\n" " int y = rand(), z = rand();\n" " if (y || !y && z);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11]: (style) Redundant condition: !y. 'y || (!y && z)' is equivalent to 'y || z' [redundantCondition]\n", errout_str()); check("void f() {\n" " if (!a || a && b) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:12]: (style) Redundant condition: a. '!a || (a && b)' is equivalent to '!a || b' [redundantCondition]\n", errout_str()); check("void f(const Token *tok) {\n" " if (!tok->next()->function() ||\n" " (tok->next()->function() && tok->next()->function()->isConstructor()));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:34]: (style) Redundant condition: tok->next()->function(). '!A || (A && B)' is equivalent to '!A || B' [redundantCondition]\n", errout_str()); check("void f() {\n" " if (!tok->next()->function() ||\n" " (!tok->next()->function() && tok->next()->function()->isConstructor()));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " if (!tok->next()->function() ||\n" " (!tok2->next()->function() && tok->next()->function()->isConstructor()));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(const Token *tok) {\n" " if (!tok->next(1)->function(1) ||\n" " (tok->next(1)->function(1) && tok->next(1)->function(1)->isConstructor()));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:36]: (style) Redundant condition: tok->next(1)->function(1). '!A || (A && B)' is equivalent to '!A || B' [redundantCondition]\n", errout_str()); check("void f() {\n" " if (!tok->next()->function(1) ||\n" " (tok->next()->function(2) && tok->next()->function()->isConstructor()));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " int y = rand(), z = rand();\n" " if (y==0 || y!=0 && z);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:13]: (style) Redundant condition: y!=0. 'y==0 || (y!=0 && z)' is equivalent to 'y==0 || z' [redundantCondition]\n", errout_str()); check("void f() {\n" " if (x>0 || (x<0 && y)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Test Token::expressionString, TODO move this test check("void f() {\n" " if (!dead || (dead && (*it).ticks > 0)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:13]: (style) Redundant condition: dead. '!dead || (dead && (*it).ticks>0)' is equivalent to '!dead || (*it).ticks>0' [redundantCondition]\n", errout_str()); check("void f() {\n" " if (!x || (x && (2>(y-1)))) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:10]: (style) Redundant condition: x. '!x || (x && 2>(y-1))' is equivalent to '!x || 2>(y-1)' [redundantCondition]\n", errout_str()); check("void f(bool a, bool b) {\n" " if (a || (a && b)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Redundant condition: a. 'a || (a && b)' is equivalent to 'a' [redundantCondition]\n", errout_str()); check("void f(bool a, bool b) {\n" " if (a && (a || b)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Redundant condition: a. 'a && (a || b)' is equivalent to 'a' [redundantCondition]\n", errout_str()); } @@ -3113,14 +3179,14 @@ class TestCondition : public TestFixture { void clarifyCondition2() { check("void f() {\n" " if (x & 3 == 2) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:8]: (style) Suspicious condition (bitwise operator + comparison); Clarify expression with parentheses. [clarifyCondition]\n" "[test.cpp:2:11]: (style) Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition]\n" "[test.cpp:2:11]: (style) Condition 'x&3==2' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f() {\n" " if (a & fred1.x == fred2.y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:8]: (style) Suspicious condition (bitwise operator + comparison); Clarify expression with parentheses. [clarifyCondition]\n" "[test.cpp:2:11]: (style) Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition]\n" , errout_str()); @@ -3130,50 +3196,50 @@ class TestCondition : public TestFixture { void clarifyCondition3() { check("void f(int w) {\n" " if(!w & 0x8000) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition]\n", errout_str()); check("void f(int w) {\n" " if((!w) & 0x8000) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " if (x == foo() & 2) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:20]: (style) Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition]\n", errout_str()); check("void f() {\n" " if (2 & x == foo()) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition]\n", errout_str()); check("void f() {\n" " if (2 & (x == foo())) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(std::list &ints) { }"); + check("void f(std::list &ints) { }\n"); ASSERT_EQUALS("", errout_str()); - check("void f() { A a; }"); + check("void f() { A a; }\n"); ASSERT_EQUALS("", errout_str()); - check("void f() { a(x there are never templates + check("void f() { a(x there are never templates ASSERT_EQUALS("[test.c:1:17]: (style) Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition]\n", errout_str()); - check("class A;"); + check("class A;\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " if (result != (char *)&inline_result) { }\n" // don't simplify and verify cast - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #8495 check("void f(bool a, bool b) {\n" " C & a & b;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -3188,13 +3254,13 @@ class TestCondition : public TestFixture { " {\n" " return left.first < right.first;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void clarifyCondition5() { // ticket #3609 (using | in template instantiation) check("template struct CWinTraits;\n" - "CWinTraits::GetWndStyle(0);"); + "CWinTraits::GetWndStyle(0);\n"); ASSERT_EQUALS("", errout_str()); } @@ -3203,7 +3269,7 @@ class TestCondition : public TestFixture { "SharedPtr& operator=( SharedPtr const & r ) {\n" " px = r.px;\n" " return *this;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -3212,7 +3278,7 @@ class TestCondition : public TestFixture { check("void f(bool error) {\n" " bool & withoutSideEffects=found.first->second;\n" // Declaring a reference to a boolean; & is no operator at all " execute(secondExpression, &programMemory, &result, &error);\n" // Unary & - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -3222,24 +3288,24 @@ class TestCondition : public TestFixture { check("bool a();\n" "bool f(bool b) {\n" " return (a() & b);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("bool f(bool *a, bool b) {\n" " return (a[10] & b);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A { bool a; };\n" "bool f(struct A a, bool b) {\n" " return (a.a & b);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A { bool a; };\n" "bool f(struct A a, bool b) {\n" " return (A::a & b);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -3247,7 +3313,7 @@ class TestCondition : public TestFixture { check("void png_parse(uint64_t init, int buf_size) {\n" " if (init == 0x89504e470d0a1a0a || init == 0x8a4d4e470d0a1a0a)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -3256,7 +3322,7 @@ class TestCondition : public TestFixture { "void foo() {\n" " if( ( value >= 0x7ff0000000000001ULL )\n" " && ( value <= 0x7fffffffffffffffULL ) );\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -3266,7 +3332,7 @@ class TestCondition : public TestFixture { " int x1 = s->x;\n" " int x2 = s->x;\n" " if (x1 == 10 && x2 == 10) {}\n" // << - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:10] -> [test.cpp:4:22]: (style) Condition 'x2==10' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f ()\n"// #8220 @@ -3282,27 +3348,27 @@ class TestCondition : public TestFixture { " a ++;\n" " }\n" " ret = b;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:27] -> [test.cpp:8:40]: (style) Condition '8 [test.cpp:2:30]: (style) Return value 'x==0' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f() {\n" // #6898 (Token::expressionString) " int x = 0;\n" " A(x++ == 1);\n" " A(x++ == 2);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9]: (style) Condition 'x++==1' is always false [knownConditionTrueFalse]\n" "[test.cpp:4:9]: (style) Condition 'x++==2' is always false [knownConditionTrueFalse]\n", errout_str()); @@ -3314,68 +3380,68 @@ class TestCondition : public TestFixture { " if (bar == 2)\n" " ret = true;\n" " return ret;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); - check("void f1(const std::string &s) { if(s.empty()) if(s.size() == 0) {}}"); + check("void f1(const std::string &s) { if(s.empty()) if(s.size() == 0) {}}\n"); ASSERT_EQUALS("[test.cpp:1:43] -> [test.cpp:1:59]: (style) Condition 's.size()==0' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f() {\n" " int buf[42];\n" " if( buf != 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:12]: (style) Condition 'buf!=0' is always true [knownConditionTrueFalse]\n", errout_str()); // #8924 check("void f() {\n" " int buf[42];\n" " if( !buf ) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8]: (style) Condition '!buf' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f() {\n" " int buf[42];\n" " bool b = buf;\n" " if( b ) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:8]: (style) Condition 'b' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f() {\n" " int buf[42];\n" " bool b = buf;\n" " if( !b ) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:8]: (style) Condition '!b' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f() {\n" " int buf[42];\n" " int * p = nullptr;\n" " if( buf == p ) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:12]: (style) Condition 'buf==p' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f(bool x) {\n" " int buf[42];\n" " if( buf || x ) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8]: (style) Condition 'buf' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f(int * p) {\n" " int buf[42];\n" " if( buf == p ) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " int buf[42];\n" " int p[42];\n" " if( buf == p ) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " int buf[42];\n" " if( buf == 1) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Avoid FP when condition comes from macro @@ -3384,7 +3450,7 @@ class TestCondition : public TestFixture { " int x = 0;\n" " if (a) { return; }\n" // <- this is just here to fool simplifyKnownVariabels " if (NOT x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("#define M x != 0\n" @@ -3392,27 +3458,27 @@ class TestCondition : public TestFixture { " int x = 0;\n" " if (a) { return; }\n" // <- this is just here to fool simplifyKnownVariabels " if (M) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("#define IF(X) if (X && x())\n" "void f() {\n" " IF(1) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Avoid FP for sizeof condition check("void f() {\n" " if (sizeof(char) != 123) {}\n" " if (123 != sizeof(char)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " int x = 123;\n" " if (sizeof(char) != x) {}\n" " if (x != sizeof(char)) {}\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:3]: (style) Condition 'sizeof(char)!=x' is always true\n" "[test.cpp:4]: (style) Condition 'x!=sizeof(char)' is always true\n", "", errout_str()); @@ -3421,7 +3487,7 @@ class TestCondition : public TestFixture { check("void f() {\n" " int x = 0;\n" " assert(x == 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9363 - do not warn about value passed to function @@ -3429,7 +3495,7 @@ class TestCondition : public TestFixture { " if (b) {\n" " if (bar(!b)) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); @@ -3444,7 +3510,7 @@ class TestCondition : public TestFixture { " assert((int)(0==0));\n" " assert((int)(0==0) && \"bla\");\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #7750 char literals in boolean expressions @@ -3453,7 +3519,7 @@ class TestCondition : public TestFixture { " if(L'b'){}\n" " if(1 && 'c'){}\n" " int x = 'd' ? 1 : 2;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #8206 - knownCondition always false @@ -3461,26 +3527,26 @@ class TestCondition : public TestFixture { "{\n" " if(i > 4)\n" " for( int x = 0; i < 3; ++x){}\n" // << - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:14] -> [test.cpp:4:29]: (style) Condition 'i<3' is always false [knownConditionTrueFalse]\n", errout_str()); // Skip literals - check("void f() { if(true) {} }"); + check("void f() { if(true) {} }\n"); ASSERT_EQUALS("", errout_str()); - check("void f() { if(false) {} }"); + check("void f() { if(false) {} }\n"); ASSERT_EQUALS("", errout_str()); - check("void f() { if(!true) {} }"); + check("void f() { if(!true) {} }\n"); ASSERT_EQUALS("", errout_str()); - check("void f() { if(!false) {} }"); + check("void f() { if(!false) {} }\n"); ASSERT_EQUALS("", errout_str()); - check("void f() { if(0) {} }"); + check("void f() { if(0) {} }\n"); ASSERT_EQUALS("", errout_str()); - check("void f() { if(1) {} }"); + check("void f() { if(1) {} }\n"); ASSERT_EQUALS("", errout_str()); check("void f(int i) {\n" @@ -3489,36 +3555,36 @@ class TestCondition : public TestFixture { " else if (!b && i == 1) {}\n" " if (b)\n" " {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:14]: (style) Condition '!b' is always true [knownConditionTrueFalse]\n", errout_str()); - check("bool f() { return nullptr; }"); + check("bool f() { return nullptr; }\n"); ASSERT_EQUALS("", errout_str()); check("enum E { A };\n" - "bool f() { return A; }"); + "bool f() { return A; }\n"); ASSERT_EQUALS("", errout_str()); check("bool f() {\n" " const int x = 0;\n" " return x;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); - check("int f(void){return 1/abs(10);}"); + check("int f(void){return 1/abs(10);}\n"); ASSERT_EQUALS("", errout_str()); check("bool f() {\n" " int x = 0;\n" " return x;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("bool f() {\n" " const int a = 50;\n" " const int b = 52;\n" " return a+b;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:13]: (style) Return value 'a+b' is always true [knownConditionTrueFalse]\n", errout_str()); check("int f() {\n" @@ -3527,7 +3593,7 @@ class TestCondition : public TestFixture { " a++;\n" " b++;\n" " return a+b;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("bool& g();\n" @@ -3535,7 +3601,7 @@ class TestCondition : public TestFixture { " bool & b = g();\n" " b = false;\n" " return b;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A {\n" @@ -3544,13 +3610,13 @@ class TestCondition : public TestFixture { " b = false;\n" " return b;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("bool f(long maxtime) {\n" " if (std::time(0) > maxtime)\n" " return std::time(0) > maxtime;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(double param) {\n" @@ -3560,7 +3626,7 @@ class TestCondition : public TestFixture { " }\n" " if (param<0.)\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int i) {\n" @@ -3570,7 +3636,7 @@ class TestCondition : public TestFixture { " }\n" " if (cond && (42==i))\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // 8842 crash @@ -3580,15 +3646,15 @@ class TestCondition : public TestFixture { " void f() {\n" " if (b) return;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("void f(const char* x, const char* t) {\n" " if (!(strcmp(x, y) == 0)) { return; }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(const int a[]){ if (a == 0){} }"); + check("void f(const int a[]){ if (a == 0){} }\n"); ASSERT_EQUALS("", errout_str()); check("struct S {\n" @@ -3599,7 +3665,7 @@ class TestCondition : public TestFixture { " bool c = s [test.cpp:3:9]: (style) Condition 'handle' is always true [knownConditionTrueFalse]\n", errout_str()); check("int f(void *handle) {\n" " if (handle == 0) return 0;\n" " if (handle) return 1;\n" " else return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9]: (style) Condition 'handle' is always true [knownConditionTrueFalse]\n", errout_str()); check("int f(void *handle) {\n" " if (handle != 0) return 0;\n" " if (handle) return 1;\n" " else return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:16] -> [test.cpp:3:9]: (warning) Identical condition 'handle!=0', second condition is always false [identicalConditionAfterEarlyExit]\n", errout_str()); check("int f(void *handle) {\n" " if (handle != nullptr) return 0;\n" " if (handle) return 1;\n" " else return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:16] -> [test.cpp:3:9]: (warning) Identical condition 'handle!=nullptr', second condition is always false [identicalConditionAfterEarlyExit]\n", errout_str()); + check("void f(const char* p) {\n" // #13716 + " if (!p) {}\n" + " if (p == NULL) {}\n" + " if (p == nullptr) {}\n" + " if (p == 0) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:11]: (style) The if condition is the same as the previous if condition [duplicateCondition]\n", + errout_str()); + + check("int f(const char* p) {\n" // #13717 + " if (p) {}\n" + " else if (!p) {}\n" + " else if (p == NULL) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:14]: (style) Expression is always true because 'else if' condition is opposite to previous condition at line 2. [multiCondition]\n" + "[test.cpp:4:16]: (style) Expression is always false because 'else if' condition matches previous condition at line 3. [multiCondition]\n", + errout_str()); + check("void f(void* x, void* y) {\n" " if (x == nullptr && y == nullptr)\n" " return;\n" " if (x == nullptr || y == nullptr)\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void* g();\n" @@ -3655,7 +3739,7 @@ class TestCondition : public TestFixture { " break;\n" " }\n" " if (a) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void* g();\n" @@ -3664,26 +3748,26 @@ class TestCondition : public TestFixture { " a = g();\n" " }\n" " if (a) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:12] -> [test.cpp:6:9]: (style) Condition 'a' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f(int * x, bool b) {\n" " if (!x && b) {}\n" " else if (x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " const std::string x=\"xyz\";\n" " if(!x.empty()){}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8]: (style) Condition '!x.empty()' is always true [knownConditionTrueFalse]\n", errout_str()); check("std::string g();\n" "void f() {\n" " const std::string msg = g();\n" " if(!msg.empty()){}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int *array, int size ) {\n" @@ -3692,7 +3776,7 @@ class TestCondition : public TestFixture { " continue;\n" " if(array){}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:12]: (style) Condition 'array' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f(int *array, int size ) {\n" @@ -3701,7 +3785,7 @@ class TestCondition : public TestFixture { " continue;\n" " else if(array){}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:17]: (style) Condition 'array' is always true [knownConditionTrueFalse]\n", errout_str()); // #9277 @@ -3711,7 +3795,7 @@ class TestCondition : public TestFixture { " return 0;\n" " else\n" " return 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9954 @@ -3733,7 +3817,7 @@ class TestCondition : public TestFixture { " bool x = false;\n" " g({0, 1}, x);\n" " if (x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9318 @@ -3744,7 +3828,7 @@ class TestCondition : public TestFixture { " return;\n" " auto b = dynamic_cast(x);\n" " if (b) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int foo() {\n" @@ -3762,7 +3846,7 @@ class TestCondition : public TestFixture { check("bool g();\n" "void f(bool x) {\n" " if (x) while(x) x = g();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // isLikelyStream @@ -3772,7 +3856,7 @@ class TestCondition : public TestFixture { " iss >> x;\n" " if (!iss) break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9332 @@ -3784,14 +3868,14 @@ class TestCondition : public TestFixture { " void* c = a.g();\n" " if (!c) return;\n" " bool compare = c == b;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9361 check("void f(char c) {\n" " if (c == '.') {}\n" " else if (isdigit(c) != 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9351 @@ -3799,7 +3883,7 @@ class TestCondition : public TestFixture { " const bool b = x < 42;\n" " if(b) return b?0:-1;\n" " return 42;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:3:18]: (style) Condition 'b' is always true [knownConditionTrueFalse]\n", errout_str()); // #9362 @@ -3809,7 +3893,7 @@ class TestCondition : public TestFixture { " if((v != 0x00)) {\n" " if( (v & 0x01) == 0x00) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9367 @@ -3818,25 +3902,25 @@ class TestCondition : public TestFixture { " return;\n" " if (x % 360L == 0)\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f(int a, int b) {\n" " static const int x = 10;\n" " return x == 1 ? a : b;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("const bool x = false;\n" "void f() {\n" " if (x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("const bool x = false;\n" "void f() {\n" " if (!x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9709 @@ -3847,7 +3931,7 @@ class TestCondition : public TestFixture { " if (r != nullptr)\n" " ok = a != 0;\n" " if (ok) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9816 @@ -4036,7 +4120,7 @@ class TestCondition : public TestFixture { check("void foo(unsigned int max) {\n" " unsigned int num = max - 1;\n" " if (num < 0) {}\n" // <- do not report knownConditionTrueFalse - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #10297 @@ -4375,7 +4459,7 @@ class TestCondition : public TestFixture { ASSERT_EQUALS("", errout_str()); // #8358 - check("void f(double d) { if ((d * 0) != 0) {} }"); + check("void f(double d) { if ((d * 0) != 0) {} }\n"); ASSERT_EQUALS("", errout_str()); // #6870 @@ -4581,11 +4665,7 @@ class TestCondition : public TestFixture { " if (o[1] == '\\0') {}\n" " }\n" "}\n"); - if (std::numeric_limits::is_signed) { - ASSERT_EQUALS("[test.cpp:6:18]: (style) Condition 'o[1]=='\\0'' is always false [knownConditionTrueFalse]\n", errout_str()); - } else { - ASSERT_EQUALS("[test.cpp:4:25] -> [test.cpp:6:18]: (style) Condition 'o[1]=='\\0'' is always false [knownConditionTrueFalse]\n", errout_str()); - } + ASSERT_EQUALS("[test.cpp:6:18]: (style) Condition 'o[1]=='\\0'' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f(int x) {\n" // #11449 " int i = x;\n" @@ -4659,7 +4739,7 @@ class TestCondition : public TestFixture { " }\n" " }\n" "}\n"); - ASSERT_EQUALS("[test.cpp:5:18]: (style) Condition 'S::s' is always true [knownConditionTrueFalse]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:3:10] -> [test.cpp:5:18]: (warning) Identical inner 'if' condition is always true. [identicalInnerCondition]\n", errout_str()); check("void f() {\n" // #10811 " int i = 0;\n" @@ -4739,7 +4819,7 @@ class TestCondition : public TestFixture { " return 9;\n" " \n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int g();\n" // #10561 @@ -4754,7 +4834,7 @@ class TestCondition : public TestFixture { " }\n" " catch (...) {}\n" " return b ? 1 : 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct S {\n" @@ -4786,6 +4866,111 @@ class TestCondition : public TestFixture { " }\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("struct S {\n" // #14392 + " bool g() const { return m; }\n" + " bool m{};\n" + "};\n" + "bool f(S s) {\n" + " if (s.g()) {\n" + " bool b = s.g();\n" + " return b;\n" + " }\n" + " return false;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6:12] -> [test.cpp:7:21]: (style) Assigned value 's.g()' is always true [knownConditionTrueFalse]\n", errout_str()); + + check("void f(const void* p) {\n" // #11519 + " bool b = false;\n" + " if (!p && !b) {}\n" + " if (!b) {}\n" + " (void)b;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:15]: (style) Condition '!b' is always true [knownConditionTrueFalse]\n" + "[test.cpp:4:9]: (style) Condition '!b' is always true [knownConditionTrueFalse]\n", + errout_str()); + + check("struct C {\n" // #12532 + " void f() const;\n" + " int a, b;\n" + "};\n" + "void C::f() const {\n" + " if (a)\n" + " return;\n" + " if (!b) {}\n" + " if (a) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6:9] -> [test.cpp:9:9]: (warning) Identical condition 'a', second condition is always false [identicalConditionAfterEarlyExit]\n", + errout_str()); + + check("bool b() { return false; }\n" // #10452 + "void f() {\n" + " if (b()) {}\n" + " if (!b()) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:10]: (style) Condition 'b()' is always false [knownConditionTrueFalse]\n" + "[test.cpp:4:9]: (style) Condition '!b()' is always true [knownConditionTrueFalse]\n", + errout_str()); + + 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()); + + check("void f() {\n" + " if (42) {}\n" + " if (42U) {}\n" + " if (42L) {}\n" + " if (42UL) {}\n" + " if (42LL) {}\n" + " if (042) {}\n" + " if (0x42) {}\n" + " if (0b101010) {}\n" + " if (!42) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:9]: (style) Condition '42' is always true [knownConditionTrueFalse]\n" + "[test.cpp:3:9]: (style) Condition '42U' is always true [knownConditionTrueFalse]\n" + "[test.cpp:4:9]: (style) Condition '42L' is always true [knownConditionTrueFalse]\n" + "[test.cpp:5:9]: (style) Condition '42UL' is always true [knownConditionTrueFalse]\n" + "[test.cpp:6:9]: (style) Condition '42LL' is always true [knownConditionTrueFalse]\n" + "[test.cpp:7:9]: (style) Condition '042' is always true [knownConditionTrueFalse]\n" + "[test.cpp:8:9]: (style) Condition '0x42' is always true [knownConditionTrueFalse]\n" + "[test.cpp:9:9]: (style) Condition '0b101010' is always true [knownConditionTrueFalse]\n" + "[test.cpp:10:9]: (style) Condition '!42' is always false [knownConditionTrueFalse]\n", + errout_str()); } void alwaysTrueSymbolic() @@ -4805,10 +4990,10 @@ class TestCondition : public TestFixture { "}\n"); ASSERT_EQUALS("[test.cpp:2:10] -> [test.cpp:4:14]: (style) Condition 'x==y' is always false [knownConditionTrueFalse]\n", errout_str()); - check("void f(bool a, bool b) { if (a == b && a && !b){} }"); + check("void f(bool a, bool b) { if (a == b && a && !b){} }\n"); ASSERT_EQUALS("[test.cpp:1:41] -> [test.cpp:1:46]: (style) Condition '!b' is always false [knownConditionTrueFalse]\n", errout_str()); - check("bool f(bool a, bool b) { if(a && b && (!a)){} }"); + check("bool f(bool a, bool b) { if(a && b && (!a)){} }\n"); ASSERT_EQUALS("[test.cpp:1:29] -> [test.cpp:1:40]: (style) Condition '!a' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f(int x, int y) {\n" @@ -5019,6 +5204,52 @@ class TestCondition : public TestFixture { " if (i < 0) {}\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("struct A { int x; int y; };\n" + "void use(int);\n" + "void test(A a) {\n" + " int i = a.x;\n" + " int j = a.x;\n" + " use(j);\n" + " if (i == j) {}\n" + " if (i == a.x) {}\n" + " if (j == a.x) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:7:11]: (style) Condition 'i==j' is always true [knownConditionTrueFalse]\n" + "[test.cpp:8:11]: (style) Condition 'i==a.x' is always true [knownConditionTrueFalse]\n" + "[test.cpp:9:11]: (style) Condition 'j==a.x' is always true [knownConditionTrueFalse]\n", + errout_str()); + + check("struct S { int i; };\n" // #12795 + "struct T {\n" + " std::map m;\n" + " S* get(const std::string& s) { return m[s]; }\n" + " void modify() { for (const auto& e : m) e.second->i = 0; }\n" + "};\n" + "void f(T& t) {\n" + " const S* p = t.get(\"abc\");\n" + " const int o = p->i;\n" + " t.modify();\n" + " if (p->i == o) {}\n" + "}\n"); + TODO_ASSERT_EQUALS("", + "[test.cpp:11:14]: (style) Condition 'p->i==o' is always true [knownConditionTrueFalse]\n", + errout_str()); + + check("void f(int x) {\n" // #12320 + " int a = 0, b = 0, c = 0;\n" + " a = x;\n" + " if (a) b = x;\n" + " if (b) c = x;\n" + " if (c) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f(int a, int b) {\n" // #11437 + " a = a < b ? b : a;\n" + " if (a != b) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void alwaysTrueInfer() { @@ -5027,7 +5258,7 @@ class TestCondition : public TestFixture { " x++;\n" " if (x == 1) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:4:15]: (style) Condition 'x==1' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f(int x) {\n" @@ -5035,7 +5266,7 @@ class TestCondition : public TestFixture { " x++;\n" " if (x != 1) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:4:15]: (style) Condition 'x!=1' is always true [knownConditionTrueFalse]\n", errout_str()); // #6890 @@ -5047,7 +5278,7 @@ class TestCondition : public TestFixture { " if (x == -1) {}\n" " else {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:6:15]: (style) Condition 'x==-1' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f(int i) {\n" @@ -5058,7 +5289,7 @@ class TestCondition : public TestFixture { " if (x != -1) {}\n" " else {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:6:15]: (style) Condition 'x!=-1' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f(int i) {\n" @@ -5069,7 +5300,7 @@ class TestCondition : public TestFixture { " if (x >= -1) {}\n" " else {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:6:15]: (style) Condition 'x>=-1' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f(int i) {\n" @@ -5080,7 +5311,7 @@ class TestCondition : public TestFixture { " if (x > -1) {}\n" " else {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:6:15]: (style) Condition 'x>-1' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f(int i) {\n" @@ -5091,7 +5322,7 @@ class TestCondition : public TestFixture { " if (x < -1) {}\n" " else {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:6:15]: (style) Condition 'x<-1' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f(int i) {\n" @@ -5102,7 +5333,7 @@ class TestCondition : public TestFixture { " if (x <= -1) {}\n" " else {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:6:15]: (style) Condition 'x<=-1' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f(int i) {\n" @@ -5113,7 +5344,7 @@ class TestCondition : public TestFixture { " if (x > 7) {}\n" " else {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:6:15]: (style) Condition 'x>7' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f(int i) {\n" @@ -5124,7 +5355,7 @@ class TestCondition : public TestFixture { " if (x > 9) {}\n" " else {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int i) {\n" @@ -5135,7 +5366,7 @@ class TestCondition : public TestFixture { " if (x > 10) {}\n" " else {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #11100 @@ -5160,7 +5391,7 @@ class TestCondition : public TestFixture { " if(pos > 0)\n" " --pos;\n" " return pos;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:13] -> [test.cpp:5:16]: (style) Condition 'pos>0' is always true [knownConditionTrueFalse]\n", errout_str()); // #9721 @@ -5169,7 +5400,7 @@ class TestCondition : public TestFixture { " if ( (x>255) || (-128>x) )\n" " return;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:30]: (style) Condition '-128>x' is always false [knownConditionTrueFalse]\n", errout_str()); // #8778 @@ -5183,7 +5414,7 @@ class TestCondition : public TestFixture { check("void f() {\n" " for(int x = 0; x < 3; ++x)\n" " if(x == -5) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:14]: (style) Condition 'x==-5' is always false [knownConditionTrueFalse]\n", errout_str()); // #8407 @@ -5192,7 +5423,7 @@ class TestCondition : public TestFixture { " if(i == 0) return 1; \n" // << " else return 0;\n" " return -1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:14]: (style) Condition 'i==0' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f(unsigned int u1, unsigned int u2) {\n" @@ -5264,7 +5495,7 @@ class TestCondition : public TestFixture { " c2(g );\n" " if ( !g.empty() )\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int flag) {\n" @@ -5275,7 +5506,7 @@ class TestCondition : public TestFixture { " c2(g );\n" " if ( !g.empty() )\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A {\n" @@ -5321,11 +5552,7 @@ class TestCondition : public TestFixture { " buffer.back() == '\\n' ||\n" " buffer.back() == '\\0') {}\n" "}\n"); - if (std::numeric_limits::is_signed) { - ASSERT_EQUALS("[test.cpp:5:22]: (style) Condition 'buffer.back()=='\\0'' is always false [knownConditionTrueFalse]\n", errout_str()); - } else { - ASSERT_EQUALS("[test.cpp:3:22] -> [test.cpp:5:22]: (style) Condition 'buffer.back()=='\\0'' is always false [knownConditionTrueFalse]\n", errout_str()); - } + ASSERT_EQUALS("[test.cpp:5:22]: (style) Condition 'buffer.back()=='\\0'' is always false [knownConditionTrueFalse]\n", errout_str()); // #9353 check("struct X { std::string s; };\n" @@ -5490,7 +5717,7 @@ class TestCondition : public TestFixture { " {;}\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:20] -> [test.cpp:7:27]: (style) Condition 'i==1' is always true [knownConditionTrueFalse]\n", errout_str()); // #10863 @@ -5519,7 +5746,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" @@ -5589,12 +5816,38 @@ class TestCondition : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void alwaysTrueSideEffect() { + check("bool check(const char* const);\n" // #14416 + "void create(const char*);\n" + "void f(const char* n) {\n" + " if (!check(n)) {\n" + " create(n);\n" + " if (check(n)) {}\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + + void alwaysTruePremiumMisra() { + const char code[] = "void f() {\n" + " if (3 > 2) {}\n" + "}\n"; + + check(code); + ASSERT_EQUALS("", errout_str()); + + Settings misraSettings; + misraSettings.premiumArgs = "--misra-c-2012"; + check(code, misraSettings); + ASSERT_EQUALS("[test.cpp:2:9]: (style) Condition '3>2' is always true [knownConditionTrueFalse]\n", errout_str()); + } + void multiConditionAlwaysTrue() { check("void f() {\n" " int val = 0;\n" " if (val < 0) continue;\n" " if (val > 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -5602,7 +5855,7 @@ class TestCondition : public TestFixture { " if (val < 0) {\n" " if (val > 0) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -5610,7 +5863,7 @@ class TestCondition : public TestFixture { " if (val < 0) {\n" " if (val < 0) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -5618,7 +5871,7 @@ class TestCondition : public TestFixture { " int foo = 0;\n" " if (activate) {}\n" " else if (foo) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:7]: (style) Condition 'activate' is always false [knownConditionTrueFalse]\n" "[test.cpp:5:12]: (style) Condition 'foo' is always false [knownConditionTrueFalse]\n", errout_str()); @@ -5626,7 +5879,7 @@ class TestCondition : public TestFixture { check("void f() {\n" " const int b[2] = { 1,0 };\n" " if(b[1] == 2) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11]: (style) Condition 'b[1]==2' is always false [knownConditionTrueFalse]\n", errout_str()); // #9878 @@ -5643,40 +5896,40 @@ class TestCondition : public TestFixture { check("void f(bool x) {\n" " if(x) {}\n" " if(x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:8] -> [test.cpp:3:8]: (style) The if condition is the same as the previous if condition [duplicateCondition]\n", errout_str()); check("void f(int x) {\n" " if(x == 1) {}\n" " if(x == 1) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:10] -> [test.cpp:3:10]: (style) The if condition is the same as the previous if condition [duplicateCondition]\n", errout_str()); check("void f(int x) {\n" " if(x == 1) {}\n" " if(x == 2) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" " if(x == 1) {}\n" " if(x != 1) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(bool x) {\n" " if(x) {}\n" " g();\n" " if(x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" " if(x == 1) { x++; }\n" " if(x == 1) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #8996 @@ -5688,7 +5941,7 @@ class TestCondition : public TestFixture { " g(d);\n" " if (a) {}\n" " if (b) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9311 @@ -5703,7 +5956,7 @@ class TestCondition : public TestFixture { " g(d);\n" " if (a) {}\n" " if (b) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #8993 @@ -5711,7 +5964,7 @@ class TestCondition : public TestFixture { " auto y = x;\n" " if (x.empty()) y = \"1\";\n" " if (y.empty()) return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9106 @@ -5719,7 +5972,7 @@ class TestCondition : public TestFixture { "void f(A a, int c) {\n" " if (a.b) a.b = c;\n" " if (a.b) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A {\n" @@ -5841,7 +6094,7 @@ class TestCondition : public TestFixture { " ;\n" " if (other.mPA.cols > 0 && other.mPA.rows > 0)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" // #11202 @@ -5863,32 +6116,54 @@ class TestCondition : public TestFixture { " if (strlen(s2) > 0) {}\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("void g(int*);\n" // #14428 + "int f(int* const p) {\n" + " int i = 0;\n" + " if (*p == 0)\n" + " g(p);\n" + " if (*p == 0)\n" + " i = 1;\n" + " return i;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void g(const int*);\n" + "int f(const int* const p) {\n" + " int i = 0;\n" + " if (*p == 0)\n" + " g(p);\n" + " if (*p == 0)\n" + " i = 1;\n" + " return i;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:12] -> [test.cpp:6:12]: (style) The if condition is the same as the previous if condition [duplicateCondition]\n", errout_str()); } void checkInvalidTestForOverflow() { check("void f(char *p, unsigned int x) {\n" " assert((p + x) < p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:20]: (warning) Invalid test for overflow '(p+x)= p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:20]: (warning) Invalid test for overflow '(p+x)>=p'; pointer overflow is undefined behavior. Some mainstream compilers remove such overflow tests when optimising the code and assume it's always true. [invalidTestForOverflow]\n", errout_str()); check("void f(char *p, unsigned int x) {\n" " assert(p > (p + x));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:14]: (warning) Invalid test for overflow 'p>(p+x)'; pointer overflow is undefined behavior. Some mainstream compilers remove such overflow tests when optimising the code and assume it's always false. [invalidTestForOverflow]\n", errout_str()); check("void f(char *p, unsigned int x) {\n" " assert(p <= (p + x));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:14]: (warning) Invalid test for overflow 'p<=(p+x)'; pointer overflow is undefined behavior. Some mainstream compilers remove such overflow tests when optimising the code and assume it's always true. [invalidTestForOverflow]\n", errout_str()); check("void f(signed int x) {\n" // unsigned overflow => don't warn " assert(x + 100U < x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); @@ -5896,57 +6171,57 @@ class TestCondition : public TestFixture { #define MSG(EXPR, RESULT) "[test.cpp:1:30]: (warning) Invalid test for overflow '" EXPR "'; signed integer overflow is undefined behavior. Some mainstream compilers remove such overflow tests when optimising the code and assume it's always " RESULT ". [invalidTestForOverflow]\n" - check("int f(int x) { return x + 10 > x; }"); + check("int f(int x) { return x + 10 > x; }\n"); ASSERT_EQUALS(MSG("x+10>x", "true"), errout_str()); - check("int f(int x) { return x + 10 >= x; }"); + check("int f(int x) { return x + 10 >= x; }\n"); ASSERT_EQUALS(MSG("x+10>=x", "true"), errout_str()); - check("int f(int x) { return x + 10 < x; }"); + check("int f(int x) { return x + 10 < x; }\n"); ASSERT_EQUALS(MSG("x+10 x; }"); + check("int f(int x) { return x - 10 > x; }\n"); ASSERT_EQUALS(MSG("x-10>x", "false"), errout_str()); - check("int f(int x) { return x - 10 >= x; }"); + check("int f(int x) { return x - 10 >= x; }\n"); ASSERT_EQUALS(MSG("x-10>=x", "false"), errout_str()); - check("int f(int x) { return x - 10 < x; }"); + check("int f(int x) { return x - 10 < x; }\n"); ASSERT_EQUALS(MSG("x-10 x; }"); + check("int f(int x, int y) { return x + y > x; }\n"); ASSERT_EQUALS(MSG("x+y>x", "y>0"), errout_str()); - check("int f(int x, int y) { return x + y >= x; }"); + check("int f(int x, int y) { return x + y >= x; }\n"); ASSERT_EQUALS(MSG("x+y>=x", "y>=0"), errout_str()); // x - y < x - check("int f(int x, int y) { return x - y < x; }"); + check("int f(int x, int y) { return x - y < x; }\n"); ASSERT_EQUALS(MSG("x-y0"), errout_str()); - check("int f(int x, int y) { return x - y <= x; }"); + check("int f(int x, int y) { return x - y <= x; }\n"); ASSERT_EQUALS(MSG("x-y<=x", "y>=0"), errout_str()); - check("int f(int x, int y) { return x - y > x; }"); + check("int f(int x, int y) { return x - y > x; }\n"); ASSERT_EQUALS(MSG("x-y>x", "y<0"), errout_str()); - check("int f(int x, int y) { return x - y >= x; }"); + check("int f(int x, int y) { return x - y >= x; }\n"); ASSERT_EQUALS(MSG("x-y>=x", "y<=0"), errout_str()); } @@ -5955,55 +6230,55 @@ class TestCondition : public TestFixture { " enum states {A,B,C};\n" " const unsigned g_flags = B|C;\n" " if(g_flags & A) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:16]: (style) Condition 'g_flags&A' is always false [knownConditionTrueFalse]\n", errout_str()); check("void f() {\n" " int a = 5;" " if(a) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:22]: (style) Condition 'a' is always true [knownConditionTrueFalse]\n", errout_str()); check("void f() {\n" " int a = 5;" " while(a + 1) { a--; }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " int a = 5;" " while(a + 1) { return; }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:27]: (style) Condition 'a+1' is always true [knownConditionTrueFalse]\n", errout_str()); } void alwaysTrueFalseInLogicalOperators() { check("bool f();\n" - "void foo() { bool x = true; if(x||f()) {}}"); + "void foo() { bool x = true; if(x||f()) {}}\n"); ASSERT_EQUALS("[test.cpp:2:32]: (style) Condition 'x' is always true [knownConditionTrueFalse]\n", errout_str()); - check("void foo(bool b) { bool x = true; if(x||b) {}}"); + check("void foo(bool b) { bool x = true; if(x||b) {}}\n"); ASSERT_EQUALS("[test.cpp:1:38]: (style) Condition 'x' is always true [knownConditionTrueFalse]\n", errout_str()); - check("void foo(bool b) { if(true||b) {}}"); + check("void foo(bool b) { if(true||b) {}}\n"); ASSERT_EQUALS("", errout_str()); check("bool f();\n" - "void foo() { bool x = false; if(x||f()) {}}"); + "void foo() { bool x = false; if(x||f()) {}}\n"); ASSERT_EQUALS("[test.cpp:2:33]: (style) Condition 'x' is always false [knownConditionTrueFalse]\n", errout_str()); check("bool f();\n" - "void foo() { bool x = false; if(x&&f()) {}}"); + "void foo() { bool x = false; if(x&&f()) {}}\n"); ASSERT_EQUALS("[test.cpp:2:33]: (style) Condition 'x' is always false [knownConditionTrueFalse]\n", errout_str()); - check("void foo(bool b) { bool x = false; if(x&&b) {}}"); + check("void foo(bool b) { bool x = false; if(x&&b) {}}\n"); ASSERT_EQUALS("[test.cpp:1:39]: (style) Condition 'x' is always false [knownConditionTrueFalse]\n", errout_str()); - check("void foo(bool b) { if(false&&b) {}}"); + check("void foo(bool b) { if(false&&b) {}}\n"); ASSERT_EQUALS("", errout_str()); check("bool f();\n" - "void foo() { bool x = true; if(x&&f()) {}}"); + "void foo() { bool x = true; if(x&&f()) {}}\n"); ASSERT_EQUALS("[test.cpp:2:32]: (style) Condition 'x' is always true [knownConditionTrueFalse]\n", errout_str()); // #9578 @@ -6018,12 +6293,26 @@ 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" + "}\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() { check("void f(char *ptr) {\n" " if (ptr + 1 != 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning) Comparison is wrong. Result of 'ptr+1' can't be 0 unless there is pointer overflow, and pointer overflow is undefined behaviour. [pointerAdditionResultNotNull]\n", errout_str()); } @@ -6033,7 +6322,7 @@ class TestCondition : public TestFixture { check("void f(int& x, int y) {\n" " if (x == y)\n" " x = y;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11]: style: Assignment 'x=y' is redundant with condition 'x==y'. [duplicateConditionalAssign]\n" "[test.cpp:2:11]: note: Condition 'x==y'\n" "[test.cpp:3:11]: note: Assignment 'x=y' is redundant\n", errout_str()); @@ -6041,7 +6330,7 @@ class TestCondition : public TestFixture { check("void f(int& x, int y) {\n" " if (x != y)\n" " x = y;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: style: The statement 'if (x!=y) x=y' is logically equivalent to 'x=y'. [duplicateConditionalAssign]\n" "[test.cpp:3:11]: note: Assignment 'x=y'\n" "[test.cpp:2:11]: note: Condition 'x!=y' is redundant\n", errout_str()); @@ -6051,7 +6340,7 @@ class TestCondition : public TestFixture { " x = y;\n" " else\n" " x = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11]: style: Assignment 'x=y' is redundant with condition 'x==y'. [duplicateConditionalAssign]\n" "[test.cpp:2:11]: note: Condition 'x==y'\n" "[test.cpp:3:11]: note: Assignment 'x=y' is redundant\n", errout_str()); @@ -6061,13 +6350,13 @@ class TestCondition : public TestFixture { " x = y;\n" " else\n" " x = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int& x, int y) {\n" " if (x == y)\n" " x = y + 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void g();\n" @@ -6076,7 +6365,7 @@ class TestCondition : public TestFixture { " x = y;\n" " g();\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("bool f(bool b) {\n" @@ -6122,12 +6411,12 @@ class TestCondition : public TestFixture { void checkAssignmentInCondition() { check("void f(std::string s) {\n" " if (s=\"123\"){}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:10]: (style) Suspicious assignment in condition. Condition 's=\"123\"' is always true. [assignmentInCondition]\n", errout_str()); check("void f(std::string *p) {\n" " if (p=foo()){}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(uint32_t u) {\n" // #2490 @@ -6143,65 +6432,65 @@ class TestCondition : public TestFixture { check("void f(unsigned char c) {\n" " if (c == 256) {}\n" - "}", dinit(CheckOptions, $.s = &settingsUnix64)); + "}\n", settingsUnix64); ASSERT_EQUALS("[test.cpp:2:12]: (style) Comparing expression of type 'unsigned char' against value 256. Condition is always false. [compareValueOutOfTypeRangeError]\n", errout_str()); check("void f(unsigned char* b, int i) {\n" // #6372 " if (b[i] == 256) {}\n" - "}", dinit(CheckOptions, $.s = &settingsUnix64)); + "}\n", settingsUnix64); ASSERT_EQUALS("[test.cpp:2:15]: (style) Comparing expression of type 'unsigned char' against value 256. Condition is always false. [compareValueOutOfTypeRangeError]\n", errout_str()); check("void f(unsigned char c) {\n" " if (c == 255) {}\n" - "}", dinit(CheckOptions, $.s = &settingsUnix64)); + "}\n", settingsUnix64); ASSERT_EQUALS("", errout_str()); check("void f(bool b) {\n" " if (b == true) {}\n" - "}", dinit(CheckOptions, $.s = &settingsUnix64)); + "}\n", settingsUnix64); ASSERT_EQUALS("", errout_str()); // #10372 check("void f(signed char x) {\n" " if (x == 0xff) {}\n" - "}", dinit(CheckOptions, $.s = &settingsUnix64)); + "}\n", settingsUnix64); ASSERT_EQUALS("[test.cpp:2:12]: (style) Comparing expression of type 'signed char' against value 255. Condition is always false. [compareValueOutOfTypeRangeError]\n", errout_str()); check("void f(short x) {\n" " if (x == 0xffff) {}\n" - "}", dinit(CheckOptions, $.s = &settingsUnix64)); + "}\n", settingsUnix64); ASSERT_EQUALS("[test.cpp:2:12]: (style) Comparing expression of type 'signed short' against value 65535. Condition is always false. [compareValueOutOfTypeRangeError]\n", errout_str()); check("void f(int x) {\n" " if (x == 0xffffffff) {}\n" - "}", dinit(CheckOptions, $.s = &settingsUnix64)); + "}\n", settingsUnix64); ASSERT_EQUALS("", errout_str()); check("void f(long x) {\n" " if (x == ~0L) {}\n" - "}", dinit(CheckOptions, $.s = &settingsUnix64)); + "}\n", settingsUnix64); ASSERT_EQUALS("", errout_str()); check("void f(long long x) {\n" " if (x == ~0LL) {}\n" - "}", dinit(CheckOptions, $.s = &settingsUnix64)); + "}\n", settingsUnix64); ASSERT_EQUALS("", errout_str()); check("int f(int x) {\n" " const int i = 0xFFFFFFFF;\n" " if (x == i) {}\n" - "}", dinit(CheckOptions, $.s = &settingsUnix64)); + "}\n", settingsUnix64); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " char c;\n" " if ((c = foo()) != -1) {}\n" - "}", dinit(CheckOptions, $.s = &settingsUnix64)); + "}\n", settingsUnix64); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" " if (x < 3000000000) {}\n" - "}", dinit(CheckOptions, $.s = &settingsUnix64)); + "}\n", settingsUnix64); ASSERT_EQUALS("[test.cpp:2:11]: (style) Comparing expression of type 'signed int' against value 3000000000. Condition is always true. [compareValueOutOfTypeRangeError]\n", errout_str()); check("void f(const signed char i) {\n" // #8545 @@ -6211,7 +6500,7 @@ class TestCondition : public TestFixture { " if (i < +128) {}\n" // warn " if (i <= +127) {}\n" // warn " if (i <= +126) {}\n" - "}\n", dinit(CheckOptions, $.s = &settingsUnix64)); + "}\n", settingsUnix64); ASSERT_EQUALS("[test.cpp:2:15]: (style) Comparing expression of type 'const signed char' against value -129. Condition is always true. [compareValueOutOfTypeRangeError]\n" "[test.cpp:3:15]: (style) Comparing expression of type 'const signed char' against value -128. Condition is always true. [compareValueOutOfTypeRangeError]\n" "[test.cpp:5:15]: (style) Comparing expression of type 'const signed char' against value 128. Condition is always true. [compareValueOutOfTypeRangeError]\n" @@ -6220,37 +6509,62 @@ class TestCondition : public TestFixture { check("void f(const unsigned char u) {\n" " if (u > 0) {}\n" - " if (u < 0) {}\n" // warn - " if (u >= 0) {}\n" // warn + " if (u < 0) {}\n" + " if (u >= 0) {}\n" " if (u <= 0) {}\n" " if (u > 255) {}\n" // warn " if (u < 255) {}\n" " if (u >= 255) {}\n" " if (u <= 255) {}\n" // warn " if (0 < u) {}\n" - " if (0 > u) {}\n" // warn - " if (0 <= u) {}\n" // warn + " if (0 > u) {}\n" + " if (0 <= u) {}\n" " if (0 >= u) {}\n" " if (255 < u) {}\n" // warn " if (255 > u) {}\n" " if (255 <= u) {}\n" " if (255 >= u) {}\n" // warn - "}\n", dinit(CheckOptions, $.s = &settingsUnix64)); - ASSERT_EQUALS("[test.cpp:3:14]: (style) Comparing expression of type 'const unsigned char' against value 0. Condition is always false. [compareValueOutOfTypeRangeError]\n" - "[test.cpp:4:14]: (style) Comparing expression of type 'const unsigned char' against value 0. Condition is always true. [compareValueOutOfTypeRangeError]\n" - "[test.cpp:6:14]: (style) Comparing expression of type 'const unsigned char' against value 255. Condition is always false. [compareValueOutOfTypeRangeError]\n" + "}\n", settingsUnix64); + ASSERT_EQUALS("[test.cpp:6:14]: (style) Comparing expression of type 'const unsigned char' against value 255. Condition is always false. [compareValueOutOfTypeRangeError]\n" "[test.cpp:9:14]: (style) Comparing expression of type 'const unsigned char' against value 255. Condition is always true. [compareValueOutOfTypeRangeError]\n" - "[test.cpp:11:9]: (style) Comparing expression of type 'const unsigned char' against value 0. Condition is always false. [compareValueOutOfTypeRangeError]\n" - "[test.cpp:12:9]: (style) Comparing expression of type 'const unsigned char' against value 0. Condition is always true. [compareValueOutOfTypeRangeError]\n" "[test.cpp:14:9]: (style) Comparing expression of type 'const unsigned char' against value 255. Condition is always false. [compareValueOutOfTypeRangeError]\n" "[test.cpp:17:9]: (style) Comparing expression of type 'const unsigned char' against value 255. Condition is always true. [compareValueOutOfTypeRangeError]\n", errout_str()); check("void f(bool b) {\n" // #14037 " if (b != 2) {}\n" - "}\n", dinit(CheckOptions, $.s = &settingsUnix64)); + "}\n", settingsUnix64); ASSERT_EQUALS("[test.cpp:2:14]: (style) Comparing expression of type 'bool' against value 2. Condition is always true. [compareValueOutOfTypeRangeError]\n", errout_str()); + + check("void f(const std::uint32_t& u) {\n" // #9078 + " if (u >= UINT32_MAX) {}\n" + " if (u <= UINT32_MAX) {}\n" + " if (u > UINT32_MAX) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:14]: (style) Comparing expression of type 'const unsigned int &' against value 4294967295. Condition is always true. [compareValueOutOfTypeRangeError]\n" + "[test.cpp:4:13]: (style) Comparing expression of type 'const unsigned int &' against value 4294967295. Condition is always false. [compareValueOutOfTypeRangeError]\n", + errout_str()); + + check("void f() {\n" + " long long ll = 1024 * 1024 * 1024;\n" + " if (ll * 8 < INT_MAX) {}\n" + " if (INT_MAX > ll * 8) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("bool f(int a, int b) {\n" // #12896 + " if (a < INT_MIN && b > INT_MAX)\n" + " return true;\n" + " return false;\n" + "}\n" + "bool g(int x) {\n" // #6796 + " return (x > INT_MAX) ? true : false;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:13]: (style) Comparing expression of type 'signed int' against value -2147483648. Condition is always false. [compareValueOutOfTypeRangeError]\n" + "[test.cpp:2:28]: (style) Comparing expression of type 'signed int' against value 2147483647. Condition is always false. [compareValueOutOfTypeRangeError]\n" + "[test.cpp:7:17]: (style) Comparing expression of type 'signed int' against value 2147483647. Condition is always false. [compareValueOutOfTypeRangeError]\n", + errout_str()); } void knownConditionCast() { @@ -6310,7 +6624,7 @@ class TestCondition : public TestFixture { " }\n" "\n" " S1 mS;\n" - "};" + "};\n" ); ASSERT_EQUALS("[test.cpp:13:11] -> [test.cpp:18:13]: (style) Condition 'mS.b' is always false [knownConditionTrueFalse]\n", errout_str()); } diff --git a/test/testconstructors.cpp b/test/testconstructors.cpp index 8023990f629..4de49f54311 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 @@ -31,25 +31,28 @@ class TestConstructors : public TestFixture { private: const Settings settings = settingsBuilder().severity(Severity::style).severity(Severity::warning).build(); + const Settings settings_i = settingsBuilder(settings).certainty(Certainty::inconclusive).build(); struct CheckOptions { - CheckOptions() = default; bool inconclusive = false; - const Settings* s = nullptr; }; #define check(...) check_(__FILE__, __LINE__, __VA_ARGS__) template void check_(const char* file, int line, const char (&code)[size], const CheckOptions& options = make_default_obj()) { - const Settings settings1 = settingsBuilder(options.s ? *options.s : settings).certainty(Certainty::inconclusive, options.inconclusive).build(); + const Settings settings1 = options.inconclusive ? settings_i : settings; - // Tokenize.. + check_(file, line, code, settings1); + } + + template + void check_(const char* file, int line, const char (&code)[size], const Settings& settings1) { SimpleTokenizer tokenizer(settings1, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); // Check class constructors.. - CheckClass checkClass(&tokenizer, &settings1, this); + CheckClassImpl checkClass(&tokenizer, settings1, *this); checkClass.constructors(); } @@ -89,6 +92,7 @@ class TestConstructors : public TestFixture { TEST_CASE(noConstructor13); // #9998 TEST_CASE(noConstructor14); // #10770 TEST_CASE(noConstructor15); // #5499 + TEST_CASE(noConstructor16); TEST_CASE(forwardDeclaration); // ticket #4290/#3190 @@ -119,6 +123,7 @@ class TestConstructors : public TestFixture { TEST_CASE(initvar_derived_pod_struct_with_union); // #11101 TEST_CASE(initvar_private_constructor); // BUG 2354171 - private constructor + TEST_CASE(initvar_derived_private_constructor); TEST_CASE(initvar_copy_constructor); // ticket #1611 TEST_CASE(initvar_nested_constructor); // ticket #1375 TEST_CASE(initvar_nocopy1); // ticket #2474 @@ -235,21 +240,21 @@ class TestConstructors : public TestFixture { "{\n" "public:\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class Fred\n" "{\n" "private:\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:1:1]: (style) The class 'Fred' does not declare a constructor although it has private member variables which likely require initialization. [noConstructor]\n", errout_str()); check("struct Fred\n" "{\n" "private:\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:1:1]: (style) The struct 'Fred' does not declare a constructor although it has private member variables which likely require initialization. [noConstructor]\n", errout_str()); } @@ -262,7 +267,7 @@ class TestConstructors : public TestFixture { " Fred(Fred const & other) : i(other.i) {}\n" " Fred(Fred && other) : i(other.i) {}\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class Fred\n" @@ -272,7 +277,7 @@ class TestConstructors : public TestFixture { " Fred(Fred const & other) {i=other.i}\n" " Fred(Fred && other) {i=other.i}\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class Fred\n" @@ -282,7 +287,7 @@ class TestConstructors : public TestFixture { " Fred(Fred const & other) {}\n" " Fred(Fred && other) {}\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'Fred::i' is not initialized in the constructor. [uninitMemberVar]\n" "[test.cpp:5:5]: (warning) Member variable 'Fred::i' is not initialized in the copy constructor. [uninitMemberVar]\n" "[test.cpp:6:5]: (warning) Member variable 'Fred::i' is not initialized in the move constructor. [uninitMemberVar]\n", errout_str()); @@ -293,7 +298,7 @@ class TestConstructors : public TestFixture { " Fred(Fred const & other) {}\n" " Fred(Fred && other) {}\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:5]: (warning) Member variable 'Fred::i' is not initialized in the constructor. [uninitMemberVar]\n" "[test.cpp:4:5]: (warning) Member variable 'Fred::i' is not initialized in the copy constructor. [uninitMemberVar]\n" "[test.cpp:5:5]: (warning) Member variable 'Fred::i' is not initialized in the move constructor. [uninitMemberVar]\n", errout_str()); @@ -307,7 +312,7 @@ class TestConstructors : public TestFixture { " int i;\n" "};\n" "Fred::Fred() :i(0)\n" - "{ }"); + "{ }\n"); ASSERT_EQUALS("", errout_str()); check("struct Fred\n" @@ -316,7 +321,7 @@ class TestConstructors : public TestFixture { " int i;\n" "};\n" "Fred::Fred()\n" - "{ i = 0; }"); + "{ i = 0; }\n"); ASSERT_EQUALS("", errout_str()); check("struct Fred\n" @@ -325,7 +330,7 @@ class TestConstructors : public TestFixture { " int i;\n" "};\n" "Fred::Fred()\n" - "{ }"); + "{ }\n"); ASSERT_EQUALS("[test.cpp:6:7]: (warning) Member variable 'Fred::i' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -360,7 +365,7 @@ class TestConstructors : public TestFixture { " }\n" "private:\n" " int mValue;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -370,7 +375,7 @@ class TestConstructors : public TestFixture { " A(const T & t) { x = t.x; }\n" "private:\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("template struct A {\n" @@ -378,7 +383,7 @@ class TestConstructors : public TestFixture { " A(const T & t) : x(t.x) { }\n" "private:\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("template struct A {\n" @@ -387,7 +392,7 @@ class TestConstructors : public TestFixture { "private:\n" " int x;\n" " int y;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:2:5]: (warning) Member variable 'A::y' is not initialized in the constructor. [uninitMemberVar]\n" "[test.cpp:3:5]: (warning) Member variable 'A::y' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -396,14 +401,14 @@ class TestConstructors : public TestFixture { check("class Fred;\n" "struct Fred {\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } void simple8() { check("struct Fred { int x; };\n" "class Barney { Fred fred; };\n" - "class Wilma { struct Betty { int x; } betty; };"); + "class Wilma { struct Betty { int x; } betty; };\n"); ASSERT_EQUALS("[test.cpp:2:1]: (style) The class 'Barney' does not declare a constructor although it has private member variables which likely require initialization. [noConstructor]\n" "[test.cpp:3:1]: (style) The class 'Wilma' does not declare a constructor although it has private member variables which likely require initialization. [noConstructor]\n", errout_str()); } @@ -414,7 +419,7 @@ class TestConstructors : public TestFixture { " Fred() : x(0) { }\n" "private:\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -424,7 +429,7 @@ class TestConstructors : public TestFixture { " Fred() = default;\n" "private:\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:5]: (warning) Member variable 'Fred::x' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("struct S {\n" // #9391 @@ -452,7 +457,7 @@ class TestConstructors : public TestFixture { " int b{1}, c{2};\n" " int d, e{3};\n" " int f{4}, g;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:5]: (warning) Member variable 'Fred::d' is not initialized in the constructor. [uninitMemberVar]\n" "[test.cpp:3:5]: (warning) Member variable 'Fred::g' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -464,7 +469,7 @@ class TestConstructors : public TestFixture { " Fred() { Init(); }\n" " void Init(int i = 0);\n" "};\n" - "void Fred::Init(int i) { x = i; }"); + "void Fred::Init(int i) { x = i; }\n"); ASSERT_EQUALS("", errout_str()); check("class Fred {\n" @@ -474,7 +479,7 @@ class TestConstructors : public TestFixture { " Fred() { Init(0); }\n" " void Init(int i, int j = 0);\n" "};\n" - "void Fred::Init(int i, int j) { x = i; y = j; }"); + "void Fred::Init(int i, int j) { x = i; y = j; }\n"); ASSERT_EQUALS("", errout_str()); } @@ -482,7 +487,7 @@ class TestConstructors : public TestFixture { check("class Fred {\n" " int x=1;\n" " int *y=0;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -495,7 +500,7 @@ class TestConstructors : public TestFixture { " {}\n" "private:\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class Fred : public Base {" @@ -506,7 +511,7 @@ class TestConstructors : public TestFixture { " {}\n" "private:\n" " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -585,7 +590,7 @@ class TestConstructors : public TestFixture { check("class Fred\n" "{\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:1:1]: (style) The class 'Fred' does not declare a constructor although it has private member variables which likely require initialization. [noConstructor]\n", errout_str()); } @@ -597,7 +602,7 @@ class TestConstructors : public TestFixture { "};\n" "\n" "void Fred::foobar()\n" - "{ }"); + "{ }\n"); ASSERT_EQUALS("", errout_str()); } @@ -606,7 +611,7 @@ class TestConstructors : public TestFixture { "{\n" "private:\n" " static int foobar;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -615,7 +620,7 @@ class TestConstructors : public TestFixture { "{\n" "public:\n" " int foobar;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -623,7 +628,7 @@ class TestConstructors : public TestFixture { check("namespace Foo\n" "{\n" " int i;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -637,14 +642,14 @@ class TestConstructors : public TestFixture { "private:\n" " cpucyclesT m_v;\n" " bool m_b;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } void noConstructor7() { // ticket #4391 check("short bar;\n" - "class foo;"); + "class foo;\n"); ASSERT_EQUALS("", errout_str()); } @@ -652,7 +657,7 @@ class TestConstructors : public TestFixture { // ticket #4404 check("class LineSegment;\n" "class PointArray { };\n" - "void* tech_ = NULL;"); + "void* tech_ = NULL;\n"); ASSERT_EQUALS("", errout_str()); } @@ -663,7 +668,7 @@ class TestConstructors : public TestFixture { " CGreeting() : CGreetingBase(), MessageSet(false) {}\n" "private:\n" " bool MessageSet;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -683,28 +688,28 @@ class TestConstructors : public TestFixture { " virtual ~A();\n" "private:\n" " wxTimer *WxTimer1;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } void noConstructor11() { // #3552 check("class Fred { int x; };\n" - "union U { int y; Fred fred; };"); + "union U { int y; Fred fred; };\n"); ASSERT_EQUALS("", errout_str()); } void noConstructor12() { // #8951 - check("class Fred { int x{0}; };"); + check("class Fred { int x{0}; };\n"); ASSERT_EQUALS("", errout_str()); - check("class Fred { int x=0; };"); + check("class Fred { int x=0; };\n"); ASSERT_EQUALS("", errout_str()); - check("class Fred { int x[1]={0}; };"); // #8850 + check("class Fred { int x[1]={0}; };\n"); // #8850 ASSERT_EQUALS("", errout_str()); - check("class Fred { int x[1]{0}; };"); + check("class Fred { int x[1]{0}; };\n"); ASSERT_EQUALS("", errout_str()); } @@ -754,19 +759,59 @@ class TestConstructors : public TestFixture { ASSERT_EQUALS("[test.cpp:3:5]: (warning) Member variable 'C::i2' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } + void noConstructor16() { + check("struct S {\n" // #14546 + " int a = 0, b;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:16]: (warning) Member variable 'S::b' has no initializer. [uninitMemberVarNoCtor]\n", errout_str()); + + check("struct S {\n" + " int a, b;\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct S {\n" + " explicit S(int);\n" + " S(const S&);\n" + " int i;\n" + "};\n" + "struct T {\n" + " S s;\n" + " int j{};\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); + + const char code[] = "struct S { int i = 0; };\n" // #14697 + "struct T {\n" + " S s;\n" + " int j;\n" + "};\n" + "struct U {\n" + " std::string a;\n" + " int k;\n" + "};\n"; + const Settings s = settingsBuilder(settings).cpp(Standards::CPP11).build(); + check(code, s); + ASSERT_EQUALS("", errout_str()); + check(code); + ASSERT_EQUALS("[test.cpp:4:9]: (warning) Member variable 'T::j' has no initializer. [uninitMemberVarNoCtor]\n" + "[test.cpp:8:9]: (warning) Member variable 'U::k' has no initializer. [uninitMemberVarNoCtor]\n", + errout_str()); + } + // ticket #4290 "False Positive: style (noConstructor): The class 'foo' does not have a constructor." // ticket #3190 "SymbolDatabase: Parse of sub class constructor fails" void forwardDeclaration() { check("class foo;\n" - "int bar;"); + "int bar;\n"); ASSERT_EQUALS("", errout_str()); check("class foo;\n" - "class foo;"); + "class foo;\n"); ASSERT_EQUALS("", errout_str()); check("class foo{};\n" - "class foo;"); + "class foo;\n"); ASSERT_EQUALS("", errout_str()); } @@ -776,7 +821,7 @@ class TestConstructors : public TestFixture { " Fred()\n" " { this->i = 0; }\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -791,7 +836,7 @@ class TestConstructors : public TestFixture { " i = 1;\n" " }\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -810,7 +855,7 @@ class TestConstructors : public TestFixture { "\n" " const Fred & operator=(const Fred &fred)\n" " { i = fred.i; return *this; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct Fred {\n" @@ -821,7 +866,7 @@ class TestConstructors : public TestFixture { "\n" " const Fred & operator=(const Fred &fred)\n" " { i = fred.i; return *this; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct A\n" @@ -836,7 +881,7 @@ class TestConstructors : public TestFixture { "\n" " int i;\n" " int j;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -847,7 +892,7 @@ class TestConstructors : public TestFixture { " Fred() { i = 0; }\n" " void operator=(const Fred &fred) { }\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:10]: (warning) Member variable 'Fred::i' is not assigned a value in 'Fred::operator='. [operatorEqVarError]\n", errout_str()); } @@ -859,7 +904,7 @@ class TestConstructors : public TestFixture { "private:\n" " void Init() { i = 0; }\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -876,7 +921,7 @@ class TestConstructors : public TestFixture { " }\n" " return *this\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:12]: (warning) Member variable 'Fred::i' is not assigned a value in 'Fred::operator='. [operatorEqVarError]\n", errout_str()); check("class Fred\n" @@ -891,7 +936,7 @@ class TestConstructors : public TestFixture { " }\n" " return *this\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:12]: (warning) Member variable 'Fred::i' is not assigned a value in 'Fred::operator='. [operatorEqVarError]\n", errout_str()); check("class Fred\n" @@ -906,7 +951,7 @@ class TestConstructors : public TestFixture { " }\n" " return *this\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:12]: (warning) Member variable 'Fred::i' is not assigned a value in 'Fred::operator='. [operatorEqVarError]\n", errout_str()); check("class Fred\n" @@ -921,7 +966,7 @@ class TestConstructors : public TestFixture { " }\n" " return *this\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -936,7 +981,7 @@ class TestConstructors : public TestFixture { " Fred(rhs).swap(*this);\n" " return *this;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -946,7 +991,7 @@ class TestConstructors : public TestFixture { " Fred & operator=(const Fred &rhs) {\n" " return *this;\n" " }\n" - "};",dinit(CheckOptions, $.inconclusive = true)); + "};\n",dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:3:12]: (warning, inconclusive) Member variable 'Fred::data' is not assigned a value in 'Fred::operator='. [operatorEqVarError]\n", errout_str()); check("struct Fred {\n" @@ -954,7 +999,7 @@ class TestConstructors : public TestFixture { " Fred & operator=(const Fred &rhs) {\n" " return *this;\n" " }\n" - "};",dinit(CheckOptions, $.inconclusive = true)); + "};\n",dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:3:12]: (warning, inconclusive) Member variable 'Fred::ints' is not assigned a value in 'Fred::operator='. [operatorEqVarError]\n", errout_str()); check("struct Fred {\n" @@ -962,7 +1007,7 @@ class TestConstructors : public TestFixture { " Fred & operator=(const Fred &rhs) {\n" " return *this;\n" " }\n" - "};",dinit(CheckOptions, $.inconclusive = true)); + "};\n",dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:3:12]: (warning, inconclusive) Member variable 'Fred::data' is not assigned a value in 'Fred::operator='. [operatorEqVarError]\n", errout_str()); } @@ -1068,7 +1113,7 @@ class TestConstructors : public TestFixture { " int b;\n" " Fred() { b = 0; }\n" " };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); @@ -1088,7 +1133,7 @@ class TestConstructors : public TestFixture { " int b;\n" " Fred() { b = 0; }\n" " };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); @@ -1108,7 +1153,7 @@ class TestConstructors : public TestFixture { " int b;\n" " Fred() { b = 0; }\n" " };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); @@ -1130,7 +1175,7 @@ class TestConstructors : public TestFixture { " Fred() { b = 0; }\n" " };\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); @@ -1152,7 +1197,7 @@ class TestConstructors : public TestFixture { " Fred() { }\n" " };\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:7:13]: (warning) Member variable 'Fred::a' is not initialized in the constructor. [uninitMemberVar]\n" "[test.cpp:16:13]: (warning) Member variable 'Fred::b' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); @@ -1172,7 +1217,7 @@ class TestConstructors : public TestFixture { "c::c()\n" "{\n" " m_iMyInt1 = m_iMyInt2 = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1205,7 +1250,7 @@ class TestConstructors : public TestFixture { "void c::InitInt()\n" "{\n" " m_iMyInt = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1218,7 +1263,7 @@ class TestConstructors : public TestFixture { " Fred();\n" "};\n" "Fred::Fred() : s(NULL)\n" - "{ }"); + "{ }\n"); ASSERT_EQUALS("", errout_str()); check("struct Fred\n" @@ -1227,7 +1272,7 @@ class TestConstructors : public TestFixture { " Fred();\n" "};\n" "Fred::Fred()\n" - "{ s = NULL; }"); + "{ s = NULL; }\n"); ASSERT_EQUALS("", errout_str()); check("struct Fred\n" @@ -1236,7 +1281,7 @@ class TestConstructors : public TestFixture { " Fred();\n" "};\n" "Fred::Fred()\n" - "{ }"); + "{ }\n"); ASSERT_EQUALS("[test.cpp:6:7]: (warning) Member variable 'Fred::s' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -1248,7 +1293,7 @@ class TestConstructors : public TestFixture { "private:\n" " void update() const;\n" " mutable int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1259,7 +1304,7 @@ class TestConstructors : public TestFixture { "public:\n" " Fred() { }\n" " static void *p;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1272,7 +1317,7 @@ class TestConstructors : public TestFixture { "\n" "private:\n" " std::map * values_{};\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1290,7 +1335,7 @@ class TestConstructors : public TestFixture { " {\n" " U.a = 0;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class Fred\n" @@ -1304,7 +1349,7 @@ class TestConstructors : public TestFixture { " Fred()\n" " {\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:9:5]: (warning) Member variable 'Fred::U' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -1315,7 +1360,7 @@ class TestConstructors : public TestFixture { "public:\n" " A(int n) { }\n" " A() : A(42) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'A::number' is not initialized in the constructor. [uninitMemberVar]\n" "[test.cpp:5:5]: (warning) Member variable 'A::number' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); @@ -1324,7 +1369,7 @@ class TestConstructors : public TestFixture { "public:\n" " A(int n) { number = n; }\n" " A() : A(42) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class A {\n" @@ -1332,7 +1377,7 @@ class TestConstructors : public TestFixture { "public:\n" " A(int n) : A() { }\n" " A() {}\n" - "};", dinit(CheckOptions, $.inconclusive = true)); + "};\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'A::number' is not initialized in the constructor. [uninitMemberVar]\n" "[test.cpp:5:5]: (warning, inconclusive) Member variable 'A::number' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); @@ -1341,7 +1386,7 @@ class TestConstructors : public TestFixture { "public:\n" " A(int n) : A() { }\n" " A() { number = 42; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class A {\n" @@ -1349,7 +1394,7 @@ class TestConstructors : public TestFixture { "public:\n" " A(int n) { }\n" " A() : A{42} {}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'A::number' is not initialized in the constructor. [uninitMemberVar]\n" "[test.cpp:5:5]: (warning) Member variable 'A::number' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); @@ -1358,7 +1403,7 @@ class TestConstructors : public TestFixture { "public:\n" " A(int n) { number = n; }\n" " A() : A{42} {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class A {\n" @@ -1366,7 +1411,7 @@ class TestConstructors : public TestFixture { "public:\n" " A(int n) : A{} { }\n" " A() {}\n" - "};", dinit(CheckOptions, $.inconclusive = true)); + "};\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'A::number' is not initialized in the constructor. [uninitMemberVar]\n" "[test.cpp:5:5]: (warning, inconclusive) Member variable 'A::number' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); @@ -1375,7 +1420,7 @@ class TestConstructors : public TestFixture { "public:\n" " A(int n) : A{} { }\n" " A() { number = 42; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // Ticket #6675 @@ -1385,7 +1430,7 @@ class TestConstructors : public TestFixture { " int foo_;\n" "};\n" "Foo::Foo() : Foo(0) {}\n" - "Foo::Foo(int foo) : foo_(foo) {}"); + "Foo::Foo(int foo) : foo_(foo) {}\n"); ASSERT_EQUALS("", errout_str()); // Noexcept ctors @@ -1397,7 +1442,7 @@ class TestConstructors : public TestFixture { " A() noexcept;\n" "};\n" "\n" - "A::A() noexcept: A(0) {}"); + "A::A() noexcept: A(0) {}\n"); ASSERT_EQUALS("", errout_str()); // Ticket #8581 @@ -1407,7 +1452,7 @@ class TestConstructors : public TestFixture { "public:\n" " A(int a) : _a(a) {}\n" " A(float a) : A(int(a)) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // Ticket #8258 @@ -1419,7 +1464,7 @@ class TestConstructors : public TestFixture { " int _a;\n" " int _b;\n" " F _f;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1443,7 +1488,7 @@ class TestConstructors : public TestFixture { " : a(true)\n" " , b(0)\n" "{\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1458,7 +1503,7 @@ class TestConstructors : public TestFixture { "public:\n" " Derived() {}\n" " void foo() override;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:9:3]: (warning) Member variable 'Base::x' is not initialized in the constructor. Maybe it should be initialized directly in the class Base? [uninitDerivedMemberVar]\n", errout_str()); check("struct A {\n" // #3462 @@ -1545,7 +1590,7 @@ class TestConstructors : public TestFixture { "class C : public S {\n" "public:\n" " C() { all = 0; tick = 0; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct S {\n" @@ -1561,7 +1606,7 @@ class TestConstructors : public TestFixture { "class C : public S {\n" "public:\n" " C() { flag1 = flag2 = 0; tick = 0; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct S {\n" @@ -1577,7 +1622,7 @@ class TestConstructors : public TestFixture { "class C : public S {\n" "public:\n" " C() {}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:13:5]: (warning) Member variable 'S::all' is not initialized in the constructor. Maybe it should be initialized directly in the class S? [uninitDerivedMemberVar]\n" "[test.cpp:13:5]: (warning) Member variable 'S::flag1' is not initialized in the constructor. Maybe it should be initialized directly in the class S? [uninitDerivedMemberVar]\n" "[test.cpp:13:5]: (warning) Member variable 'S::flag2' is not initialized in the constructor. Maybe it should be initialized directly in the class S? [uninitDerivedMemberVar]\n", errout_str()); @@ -1593,7 +1638,7 @@ class TestConstructors : public TestFixture { " Fred();\n" "};\n" "Fred::Fred()\n" - "{ }", dinit(CheckOptions, $.s = &s)); + "{ }\n", s); ASSERT_EQUALS("[test.cpp:7:7]: (warning) Member variable 'Fred::var' is not initialized in the constructor. [uninitMemberVarPrivate]\n", errout_str()); } @@ -1606,10 +1651,19 @@ class TestConstructors : public TestFixture { " Fred();\n" "};\n" "Fred::Fred()\n" - "{ }", dinit(CheckOptions, $.s = &s)); + "{ }\n", s); ASSERT_EQUALS("", errout_str()); } } + void initvar_derived_private_constructor() { + check("class B { int i; };\n" + "class D : B {\n" + " explicit D(int) {}\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:1:1]: (style) The class 'B' does not declare a constructor although it has private member variables which likely require initialization. [noConstructor]\n" + "[test.cpp:3:14]: (warning) Member variable 'B::i' is not initialized in the constructor. Maybe it should be initialized directly in the class B? [uninitDerivedMemberVarPrivate]\n", + errout_str()); + } void initvar_copy_constructor() { // ticket #1611 check("class Fred\n" @@ -1619,7 +1673,7 @@ class TestConstructors : public TestFixture { "public:\n" " Fred() { };\n" " Fred(const Fred &) { };\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class Fred\n" @@ -1629,7 +1683,7 @@ class TestConstructors : public TestFixture { "public:\n" " Fred() { };\n" " Fred(const Fred &) { };\n" - "};", dinit(CheckOptions, $.inconclusive = true)); + "};\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:7:5]: (warning, inconclusive) Member variable 'Fred::var' is not assigned in the copy constructor. Should it be copied? [missingMemberCopy]\n", errout_str()); check("class Fred\n" @@ -1677,7 +1731,7 @@ class TestConstructors : public TestFixture { "A::A(){}\n" "A::B::B(int x){}\n" "A::B::C::C(int y){}\n" - "A::B::C::D::D(int z){}"); + "A::B::C::D::D(int z){}\n"); // Note that the example code is not compilable. The A constructor must // explicitly initialize A::b. A warning for A::b is not necessary. ASSERT_EQUALS("[test.cpp:20:4]: (warning) Member variable 'A::a' is not initialized in the constructor. [uninitMemberVar]\n" @@ -1707,7 +1761,7 @@ class TestConstructors : public TestFixture { "A::A(){}\n" "A::B::B(int x){}\n" "A::B::C::C(int y){}\n" - "A::B::C::D::D(const A::B::C::D & d){}"); + "A::B::C::D::D(const A::B::C::D & d){}\n"); // Note that the example code is not compilable. The A constructor must // explicitly initialize A::b. A warning for A::b is not necessary. ASSERT_EQUALS("[test.cpp:20:4]: (warning) Member variable 'A::a' is not initialized in the constructor. [uninitMemberVar]\n" @@ -1738,7 +1792,7 @@ class TestConstructors : public TestFixture { "A::A(){}\n" "A::B::B(int x){}\n" "A::B::C::C(int y){}\n" - "A::B::C::D::D(const A::B::C::D::E & e){}"); + "A::B::C::D::D(const A::B::C::D::E & e){}\n"); // Note that the example code is not compilable. The A constructor must // explicitly initialize A::b. A warning for A::b is not necessary. ASSERT_EQUALS("[test.cpp:21:4]: (warning) Member variable 'A::a' is not initialized in the constructor. [uninitMemberVar]\n" @@ -1760,7 +1814,7 @@ class TestConstructors : public TestFixture { " A(const A&){}\n" " A(A &&){}\n" " const A& operator=(const A&){return *this;}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class B\n" @@ -1775,7 +1829,7 @@ class TestConstructors : public TestFixture { " A(const A&){}\n" " A(A &&){}\n" " const A& operator=(const A&){return *this;}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class B\n" @@ -1792,7 +1846,7 @@ class TestConstructors : public TestFixture { " A(const A&){}\n" " A(A &&){}\n" " const A& operator=(const A&){return *this;}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class B\n" @@ -1808,7 +1862,7 @@ class TestConstructors : public TestFixture { " A(const A&){}\n" " A(A &&){}\n" " const A& operator=(const A&){return *this;}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class A : public std::vector\n" @@ -1824,7 +1878,7 @@ class TestConstructors : public TestFixture { " B(const B&){}\n" " B(B &&){}\n" " const B& operator=(const B&){return *this;}\n" - "};", dinit(CheckOptions, $.inconclusive = true)); + "};\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:11:5]: (warning, inconclusive) Member variable 'B::a' is not assigned in the copy constructor. Should it be copied? [missingMemberCopy]\n" "[test.cpp:12:5]: (warning, inconclusive) Member variable 'B::a' is not assigned in the move constructor. Should it be moved? [missingMemberCopy]\n" "[test.cpp:13:14]: (warning, inconclusive) Member variable 'B::a' is not assigned a value in 'B::operator='. [operatorEqVarError]\n", @@ -1844,7 +1898,7 @@ class TestConstructors : public TestFixture { " A(const A&){}\n" " A(A &&){}\n" " const A& operator=(const A&){return *this;}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:13:5]: (warning) Member variable 'A::m_SemVar' is not initialized in the move constructor. [uninitMemberVar]\n", errout_str()); check("class B\n" @@ -1862,7 +1916,7 @@ class TestConstructors : public TestFixture { " A(const A&){}\n" " A(A &&){}\n" " const A& operator=(const A&){return *this;}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class A\n" @@ -1872,7 +1926,7 @@ class TestConstructors : public TestFixture { " A(){}\n" " A(const A&){}\n" " const A& operator=(const A&){return *this;}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1890,7 +1944,7 @@ class TestConstructors : public TestFixture { " A(){}\n" " A(const A&){}\n" " const A& operator=(const A&){return *this;}\n" - "};", dinit(CheckOptions, $.inconclusive = true)); + "};\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("class B\n" @@ -1907,7 +1961,7 @@ class TestConstructors : public TestFixture { " A(){}\n" " A(const A&){}\n" " const A& operator=(const A&){return *this;}\n" - "};", dinit(CheckOptions, $.inconclusive = true)); + "};\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:12:5]: (warning) Member variable 'A::m_SemVar' is not initialized in the constructor. [uninitMemberVar]\n" "[test.cpp:13:5]: (warning) Member variable 'A::m_SemVar' is not initialized in the copy constructor. [uninitMemberVar]\n" "[test.cpp:14:14]: (warning) Member variable 'A::m_SemVar' is not assigned a value in 'A::operator='. [operatorEqVarError]\n", errout_str()); @@ -1918,14 +1972,14 @@ class TestConstructors : public TestFixture { " B b;\n" " A() {}\n" " A(const A& rhs) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct A {\n" " B b;\n" " A() {}\n" " A(const A& rhs) {}\n" - "};", dinit(CheckOptions, $.inconclusive = true)); + "};\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:4:5]: (warning, inconclusive) Member variable 'A::b' is not assigned in the copy constructor. Should it be copied? [missingMemberCopy]\n", errout_str()); } @@ -1941,7 +1995,7 @@ class TestConstructors : public TestFixture { "}\n" "void S::Set(const T& val) {\n" " t = val;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } @@ -1950,7 +2004,7 @@ class TestConstructors : public TestFixture { " Foo(int m) { this->setMember(m); }\n" " void setMember(int m) { member = m; }\n" " int member;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1962,7 +2016,7 @@ class TestConstructors : public TestFixture { "public:\n" " Fred() : var(0) {}\n" " ~Fred() {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1970,7 +2024,7 @@ class TestConstructors : public TestFixture { check("class something {\n" " int * ( something :: * process()) () { return 0; }\n" " something() { process(); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1981,7 +2035,7 @@ class TestConstructors : public TestFixture { " int& pa = a;\n" " pa = 4;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct S {\n" @@ -1990,7 +2044,7 @@ class TestConstructors : public TestFixture { " int* pa = &a;\n" " *pa = 4;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct S {\n" @@ -2000,7 +2054,7 @@ class TestConstructors : public TestFixture { " for (int i = 0; i < 2; i++)\n" " *pa++ = i;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct S {\n" @@ -2009,7 +2063,7 @@ class TestConstructors : public TestFixture { " int* pa = a[1];\n" " *pa = 0;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:5]: (warning) Member variable 'S::a' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("struct S {\n" @@ -2018,7 +2072,7 @@ class TestConstructors : public TestFixture { " int pa = a;\n" " pa = 4;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:5]: (warning) Member variable 'S::a' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -2037,7 +2091,7 @@ class TestConstructors : public TestFixture { " A() {\n" " Wrapper::foo(x);\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -2055,7 +2109,7 @@ class TestConstructors : public TestFixture { " d = rhs.get();\n" " }\n" " double d;\n" - "};", dinit(CheckOptions, $.s = &s)); + "};\n", s); ASSERT_EQUALS("", errout_str()); check("struct S {\n" // #8485 @@ -2082,14 +2136,14 @@ class TestConstructors : public TestFixture { "{ }\n" "\n" "void Fred::operator=(const Fred &f)\n" - "{ }", dinit(CheckOptions, $.inconclusive = true)); + "{ }\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:13:12]: (warning, inconclusive) Member variable 'Fred::ints' is not assigned a value in 'Fred::operator='. [operatorEqVarError]\n", errout_str()); const Settings s = settingsBuilder().certainty(Certainty::inconclusive).severity(Severity::style).severity(Severity::warning).library("std.cfg").build(); check("struct S {\n" " S& operator=(const S& s) { return *this; }\n" " std::mutex m;\n" - "};\n", dinit(CheckOptions, $.s = &s)); + "};\n", s); ASSERT_EQUALS("", errout_str()); } @@ -2107,7 +2161,7 @@ class TestConstructors : public TestFixture { "\n" "private:\n" " ECODES _code;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:10:5]: (warning) Member variable 'Fred::_code' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); @@ -2120,7 +2174,7 @@ class TestConstructors : public TestFixture { " B() {}\n" "private:\n" " float f;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:3]: (warning) Member variable 'B::f' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("class C\n" @@ -2133,7 +2187,7 @@ class TestConstructors : public TestFixture { "\n" "C::C(FILE *fp) {\n" " C::fp = fp;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2144,7 +2198,7 @@ class TestConstructors : public TestFixture { " John() { (*this).i = 0; }\n" "private:\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -2159,7 +2213,7 @@ class TestConstructors : public TestFixture { " Bar();\n" " };\n" " Bar bars[2];\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // Using struct that doesn't have constructor @@ -2172,7 +2226,7 @@ class TestConstructors : public TestFixture { " int x;\n" " };\n" " Bar bars[2];\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'Foo::bars' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -2186,7 +2240,7 @@ class TestConstructors : public TestFixture { " int x;\n" " };\n" " struct Bar bar;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -2198,7 +2252,7 @@ class TestConstructors : public TestFixture { " Foo &operator=(const Foo &)\n" " { return *this; }\n" " static int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -2209,7 +2263,7 @@ class TestConstructors : public TestFixture { " explicit Foo(int i) : Bar(mi=i) { }\n" "private:\n" " int mi;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class Foo : public Bar\n" @@ -2218,7 +2272,7 @@ class TestConstructors : public TestFixture { " explicit Foo(int i) : Bar{mi=i} { }\n" "private:\n" " int mi;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -2239,7 +2293,7 @@ class TestConstructors : public TestFixture { " Foo copy(rhs);\n" " copy.Swap(*this);\n" " return *this;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2256,7 +2310,7 @@ class TestConstructors : public TestFixture { " {\n" " }\n" " return *this;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:11]: (warning) Member variable 'Foo::a' is not assigned a value in 'Foo::operator='. [operatorEqVarError]\n", errout_str()); } @@ -2270,7 +2324,7 @@ class TestConstructors : public TestFixture { "Prefs::Prefs(wxSize size)\n" "{\n" " SetMinSize( wxSize( 48,48 ) );\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:8]: (warning) Member variable 'Prefs::xasd' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -2282,7 +2336,7 @@ class TestConstructors : public TestFixture { " int var1;\n" " int var2;\n" "};\n" - "A::A() : var1(0) { }"); + "A::A() : var1(0) { }\n"); ASSERT_EQUALS("[test.cpp:8:4]: (warning) Member variable 'A::var2' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -2293,7 +2347,7 @@ class TestConstructors : public TestFixture { "private:\n" " int var;\n" "};\n" - "A::A(int a) { }"); + "A::A(int a) { }\n"); ASSERT_EQUALS("[test.cpp:7:4]: (warning) Member variable 'A::var' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -2309,7 +2363,7 @@ class TestConstructors : public TestFixture { " : x(x), y(y)\n" " {}\n" " int x, y;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'Point::x' is not initialized in the constructor. [uninitMemberVar]\n" "[test.cpp:4:5]: (warning) Member variable 'Point::y' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -2321,7 +2375,7 @@ class TestConstructors : public TestFixture { "public:\n" " A()\n" " {}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:5:5]: (warning) Member variable 'A::ints' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -2336,7 +2390,7 @@ class TestConstructors : public TestFixture { "};\n" "Foo::Foo()\n" "{\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:6]: (warning) Member variable 'Foo::mMember' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); // single namespace @@ -2352,7 +2406,7 @@ class TestConstructors : public TestFixture { " Foo::Foo()\n" " {\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:10:10]: (warning) Member variable 'Foo::mMember' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); // constructor outside namespace @@ -2368,7 +2422,7 @@ class TestConstructors : public TestFixture { "}\n" "Foo::Foo()\n" "{\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // constructor outside namespace @@ -2384,7 +2438,7 @@ class TestConstructors : public TestFixture { "}\n" "Output::Foo::Foo()\n" "{\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:11:14]: (warning) Member variable 'Foo::mMember' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); // constructor outside namespace with using, #4792 @@ -2401,7 +2455,7 @@ class TestConstructors : public TestFixture { "using namespace Output;" "Foo::Foo()\n" "{\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:11:29]: (warning) Member variable 'Foo::mMember' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); // constructor in separate namespace @@ -2420,7 +2474,7 @@ class TestConstructors : public TestFixture { " Foo::Foo()\n" " {\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:13:10]: (warning) Member variable 'Foo::mMember' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); // constructor in different separate namespace @@ -2439,7 +2493,7 @@ class TestConstructors : public TestFixture { " Foo::Foo()\n" " {\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // constructor in different separate namespace (won't compile) @@ -2458,7 +2512,7 @@ class TestConstructors : public TestFixture { " Output::Foo::Foo()\n" " {\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // constructor in nested separate namespace @@ -2480,7 +2534,7 @@ class TestConstructors : public TestFixture { " {\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:15:14]: (warning) Member variable 'Foo::mMember' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); // constructor in nested different separate namespace @@ -2502,7 +2556,7 @@ class TestConstructors : public TestFixture { " {\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // constructor in nested different separate namespace @@ -2524,7 +2578,7 @@ class TestConstructors : public TestFixture { " {\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2538,7 +2592,7 @@ class TestConstructors : public TestFixture { "};\n" "Fred::~Fred()\n" "{\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2556,7 +2610,7 @@ class TestConstructors : public TestFixture { " {\n" " foo.set(0);\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct Foo\n" @@ -2571,7 +2625,7 @@ class TestConstructors : public TestFixture { " Bar()\n" " {\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:10:5]: (warning) Member variable 'Bar::foo' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -2588,7 +2642,7 @@ class TestConstructors : public TestFixture { " {\n" " foo[0].a = 0;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct Foo\n" @@ -2602,7 +2656,7 @@ class TestConstructors : public TestFixture { " Bar()\n" " {\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:9:5]: (warning) Member variable 'Bar::foo' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -2618,7 +2672,7 @@ class TestConstructors : public TestFixture { " A() { }\n" "private:\n" " Altren value;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -2642,7 +2696,7 @@ class TestConstructors : public TestFixture { " {\n" " free(m_str);\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -2654,7 +2708,7 @@ class TestConstructors : public TestFixture { " std::streamsize dataLength_;\n" " double bitsInData_;\n" " } obj;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:9]: (warning) Member variable 'LocalClass::bitsInData_' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("struct copy_protected;\n" @@ -2665,7 +2719,7 @@ class TestConstructors : public TestFixture { " std::streamsize dataLength_;\n" " double bitsInData_;\n" " } obj;\n" - "};"); + "};\n"); ASSERT_EQUALS( "[test.cpp:5:9]: (warning) Member variable 'LocalClass::bitsInData_' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); @@ -2678,7 +2732,7 @@ class TestConstructors : public TestFixture { " std::streamsize dataLength_;\n" " double bitsInData_;\n" " } obj;\n" - "};"); + "};\n"); ASSERT_EQUALS( "[test.cpp:5:9]: (warning) Member variable 'LocalClass::bitsInData_' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); @@ -2693,7 +2747,7 @@ class TestConstructors : public TestFixture { "};\n" "Fred::Fred() {\n" " a[x::y] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2710,7 +2764,7 @@ class TestConstructors : public TestFixture { "Fred & Fred::clone(const Fred & other) {\n" " x = 0;\n" " return *this;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class Fred {\n" @@ -2724,7 +2778,7 @@ class TestConstructors : public TestFixture { "}\n" "Fred & Fred::clone(const Fred & other) {\n" " return *this;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:14]: (warning) Member variable 'Fred::x' is not assigned a value in 'Fred::operator='. [operatorEqVarError]\n", errout_str()); } @@ -2742,7 +2796,7 @@ class TestConstructors : public TestFixture { "Fred::Fred(struct C c, D d) { }\n" "Fred::Fred(E e, struct F f) { }\n" "Fred::Fred(G g, H h) { }\n" - "Fred::Fred(struct I i, struct J j) { }"); + "Fred::Fred(struct I i, struct J j) { }\n"); ASSERT_EQUALS("[test.cpp:10:7]: (warning) Member variable 'Fred::x' is not initialized in the constructor. [uninitMemberVar]\n" "[test.cpp:11:7]: (warning) Member variable 'Fred::x' is not initialized in the constructor. [uninitMemberVar]\n" "[test.cpp:12:7]: (warning) Member variable 'Fred::x' is not initialized in the constructor. [uninitMemberVar]\n" @@ -2851,7 +2905,7 @@ class TestConstructors : public TestFixture { " A(int s) {\n" " v = new int [sz = s];\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -2862,7 +2916,7 @@ class TestConstructors : public TestFixture { " A() {\n" " rtl::math::setNan(&d);\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class A {\n" " double d;\n" @@ -2870,7 +2924,7 @@ class TestConstructors : public TestFixture { " A() {\n" " ::rtl::math::setNan(&d);\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -2885,7 +2939,7 @@ class TestConstructors : public TestFixture { " }\n" " void foo(int a) { i = a; }\n" " void foo(float a) { f = a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -2917,7 +2971,7 @@ class TestConstructors : public TestFixture { " D() { foo(); }\n" " void foo() { }\n" " void foo() const { i = 0; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:18:5]: (warning) Member variable 'C::i' is not initialized in the constructor. [uninitMemberVar]\n" "[test.cpp:25:5]: (warning) Member variable 'D::i' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -2934,7 +2988,7 @@ class TestConstructors : public TestFixture { "}\n" "using namespace NS;\n" "MyClass::~MyClass() { }\n" - "MyClass::MyClass() : SomeVar(false) { }"); + "MyClass::MyClass() : SomeVar(false) { }\n"); ASSERT_EQUALS("", errout_str()); } @@ -2952,7 +3006,7 @@ class TestConstructors : public TestFixture { "}\n" "void MyClass::Restart() {\n" " m_retCode = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2965,7 +3019,7 @@ class TestConstructors : public TestFixture { " {\n" " if (1) {}\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:5:4]: (warning) Member variable 'Foo::member' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("class Foo {\n" " friend class Bar;\n" @@ -2975,7 +3029,7 @@ class TestConstructors : public TestFixture { " {\n" " while (1) {}\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:5:4]: (warning) Member variable 'Foo::member' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("class Foo {\n" " friend class Bar;\n" @@ -2985,7 +3039,7 @@ class TestConstructors : public TestFixture { " {\n" " for (;;) {}\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:5:4]: (warning) Member variable 'Foo::member' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -2997,7 +3051,7 @@ class TestConstructors : public TestFixture { " int x;\n" " };\n" "};\n" - "app::B::B(void){}"); + "app::B::B(void){}\n"); ASSERT_EQUALS("[test.cpp:8:9]: (warning) Member variable 'B::x' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -3037,7 +3091,7 @@ class TestConstructors : public TestFixture { check("struct C {\n" // #13989 " C() = default;\n" " std::list::const_iterator it;\n" - "};\n", dinit(CheckOptions, $.s = &s)); + "};\n", s); ASSERT_EQUALS("[test.cpp:2:5]: (warning) Member variable 'C::it' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -3049,7 +3103,7 @@ class TestConstructors : public TestFixture { "\n" "private:\n" " char name[255];\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'John::name' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("class John\n" @@ -3059,7 +3113,7 @@ class TestConstructors : public TestFixture { "\n" "private:\n" " char name[255];\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class John\n" @@ -3069,7 +3123,7 @@ class TestConstructors : public TestFixture { "\n" "private:\n" " char name[255];\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class John\n" @@ -3078,7 +3132,7 @@ class TestConstructors : public TestFixture { " John() { }\n" "\n" " double operator[](const unsigned long i);\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class A;\n" @@ -3087,7 +3141,7 @@ class TestConstructors : public TestFixture { "public:\n" " John() { }\n" " A a[5];\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class A;\n" @@ -3096,7 +3150,7 @@ class TestConstructors : public TestFixture { "public:\n" " John() { }\n" " A (*a)[5];\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:5:5]: (warning) Member variable 'John::a' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -3108,7 +3162,7 @@ class TestConstructors : public TestFixture { "\n" "private:\n" " char name[255];\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // #5754 @@ -3119,7 +3173,7 @@ class TestConstructors : public TestFixture { "\n" "private:\n" " char name[255];\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3136,7 +3190,7 @@ class TestConstructors : public TestFixture { " memset(a,0,sizeof(a));\n" " memset(b,0,sizeof(b));\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3153,7 +3207,7 @@ class TestConstructors : public TestFixture { " if (snprintf(a,10,\"a\")) { }\n" " if (snprintf(b,10,\"b\")) { }\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3165,7 +3219,7 @@ class TestConstructors : public TestFixture { "public:\n" " Foo()\n" " { }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3177,7 +3231,7 @@ class TestConstructors : public TestFixture { " static const char STR[];\n" "};\n" "const char Foo::STR[] = \"abc\";\n" - "Foo::Foo() { }"); + "Foo::Foo() { }\n"); ASSERT_EQUALS("", errout_str()); } @@ -3187,7 +3241,7 @@ class TestConstructors : public TestFixture { " int array[10];\n" "public:\n" " Foo() { }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:5:5]: (warning) Member variable 'Foo::array' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("class Foo\n" @@ -3195,7 +3249,7 @@ class TestConstructors : public TestFixture { " int array[10];\n" "public:\n" " Foo() { memset(array, 0, sizeof(array)); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class Foo\n" @@ -3203,7 +3257,7 @@ class TestConstructors : public TestFixture { " int array[10];\n" "public:\n" " Foo() { ::memset(array, 0, sizeof(array)); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3212,7 +3266,7 @@ class TestConstructors : public TestFixture { " char a[10];\n" "public:\n" " Foo() { ::ZeroMemory(a); }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -3223,7 +3277,7 @@ class TestConstructors : public TestFixture { " BaseGDL* eArr[3];\n" "public:\n" " IxExprListT() {}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:5]: (warning) Member variable 'IxExprListT::eArr' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("struct sRAIUnitDefBL {\n" " sRAIUnitDefBL();\n" @@ -3232,7 +3286,7 @@ class TestConstructors : public TestFixture { "struct sRAIUnitDef {\n" " sRAIUnitDef() {}\n" " sRAIUnitDefBL *List[35];\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:3]: (warning) Member variable 'sRAIUnitDef::List' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -3248,7 +3302,7 @@ class TestConstructors : public TestFixture { " std::array e;\n" " std::array f;\n" "S() {}\n" - "};\n", dinit(CheckOptions, $.s = &s)); + "};\n", s); ASSERT_EQUALS("[test.cpp:10:1]: (warning) Member variable 'S::a' is not initialized in the constructor. [uninitMemberVar]\n" "[test.cpp:10:1]: (warning) Member variable 'S::b' is not initialized in the constructor. [uninitMemberVar]\n" @@ -3279,7 +3333,7 @@ class TestConstructors : public TestFixture { "\n" "private:\n" " char a[2][2];\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3290,7 +3344,7 @@ class TestConstructors : public TestFixture { " char a[2][2][2];\n" "public:\n" " John() { a[0][0][0] = 0; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3301,7 +3355,7 @@ class TestConstructors : public TestFixture { " Foo()\n" " : bar({\"a\", \"b\"})\n" " {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3317,7 +3371,7 @@ class TestConstructors : public TestFixture { " Fred() : f{0, true} { }\n" " float get() const;\n" "};\n" - "float Fred::get() const { return g; }"); + "float Fred::get() const { return g; }\n"); ASSERT_EQUALS("[test.cpp:9:5]: (warning) Member variable 'Fred::g' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -3333,7 +3387,7 @@ class TestConstructors : public TestFixture { "public:\n" " A() {\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class A\n" @@ -3347,7 +3401,7 @@ class TestConstructors : public TestFixture { "public:\n" " A() {\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:10:5]: (warning) Member variable 'A::b' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("class A\n" @@ -3362,7 +3416,7 @@ class TestConstructors : public TestFixture { "public:\n" " A() {\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3379,7 +3433,7 @@ class TestConstructors : public TestFixture { "public:\n" " Fred()\n" " { }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:11:5]: (warning) Member variable 'Fred::p' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("struct POINT\n" @@ -3395,7 +3449,7 @@ class TestConstructors : public TestFixture { "public:\n" " Fred()\n" " { }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct POINT\n" @@ -3411,7 +3465,7 @@ class TestConstructors : public TestFixture { "public:\n" " Fred()\n" " { }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // non static data-member initialization @@ -3427,7 +3481,7 @@ class TestConstructors : public TestFixture { "public:\n" " Fred()\n" " { }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3439,13 +3493,13 @@ class TestConstructors : public TestFixture { "public:\n" " Fred()\n" " { a = 0; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class Fred {\n" "private:\n" " union { int a{}; int b; };\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3459,7 +3513,7 @@ class TestConstructors : public TestFixture { "public:\n" " Fred() : data_type(0)\n" " { }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:8:5]: (warning) Member variable 'Fred::data' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -3472,7 +3526,7 @@ class TestConstructors : public TestFixture { "private:\n" " void Init();" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // Unknown non-member function (friend class) @@ -3483,7 +3537,7 @@ class TestConstructors : public TestFixture { "private:\n" " friend ABC;\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // Unknown non-member function (is Init a virtual function?) @@ -3493,7 +3547,7 @@ class TestConstructors : public TestFixture { " Fred() { Init(); }\n" "private:\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'Fred::i' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); // Unknown non-member function @@ -3503,7 +3557,7 @@ class TestConstructors : public TestFixture { " Fred() { Init(); }\n" "private:\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'Fred::i' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); // Unknown non-member function @@ -3514,7 +3568,7 @@ class TestConstructors : public TestFixture { " Fred() { Init(); }\n" "private:\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:5:5]: (warning) Member variable 'Fred::i' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); // Unknown member functions and unknown static functions @@ -3534,7 +3588,7 @@ class TestConstructors : public TestFixture { " static void static_f();\n" "private:\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:7:5]: (warning) Member variable 'Fred::i' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); // Unknown overloaded member functions @@ -3547,7 +3601,7 @@ class TestConstructors : public TestFixture { " void func();\n" "private:\n" " int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3559,7 +3613,7 @@ class TestConstructors : public TestFixture { " Fred() {}\n" "private:\n" " unsigned int i;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:5:5]: (warning) Member variable 'Fred::i' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -3570,7 +3624,7 @@ class TestConstructors : public TestFixture { "struct Y {\n" " Y() {}\n" " X x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3586,7 +3640,7 @@ class TestConstructors : public TestFixture { " if(!(in >> foo))\n" " throw 0;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3598,7 +3652,7 @@ class TestConstructors : public TestFixture { " typedef int * pointer;\n" " Foo() : a(0) {}\n" " pointer a;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3609,7 +3663,7 @@ class TestConstructors : public TestFixture { "public:\n" " int * pointer;\n" " Foo() { memset(this, 0, sizeof(*this)); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); @@ -3618,7 +3672,7 @@ class TestConstructors : public TestFixture { "public:\n" " int * pointer;\n" " Foo() { ::memset(this, 0, sizeof(*this)); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); @@ -3627,13 +3681,13 @@ class TestConstructors : public TestFixture { " int * p;\n" " char c;\n" " Foo() { memset(p, 0, sizeof(int)); }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'Foo::c' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("struct Foo {\n" " int i;\n" " char c;\n" " Foo() { memset(&i, 0, sizeof(int)); }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'Foo::c' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("struct Foo { int f; };\n" "struct Bar { int b; };\n" @@ -3647,7 +3701,7 @@ class TestConstructors : public TestFixture { "int main() {\n" " FooBar foobar;\n" " return foobar.foo.f + foobar.bar.b;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:3]: (warning) Member variable 'FooBar::bar' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("struct Foo { int f; };\n" "struct Bar { int b; };\n" @@ -3661,7 +3715,7 @@ class TestConstructors : public TestFixture { "int main() {\n" " FooBar foobar;\n" " return foobar.foo.f + foobar.bar.b;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:3]: (warning) Member variable 'FooBar::bar' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); // #7755 @@ -3670,7 +3724,7 @@ class TestConstructors : public TestFixture { " memset(this->data, 0, 42);\n" " }\n" " char data[42];\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3680,7 +3734,7 @@ class TestConstructors : public TestFixture { check("class Foo {\n" " int foo;\n" " Foo() { }\n" - "};", dinit(CheckOptions, $.s = &s)); + "};\n", s); ASSERT_EQUALS("", errout_str()); } @@ -3689,7 +3743,7 @@ class TestConstructors : public TestFixture { check("class Foo {\n" " int foo;\n" " Foo() { }\n" - "};", dinit(CheckOptions, $.s = &s)); + "};\n", s); ASSERT_EQUALS("[test.cpp:3:5]: (warning) Member variable 'Foo::foo' is not initialized in the constructor. [uninitMemberVarPrivate]\n", errout_str()); } } @@ -3702,7 +3756,7 @@ class TestConstructors : public TestFixture { " Foo() { }\n" "public:\n" " explicit Foo(int _i) { }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:7:14]: (warning) Member variable 'Foo::foo' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -3723,7 +3777,7 @@ class TestConstructors : public TestFixture { "int* A::f(int* p)\n" "{\n" " return p;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -3737,7 +3791,7 @@ class TestConstructors : public TestFixture { " int *i;\n" "public:\n" " Fred() { }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3751,7 +3805,7 @@ class TestConstructors : public TestFixture { " Fred() { }\n" "private:\n" " int x;\n" - "};", dinit(CheckOptions, $.s = &s)); + "};\n", s); ASSERT_EQUALS("", errout_str()); } @@ -3761,7 +3815,7 @@ class TestConstructors : public TestFixture { "public:\n" " Fred() { }\n" " int *operator [] (int index) { return 0; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -3775,7 +3829,7 @@ class TestConstructors : public TestFixture { " { f.d = 0; }\n" "\n" " double d;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class Fred\n" @@ -3787,7 +3841,7 @@ class TestConstructors : public TestFixture { " { }\n" "\n" " double d;\n" - "};"); + "};\n"); TODO_ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'Fred::d' is not initialized in the constructor. [uninitMemberVar]\n", "", errout_str()); } @@ -3801,7 +3855,7 @@ class TestConstructors : public TestFixture { " { f.d = 0; return true; }\n" "\n" " double d;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class Fred\n" @@ -3813,7 +3867,7 @@ class TestConstructors : public TestFixture { " { return true; }\n" "\n" " double d;\n" - "};"); + "};\n"); TODO_ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'Fred::d' is not initialized in the constructor. [uninitMemberVar]\n", "", errout_str()); } @@ -3827,7 +3881,7 @@ class TestConstructors : public TestFixture { " { d = 0; return true; }\n" "\n" " double d;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class Fred\n" @@ -3839,7 +3893,7 @@ class TestConstructors : public TestFixture { " { return true; }\n" "\n" " double d;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'Fred::d' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -3853,7 +3907,7 @@ class TestConstructors : public TestFixture { " { f.d = 0; }\n" "\n" " double d;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class Fred\n" @@ -3865,7 +3919,7 @@ class TestConstructors : public TestFixture { " { }\n" "\n" " double d;\n" - "};"); + "};\n"); TODO_ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'Fred::d' is not initialized in the constructor. [uninitMemberVar]\n", "", errout_str()); } @@ -3879,7 +3933,7 @@ class TestConstructors : public TestFixture { "public:\n" " A() { Init( B ); };\n" " void Init( Structure& S ) { S.C = 0; };\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct Structure {\n" @@ -3891,7 +3945,7 @@ class TestConstructors : public TestFixture { "public:\n" " A() { Init( B ); };\n" " void Init(const Structure& S) { }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:8:5]: (warning) Member variable 'A::B' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); } @@ -3916,7 +3970,7 @@ class TestConstructors : public TestFixture { "A::B::B()\n" "{\n" " i = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class B\n" @@ -3942,7 +3996,7 @@ class TestConstructors : public TestFixture { "\n" "A::B::B()\n" "{\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:18:4]: (warning) Member variable 'B::j' is not initialized in the constructor. [uninitMemberVar]\n" "[test.cpp:22:7]: (warning) Member variable 'B::i' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); @@ -3963,7 +4017,7 @@ class TestConstructors : public TestFixture { "public:\n" " Foo() { }\n" "};\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("namespace n1\n" @@ -3985,7 +4039,7 @@ class TestConstructors : public TestFixture { "public:\n" " Foo() { }\n" "};\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:11:10]: (warning) Member variable 'Foo::i' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("namespace n1\n" @@ -4007,7 +4061,7 @@ class TestConstructors : public TestFixture { "public:\n" " Foo() { }\n" "};\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -4028,7 +4082,7 @@ class TestConstructors : public TestFixture { "\n" " void init(int value)\n" " { i = value; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class A\n" @@ -4046,7 +4100,7 @@ class TestConstructors : public TestFixture { "\n" " void init(int value)\n" " { }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:7:5]: (warning) Member variable 'A::i' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("class bar {\n" // #9887 @@ -4067,7 +4121,7 @@ class TestConstructors : public TestFixture { " int a;\n" " A() { a=0; }\n" " A(A const &a) { operator=(a); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct A {\n" @@ -4078,7 +4132,7 @@ class TestConstructors : public TestFixture { " a = rhs.a;\n" " return *this;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct A {\n" @@ -4088,7 +4142,7 @@ class TestConstructors : public TestFixture { " A & operator = (const A & rhs) {\n" " return *this;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'A::a' is not initialized in the copy constructor. [uninitMemberVar]\n" "[test.cpp:5:9]: (warning) Member variable 'A::a' is not assigned a value in 'A::operator='. [operatorEqVarError]\n", errout_str()); } @@ -4100,28 +4154,28 @@ class TestConstructors : public TestFixture { "struct B {\n" " A* a;\n" " B() { }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:5]: (warning) Member variable 'B::a' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("struct A;\n" "struct B {\n" " A* a;\n" " B() { }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'B::a' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("struct A;\n" "struct B {\n" " const A* a;\n" " B() { }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'B::a' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("struct A;\n" "struct B {\n" " A* const a;\n" " B() { }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'B::a' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); check("class Test {\n" // #8498 @@ -4152,6 +4206,18 @@ class TestConstructors : public TestFixture { " std::map* pMap = nullptr;\n" "};\n"); ASSERT_EQUALS("", errout_str()); + + check("struct S {\n" // #6294 + " S() : r(new int) {\n" + " *p = 0;\n" + " *(q) = 1;\n" + " *r = 2;\n" + " }\n" + " int *p, *q, *r;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:5]: (warning) Member variable 'S::p' is not initialized in the constructor. [uninitMemberVar]\n" + "[test.cpp:2:5]: (warning) Member variable 'S::q' is not initialized in the constructor. [uninitMemberVar]\n", + errout_str()); } void uninitConstVar() { @@ -4160,7 +4226,7 @@ class TestConstructors : public TestFixture { " A* const a;\n" " B() { }\n" " B(B& b) { }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Member variable 'B::a' is not initialized in the constructor. [uninitMemberVar]\n" "[test.cpp:5:5]: (warning) Member variable 'B::a' is not initialized in the copy constructor. [uninitMemberVar]\n", errout_str()); @@ -4168,21 +4234,21 @@ class TestConstructors : public TestFixture { "struct B {\n" " A* const a;\n" " B& operator=(const B& r) { }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // #3804 check("struct B {\n" " const int a;\n" " B() { }\n" " B(B& b) { }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:5]: (warning) Member variable 'B::a' is not initialized in the constructor. [uninitMemberVar]\n" "[test.cpp:4:5]: (warning) Member variable 'B::a' is not initialized in the copy constructor. [uninitMemberVar]\n", errout_str()); check("struct B {\n" " const int a;\n" " B& operator=(const B& r) { }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4192,7 +4258,7 @@ class TestConstructors : public TestFixture { "public:\n" " C() _STLP_NOTHROW {}\n" " C(const C&) _STLP_NOTHROW {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4201,7 +4267,7 @@ class TestConstructors : public TestFixture { " int mValue;\n" "public:\n" " operatorX() : mValue(0) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4211,7 +4277,7 @@ class TestConstructors : public TestFixture { " T* mElements;\n" "};\n" "template Container::Container() : mElements(nullptr) {}\n" - "Container intContainer;"); + "Container intContainer;\n"); ASSERT_EQUALS("", errout_str()); } @@ -4221,7 +4287,7 @@ class TestConstructors : public TestFixture { "public:\n" " SelectionPosition() {}\n" " const rvec &x() const;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4236,7 +4302,7 @@ class TestConstructors : public TestFixture { " x = 1;\n" " return true;\n" " }\n" - "};", dinit(CheckOptions, $.inconclusive = true)); + "};\n", dinit(CheckOptions, $.inconclusive = true)); TODO_ASSERT_EQUALS("[test.cpp:3]: (warning, inconclusive) Member variable 'C::x' is not initialized in the constructor.\n", "[test.cpp:3:5]: (warning) Member variable 'C::x' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); @@ -4250,7 +4316,7 @@ class TestConstructors : public TestFixture { " x = 1;\n" " return true;\n" " }\n" - "};", dinit(CheckOptions, $.inconclusive = true)); + "};\n", dinit(CheckOptions, $.inconclusive = true)); TODO_ASSERT_EQUALS("[test.cpp:3]: (warning, inconclusive) Member variable 'C::x' is not initialized in the constructor.\n", "[test.cpp:3:5]: (warning) Member variable 'C::x' is not initialized in the constructor. [uninitMemberVar]\n", errout_str()); @@ -4264,7 +4330,7 @@ class TestConstructors : public TestFixture { " x = 1;\n" " return true;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4277,7 +4343,7 @@ class TestConstructors : public TestFixture { " x = 1;\n" " return true;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4287,7 +4353,7 @@ class TestConstructors : public TestFixture { " i = i * SetValue();\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4297,7 +4363,7 @@ class TestConstructors : public TestFixture { " i = i / SetValue();\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4307,7 +4373,7 @@ class TestConstructors : public TestFixture { " i = i % SetValue();\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4317,7 +4383,7 @@ class TestConstructors : public TestFixture { " i = i + SetValue();\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4327,7 +4393,7 @@ class TestConstructors : public TestFixture { " i = i - SetValue();\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4337,7 +4403,7 @@ class TestConstructors : public TestFixture { " i = i << SetValue();\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4347,7 +4413,7 @@ class TestConstructors : public TestFixture { " i = i >> SetValue();\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4357,7 +4423,7 @@ class TestConstructors : public TestFixture { " i = i ^ SetValue();\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4372,7 +4438,7 @@ class TestConstructors : public TestFixture { " x = 1;\n" " return true;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4385,7 +4451,7 @@ class TestConstructors : public TestFixture { " x = 1;\n" " return true;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4395,7 +4461,7 @@ class TestConstructors : public TestFixture { " i *= SetValue();\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4405,7 +4471,7 @@ class TestConstructors : public TestFixture { " i /= SetValue();\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4415,7 +4481,7 @@ class TestConstructors : public TestFixture { " i %= SetValue();\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4425,7 +4491,7 @@ class TestConstructors : public TestFixture { " i += SetValue();\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4435,7 +4501,7 @@ class TestConstructors : public TestFixture { " i -= SetValue();\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4445,7 +4511,7 @@ class TestConstructors : public TestFixture { " i <<= SetValue();\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4455,7 +4521,7 @@ class TestConstructors : public TestFixture { " i >>= SetValue();\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4465,7 +4531,7 @@ class TestConstructors : public TestFixture { " i ^= SetValue();\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4480,7 +4546,7 @@ class TestConstructors : public TestFixture { " x = 1;\n" " return true;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4493,7 +4559,7 @@ class TestConstructors : public TestFixture { " x = 1;\n" " return true;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4502,7 +4568,7 @@ class TestConstructors : public TestFixture { " bool b = (0 < SetValue());\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4511,7 +4577,7 @@ class TestConstructors : public TestFixture { " bool b = (0 <= SetValue());\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4520,7 +4586,7 @@ class TestConstructors : public TestFixture { " bool b = (0 > SetValue());\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct C {\n" @@ -4529,7 +4595,7 @@ class TestConstructors : public TestFixture { " bool b = (0 >= SetValue());\n" " }\n" " int SetValue() { return x = 1; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -4547,7 +4613,7 @@ class TestConstructors : public TestFixture { "class C {\n" " private:\n" " A* b;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("template class A{};\n" @@ -4559,7 +4625,7 @@ class TestConstructors : public TestFixture { " bool m_value;\n" "};\n" "template\n" - "A>::A() : m_value(false) {}"); + "A>::A() : m_value(false) {}\n"); ASSERT_EQUALS("", errout_str()); check("template struct S;\n" // #11177 @@ -4578,7 +4644,7 @@ class TestConstructors : public TestFixture { "public:\n" " A& operator=() { return *this; }\n" "};\n" - "A a;"); + "A a;\n"); ASSERT_EQUALS("", errout_str()); } diff --git a/test/testcppcheck.cpp b/test/testcppcheck.cpp index c4b818b79b9..ffd4d387cfc 100644 --- a/test/testcppcheck.cpp +++ b/test/testcppcheck.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +20,7 @@ #include "color.h" #include "cppcheck.h" #include "errorlogger.h" +#include "errortypes.h" #include "filesettings.h" #include "fixture.h" #include "helpers.h" @@ -31,10 +32,9 @@ #include "suppressions.h" #include -#include +#include #include #include -#include #include #include #include @@ -81,7 +81,9 @@ class TestCppcheck : public TestFixture { TEST_CASE(isPremiumCodingStandardId); TEST_CASE(getDumpFileContentsRawTokens); TEST_CASE(getDumpFileContentsLibrary); + TEST_CASE(checkPlistOutput); TEST_CASE(premiumResultsCache); + TEST_CASE(purgedConfiguration); } void getErrorMessages() const { @@ -170,11 +172,10 @@ class TestCppcheck : public TestFixture { { REDIRECT; ScopedFile file(fname, - "int main()\n" + "void f()\n" "{\n" - " int i = *((int*)0);\n" - " return 0;\n" - "}"); + " (void)(*((int*)0));\n" + "}\n"); int called = 0; std::unordered_set addons; @@ -195,7 +196,7 @@ class TestCppcheck : public TestFixture { if (tools && !nocmd) { f = getExecuteCommand(fname, called); } - CppCheck cppcheck(s, supprs, errorLogger, false, f); + CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, f); ASSERT_EQUALS(1, cppcheck.check(FileWithDetails(file.path(), Path::identify(file.path(), false), 0))); // TODO: how to properly disable these warnings? errorLogger.ids.erase(std::remove_if(errorLogger.ids.begin(), errorLogger.ids.end(), [](const std::string& id) { @@ -240,26 +241,25 @@ class TestCppcheck : public TestFixture { } void checkWithFile() const { - checkWithFileInternal("file.cpp", false); + checkWithFileInternal("file.c", false); } void checkWithFileWithTools() const { - checkWithFileInternal("file_tools.cpp", true); + checkWithFileInternal("file_tools.c", true); } void checkWithFileWithToolsNoCommand() const { - checkWithFileInternal("file_tools_nocmd.cpp", true, true); + checkWithFileInternal("file_tools_nocmd.c", true, true); } void checkWithFSInternal(const std::string& fname, bool tools, bool nocmd = false) const { REDIRECT; ScopedFile file(fname, - "int main()\n" + "void f()\n" "{\n" - " int i = *((int*)0);\n" - " return 0;\n" - "}"); + " (void)(*((int*)0));\n" + "}\n"); int called = 0; std::unordered_set addons; @@ -280,7 +280,7 @@ class TestCppcheck : public TestFixture { if (tools && !nocmd) { f = getExecuteCommand(fname, called); } - CppCheck cppcheck(s, supprs, errorLogger, false, f); + CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, f); FileSettings fs{file.path(), Path::identify(file.path(), false), 0}; ASSERT_EQUALS(1, cppcheck.check(fs)); // TODO: how to properly disable these warnings? @@ -325,31 +325,30 @@ class TestCppcheck : public TestFixture { } void checkWithFS() const { - checkWithFSInternal("fs.cpp", false); + checkWithFSInternal("fs.c", false); } void checkWithFSWithTools() const { - checkWithFSInternal("fs_tools.cpp", true); + checkWithFSInternal("fs_tools.c", true); } void checkWithFSWithToolsNoCommand() const { - checkWithFSInternal("fs_tools_nocmd.cpp", true, true); + checkWithFSInternal("fs_tools_nocmd.c", true, true); } void suppress_error_library() const { - ScopedFile file("suppr_err_lib.cpp", - "int main()\n" + ScopedFile file("suppr_err_lib.c", + "void f()\n" "{\n" - " int i = *((int*)0);\n" - " return 0;\n" - "}"); + " (void)(*((int*)0));\n" + "}\n"); - const char xmldata[] = R"()"; + const char xmldata[] = R"()"; const Settings s = settingsBuilder().libraryxml(xmldata).build(); Suppressions supprs; ErrorLogger2 errorLogger; - CppCheck cppcheck(s, supprs, errorLogger, false, {}); + CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, {}); ASSERT_EQUALS(0, cppcheck.check(FileWithDetails(file.path(), Path::identify(file.path(), false), 0))); // TODO: how to properly disable these warnings? errorLogger.ids.erase(std::remove_if(errorLogger.ids.begin(), errorLogger.ids.end(), [](const std::string& id) { @@ -364,18 +363,18 @@ class TestCppcheck : public TestFixture { ScopedFile file("inc.h", "inline void f()\n" "{\n" - " (void)*((int*)0);\n" - "}"); - ScopedFile test_file_a("a.cpp", - "#include \"inc.h\""); - ScopedFile test_file_b("b.cpp", - "#include \"inc.h\""); + " (void)(*((int*)0));\n" + "}\n"); + ScopedFile test_file_a("a.c", + "#include \"inc.h\"\n"); + ScopedFile test_file_b("b.c", + "#include \"inc.h\"\n"); // this is the "simple" format const auto s = dinit(Settings, $.templateFormat = templateFormat); // TODO: remove when we only longer rely on toString() in unique message handling Suppressions supprs; ErrorLogger2 errorLogger; - CppCheck cppcheck(s, supprs, errorLogger, false, {}); + CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, {}); ASSERT_EQUALS(1, cppcheck.check(FileWithDetails(test_file_a.path(), Path::identify(test_file_a.path(), false), 0))); ASSERT_EQUALS(1, cppcheck.check(FileWithDetails(test_file_b.path(), Path::identify(test_file_b.path(), false), 0))); // TODO: how to properly disable these warnings? @@ -385,29 +384,29 @@ class TestCppcheck : public TestFixture { // the internal errorlist is cleared after each check() call ASSERT_EQUALS(2, errorLogger.errmsgs.size()); auto it = errorLogger.errmsgs.cbegin(); - ASSERT_EQUALS("a.cpp", it->file0); + ASSERT_EQUALS("a.c", it->file0); ASSERT_EQUALS("nullPointer", it->id); ++it; - ASSERT_EQUALS("b.cpp", it->file0); + ASSERT_EQUALS("b.c", it->file0); ASSERT_EQUALS("nullPointer", it->id); } void unique_errors_2() const { - ScopedFile test_file("c.cpp", + ScopedFile test_file("c.c", "void f()\n" "{\n" "const long m[9] = {};\n" "long a=m[9], b=m[9];\n" "(void)a;\n" "(void)b;\n" - "}"); + "}\n"); // this is the "simple" format const auto s = dinit(Settings, $.templateFormat = templateFormat); // TODO: remove when we only longer rely on toString() in unique message handling? Suppressions supprs; ErrorLogger2 errorLogger; - CppCheck cppcheck(s, supprs, errorLogger, false, {}); + CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, {}); ASSERT_EQUALS(1, cppcheck.check(FileWithDetails(test_file.path(), Path::identify(test_file.path(), false), 0))); // TODO: how to properly disable these warnings? errorLogger.errmsgs.erase(std::remove_if(errorLogger.errmsgs.begin(), errorLogger.errmsgs.end(), [](const ErrorMessage& msg) { @@ -416,7 +415,7 @@ class TestCppcheck : public TestFixture { // the internal errorlist is cleared after each check() call ASSERT_EQUALS(2, errorLogger.errmsgs.size()); auto it = errorLogger.errmsgs.cbegin(); - ASSERT_EQUALS("c.cpp", it->file0); + ASSERT_EQUALS("c.c", it->file0); ASSERT_EQUALS(1, it->callStack.size()); { auto stack = it->callStack.cbegin(); @@ -425,7 +424,7 @@ class TestCppcheck : public TestFixture { } ASSERT_EQUALS("arrayIndexOutOfBounds", it->id); ++it; - ASSERT_EQUALS("c.cpp", it->file0); + ASSERT_EQUALS("c.c", it->file0); ASSERT_EQUALS(1, it->callStack.size()); { auto stack = it->callStack.cbegin(); @@ -441,7 +440,7 @@ class TestCppcheck : public TestFixture { { const auto s = dinit(Settings, $.premiumArgs = ""); - CppCheck cppcheck(s, supprs, errorLogger, false, {}); + CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, {}); ASSERT_EQUALS(false, cppcheck.isPremiumCodingStandardId("misra-c2012-0.0")); ASSERT_EQUALS(false, cppcheck.isPremiumCodingStandardId("misra-c2023-0.0")); @@ -458,7 +457,7 @@ class TestCppcheck : public TestFixture { { const auto s = dinit(Settings, $.premiumArgs = "--misra-c-2012 --cert-c++-2016 --autosar"); - CppCheck cppcheck(s, supprs, errorLogger, false, {}); + CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, {}); ASSERT_EQUALS(false, cppcheck.isPremiumCodingStandardId("misra-c2012-0.0")); ASSERT_EQUALS(true, cppcheck.isPremiumCodingStandardId("premium-misra-c-2012-0.0")); @@ -478,11 +477,11 @@ class TestCppcheck : public TestFixture { s.basePaths.emplace_back("/some/path"); Suppressions supprs; ErrorLogger2 errorLogger; - CppCheck cppcheck(s, supprs, errorLogger, false, {}); - std::vector files{"/some/path/test.cpp"}; + CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, {}); + std::vector files{"/some/path/test.c"}; simplecpp::TokenList tokens1(files); const std::string expected = " \n" - " \n" + " \n" " \n"; ASSERT_EQUALS(expected, cppcheck.getDumpFileContentsRawTokens(files, tokens1)); @@ -490,11 +489,10 @@ class TestCppcheck : public TestFixture { "y\n" ";\n"; - std::istringstream fin(code); simplecpp::OutputList outputList; - const simplecpp::TokenList tokens2(fin, files, "", &outputList); + const simplecpp::TokenList tokens2(code, files, "", {}, &outputList); const std::string expected2 = " \n" - " \n" + " \n" " \n" " \n" " \n" @@ -510,8 +508,8 @@ class TestCppcheck : public TestFixture { { Settings s; s.libraries.emplace_back("std.cfg"); - CppCheck cppcheck(s, supprs, errorLogger, false, {}); - //std::vector files{ "/some/path/test.cpp" }; + CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, {}); + //std::vector files{ "/some/path/test.c" }; const std::string expected = " \n"; ASSERT_EQUALS(expected, cppcheck.getLibraryDumpData()); } @@ -520,12 +518,48 @@ class TestCppcheck : public TestFixture { Settings s; s.libraries.emplace_back("std.cfg"); s.libraries.emplace_back("posix.cfg"); - CppCheck cppcheck(s, supprs, errorLogger, false, {}); + CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, {}); const std::string expected = " \n \n"; ASSERT_EQUALS(expected, cppcheck.getLibraryDumpData()); } } + void checkPlistOutput() const { + Suppressions supprs; + ErrorLogger2 errorLogger; + + { + const auto s = dinit(Settings, $.templateFormat = templateFormat, $.plistOutput = "output"); + const ScopedFile file("file", ""); + CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, {}); + const FileWithDetails fileWithDetails {file.path(), Path::identify(file.path(), false), 0}; + + 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()); + } + + { + const auto s = dinit(Settings, $.plistOutput = "output"); + const ScopedFile file("file.c", ""); + CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, {}); + const FileWithDetails fileWithDetails {file.path(), Path::identify(file.path(), false), 0}; + + 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()); + } + + { + 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)); + } + } + void premiumResultsCache() const { // Trac #13889 - cached misra results are shown after removing --premium=misra-c-2012 option @@ -535,11 +569,11 @@ class TestCppcheck : public TestFixture { std::vector files; - std::istringstream istr("void f();\nint x;\n"); - const simplecpp::TokenList tokens(istr, files, "m1.c"); + const char code[] = "void f();\nint x;\n"; + simplecpp::TokenList tokens(code, files, "m1.c"); - Preprocessor preprocessor(settings, errorLogger, Standards::Language::C); - ASSERT(preprocessor.loadFiles(tokens, files)); + Preprocessor preprocessor(tokens, settings, errorLogger, Standards::Language::C); + ASSERT(preprocessor.loadFiles(files)); AddonInfo premiumaddon; premiumaddon.name = "premiumaddon.json"; @@ -550,16 +584,43 @@ class TestCppcheck : public TestFixture { settings.addonInfos.push_back(premiumaddon); settings.premiumArgs = "misra-c-2012"; - CppCheck check(settings, supprs, errorLogger, false, {}); - const size_t hash1 = check.calculateHash(preprocessor, tokens); + CppCheck check(settings, supprs, errorLogger, nullptr, false, {}); + const size_t hash1 = check.calculateHash(preprocessor); settings.premiumArgs = ""; - const size_t hash2 = check.calculateHash(preprocessor, tokens); + const size_t hash2 = check.calculateHash(preprocessor); // cppcheck-suppress knownConditionTrueFalse ASSERT(hash1 != hash2); } + void purgedConfiguration() const + { + ScopedFile test_file("test.cpp", + "#ifdef X\n" + "#endif\n" + "int main() {}\n"); + + // this is the "simple" format + const auto s = dinit(Settings, + $.templateFormat = templateFormat, // TODO: remove when we only longer rely on toString() in unique message handling + $.severity.enable (Severity::information); + $.debugwarnings = true); + Suppressions supprs; + ErrorLogger2 errorLogger; + CppCheck cppcheck(s, supprs, errorLogger, nullptr, false, {}); + ASSERT_EQUALS(1, cppcheck.check(FileWithDetails(test_file.path(), Path::identify(test_file.path(), false), 0))); + // TODO: how to properly disable these warnings? + errorLogger.errmsgs.erase(std::remove_if(errorLogger.errmsgs.begin(), errorLogger.errmsgs.end(), [](const ErrorMessage& msg) { + return msg.id == "logChecker"; + }), errorLogger.errmsgs.end()); + // the internal errorlist is cleared after each check() call + ASSERT_EQUALS(1, errorLogger.errmsgs.size()); + auto it = errorLogger.errmsgs.cbegin(); + ASSERT_EQUALS("test.cpp:0:0: information: The configuration 'X=X' was not checked because its code equals another one. [purgedConfiguration]", + it->toString(false, templateFormat, "")); + } + // TODO: test suppressions // TODO: test all with FS }; diff --git a/test/testerrorlogger.cpp b/test/testerrorlogger.cpp index ca036b90ea5..c849d3a0c61 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 @@ -51,7 +51,10 @@ class TestErrorLogger : public TestFixture { TEST_CASE(ErrorMessageConstructLocations); TEST_CASE(ErrorMessageVerbose); TEST_CASE(ErrorMessageVerboseLocations); + TEST_CASE(ErrorMessageVerboseSymbol); + TEST_CASE(ErrorMessageVerboseNewline); TEST_CASE(ErrorMessageFromInternalError); + TEST_CASE(ErrorMessageCode); TEST_CASE(CustomFormat); TEST_CASE(CustomFormat2); TEST_CASE(CustomFormatLocations); @@ -137,7 +140,7 @@ class TestErrorLogger : public TestFixture { ASSERT_EQUALS("info", loc.getinfo()); } { - const SimpleTokenList tokenlist("a", "dir/a.cpp"); + const SimpleTokenList tokenlist("a\n", "dir/a.cpp"); { const ErrorMessage::FileLocation loc(tokenlist.front(), &tokenlist.get()); ASSERT_EQUALS("dir/a.cpp", loc.getOrigFile(false)); @@ -170,7 +173,7 @@ class TestErrorLogger : public TestFixture { } } { - const SimpleTokenList tokenlist("a", "dir\\a.cpp"); + const SimpleTokenList tokenlist("a\n", "dir\\a.cpp"); { const ErrorMessage::FileLocation loc(tokenlist.front(), &tokenlist.get()); ASSERT_EQUALS("dir\\a.cpp", loc.getOrigFile(false)); @@ -210,12 +213,12 @@ class TestErrorLogger : public TestFixture { ASSERT_EQUALS("dir/a.cpp", ErrorMessage::FileLocation("dir/a.cpp", "info", 1, 1).getfile(false)); ASSERT_EQUALS("dir/a.cpp", ErrorMessage::FileLocation("dir\\a.cpp", "info", 1, 1).getfile(false)); { - const SimpleTokenList tokenlist("a", "dir/a.cpp"); + const SimpleTokenList tokenlist("a\n", "dir/a.cpp"); ASSERT_EQUALS("dir/a.cpp", ErrorMessage::FileLocation(tokenlist.front(), &tokenlist.get()).getfile(false)); ASSERT_EQUALS("dir/a.cpp", ErrorMessage::FileLocation(tokenlist.front(), "info", &tokenlist.get()).getfile(false)); } { - const SimpleTokenList tokenlist("a", "dir\\a.cpp"); + const SimpleTokenList tokenlist("a\n", "dir\\a.cpp"); ASSERT_EQUALS("dir/a.cpp", ErrorMessage::FileLocation(tokenlist.front(), &tokenlist.get()).getfile(false)); ASSERT_EQUALS("dir/a.cpp", ErrorMessage::FileLocation(tokenlist.front(), "info", &tokenlist.get()).getfile(false)); } @@ -284,6 +287,27 @@ class TestErrorLogger : public TestFixture { ASSERT_EQUALS("[foo.cpp:5] -> [bar.cpp:8]: (error) Verbose error", msg.toString(true, templateFormat, "")); } + void ErrorMessageVerboseSymbol() const { + std::list locs(1, fooCpp5); + ErrorMessage msg(std::move(locs), "", Severity::error, "$symbol:sym\nProgramming error with $symbol.\nVerbose error about $symbol", "errorId", Certainty::normal); + ASSERT_EQUALS(1, msg.callStack.size()); + ASSERT_EQUALS("Programming error with sym.", msg.shortMessage()); + ASSERT_EQUALS("Verbose error about sym", msg.verboseMessage()); + ASSERT_EQUALS("[foo.cpp:5]: (error) Programming error with sym.", msg.toString(false, templateFormat, "")); + ASSERT_EQUALS("[foo.cpp:5]: (error) Verbose error about sym", msg.toString(true, templateFormat, "")); + ASSERT_EQUALS("sym\n", msg.symbolNames()); + } + + void ErrorMessageVerboseNewline() const { + std::list locs(1, fooCpp5); + ErrorMessage msg(std::move(locs), "", Severity::error, "Programming error.\nVerbose error\nEven more verbose", "errorId", Certainty::normal); + ASSERT_EQUALS(1, msg.callStack.size()); + ASSERT_EQUALS("Programming error.", msg.shortMessage()); + ASSERT_EQUALS("Verbose error\nEven more verbose", msg.verboseMessage()); + ASSERT_EQUALS("[foo.cpp:5]: (error) Programming error.", msg.toString(false, templateFormat, "")); + ASSERT_EQUALS("[foo.cpp:5]: (error) Verbose error\nEven more verbose", msg.toString(true, templateFormat, "")); + } + void ErrorMessageFromInternalError() const { // TODO: test with token { @@ -314,15 +338,14 @@ class TestErrorLogger : public TestFixture { } } - #define testReportType(reportType, severity, errorId, expectedClassification, expectedGuideline) \ - testReportType_(__FILE__, __LINE__, reportType, severity, errorId, expectedClassification, expectedGuideline) + #define testReportType(...) testReportType_(__FILE__, __LINE__, __VA_ARGS__) void testReportType_(const char *file, int line, ReportType reportType, Severity severity, const std::string &errorId, const std::string &expectedClassification, const std::string &expectedGuideline) const { std::list locs = { fooCpp5 }; const auto mapping = createGuidelineMapping(reportType); - ErrorMessage msg(std::move(locs), emptyString, severity, "", errorId, Certainty::normal); + ErrorMessage msg(std::move(locs), "", severity, "", errorId, Certainty::normal); msg.guideline = getGuideline(msg.id, reportType, mapping, msg.severity); msg.classification = getClassification(msg.guideline, reportType); @@ -338,10 +361,31 @@ class TestErrorLogger : public TestFixture { testReportType(ReportType::misraCpp2023, Severity::style, "premium-misra-cpp-2023-dir-0.3.2", "Required", "Dir 0.3.2"); testReportType(ReportType::misraCpp2008, Severity::style, "premium-misra-cpp-2008-3-4-1", "Required", "3-4-1"); testReportType(ReportType::misraC2012, Severity::style, "premium-misra-c-2012-dir-4.6", "Advisory", "Dir 4.6"); + testReportType(ReportType::misraC2012, Severity::style, "premium-misra-c-2012-10.4-positive-number", "Required", "10.4"); + testReportType(ReportType::misraC2012, Severity::style, "premium-misra-c-2012-10.4", "Required", "10.4"); testReportType(ReportType::misraC2012, Severity::style, "misra-c2012-dir-4.6", "Advisory", "Dir 4.6"); testReportType(ReportType::certC, Severity::error, "resourceLeak", "L3", "FIO42-C"); } + void ErrorMessageCode() const { + ScopedFile file("code.cpp", + "int i;\n" + "int i2;\n" + "int i3;\n" + ); + + ErrorMessage::FileLocation codeCpp3_5{"code.cpp", 3, 5}; + std::list locs = { codeCpp3_5 }; + ErrorMessage msg(std::move(locs), "", Severity::error, "Programming error.\nVerbose error", "errorId", Certainty::normal); + ASSERT_EQUALS(1, msg.callStack.size()); + ASSERT_EQUALS("Programming error.", msg.shortMessage()); + ASSERT_EQUALS("Verbose error", msg.verboseMessage()); + ASSERT_EQUALS("code.cpp:3:5: error: Programming error. [errorId]\n" + "int i3;\n" + " ^", + msg.toString(false, "{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\n{code}", "")); + } + void CustomFormat() const { std::list locs(1, fooCpp5); ErrorMessage msg(std::move(locs), "", Severity::error, "Programming error.\nVerbose error", "errorId", Certainty::normal); @@ -555,7 +599,7 @@ class TestErrorLogger : public TestFixture { "0 " "0 "; ErrorMessage msg; - ASSERT_THROW_INTERNAL_EQUALS(msg.deserialize(str), INTERNAL, "Internal Error: Deserialization of error message failed - invalid CWE ID - not an integer"); + ASSERT_THROW_INTERNAL_EQUALS(msg.deserialize(str), INTERNAL, "Internal Error: Deserialization of error message failed - invalid CWE ID - not an integer (invalid_argument)"); } { // invalid hash @@ -571,7 +615,7 @@ class TestErrorLogger : public TestFixture { "0 " "0 "; ErrorMessage msg; - ASSERT_THROW_INTERNAL_EQUALS(msg.deserialize(str), INTERNAL, "Internal Error: Deserialization of error message failed - invalid hash - not an integer"); + ASSERT_THROW_INTERNAL_EQUALS(msg.deserialize(str), INTERNAL, "Internal Error: Deserialization of error message failed - invalid hash - not an integer (invalid_argument)"); } { // out-of-range CWE ID diff --git a/test/testexceptionsafety.cpp b/test/testexceptionsafety.cpp index 0ec92c982e7..7e3de4405b0 100644 --- a/test/testexceptionsafety.cpp +++ b/test/testexceptionsafety.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -57,11 +57,11 @@ class TestExceptionSafety : public TestFixture { TEST_CASE(rethrowNoCurrentException2); TEST_CASE(rethrowNoCurrentException3); TEST_CASE(noFunctionCall); + TEST_CASE(entryPoint); } struct CheckOptions { - CheckOptions() = default; bool inconclusive = false; const Settings *s = nullptr; }; @@ -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() { @@ -84,18 +84,18 @@ class TestExceptionSafety : public TestFixture { " ~x() {\n" " throw e;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:9]: (warning) Class x is not safe, destructor throws exception [exceptThrowInDestructor]\n" - "[test.cpp:3:9]: (error) Exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n", errout_str()); + "[test.cpp:3:9]: (error) Unhandled exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n", errout_str()); check("class x {\n" " ~x();\n" "};\n" "x::~x() {\n" " throw e;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:5]: (warning) Class x is not safe, destructor throws exception [exceptThrowInDestructor]\n" - "[test.cpp:5:5]: (error) Exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n", errout_str()); + "[test.cpp:5:5]: (error) Unhandled exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n", errout_str()); // #3858 - throwing exception in try block in destructor. check("class x {\n" @@ -105,7 +105,7 @@ class TestExceptionSafety : public TestFixture { " } catch (...) {\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class x {\n" @@ -114,8 +114,8 @@ class TestExceptionSafety : public TestFixture { " throw e;\n" " }\n" " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:4:13]: (error) Exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n", errout_str()); + "}\n"); + ASSERT_EQUALS("[test.cpp:4:13]: (error) Unhandled exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n", errout_str()); // #11031 should not warn when noexcept false check("class A {\n" @@ -123,7 +123,7 @@ class TestExceptionSafety : public TestFixture { " ~A() noexcept(false) {\n" " throw 30;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -134,7 +134,7 @@ class TestExceptionSafety : public TestFixture { " if (x)\n" " throw 123;\n" " p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:9]: (warning) Exception thrown in invalid state, 'p' points at deallocated memory. [exceptDeallocThrow]\n", errout_str()); check("void f() {\n" @@ -143,7 +143,7 @@ class TestExceptionSafety : public TestFixture { " if (foo)\n" " throw 1;\n" " p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:9]: (warning) Exception thrown in invalid state, 'p' points at deallocated memory. [exceptDeallocThrow]\n", errout_str()); } @@ -154,7 +154,7 @@ class TestExceptionSafety : public TestFixture { " if (foo)\n" " throw 1;\n" " p = new int;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -162,7 +162,7 @@ class TestExceptionSafety : public TestFixture { " delete p;\n" " reset(p);\n" " throw 1;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } @@ -171,14 +171,14 @@ class TestExceptionSafety : public TestFixture { " static int* p = 0;\n" " delete p;\n" " throw 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " static int* p = 0;\n" " delete p;\n" " throw 1;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Exception thrown in invalid state, 'p' points at deallocated memory. [exceptDeallocThrow]\n", errout_str()); } @@ -192,7 +192,7 @@ class TestExceptionSafety : public TestFixture { " {\n" " throw err;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:9]: (style) Throwing a copy of the caught exception instead of rethrowing the original exception. [exceptRethrowCopy]\n", errout_str()); } @@ -206,7 +206,7 @@ class TestExceptionSafety : public TestFixture { " {\n" " throw err;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:9]: (style) Throwing a copy of the caught exception instead of rethrowing the original exception. [exceptRethrowCopy]\n", errout_str()); } @@ -218,7 +218,7 @@ class TestExceptionSafety : public TestFixture { " catch(std::runtime_error& err) {\n" " throw err;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:9]: (style) Throwing a copy of the caught exception instead of rethrowing the original exception. [exceptRethrowCopy]\n", errout_str()); } @@ -233,7 +233,7 @@ class TestExceptionSafety : public TestFixture { " exception err2;\n" " throw err2;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -250,7 +250,7 @@ class TestExceptionSafety : public TestFixture { " throw inner;\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:10:13]: (style) Throwing a copy of the caught exception instead of rethrowing the original exception. [exceptRethrowCopy]\n", errout_str()); check("void f() {\n" @@ -265,7 +265,7 @@ class TestExceptionSafety : public TestFixture { " throw outer;\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -277,7 +277,7 @@ class TestExceptionSafety : public TestFixture { " catch( ::std::exception err) {\n" " foo(err);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:5]: (style) Exception should be caught by reference. [catchExceptionByValue]\n", errout_str()); check("void f() {\n" @@ -287,7 +287,7 @@ class TestExceptionSafety : public TestFixture { " catch(const exception err) {\n" " foo(err);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:5]: (style) Exception should be caught by reference. [catchExceptionByValue]\n", errout_str()); check("void f() {\n" @@ -297,7 +297,7 @@ class TestExceptionSafety : public TestFixture { " catch( ::std::exception& err) {\n" " foo(err);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -307,7 +307,7 @@ class TestExceptionSafety : public TestFixture { " catch(exception* err) {\n" " foo(err);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -317,7 +317,7 @@ class TestExceptionSafety : public TestFixture { " catch(const exception& err) {\n" " foo(err);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -327,7 +327,7 @@ class TestExceptionSafety : public TestFixture { " catch(int err) {\n" " foo(err);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -337,7 +337,7 @@ class TestExceptionSafety : public TestFixture { " catch(exception* const err) {\n" " foo(err);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -347,15 +347,30 @@ class TestExceptionSafety : public TestFixture { "void func3() noexcept(true) { throw 1; }\n" "void func4() noexcept(false) { throw 1; }\n" "void func5() noexcept(true) { func1(); }\n" - "void func6() noexcept(false) { func1(); }"); - ASSERT_EQUALS("[test.cpp:2:25]: (error) Exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n" - "[test.cpp:3:31]: (error) Exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n" - "[test.cpp:5:31]: (error) Exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n", errout_str()); + "void func6() noexcept(false) { func1(); }\n"); + ASSERT_EQUALS("[test.cpp:2:25]: (error) Unhandled exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n" + "[test.cpp:3:31]: (error) Unhandled exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n" + "[test.cpp:5:31]: (error) Unhandled exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n", errout_str()); // avoid false positives check("const char *func() noexcept { return 0; }\n" - "const char *func1() noexcept { try { throw 1; } catch(...) {} return 0; }"); + "const char *func1() noexcept { try { throw 1; } catch(...) {} return 0; }\n"); ASSERT_EQUALS("", errout_str()); + + check("struct A {\n" // #14526 + " void f(int = 0, int = 1) { throw 0; }\n" + "};\n" + "void g() noexcept {\n" + " A a;\n" + " a.f();\n" + "}\n" + "void h() noexcept {\n" + " A a;\n" + " a.f(1, 3);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6:7]: (error) Unhandled exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n" + "[test.cpp:10:7]: (error) Unhandled exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n", + errout_str()); } void nothrowThrow() { @@ -363,12 +378,12 @@ class TestExceptionSafety : public TestFixture { "void func2() throw() { throw 1; }\n" "void func3() throw(int) { throw 1; }\n" "void func4() throw() { func1(); }\n" - "void func5() throw(int) { func1(); }"); - ASSERT_EQUALS("[test.cpp:2:24]: (error) Exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n" - "[test.cpp:4:24]: (error) Exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n", errout_str()); + "void func5() throw(int) { func1(); }\n"); + ASSERT_EQUALS("[test.cpp:2:24]: (error) Unhandled exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n" + "[test.cpp:4:24]: (error) Unhandled exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n", errout_str()); // avoid false positives - check("const char *func() throw() { return 0; }"); + check("const char *func() throw() { return 0; }\n"); ASSERT_EQUALS("", errout_str()); @@ -404,7 +419,7 @@ class TestExceptionSafety : public TestFixture { "{\n" " f();\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); - ASSERT_EQUALS("", errout_str()); + ASSERT_EQUALS("[test.cpp:4:5]: (error) Unhandled exception thrown in function that is an entry point. [throwInEntryPoint]\n", errout_str()); } void unhandledExceptionSpecification3() { @@ -421,23 +436,27 @@ class TestExceptionSafety : public TestFixture { "}\n"; check(code, dinit(CheckOptions, $.inconclusive = true)); - ASSERT_EQUALS("[test.cpp:3:5] -> [test.cpp:1:6]: (style, inconclusive) Unhandled exception specification when calling function f(). [unhandledExceptionSpecification]\n" + ASSERT_EQUALS("[test.cpp:10:5]: (error) Unhandled exception thrown in function that is an entry point. [throwInEntryPoint]\n" + "[test.cpp:3:5] -> [test.cpp:1:6]: (style, inconclusive) Unhandled exception specification when calling function f(). [unhandledExceptionSpecification]\n" "[test.cpp:6:5] -> [test.cpp:1:6]: (style, inconclusive) Unhandled exception specification when calling function f(). [unhandledExceptionSpecification]\n", errout_str()); const Settings s = settingsBuilder().library("gnu.cfg").build(); check(code, dinit(CheckOptions, $.inconclusive = true, $.s = &s)); - ASSERT_EQUALS("", errout_str()); + ASSERT_EQUALS("[test.cpp:3:5]: (error) Unhandled exception thrown in function that is an entry point. [throwInEntryPoint]\n" + "[test.cpp:6:5]: (error) Unhandled exception thrown in function that is an entry point. [throwInEntryPoint]\n" + "[test.cpp:10:5]: (error) Unhandled exception thrown in function that is an entry point. [throwInEntryPoint]\n", + errout_str()); } void nothrowAttributeThrow() { check("void func1() throw(int) { throw 1; }\n" "void func2() __attribute((nothrow)); void func2() { throw 1; }\n" - "void func3() __attribute((nothrow)); void func3() { func1(); }"); - ASSERT_EQUALS("[test.cpp:2:53]: (error) Exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n" - "[test.cpp:3:53]: (error) Exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n", errout_str()); + "void func3() __attribute((nothrow)); void func3() { func1(); }\n"); + ASSERT_EQUALS("[test.cpp:2:53]: (error) Unhandled exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n" + "[test.cpp:3:53]: (error) Unhandled exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n", errout_str()); // avoid false positives - check("const char *func() __attribute((nothrow)); void func1() { return 0; }"); + check("const char *func() __attribute((nothrow)); void func1() { return 0; }\n"); ASSERT_EQUALS("", errout_str()); } @@ -446,30 +465,30 @@ class TestExceptionSafety : public TestFixture { " void copyMemberValues() throw () {\n" " copyMemberValues();\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } void nothrowDeclspecThrow() { check("void func1() throw(int) { throw 1; }\n" "void __declspec(nothrow) func2() { throw 1; }\n" - "void __declspec(nothrow) func3() { func1(); }"); - ASSERT_EQUALS("[test.cpp:2:36]: (error) Exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n" - "[test.cpp:3:36]: (error) Exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n", errout_str()); + "void __declspec(nothrow) func3() { func1(); }\n"); + ASSERT_EQUALS("[test.cpp:2:36]: (error) Unhandled exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n" + "[test.cpp:3:36]: (error) Unhandled exception thrown in function declared not to throw exceptions. [throwInNoexceptFunction]\n", errout_str()); // avoid false positives - check("const char *func() __attribute((nothrow)); void func1() { return 0; }"); + check("const char *func() __attribute((nothrow)); void func1() { return 0; }\n"); ASSERT_EQUALS("", errout_str()); } void rethrowNoCurrentException1() { - check("void func1(const bool flag) { try{ if(!flag) throw; } catch (int&) { ; } }"); + check("void func1(const bool flag) { try{ if(!flag) throw; } catch (int&) { ; } }\n"); ASSERT_EQUALS("[test.cpp:1:46]: (error) Rethrowing current exception with 'throw;', it seems there is no current exception to rethrow." " If there is no current exception this calls std::terminate(). More: https://isocpp.org/wiki/faq/exceptions#throw-without-an-object [rethrowNoCurrentException]\n", errout_str()); } void rethrowNoCurrentException2() { - check("void func1() { try{ ; } catch (...) { ; } throw; }"); + check("void func1() { try{ ; } catch (...) { ; } throw; }\n"); ASSERT_EQUALS("[test.cpp:1:43]: (error) Rethrowing current exception with 'throw;', it seems there is no current exception to rethrow." " If there is no current exception this calls std::terminate(). More: https://isocpp.org/wiki/faq/exceptions#throw-without-an-object [rethrowNoCurrentException]\n", errout_str()); } @@ -477,7 +496,7 @@ class TestExceptionSafety : public TestFixture { void rethrowNoCurrentException3() { check("void on_error() { try { throw; } catch (const int &) { ; } catch (...) { ; } }\n" // exception dispatcher idiom "void func2() { try{ ; } catch (const int&) { throw; } ; }\n" - "void func3() { throw 0; }"); + "void func3() { throw 0; }\n"); ASSERT_EQUALS("", errout_str()); } @@ -490,6 +509,40 @@ class TestExceptionSafety : public TestFixture { "}\n"); ASSERT_EQUALS("", errout_str()); } + + void entryPoint() { + check("void f(int i) {\n" // #14195 + " if (i < 2)\n" + " throw 0;\n" + "}\n" + "int main(int argc, char* argv[]) {\n" + " f(argc);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6:5]: (error) Unhandled exception thrown in function that is an entry point. [throwInEntryPoint]\n", + errout_str()); + + check("void f(int i) {\n" + " if (i < 2)\n" + " throw 0;\n" + "}\n" + "int main(int argc, char* argv[]) {\n" + " try {\n" + " f(argc);\n" + " } catch (...) {\n" + " return 1;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f(int i) {\n" // #9380 + " throw i;\n" + "}\n" + "int main() {\n" + " f(123);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:5]: (error) Unhandled exception thrown in function that is an entry point. [throwInEntryPoint]\n", + errout_str()); + } }; REGISTER_TEST(TestExceptionSafety) diff --git a/test/testexecutor.cpp b/test/testexecutor.cpp index 4f952a4004d..30b2b834834 100644 --- a/test/testexecutor.cpp +++ b/test/testexecutor.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +#include "config.h" #include "errorlogger.h" #include "errortypes.h" #include "executor.h" @@ -35,7 +36,7 @@ class DummyExecutor : public Executor { public: DummyExecutor(const std::list &files, const std::list& fileSettings, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger) - : Executor(files, fileSettings, settings, suppressions, errorLogger) + : Executor(files, fileSettings, settings, suppressions, errorLogger, nullptr) {} NORETURN unsigned int check() override diff --git a/test/testfunctions.cpp b/test/testfunctions.cpp index f78356395f7..4ebe3360aba 100644 --- a/test/testfunctions.cpp +++ b/test/testfunctions.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -85,6 +85,10 @@ class TestFunctions : public TestFixture { TEST_CASE(checkMissingReturn4); TEST_CASE(checkMissingReturn5); TEST_CASE(checkMissingReturn6); // #13180 + TEST_CASE(checkMissingReturn7); // #14370 - FN try/catch + TEST_CASE(checkMissingReturn8); + TEST_CASE(checkMissingReturn9); + TEST_CASE(checkMissingReturnStdInt); // #14482 - FN std::int32_t // std::move for locar variable TEST_CASE(returnLocalStdMove1); @@ -116,35 +120,36 @@ class TestFunctions : public TestFixture { struct CheckOptions { - CheckOptions() = default; bool cpp = true; - const Settings* s = nullptr; }; #define check(...) check_(__FILE__, __LINE__, __VA_ARGS__) template void check_(const char* file, int line, const char (&code)[size], const CheckOptions& options = make_default_obj()) { - const Settings& s = options.s ? *options.s : settings; + check_(file, line, code, settings, options.cpp); + } - // Tokenize.. - SimpleTokenizer tokenizer(s, *this, options.cpp); + template + void check_(const char* file, int line, const char (&code)[size], const Settings& s, bool cpp = true) { + SimpleTokenizer tokenizer(s, *this, cpp); ASSERT_LOC(tokenizer.tokenize(code), file, line); - runChecks(tokenizer, this); + CheckFunctions check; + runChecks(check, tokenizer, *this); } void prohibitedFunctions_posix() { check("void f()\n" "{\n" " bsd_signal(SIGABRT, SIG_IGN);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (style) Obsolescent function 'bsd_signal' called. It is recommended to use 'sigaction' instead. [bsd_signalCalled]\n", errout_str()); check("int f()\n" "{\n" " int bsd_signal(0);\n" " return bsd_signal;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f()\n" @@ -153,7 +158,7 @@ class TestFunctions : public TestFixture { " if(!hp = gethostbyname(\"127.0.0.1\")) {\n" " exit(1);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:14]: (style) Obsolescent function 'gethostbyname' called. It is recommended to use 'getaddrinfo' instead. [gethostbynameCalled]\n", errout_str()); check("void f()\n" @@ -163,13 +168,13 @@ class TestFunctions : public TestFixture { " if(!hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET)) {\n" " exit(1);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:14]: (style) Obsolescent function 'gethostbyaddr' called. It is recommended to use 'getnameinfo' instead. [gethostbyaddrCalled]\n", errout_str()); check("void f()\n" "{\n" " usleep( 1000 );\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (style) Obsolescent function 'usleep' called. It is recommended to use 'nanosleep' or 'setitimer' instead. [usleepCalled]\n", errout_str()); } @@ -181,7 +186,7 @@ class TestFunctions : public TestFixture { "{\n" " n1::index();\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("std::size_t f()\n" @@ -189,19 +194,19 @@ class TestFunctions : public TestFixture { " std::size_t index(0);\n" " index++;\n" " return index;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f()\n" "{\n" " return this->index();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f()\n" "{\n" " int index( 0 );\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("const char f()\n" @@ -209,7 +214,7 @@ class TestFunctions : public TestFixture { " const char var[6] = \"index\";\n" " const char i = index(var, 0);\n" " return i;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:20]: (style) Obsolescent function 'index' called. It is recommended to use 'strchr' instead. [indexCalled]\n", errout_str()); } @@ -217,10 +222,10 @@ class TestFunctions : public TestFixture { void prohibitedFunctions_qt_index() { check("void TDataModel::forceRowRefresh(int row) {\n" " emit dataChanged(index(row, 0), index(row, columnCount() - 1));\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:22]: (style) Obsolescent function 'index' called. It is recommended to use 'strchr' instead. [indexCalled]\n" - "[test.cpp:2:37]: (style) Obsolescent function 'index' called. It is recommended to use 'strchr' instead. [indexCalled]\n", // duplicate + "[test.cpp:2:37]: (style) Obsolescent function 'index' called. It is recommended to use 'strchr' instead. [indexCalled]\n", errout_str()); } @@ -228,14 +233,14 @@ class TestFunctions : public TestFixture { check("void f()\n" "{\n" " int rindex( 0 );\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f()\n" "{\n" " const char var[7] = \"rindex\";\n" " print(rindex(var, 0));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:11]: (style) Obsolescent function 'rindex' called. It is recommended to use 'strrchr' instead. [rindexCalled]\n", errout_str()); } @@ -245,7 +250,7 @@ class TestFunctions : public TestFixture { "public:\n" " Fred() : index(0) { }\n" " int index;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -253,13 +258,13 @@ class TestFunctions : public TestFixture { check("void f()\n" "{\n" " char *x = gets(a);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:15]: (warning) Obsolete function 'gets' called. It is recommended to use 'fgets' or 'gets_s' instead. [getsCalled]\n", errout_str()); check("void f()\n" "{\n" " foo(x, gets(a));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:12]: (warning) Obsolete function 'gets' called. It is recommended to use 'fgets' or 'gets_s' instead. [getsCalled]\n", errout_str()); } @@ -267,32 +272,32 @@ class TestFunctions : public TestFixture { check("void f()\n" "{\n" " char *x = alloca(10);\n" - "}"); // #4382 - there are no VLAs in C++ + "}\n"); // #4382 - there are no VLAs in C++ ASSERT_EQUALS("[test.cpp:3:15]: (warning) Obsolete function 'alloca' called. [allocaCalled]\n", errout_str()); check("void f()\n" "{\n" " char *x = alloca(10);\n" - "}", dinit(CheckOptions, $.cpp = false)); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("[test.c:3:15]: (warning) Obsolete function 'alloca' called. In C99 and later it is recommended to use a variable length array instead. [allocaCalled]\n", errout_str()); const Settings s = settingsBuilder(settings).c(Standards::C89).cpp(Standards::CPP03).build(); check("void f()\n" "{\n" " char *x = alloca(10);\n" - "}", dinit(CheckOptions, $.s = &s)); // #4382 - there are no VLAs in C++ + "}\n", s); // #4382 - there are no VLAs in C++ ASSERT_EQUALS("", errout_str()); check("void f()\n" "{\n" " char *x = alloca(10);\n" - "}", dinit(CheckOptions, $.cpp = false, $.s = &s)); // #7558 - no alternative to alloca in C89 + "}\n", s, false); // #7558 - no alternative to alloca in C89 ASSERT_EQUALS("", errout_str()); check("void f()\n" "{\n" " char *x = alloca(10);\n" - "}", dinit(CheckOptions, $.cpp = false, $.s = &s)); + "}\n", s, false); ASSERT_EQUALS("", errout_str()); } @@ -306,7 +311,7 @@ class TestFunctions : public TestFixture { "{\n" " int b ; b = ftime ( 1 ) ;\n" " return 0 ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -316,7 +321,7 @@ class TestFunctions : public TestFixture { "{\n" " char *x = std::gets(str);\n" " char *y = gets(str);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:20]: (warning) Obsolete function 'gets' called. It is recommended to use 'fgets' or 'gets_s' instead. [getsCalled]\n" "[test.cpp:4:15]: (warning) Obsolete function 'gets' called. It is recommended to use 'fgets' or 'gets_s' instead. [getsCalled]\n", errout_str()); } @@ -327,7 +332,7 @@ class TestFunctions : public TestFixture { "{\n" " char *x = std::gets(str);\n" " usleep( 1000 );\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:20]: (warning) Obsolete function 'gets' called. It is recommended to use 'fgets' or 'gets_s' instead. [getsCalled]\n" "[test.cpp:4:5]: (style) Obsolescent function 'usleep' called. It is recommended to use 'nanosleep' or 'setitimer' instead. [usleepCalled]\n", errout_str()); } @@ -339,14 +344,14 @@ class TestFunctions : public TestFixture { " char s [ 10 ] ;\n" " gets ( s ) ;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:5]: (warning) Obsolete function 'gets' called. It is recommended to use 'fgets' or 'gets_s' instead. [getsCalled]\n", errout_str()); check("int getcontext(ucontext_t *ucp);\n" "void f (ucontext_t *ucp)\n" "{\n" " getcontext ( ucp ) ;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:5]: (portability) Obsolescent function 'getcontext' called. Applications are recommended to be rewritten to use POSIX threads. [getcontextCalled]\n", errout_str()); } @@ -357,7 +362,7 @@ class TestFunctions : public TestFixture { " char s [ 10 ] ;\n" " gets ( s ) ;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -366,7 +371,7 @@ class TestFunctions : public TestFixture { "{\n" " char *cpwd;" " crypt(pwd, cpwd);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:20]: (warning) Return value of function crypt() is not used. [ignoredReturnValue]\n" "[test.cpp:3:20]: (portability) Non reentrant function 'crypt' called. For threadsafe applications it is recommended to use the reentrant replacement function 'crypt_r'. [cryptCalled]\n", errout_str()); @@ -375,7 +380,7 @@ class TestFunctions : public TestFixture { " char *pwd = getpass(\"Password:\");" " char *cpwd;" " crypt(pwd, cpwd);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:57]: (warning) Return value of function crypt() is not used. [ignoredReturnValue]\n" "[test.cpp:3:57]: (portability) Non reentrant function 'crypt' called. For threadsafe applications it is recommended to use the reentrant replacement function 'crypt_r'. [cryptCalled]\n", errout_str()); @@ -383,7 +388,7 @@ class TestFunctions : public TestFixture { "{\n" " int crypt = 0;" " return crypt;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -392,14 +397,14 @@ class TestFunctions : public TestFixture { "{\n" " time_t t = 0;" " auto lt = std::localtime(&t);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:37]: (portability) Non reentrant function 'localtime' called. For threadsafe applications it is recommended to use the reentrant replacement function 'localtime_r'. [localtimeCalled]\n", errout_str()); // Passed as function argument check("void f()\n" "{\n" " printf(\"Magic guess: %d\", getpwent());\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:31]: (portability) Non reentrant function 'getpwent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getpwent_r'. [getpwentCalled]\n", errout_str()); // Pass return value @@ -407,14 +412,14 @@ class TestFunctions : public TestFixture { "{\n" " time_t t = 0;" " struct tm *foo = localtime(&t);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:39]: (portability) Non reentrant function 'localtime' called. For threadsafe applications it is recommended to use the reentrant replacement function 'localtime_r'. [localtimeCalled]\n", errout_str()); // Access via global namespace check("void f()\n" "{\n" " ::getpwent();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:7]: (warning) Return value of function ::getpwent() is not used. [ignoredReturnValue]\n" "[test.cpp:3:7]: (portability) Non reentrant function 'getpwent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getpwent_r'. [getpwentCalled]\n", errout_str()); @@ -422,68 +427,68 @@ class TestFunctions : public TestFixture { check("int getpwent()\n" "{\n" " return 123;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Be quiet on other namespaces check("void f()\n" "{\n" " foobar::getpwent();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Be quiet on class member functions check("void f()\n" "{\n" " foobar.getpwent();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void invalidFunctionUsage1() { - check("void f() { memset(a,b,sizeof(a)!=12); }"); + check("void f() { memset(a,b,sizeof(a)!=12); }\n"); ASSERT_EQUALS("[test.cpp:1:32]: (error) Invalid memset() argument nr 3. A non-boolean value is required. [invalidFunctionArgBool]\n", errout_str()); - check("void f() { memset(a,b,sizeof(a)!=0); }"); + check("void f() { memset(a,b,sizeof(a)!=0); }\n"); ASSERT_EQUALS("[test.cpp:1:32]: (error) Invalid memset() argument nr 3. A non-boolean value is required. [invalidFunctionArgBool]\n", errout_str()); - check("void f() { memset(a,b,!c); }"); + check("void f() { memset(a,b,!c); }\n"); ASSERT_EQUALS("[test.cpp:1:23]: (error) Invalid memset() argument nr 3. A non-boolean value is required. [invalidFunctionArgBool]\n", errout_str()); // Ticket #6990 - check("void f(bool c) { memset(a,b,c); }"); + check("void f(bool c) { memset(a,b,c); }\n"); ASSERT_EQUALS("[test.cpp:1:29]: (error) Invalid memset() argument nr 3. A non-boolean value is required. [invalidFunctionArgBool]\n", errout_str()); - check("void f() { memset(a,b,true); }"); + check("void f() { memset(a,b,true); }\n"); ASSERT_EQUALS("[test.cpp:1:23]: (error) Invalid memset() argument nr 3. A non-boolean value is required. [invalidFunctionArgBool]\n", errout_str()); // Ticket #6588 (c mode) check("void record(char* buf, int n) {\n" " memset(buf, 0, n < 255);\n" /* KO */ " memset(buf, 0, n < 255 ? n : 255);\n" /* OK */ - "}", dinit(CheckOptions, $.cpp = false)); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("[test.c:2:20]: (error) Invalid memset() argument nr 3. A non-boolean value is required. [invalidFunctionArgBool]\n", errout_str()); // Ticket #6588 (c++ mode) check("void record(char* buf, int n) {\n" " memset(buf, 0, n < 255);\n" /* KO */ " memset(buf, 0, n < 255 ? n : 255);\n" /* OK */ - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:20]: (error) Invalid memset() argument nr 3. A non-boolean value is required. [invalidFunctionArgBool]\n", errout_str()); check("int boolArgZeroIsInvalidButOneIsValid(int a, int param) {\n" " return div(a, param > 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:23]: (error) Invalid div() argument nr 2. The value is 0 or 1 (boolean) but the valid values are ':-1,1:'. [invalidFunctionArg]\n", errout_str()); check("void boolArgZeroIsValidButOneIsInvalid(int param) {\n" " strtol(a, b, param > 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:22]: (error) Invalid strtol() argument nr 3. The value is 0 or 1 (boolean) but the valid values are '0,2:36'. [invalidFunctionArg]\n", errout_str()); - check("void f() { strtol(a,b,1); }"); + check("void f() { strtol(a,b,1); }\n"); ASSERT_EQUALS("[test.cpp:1:23]: (error) Invalid strtol() argument nr 3. The value is 1 but the valid values are '0,2:36'. [invalidFunctionArg]\n", errout_str()); - check("void f() { strtol(a,b,10); }"); + check("void f() { strtol(a,b,10); }\n"); ASSERT_EQUALS("", errout_str()); check("void f(std::vector& v) {\n" // #10754 @@ -526,16 +531,16 @@ class TestFunctions : public TestFixture { } void invalidFunctionUsageStrings() { - check("size_t f() { char x = 'x'; return strlen(&x); }"); + check("size_t f() { char x = 'x'; return strlen(&x); }\n"); ASSERT_EQUALS("[test.cpp:1:42]: (error) Invalid strlen() argument nr 1. A nul-terminated string is required. [invalidFunctionArgStr]\n", errout_str()); - check("size_t f() { return strlen(&x); }"); + check("size_t f() { return strlen(&x); }\n"); ASSERT_EQUALS("", errout_str()); - check("size_t f(char x) { return strlen(&x); }"); + check("size_t f(char x) { return strlen(&x); }\n"); ASSERT_EQUALS("[test.cpp:1:34]: (error) Invalid strlen() argument nr 1. A nul-terminated string is required. [invalidFunctionArgStr]\n", errout_str()); - check("size_t f() { char x = '\\0'; return strlen(&x); }"); + check("size_t f() { char x = '\\0'; return strlen(&x); }\n"); ASSERT_EQUALS("", errout_str()); check("size_t f() {\n" @@ -545,41 +550,41 @@ class TestFunctions : public TestFixture { " else\n" " x = 'a';\n" " return strlen(&x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:17]: (error) Invalid strlen() argument nr 1. A nul-terminated string is required. [invalidFunctionArgStr]\n", errout_str()); - check("int f() { char x = '\\0'; return strcmp(\"Hello world\", &x); }"); + check("int f() { char x = '\\0'; return strcmp(\"Hello world\", &x); }\n"); ASSERT_EQUALS("", errout_str()); - check("int f() { char x = 'x'; return strcmp(\"Hello world\", &x); }"); + check("int f() { char x = 'x'; return strcmp(\"Hello world\", &x); }\n"); ASSERT_EQUALS("[test.cpp:1:54]: (error) Invalid strcmp() argument nr 2. A nul-terminated string is required. [invalidFunctionArgStr]\n", errout_str()); - check("size_t f(char x) { char * y = &x; return strlen(y); }"); + check("size_t f(char x) { char * y = &x; return strlen(y); }\n"); TODO_ASSERT_EQUALS("[test.cpp:1:42]: (error) Invalid strlen() argument nr 1. A nul-terminated string is required. [invalidFunctionArgStr]\n", "", errout_str()); - check("size_t f(char x) { char * y = &x; char *z = y; return strlen(z); }"); + check("size_t f(char x) { char * y = &x; char *z = y; return strlen(z); }\n"); TODO_ASSERT_EQUALS("[test.cpp:1:42]: (error) Invalid strlen() argument nr 1. A nul-terminated string is required. [invalidFunctionArgStr]\n", "", errout_str()); - check("size_t f() { char x = 'x'; char * y = &x; char *z = y; return strlen(z); }"); + check("size_t f() { char x = 'x'; char * y = &x; char *z = y; return strlen(z); }\n"); TODO_ASSERT_EQUALS("[test.cpp:1:42]: (error) Invalid strlen() argument nr 1. A nul-terminated string is required. [invalidFunctionArgStr]\n", "", errout_str()); - check("size_t f() { char x = '\\0'; char * y = &x; char *z = y; return strlen(z); }"); + check("size_t f() { char x = '\\0'; char * y = &x; char *z = y; return strlen(z); }\n"); ASSERT_EQUALS("", errout_str()); - check("size_t f() { char x[] = \"Hello world\"; return strlen(x); }"); + check("size_t f() { char x[] = \"Hello world\"; return strlen(x); }\n"); ASSERT_EQUALS("", errout_str()); - check("size_t f(char x[]) { return strlen(x); }"); + check("size_t f(char x[]) { return strlen(x); }\n"); ASSERT_EQUALS("", errout_str()); - check("int f(char x, char y) { return strcmp(&x, &y); }"); + check("int f(char x, char y) { return strcmp(&x, &y); }\n"); ASSERT_EQUALS("[test.cpp:1:39]: (error) Invalid strcmp() argument nr 1. A nul-terminated string is required. [invalidFunctionArgStr]\n" "[test.cpp:1:43]: (error) Invalid strcmp() argument nr 2. A nul-terminated string is required. [invalidFunctionArgStr]\n", errout_str()); - check("size_t f() { char x[] = \"Hello world\"; return strlen(&x[0]); }"); + check("size_t f() { char x[] = \"Hello world\"; return strlen(&x[0]); }\n"); ASSERT_EQUALS("", errout_str()); - check("size_t f() { char* x = \"Hello world\"; return strlen(&x[0]); }"); + check("size_t f() { char* x = \"Hello world\"; return strlen(&x[0]); }\n"); ASSERT_EQUALS("", errout_str()); check("struct S {\n" @@ -592,11 +597,11 @@ class TestFunctions : public TestFixture { " size_t l1 = strlen(&s1.x);\n" " size_t l2 = strlen(&s2.x);\n" " return l1 + l2;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:22]: (error) Invalid strlen() argument nr 1. A nul-terminated string is required. [invalidFunctionArgStr]\n" "[test.cpp:9:22]: (error) Invalid strlen() argument nr 1. A nul-terminated string is required. [invalidFunctionArgStr]\n", errout_str()); - check("const char x = 'x'; size_t f() { return strlen(&x); }"); + check("const char x = 'x'; size_t f() { return strlen(&x); }\n"); ASSERT_EQUALS("[test.cpp:1:48]: (error) Invalid strlen() argument nr 1. A nul-terminated string is required. [invalidFunctionArgStr]\n", errout_str()); check("struct someStruct {\n" @@ -611,7 +616,7 @@ class TestFunctions : public TestFixture { "int f(struct someStruct * const tp, const int k)\n" "{\n" " return strcmp(&tp->x.buf[k], \"needle\");\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct someStruct {\n" @@ -620,29 +625,29 @@ class TestFunctions : public TestFixture { "int f(struct someStruct * const tp, const int k)\n" "{\n" " return strcmp(&tp->buf[k], \"needle\");\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); - check("const char x = 'x'; size_t f() { char y = x; return strlen(&y); }"); + check("const char x = 'x'; size_t f() { char y = x; return strlen(&y); }\n"); ASSERT_EQUALS("[test.cpp:1:60]: (error) Invalid strlen() argument nr 1. A nul-terminated string is required. [invalidFunctionArgStr]\n", errout_str()); - check("const char x = '\\0'; size_t f() { return strlen(&x); }"); + check("const char x = '\\0'; size_t f() { return strlen(&x); }\n"); ASSERT_EQUALS("", errout_str()); - check("const char x = '\\0'; size_t f() { char y = x; return strlen(&y); }"); + check("const char x = '\\0'; size_t f() { char y = x; return strlen(&y); }\n"); ASSERT_EQUALS("", errout_str()); check("size_t f() {\n" " char * a = \"Hello world\";\n" " char ** b = &a;\n" " return strlen(&b[0][0]);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("size_t f() {\n" " char ca[] = \"asdf\";\n" " return strlen((char*) &ca);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #5225 @@ -653,67 +658,67 @@ class TestFunctions : public TestFixture { " strcat(str, &d);\n" " puts(str);\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:15]: (error) Invalid strcat() argument nr 2. A nul-terminated string is required. [invalidFunctionArgStr]\n", errout_str()); check("FILE* f(void) {\n" " const char fileName[1] = { \'x\' };\n" " return fopen(fileName, \"r\"); \n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:16]: (error) Invalid fopen() argument nr 1. A nul-terminated string is required. [invalidFunctionArgStr]\n", errout_str()); check("FILE* f(void) {\n" " const char fileName[2] = { \'x\', \'y\' };\n" " return fopen(fileName, \"r\"); \n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:16]: (error) Invalid fopen() argument nr 1. A nul-terminated string is required. [invalidFunctionArgStr]\n", errout_str()); check("FILE* f(void) {\n" " const char fileName[3] = { \'x\', \'y\' ,\'\\0\' };\n" " return fopen(fileName, \"r\"); \n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("FILE* f(void) {\n" " const char fileName[3] = { \'x\', \'\\0\' ,\'y\' };\n" " return fopen(fileName, \"r\"); \n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("FILE* f(void) {\n" " const char fileName[3] = { \'x\', \'y\' };\n" // implicit '\0' added at the end " return fopen(fileName, \"r\"); \n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("FILE* f(void) {\n" " const char fileName[] = { \'\\0\' };\n" " return fopen(fileName, \"r\"); \n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("FILE* f(void) {\n" " const char fileName[] = { \'0\' + 42 };\n" // no size is explicitly defined, no implicit '\0' is added " return fopen(fileName, \"r\"); \n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:16]: (error) Invalid fopen() argument nr 1. A nul-terminated string is required. [invalidFunctionArgStr]\n", errout_str()); check("FILE* f(void) {\n" " const char fileName[] = { \'0\' + 42, \'x\' };\n" // no size is explicitly defined, no implicit '\0' is added " return fopen(fileName, \"r\"); \n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:16]: (error) Invalid fopen() argument nr 1. A nul-terminated string is required. [invalidFunctionArgStr]\n", errout_str()); check("FILE* f(void) {\n" " const char fileName[2] = { \'0\' + 42 };\n" // implicitly '\0' added at the end because size is set to 2 " return fopen(fileName, \"r\"); \n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("FILE* f(void) {\n" " const char fileName[] = { };\n" " return fopen(fileName, \"r\"); \n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void scanMetaTypes()\n" // don't crash @@ -724,7 +729,7 @@ class TestFunctions : public TestFixture { " if (strstr(name, \"GammaRay::\") != name)\n" " metaTypes.push_back(mtId);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f() {\n" @@ -759,10 +764,17 @@ class TestFunctions : public TestFixture { "}\n"); ASSERT_EQUALS("", errout_str()); - check("size_t f() { wchar_t x = L'x'; return wcslen(&x); }"); + check("char* f() {\n" // #14715 + " char a[3] = { 'a', 'b', 'c' };\n" + " *a = 0;\n" + " return strdup(a);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("size_t f() { wchar_t x = L'x'; return wcslen(&x); }\n"); ASSERT_EQUALS("[test.cpp:1:46]: (error) Invalid wcslen() argument nr 1. A nul-terminated string is required. [invalidFunctionArgStr]\n", errout_str()); - check("void f() { char a[10] = \"1234567890\"; puts(a); }", dinit(CheckOptions, $.cpp = false)); // #1770 + check("void f() { char a[10] = \"1234567890\"; puts(a); }\n", dinit(CheckOptions, $.cpp = false)); // #1770 ASSERT_EQUALS("[test.c:1:44]: (error) Invalid puts() argument nr 1. A nul-terminated string is required. [invalidFunctionArgStr]\n", errout_str()); } @@ -777,7 +789,7 @@ class TestFunctions : public TestFixture { " memmove(&tgt, &src, sizeof src);\n" " memset(&tgt + sizeof src, ' ', sizeof tgt - sizeof src);\n" " }\n" - "}\n", dinit(CheckOptions, $.cpp = false, $.s = &settingsUnix32)); + "}\n", settingsUnix32, false); ASSERT_EQUALS("", errout_str()); } @@ -788,7 +800,7 @@ class TestFunctions : public TestFixture { " std::cout << sqrt(-1) << std::endl;\n" " std::cout << sqrtf(-1) << std::endl;\n" " std::cout << sqrtl(-1) << std::endl;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:25]: (error) Invalid sqrt() argument nr 1. The value is -1 but the valid values are '0.0:'. [invalidFunctionArg]\n" "[test.cpp:4:26]: (error) Invalid sqrtf() argument nr 1. The value is -1 but the valid values are '0.0:'. [invalidFunctionArg]\n" "[test.cpp:5:26]: (error) Invalid sqrtl() argument nr 1. The value is -1 but the valid values are '0.0:'. [invalidFunctionArg]\n", errout_str()); @@ -799,7 +811,7 @@ class TestFunctions : public TestFixture { " std::cout << sqrt(-0.) << std::endl;\n" " std::cout << sqrtf(-0.) << std::endl;\n" " std::cout << sqrtl(-0.) << std::endl;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" @@ -807,7 +819,7 @@ class TestFunctions : public TestFixture { " std::cout << sqrt(1) << std::endl;\n" " std::cout << sqrtf(1) << std::endl;\n" " std::cout << sqrtl(1) << std::endl;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -827,7 +839,7 @@ class TestFunctions : public TestFixture { " std::cout << log1p(-3) << std::endl;\n" " std::cout << log1pf(-3) << std::endl;\n" " std::cout << log1pl(-3) << std::endl;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:24]: (error) Invalid log() argument nr 1. The value is -2 but the valid values are '4.94066e-324:'. [invalidFunctionArg]\n" "[test.cpp:4:25]: (error) Invalid logf() argument nr 1. The value is -2 but the valid values are '1.4013e-45:'. [invalidFunctionArg]\n" "[test.cpp:5:25]: (error) Invalid logl() argument nr 1. The value is -2 but the valid values are '4.94066e-324:'. [invalidFunctionArg]\n" @@ -864,7 +876,7 @@ class TestFunctions : public TestFixture { " std::cout << log1p(-2) << std::endl;\n" " std::cout << log1pf(-2) << std::endl;\n" " std::cout << log1pl(-2) << std::endl;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:24]: (error) Invalid log() argument nr 1. The value is -1 but the valid values are '4.94066e-324:'. [invalidFunctionArg]\n" "[test.cpp:4:25]: (error) Invalid logf() argument nr 1. The value is -1 but the valid values are '1.4013e-45:'. [invalidFunctionArg]\n" "[test.cpp:5:25]: (error) Invalid logl() argument nr 1. The value is -1 but the valid values are '4.94066e-324:'. [invalidFunctionArg]\n" @@ -901,7 +913,7 @@ class TestFunctions : public TestFixture { " std::cout << log1p(-2.0) << std::endl;\n" " std::cout << log1pf(-2.0) << std::endl;\n" " std::cout << log1pl(-2.0) << std::endl;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:25]: (error) Invalid log() argument nr 1. The value is -1 but the valid values are '4.94066e-324:'. [invalidFunctionArg]\n" "[test.cpp:4:26]: (error) Invalid logf() argument nr 1. The value is -1 but the valid values are '1.4013e-45:'. [invalidFunctionArg]\n" "[test.cpp:5:26]: (error) Invalid logl() argument nr 1. The value is -1 but the valid values are '4.94066e-324:'. [invalidFunctionArg]\n" @@ -938,7 +950,7 @@ class TestFunctions : public TestFixture { " std::cout << log1p(-1.1) << std::endl;\n" " std::cout << log1pf(-1.1) << std::endl;\n" " std::cout << log1pl(-1.1) << std::endl;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:25]: (error) Invalid log() argument nr 1. The value is -0.1 but the valid values are '4.94066e-324:'. [invalidFunctionArg]\n" "[test.cpp:4:26]: (error) Invalid logf() argument nr 1. The value is -0.1 but the valid values are '1.4013e-45:'. [invalidFunctionArg]\n" "[test.cpp:5:26]: (error) Invalid logl() argument nr 1. The value is -0.1 but the valid values are '4.94066e-324:'. [invalidFunctionArg]\n" @@ -975,7 +987,7 @@ class TestFunctions : public TestFixture { " std::cout << log1p(-1.) << std::endl;\n" " std::cout << log1pf(-1.0) << std::endl;\n" " std::cout << log1pl(-1) << std::endl;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:23]: (error) Invalid log() argument nr 1. The value is 0 but the valid values are '4.94066e-324:'. [invalidFunctionArg]\n" "[test.cpp:4:25]: (error) Invalid logf() argument nr 1. The value is 0 but the valid values are '1.4013e-45:'. [invalidFunctionArg]\n" "[test.cpp:5:25]: (error) Invalid logl() argument nr 1. The value is 0 but the valid values are '4.94066e-324:'. [invalidFunctionArg]\n" @@ -1048,21 +1060,21 @@ class TestFunctions : public TestFixture { " std::cout << log1p(2.0) << std::endl;\n" " std::cout << log1pf(2.0) << std::endl;\n" " std::cout << log1pf(2.0f) << std::endl;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" " std::string *log(0);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #3473 - no warning if "log" is a variable - check("Fred::Fred() : log(0) { }"); + check("Fred::Fred() : log(0) { }\n"); ASSERT_EQUALS("", errout_str()); // #5748 - check("void f() { foo.log(0); }"); + check("void f() { foo.log(0); }\n"); ASSERT_EQUALS("", errout_str()); } @@ -1100,7 +1112,7 @@ class TestFunctions : public TestFixture { " + acosl(0.1E-1) \n" " + acosl(+0.1E-1) \n" " + acosl(-0.1E-1);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" @@ -1108,7 +1120,7 @@ class TestFunctions : public TestFixture { " std::cout << acos(1.1) << std::endl;\n" " std::cout << acosf(1.1) << std::endl;\n" " std::cout << acosl(1.1) << std::endl;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:25]: (error) Invalid acos() argument nr 1. The value is 1.1 but the valid values are '-1.0:1.0'. [invalidFunctionArg]\n" "[test.cpp:4:26]: (error) Invalid acosf() argument nr 1. The value is 1.1 but the valid values are '-1.0:1.0'. [invalidFunctionArg]\n" "[test.cpp:5:26]: (error) Invalid acosl() argument nr 1. The value is 1.1 but the valid values are '-1.0:1.0'. [invalidFunctionArg]\n", errout_str()); @@ -1118,7 +1130,7 @@ class TestFunctions : public TestFixture { " std::cout << acos(-1.1) << std::endl;\n" " std::cout << acosf(-1.1) << std::endl;\n" " std::cout << acosl(-1.1) << std::endl;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:26]: (error) Invalid acos() argument nr 1. The value is -1.1 but the valid values are '-1.0:1.0'. [invalidFunctionArg]\n" "[test.cpp:4:27]: (error) Invalid acosf() argument nr 1. The value is -1.1 but the valid values are '-1.0:1.0'. [invalidFunctionArg]\n" "[test.cpp:5:27]: (error) Invalid acosl() argument nr 1. The value is -1.1 but the valid values are '-1.0:1.0'. [invalidFunctionArg]\n", errout_str()); @@ -1161,7 +1173,7 @@ class TestFunctions : public TestFixture { " + asinl(0.1E-1) \n" " + asinl(+0.1E-1) \n" " + asinl(-0.1E-1);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" @@ -1169,7 +1181,7 @@ class TestFunctions : public TestFixture { " std::cout << asin(1.1) << std::endl;\n" " std::cout << asinf(1.1) << std::endl;\n" " std::cout << asinl(1.1) << std::endl;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:25]: (error) Invalid asin() argument nr 1. The value is 1.1 but the valid values are '-1.0:1.0'. [invalidFunctionArg]\n" "[test.cpp:4:26]: (error) Invalid asinf() argument nr 1. The value is 1.1 but the valid values are '-1.0:1.0'. [invalidFunctionArg]\n" "[test.cpp:5:26]: (error) Invalid asinl() argument nr 1. The value is 1.1 but the valid values are '-1.0:1.0'. [invalidFunctionArg]\n", errout_str()); @@ -1179,7 +1191,7 @@ class TestFunctions : public TestFixture { " std::cout << asin(-1.1) << std::endl;\n" " std::cout << asinf(-1.1) << std::endl;\n" " std::cout << asinl(-1.1) << std::endl;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:26]: (error) Invalid asin() argument nr 1. The value is -1.1 but the valid values are '-1.0:1.0'. [invalidFunctionArg]\n" "[test.cpp:4:27]: (error) Invalid asinf() argument nr 1. The value is -1.1 but the valid values are '-1.0:1.0'. [invalidFunctionArg]\n" "[test.cpp:5:27]: (error) Invalid asinl() argument nr 1. The value is -1.1 but the valid values are '-1.0:1.0'. [invalidFunctionArg]\n", errout_str()); @@ -1192,7 +1204,7 @@ class TestFunctions : public TestFixture { " std::cout << pow(0,-10) << std::endl;\n" " std::cout << powf(0,-10) << std::endl;\n" " std::cout << powl(0,-10) << std::endl;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:19]: (warning) Passing values 0 and -10 to pow() leads to implementation-defined result. [wrongmathcall]\n" "[test.cpp:4:19]: (warning) Passing values 0 and -10 to powf() leads to implementation-defined result. [wrongmathcall]\n" "[test.cpp:5:19]: (warning) Passing values 0 and -10 to powl() leads to implementation-defined result. [wrongmathcall]\n", errout_str()); @@ -1202,7 +1214,7 @@ class TestFunctions : public TestFixture { " std::cout << pow(0,10) << std::endl;\n" " std::cout << powf(0,10) << std::endl;\n" " std::cout << powl(0,10) << std::endl;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1243,7 +1255,7 @@ class TestFunctions : public TestFixture { " std::cout << atan2l(0.1E-1,3) ;\n" " std::cout << atan2l(+0.1E-1,1) ;\n" " std::cout << atan2l(-0.1E-1,8) ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" @@ -1251,7 +1263,7 @@ class TestFunctions : public TestFixture { " std::cout << atan2(0,0) << std::endl;\n" " std::cout << atan2f(0,0) << std::endl;\n" " std::cout << atan2l(0,0) << std::endl;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:19]: (warning) Passing values 0 and 0 to atan2() leads to implementation-defined result. [wrongmathcall]\n" "[test.cpp:4:19]: (warning) Passing values 0 and 0 to atan2f() leads to implementation-defined result. [wrongmathcall]\n" "[test.cpp:5:19]: (warning) Passing values 0 and 0 to atan2l() leads to implementation-defined result. [wrongmathcall]\n", errout_str()); @@ -1264,7 +1276,7 @@ class TestFunctions : public TestFixture { " std::cout << fmod(1.0,0) << std::endl;\n" " std::cout << fmodf(1.0,0) << std::endl;\n" " std::cout << fmodl(1.0,0) << std::endl;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:28]: (error) Invalid fmod() argument nr 2. The value is 0 but the valid values are '!0.0'. [invalidFunctionArg]\n" "[test.cpp:4:29]: (error) Invalid fmodf() argument nr 2. The value is 0 but the valid values are '!0.0'. [invalidFunctionArg]\n" "[test.cpp:5:29]: (error) Invalid fmodl() argument nr 2. The value is 0 but the valid values are '!0.0'. [invalidFunctionArg]\n" @@ -1277,7 +1289,7 @@ class TestFunctions : public TestFixture { " std::cout << fmod(1.0,1) << std::endl;\n" " std::cout << fmodf(1.0,1) << std::endl;\n" " std::cout << fmodl(1.0,1) << std::endl;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1286,7 +1298,7 @@ class TestFunctions : public TestFixture { " print(exp(x) - 1);\n" " print(log(1 + x));\n" " print(1 - erf(x));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Expression 'exp(x) - 1' can be replaced by 'expm1(x)' to avoid loss of precision. [unpreciseMathCall]\n" "[test.cpp:3:11]: (style) Expression 'log(1 + x)' can be replaced by 'log1p(x)' to avoid loss of precision. [unpreciseMathCall]\n" "[test.cpp:4:11]: (style) Expression '1 - erf(x)' can be replaced by 'erfc(x)' to avoid loss of precision. [unpreciseMathCall]\n", errout_str()); @@ -1295,7 +1307,7 @@ class TestFunctions : public TestFixture { " print(exp(x) - 1.0);\n" " print(log(1.0 + x));\n" " print(1.0 - erf(x));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Expression 'exp(x) - 1' can be replaced by 'expm1(x)' to avoid loss of precision. [unpreciseMathCall]\n" "[test.cpp:3:11]: (style) Expression 'log(1 + x)' can be replaced by 'log1p(x)' to avoid loss of precision. [unpreciseMathCall]\n" "[test.cpp:4:12]: (style) Expression '1 - erf(x)' can be replaced by 'erfc(x)' to avoid loss of precision. [unpreciseMathCall]\n", errout_str()); @@ -1304,7 +1316,7 @@ class TestFunctions : public TestFixture { " print(exp(3 + x*f(a)) - 1);\n" " print(log(x*4 + 1));\n" " print(1 - erf(34*x + f(x) - c));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Expression 'exp(x) - 1' can be replaced by 'expm1(x)' to avoid loss of precision. [unpreciseMathCall]\n" "[test.cpp:3:11]: (style) Expression 'log(1 + x)' can be replaced by 'log1p(x)' to avoid loss of precision. [unpreciseMathCall]\n" "[test.cpp:4:11]: (style) Expression '1 - erf(x)' can be replaced by 'erfc(x)' to avoid loss of precision. [unpreciseMathCall]\n", errout_str()); @@ -1312,7 +1324,7 @@ class TestFunctions : public TestFixture { check("void foo() {\n" " print(2*exp(x) - 1);\n" " print(1 - erf(x)/2.0);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1329,67 +1341,67 @@ class TestFunctions : public TestFixture { check("void foo() {\n" " mystrcmp(a, b);\n" - "}", dinit(CheckOptions, $.s = &settings2)); + "}\n", settings2); ASSERT_EQUALS("[test.cpp:2:3]: (warning) Return value of function mystrcmp() is not used. [ignoredReturnValue]\n", errout_str()); check("void foo() {\n" " foo::mystrcmp(a, b);\n" - "}", dinit(CheckOptions, $.s = &settings2)); + "}\n", settings2); ASSERT_EQUALS("[test.cpp:2:8]: (warning) Return value of function foo::mystrcmp() is not used. [ignoredReturnValue]\n", errout_str()); check("void f() {\n" " foo x;\n" " x.mystrcmp(a, b);\n" - "}", dinit(CheckOptions, $.s = &settings2)); + "}\n", settings2); ASSERT_EQUALS("[test.cpp:3:5]: (warning) Return value of function x.mystrcmp() is not used. [ignoredReturnValue]\n", errout_str()); check("bool mystrcmp(char* a, char* b);\n" // cppcheck sees a custom strcmp definition, but it returns a value. Assume it is the one specified in the library. "void foo() {\n" " mystrcmp(a, b);\n" - "}", dinit(CheckOptions, $.s = &settings2)); + "}\n", settings2); ASSERT_EQUALS("[test.cpp:3:5]: (warning) Return value of function mystrcmp() is not used. [ignoredReturnValue]\n", errout_str()); check("void mystrcmp(char* a, char* b);\n" // cppcheck sees a custom strcmp definition which returns void! "void foo() {\n" " mystrcmp(a, b);\n" - "}", dinit(CheckOptions, $.s = &settings2)); + "}\n", settings2); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " class mystrcmp { mystrcmp() {} };\n" // strcmp is a constructor definition here - "}", dinit(CheckOptions, $.s = &settings2)); + "}\n", settings2); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " return mystrcmp(a, b);\n" - "}", dinit(CheckOptions, $.s = &settings2)); + "}\n", settings2); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " return foo::mystrcmp(a, b);\n" - "}", dinit(CheckOptions, $.s = &settings2)); + "}\n", settings2); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " if(mystrcmp(a, b));\n" - "}", dinit(CheckOptions, $.s = &settings2)); + "}\n", settings2); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " bool b = mystrcmp(a, b);\n" - "}", dinit(CheckOptions, $.s = &settings2)); + "}\n", settings2); ASSERT_EQUALS("", errout_str()); // #6194 check("void foo() {\n" " MyStrCmp mystrcmp(x, y);\n" - "}", dinit(CheckOptions, $.s = &settings2)); + "}\n", settings2); ASSERT_EQUALS("", errout_str()); // #6197 check("void foo() {\n" " abc::def.mystrcmp(a,b);\n" - "}", dinit(CheckOptions, $.s = &settings2)); + "}\n", settings2); ASSERT_EQUALS("", errout_str()); // #6233 @@ -1400,30 +1412,30 @@ class TestFunctions : public TestFixture { " };\n" " lambda(13.3);\n" " return 0;\n" - "}"); - ASSERT_EQUALS("", errout_str()); + "}\n"); + ASSERT_EQUALS("", errout_str()); // TODO: use settings2? // #6669 check("void foo(size_t size) {\n" " void * res{malloc(size)};\n" - "}"); - ASSERT_EQUALS("", errout_str()); + "}\n"); + ASSERT_EQUALS("", errout_str()); // TODO: use settings2? // #7447 check("void foo() {\n" " int x{mystrcmp(a,b)};\n" - "}", dinit(CheckOptions, $.s = &settings2)); + "}\n", settings2); ASSERT_EQUALS("", errout_str()); // #7905 check("void foo() {\n" " int x({mystrcmp(a,b)});\n" - "}", dinit(CheckOptions, $.s = &settings2)); + "}\n", settings2); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" // don't crash " DEBUG(123)(mystrcmp(a,b))(fd);\n" - "}", dinit(CheckOptions, $.s = &settings2)); + "}\n", settings2); check("struct teststruct {\n" " int testfunc1() __attribute__ ((warn_unused_result)) { return 1; }\n" " [[nodiscard]] int testfunc2() { return 1; }\n" @@ -1434,7 +1446,7 @@ class TestFunctions : public TestFixture { " TestStruct1.testfunc1();\n" " TestStruct1.testfunc2();\n" " return 0;\n" - "}", dinit(CheckOptions, $.s = &settings2)); + "}\n", settings2); ASSERT_EQUALS("[test.cpp:4:18]: (warning) Return value of function testfunc1() is not used. [ignoredReturnValue]\n" "[test.cpp:4:31]: (warning) Return value of function testfunc2() is not used. [ignoredReturnValue]\n" "[test.cpp:8:17]: (warning) Return value of function TestStruct1.testfunc1() is not used. [ignoredReturnValue]\n" @@ -1444,34 +1456,34 @@ class TestFunctions : public TestFixture { check("template uint8_t b(std::tuple d) {\n" " std::tuple c{std::move(d)};\n" " return std::get<0>(c);\n" - "}"); - ASSERT_EQUALS("", errout_str()); + "}\n"); + ASSERT_EQUALS("", errout_str()); // TODO: use settings2? check("struct A { int x; };\n" "template \n" "A f(int x, Ts... xs) {\n" " return {std::move(x), static_cast(xs)...};\n" "}\n" - "A g() { return f(1); }"); - ASSERT_EQUALS("", errout_str()); + "A g() { return f(1); }\n"); + ASSERT_EQUALS("", errout_str()); // TODO: use settings2? // #8412 - unused operator result check("void foo() {\n" " !mystrcmp(a, b);\n" - "}", dinit(CheckOptions, $.s = &settings2)); + "}\n", settings2); ASSERT_EQUALS("[test.cpp:2:4]: (warning) Return value of function mystrcmp() is not used. [ignoredReturnValue]\n", errout_str()); check("void f(std::vector v) {\n" " delete *v.begin();\n" "}\n"); - ASSERT_EQUALS("", errout_str()); + ASSERT_EQUALS("", errout_str()); // TODO: use settings2? check("int __attribute__((pure)) p_foo(int);\n" // #12697 "int __attribute__((const)) c_foo(int);\n" "void f() {\n" " p_foo(0);\n" " c_foo(0);\n" - "}\n"); + "}\n"); // TODO: use settings2? ASSERT_EQUALS("[test.cpp:4:5]: (warning) Return value of function p_foo() is not used. [ignoredReturnValue]\n" "[test.cpp:5:5]: (warning) Return value of function c_foo() is not used. [ignoredReturnValue]\n", errout_str()); @@ -1490,24 +1502,24 @@ class TestFunctions : public TestFixture { check("void foo() {\n" " mystrcmp(a, b);\n" - "}", dinit(CheckOptions, $.s = &settings2)); + "}\n", settings2); ASSERT_EQUALS("[test.cpp:2:3]: (style) Error code from the return value of function mystrcmp() is not used. [ignoredReturnErrorCode]\n", errout_str()); } void memsetZeroBytes() { check("void f() {\n" " memset(p, 10, 0x0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (warning) memset() called to fill 0 bytes. [memsetZeroBytes]\n", errout_str()); check("void f() {\n" " memset(p, sizeof(p), 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (warning) memset() called to fill 0 bytes. [memsetZeroBytes]\n", errout_str()); check("void f() {\n" " memset(p, sizeof(p), i);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #6269 false positives in case of overloaded standard library functions @@ -1516,13 +1528,13 @@ class TestFunctions : public TestFixture { " void f( void ) {\n" " memset( 0 );\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // #7285 check("void f() {\n" " memset(&tm, sizeof(tm), 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (warning) memset() called to fill 0 bytes. [memsetZeroBytes]\n", errout_str()); } @@ -1533,7 +1545,7 @@ class TestFunctions : public TestFixture { " memset(is, 1.0f, 40);\n" " int* is2 = new int[10];\n" " memset(is2, 0.1f, 40);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:17]: (portability) The 2nd memset() argument '1.0f' is a float, its representation is implementation defined. [memsetFloat]\n" "[test.cpp:5:18]: (portability) The 2nd memset() argument '0.1f' is a float, its representation is implementation defined. [memsetFloat]\n", errout_str()); @@ -1541,19 +1553,19 @@ class TestFunctions : public TestFixture { " int* is = new int[10];\n" " float g = computeG();\n" " memset(is, g, 40);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:16]: (portability) The 2nd memset() argument 'g' is a float, its representation is implementation defined. [memsetFloat]\n", errout_str()); check("void f() {\n" " int* is = new int[10];\n" " memset(is, 0.0f, 40);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" // FP " float x = 2.3f;\n" " memset(a, (x?64:0), 40);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -1561,7 +1573,7 @@ class TestFunctions : public TestFixture { " memset(ss, 256, 4);\n" " short ss2[2];\n" " memset(ss2, -129, 4);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:16]: (warning) The 2nd memset() argument '256' doesn't fit into an 'unsigned char'. [memsetValueOutOfRange]\n" "[test.cpp:5:18]: (warning) The 2nd memset() argument '-129' doesn't fit into an 'unsigned char'. [memsetValueOutOfRange]\n", errout_str()); @@ -1576,50 +1588,50 @@ class TestFunctions : public TestFixture { " memset(cs2, 255, 30);\n" " char cs3[30];\n" " memset(cs3, 0, 30);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " int is[10];\n" " const int i = g();\n" " memset(is, 1.0f + i, 40);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:21]: (portability) The 2nd memset() argument '1.0f+i' is a float, its representation is implementation defined. [memsetFloat]\n", errout_str()); } void checkMissingReturn1() { - check("int f() {}"); + check("int f() {}\n"); ASSERT_EQUALS("[test.cpp:1:10]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); { - const char code[] = "int main(void) {}"; + const char code[] = "int main(void) {}\n"; { const Settings s = settingsBuilder().c(Standards::C89).build(); - check(code, dinit(CheckOptions, $.cpp = false, $.s = &s)); // c code (c89) + check(code, s, false); // c code (c89) ASSERT_EQUALS("[test.c:1:17]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); } { const Settings s = settingsBuilder().c(Standards::C99).build(); - check(code, dinit(CheckOptions, $.cpp = false, $.s = &s)); // c code (c99) + check(code, s, false); // c code (c99) ASSERT_EQUALS("", errout_str()); - check(code, dinit(CheckOptions, $.s = &s)); // c++ code + check(code, s); // c++ code ASSERT_EQUALS("", errout_str()); } } - check("F(A,B) { x=1; }"); + check("F(A,B) { x=1; }\n"); ASSERT_EQUALS("", errout_str()); - check("auto foo4() -> void {}"); + check("auto foo4() -> void {}\n"); ASSERT_EQUALS("", errout_str()); - check("void STDCALL foo() {}"); + check("void STDCALL foo() {}\n"); ASSERT_EQUALS("", errout_str()); - check("void operator=(int y) { x=y; }"); + check("void operator=(int y) { x=y; }\n"); ASSERT_EQUALS("", errout_str()); check("int f() {\n" @@ -1635,14 +1647,14 @@ class TestFunctions : public TestFixture { check("int foo(int x) {\n" " return 1;\n" " (void)x;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int foo(int x) {\n" " if (x) goto out;\n" " return 1;\n" "out:\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); // switch @@ -1651,7 +1663,7 @@ class TestFunctions : public TestFixture { " case 1: break;\n" // <- error " case 2: return 1;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:17]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); check("int f() {\n" @@ -1659,7 +1671,7 @@ class TestFunctions : public TestFixture { " case 1: return 2; break;\n" " default: return 1;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("bool test(unsigned char v1, int v2) {\n" @@ -1673,7 +1685,7 @@ class TestFunctions : public TestFixture { " default:\n" " return true;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // if/else @@ -1681,7 +1693,7 @@ class TestFunctions : public TestFixture { " if (x) {\n" " return 1;\n" " }\n" // <- error (missing else) - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:5]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); check("int f(int x) {\n" @@ -1690,19 +1702,19 @@ class TestFunctions : public TestFixture { " } else {\n" " return 1;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); check("int f() {\n" " if (!0) {\n" " return 1;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f() {\n" " if (!0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:14]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); // loop @@ -1710,7 +1722,7 @@ class TestFunctions : public TestFixture { " while (1) {\n" " dostuff();\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // return {..} @@ -1719,20 +1731,20 @@ class TestFunctions : public TestFixture { " return {};\n" " else\n" " return {1, 2};\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // noreturn function - check("int f(int x) { exit(0); }"); + check("int f(int x) { exit(0); }\n"); ASSERT_EQUALS("", errout_str()); - check("int f(int x) { assert(0); }"); + check("int f(int x) { assert(0); }\n"); ASSERT_EQUALS("", errout_str()); - check("int f(int x) { if (x) return 1; else return bar({1}, {}); }"); + check("int f(int x) { if (x) return 1; else return bar({1}, {}); }\n"); ASSERT_EQUALS("", errout_str()); - check("auto f() -> void {}"); // #10342 + check("auto f() -> void {}\n"); // #10342 ASSERT_EQUALS("", errout_str()); check("struct S1 {\n" // #7433 @@ -1752,36 +1764,36 @@ class TestFunctions : public TestFixture { errout_str()); // #11171 - check("std::enable_if_t f() {}"); + check("std::enable_if_t f() {}\n"); ASSERT_EQUALS("", errout_str()); - check("std::enable_if_t f() {}"); + check("std::enable_if_t f() {}\n"); ASSERT_EQUALS( "[test.cpp:1:51]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); - check("template std::enable_if_t{}, int> f(T) {}"); + check("template std::enable_if_t{}, int> f(T) {}\n"); ASSERT_EQUALS( "[test.cpp:1:71]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); - check("template std::enable_if_t{}> f(T) {}"); + check("template std::enable_if_t{}> f(T) {}\n"); ASSERT_EQUALS("", errout_str()); - check("typename std::enable_if::type f() {}"); + check("typename std::enable_if::type f() {}\n"); ASSERT_EQUALS("", errout_str()); - check("typename std::enable_if::type f() {}"); + check("typename std::enable_if::type f() {}\n"); ASSERT_EQUALS( "[test.cpp:1:64]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); - check("template typename std::enable_if{}, int>::type f(T) {}"); + check("template typename std::enable_if{}, int>::type f(T) {}\n"); ASSERT_EQUALS( "[test.cpp:1:84]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); - check("template typename std::enable_if{}>::type f(T) {}"); + check("template typename std::enable_if{}>::type f(T) {}\n"); ASSERT_EQUALS("", errout_str()); check("struct S {\n" @@ -1880,37 +1892,97 @@ class TestFunctions : public TestFixture { ASSERT_EQUALS("[test.cpp:3:5]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); } + void checkMissingReturn7() {// #14370 FN try/catch + check("int foo(void) {\n" + " try { return readData(); }\n" + " catch (...) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:18]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); + + check("int foo(void) {\n" + " try { return readData(); }\n" + " catch (const E& e) {}\n" + " catch (...) { return 2; }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:25]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); + + check("int foo(void) {\n" + " try { x=1; }\n" + " catch (...) { return 2; }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:11]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); + + check("int foo(void) {\n" + " try { return readData(); }\n" + " catch (...) { return 0; }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("int foo(void)\n" + " try { x=1; }\n" + " catch (...) { return 2; }\n"); + ASSERT_EQUALS("[test.cpp:2:11]: (error) Found an exit path from function with non-void return type that has missing return statement [missingReturn]\n", errout_str()); + + check("int foo(void)\n" + " try { return readData(); }\n" + " catch (...) { }\n"); + 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 checkMissingReturn9() { + check("struct S { int v; };\n" + " S operator/(S x, S y) { return { x.v / y.v }; }\n" + " S f(int a, int b) {\n" + " if (b) { return S{ a } / S{ b }; }\n" + " else { return {}; }\n" + "}\n"); + 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()); + } + // NRVO check void returnLocalStdMove1() { - check("struct A{}; A f() { A var; return std::move(var); }"); + check("struct A{}; A f() { A var; return std::move(var); }\n"); ASSERT_EQUALS("[test.cpp:1:45]: (performance) Using std::move for returning object by-value from function will affect copy elision optimization." " More: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-return-move-local [returnStdMoveLocal]\n", errout_str()); } // RVO, C++03 ctor style void returnLocalStdMove2() { - check("struct A{}; A f() { return std::move( A() ); }"); + check("struct A{}; A f() { return std::move( A() ); }\n"); ASSERT_EQUALS("[test.cpp:1:40]: (performance) Using std::move for returning object by-value from function will affect copy elision optimization." " More: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-return-move-local [returnStdMoveLocal]\n", errout_str()); } // RVO, new ctor style void returnLocalStdMove3() { - check("struct A{}; A f() { return std::move(A{}); }"); + check("struct A{}; A f() { return std::move(A{}); }\n"); ASSERT_EQUALS("[test.cpp:1:39]: (performance) Using std::move for returning object by-value from function will affect copy elision optimization." " More: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-return-move-local [returnStdMoveLocal]\n", errout_str()); } // Function argument void returnLocalStdMove4() { - check("struct A{}; A f(A a) { return std::move(A{}); }"); + check("struct A{}; A f(A a) { return std::move(A{}); }\n"); ASSERT_EQUALS("[test.cpp:1:42]: (performance) Using std::move for returning object by-value from function will affect copy elision optimization." " More: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-return-move-local [returnStdMoveLocal]\n", errout_str()); } void returnLocalStdMove5() { check("struct A{} a; A f1() { return std::move(a); }\n" - "A f2() { volatile A var; return std::move(var); }"); + "A f2() { volatile A var; return std::move(var); }\n"); ASSERT_EQUALS("", errout_str()); check("struct S { std::string msg{ \"abc\" }; };\n" @@ -1937,14 +2009,14 @@ class TestFunctions : public TestFixture { " int *a;\n" " a = malloc( -10 );\n" " free(a);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:17]: (error) Invalid malloc() argument nr 1. The value is -10 but the valid values are '0:'. [invalidFunctionArg]\n", errout_str()); check("void f() {\n" " int *a;\n" " a = alloca( -10 );\n" " free(a);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8]: (warning) Obsolete function 'alloca' called. [allocaCalled]\n" "[test.cpp:3:17]: (error) Invalid alloca() argument nr 1. The value is -10 but the valid values are '0:'. [invalidFunctionArg]\n", errout_str()); } @@ -1955,12 +2027,12 @@ class TestFunctions : public TestFixture { check("void f() {\n" " lib_func();" - "}", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("[test.cpp:2:5]: (information) --check-library: There is no matching configuration for function lib_func() [checkLibraryFunction]\n", errout_str()); check("void f(void* v) {\n" " lib_func(v);" - "}", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("[test.cpp:2:5]: (information) --check-library: There is no matching configuration for function lib_func() [checkLibraryFunction]\n", errout_str()); // #10105 @@ -1976,7 +2048,7 @@ class TestFunctions : public TestFixture { "\n" " void testFunctionReturnType() {\n" " }\n" - "};", dinit(CheckOptions, $.s = &s)); + "};\n", s); ASSERT_EQUALS("", errout_str()); // #11183 @@ -1986,7 +2058,7 @@ class TestFunctions : public TestFixture { "\n" "void f() {\n" " cb(std::string(\"\"));\n" - "}", dinit(CheckOptions, $.s = &s)); + "}\n", s); TODO_ASSERT_EQUALS("", "[test.cpp:6:5]: (information) --check-library: There is no matching configuration for function cb() [checkLibraryFunction]\n", errout_str()); // #7375 @@ -1994,38 +2066,38 @@ class TestFunctions : public TestFixture { " struct S { int i; char c; };\n" " size_t s = sizeof(S);\n" " static_assert(s == 9);\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("", errout_str()); check("void f(char) {}\n" "void g() {\n" " f(int8_t(1));\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("", errout_str()); check("void f(std::uint64_t& u) {\n" " u = std::uint32_t(u) * std::uint64_t(100);\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("", errout_str()); - check("void f() { throw(1); }\n", dinit(CheckOptions, $.s = &s)); // #8958 + check("void f() { throw(1); }\n", s); // #8958 ASSERT_EQUALS("", errout_str()); check("using namespace std;\n" - "void f() { throw range_error(\"abc\"); }\n", dinit(CheckOptions, $.s = &s)); + "void f() { throw range_error(\"abc\"); }\n", s); ASSERT_EQUALS("", errout_str()); check("class C {\n" // #9002 "public:\n" " static int f() { return 1; }\n" "};\n" - "void g() { C::f(); }\n", dinit(CheckOptions, $.s = &s)); + "void g() { C::f(); }\n", s); ASSERT_EQUALS("", errout_str()); check("void f(const std::vector& v) {\n" // #11223 " for (const auto& s : v)\n" " s.find(\"\");\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("[test.cpp:3:11]: (warning) Return value of function s.find() is not used. [ignoredReturnValue]\n", errout_str()); check("void f() {\n" @@ -2035,19 +2107,19 @@ class TestFunctions : public TestFixture { " q->push_back(1);\n" " auto* r = new std::vector;\n" " r->push_back(1);\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " auto p = std::make_shared>();\n" " p->push_back(1);\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("", errout_str()); check("void f(std::vector>& v) {\n" " auto it = v.begin();\n" " it->push_back(1);\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -2057,7 +2129,7 @@ class TestFunctions : public TestFixture { " w.push_back(1);\n" " auto x = std::vector(1);\n" " x.push_back(1);\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -2065,7 +2137,7 @@ class TestFunctions : public TestFixture { " p->push_back(1);\n" " auto q{ std::make_shared>{} };\n" " q->push_back(1);\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); TODO_ASSERT_EQUALS("", "[test.cpp:2:5]: (debug) auto token with no type. [autoNoType]\n" "[test.cpp:4:5]: (debug) auto token with no type. [autoNoType]\n" @@ -2078,12 +2150,12 @@ class TestFunctions : public TestFixture { " std::list::iterator it;\n" " for (it = l.begin(); it != l.end(); ++it)\n" " it->g(0);\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("", filter_valueflow(errout_str())); check("auto f() {\n" " return std::runtime_error(\"abc\");\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); TODO_ASSERT_EQUALS("", "[test.cpp:1:1]: (debug) auto token with no type. [autoNoType]\n", errout_str()); @@ -2096,7 +2168,7 @@ class TestFunctions : public TestFixture { "void S::f(int i) const {\n" " for (const std::shared_ptr& c : v)\n" " c->f(i);\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("", errout_str()); check("namespace N {\n" @@ -2105,29 +2177,29 @@ class TestFunctions : public TestFixture { "void f() {\n" " const auto& t = N::S::s;\n" " if (t.find(\"abc\") != t.end()) {}\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("", filter_valueflow(errout_str())); check("void f(std::vector>>& v, int i, int j) {\n" " auto& s = v[i][j];\n" " s.insert(0);\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("", errout_str()); check("int f(const std::vector& v, int i, char c) {\n" " const auto& s = v[i];\n" " return s.find(c);\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("", errout_str()); check("void f() {\n" // #11604 " int (*g)() = nullptr;\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " INT (*g)() = nullptr;\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("", errout_str()); check("struct T;\n" @@ -2136,13 +2208,13 @@ class TestFunctions : public TestFixture { " auto p = get();\n" " p->h(i);\n" " p.reset(nullptr);\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("[test.cpp:5:8]: (information) --check-library: There is no matching configuration for function T::h() [checkLibraryFunction]\n", errout_str()); check("struct S : std::vector {\n" " void f(int i) { push_back(i); }\n" - "};\n", dinit(CheckOptions, $.s = &s)); + "};\n", s); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -2152,18 +2224,18 @@ class TestFunctions : public TestFixture { " auto h{ []() -> std::string { return \"xyz\"; } };\n" " auto t = h();\n" " if (t.at(0)) {}\n" - "};\n", dinit(CheckOptions, $.s = &s)); + "};\n", s); ASSERT_EQUALS("", filter_valueflow(errout_str())); check("::std::string f(const char* c) {\n" // #12365 " return ::std::string(c);\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); ASSERT_EQUALS("", errout_str()); check("template \n" "struct S : public std::vector {\n" " void resize(size_t n) { std::vector::resize(n); }\n" - "};\n", dinit(CheckOptions, $.s = &s)); + "};\n", s); ASSERT_EQUALS("", errout_str()); check("struct P {\n" // #13105 @@ -2174,8 +2246,14 @@ class TestFunctions : public TestFixture { " auto it = m->find(i);\n" " const bool b = it != m->end();\n" " return b;\n" - "}\n", dinit(CheckOptions, $.s = &s)); + "}\n", s); TODO_ASSERT_EQUALS("", "[test.cpp:6:5]: (debug) auto token with no type. [autoNoType]\n", errout_str()); + + check("template \n" // #13509 + "void f(const T& t) {\n" + " t.g();\n" + "}\n", s); + ASSERT_EQUALS("", errout_str()); } void checkUseStandardLibrary1() { diff --git a/test/testgarbage.cpp b/test/testgarbage.cpp index b2632e13500..c798950b8e3 100644 --- a/test/testgarbage.cpp +++ b/test/testgarbage.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,6 +17,7 @@ */ #include "check.h" +#include "checks.h" #include "errortypes.h" #include "fixture.h" #include "helpers.h" @@ -257,6 +258,9 @@ class TestGarbage : public TestFixture { TEST_CASE(garbageCode226); TEST_CASE(garbageCode227); TEST_CASE(garbageCode228); + TEST_CASE(garbageCode229); + TEST_CASE(garbageCode230); + TEST_CASE(garbageCode231); TEST_CASE(garbageCodeFuzzerClientMode1); // test cases created with the fuzzer client, mode 1 @@ -275,18 +279,6 @@ class TestGarbage : public TestFixture { } #define checkCodeInternal(...) checkCodeInternal_(__FILE__, __LINE__, __VA_ARGS__) - template - std::string checkCode(const char (&code)[size], bool cpp = true) { - // double the tests - run each example as C as well as C++ - - // run alternate check first. It should only ensure stability - so we catch exceptions here. - try { - (void)checkCodeInternal(code, !cpp); - } catch (const InternalError&) {} - - return checkCodeInternal(code, cpp); - } - template std::string checkCodeInternal_(const char* file, int line, const char (&code)[size], bool cpp) { // tokenize.. @@ -294,13 +286,25 @@ 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); } + template + std::string checkCode(const char (&code)[size], bool cpp = true) { + // double the tests - run each example as C as well as C++ + + // run alternate check first. It should only ensure stability - so we catch exceptions here. + try { + (void)checkCodeInternal(code, !cpp); + } catch (const InternalError&) {} + + return checkCodeInternal(code, cpp); + } + #define getSyntaxError(...) getSyntaxError_(__FILE__, __LINE__, __VA_ARGS__) template std::string getSyntaxError_(const char* file, int line, const char (&code)[size]) { @@ -317,8 +321,7 @@ class TestGarbage : public TestFixture { void final_class_x() { - - const char code[] = "class __declspec(dllexport) x final { };"; + const char code[] = "class __declspec(dllexport) x final { };\n"; SimpleTokenizer tokenizer(settings, *this); ASSERT(tokenizer.tokenize(code)); ASSERT_EQUALS("", errout_str()); @@ -326,18 +329,18 @@ class TestGarbage : public TestFixture { void wrong_syntax1() { { - const char code[] ="TR(kvmpio, PROTO(int rw), ARGS(rw), TP_(aa->rw;))"; + const char code[] ="TR(kvmpio, PROTO(int rw), ARGS(rw), TP_(aa->rw;))\n"; ASSERT_THROW_INTERNAL(checkCode(code), UNKNOWN_MACRO); ASSERT_EQUALS("", errout_str()); } { - const char code[] ="struct A { template struct { }; };"; + const char code[] ="struct A { template struct { }; };\n"; ASSERT_THROW_INTERNAL(checkCode(code), SYNTAX); } { - const char code[] ="enum ABC { A,B, typedef enum { C } };"; + const char code[] ="enum ABC { A,B, typedef enum { C } };\n"; ASSERT_THROW_INTERNAL(checkCode(code), SYNTAX); } } @@ -348,7 +351,7 @@ class TestGarbage : public TestFixture { " Y y;\n" "}\n" "\n" - "void G( template class (j) ) {}"; + "void G( template class (j) ) {}\n"; // don't segfault.. ASSERT_THROW_INTERNAL(checkCode(code), SYNTAX); @@ -363,7 +366,7 @@ class TestGarbage : public TestFixture { " for( #endif typedef typedef cb[N] )\n" " ca[N]; = cb[i]\n" " )\n" - "}"; + "}\n"; SimpleTokenizer tokenizer(settings, *this); try { @@ -377,25 +380,25 @@ class TestGarbage : public TestFixture { } void wrong_syntax4() { // #3618 - const char code[] = "typedef void (x) (int); return x&"; + const char code[] = "typedef void (x) (int); return x&\n"; ASSERT_THROW_INTERNAL(checkCode(code), SYNTAX); } void wrong_syntax_if_macro() { // #2518 #4171 - ASSERT_THROW_INTERNAL(checkCode("void f() { if MACRO(); }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void f() { if MACRO(); }\n"), SYNTAX); // #4668 - note there is no semicolon after MACRO() - ASSERT_THROW_INTERNAL(checkCode("void f() { if (x) MACRO() {} }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void f() { if (x) MACRO() {} }\n"), SYNTAX); // #4810 - note there is no semicolon after MACRO() - ASSERT_THROW_INTERNAL(checkCode("void f() { if (x) MACRO() else ; }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void f() { if (x) MACRO() else ; }\n"), SYNTAX); } void wrong_syntax_class_x_y() { // #3585 - const char code[] = "class x y { };"; + const char code[] = "class x y { };\n"; { SimpleTokenizer tokenizer(settings, *this, false); @@ -410,65 +413,65 @@ class TestGarbage : public TestFixture { } void wrong_syntax_anonymous_struct() { - ASSERT_THROW_INTERNAL(checkCode("struct { int x; } = {0};"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("struct { int x; } * = {0};"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("struct { int x; } = {0};\n"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("struct { int x; } * = {0};\n"), SYNTAX); } void syntax_case_default() { - ASSERT_THROW_INTERNAL(checkCode("void f() {switch (n) { case: z(); break;}}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void f() {switch (n) { case: z(); break;}}\n"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("void f() {switch (n) { case;: z(); break;}}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void f() {switch (n) { case;: z(); break;}}\n"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("void f() {switch (n) { case {}: z(); break;}}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void f() {switch (n) { case {}: z(); break;}}\n"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("void f() {switch (n) { case 0?{1}:{2} : z(); break;}}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void f() {switch (n) { case 0?{1}:{2} : z(); break;}}\n"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("void f() {switch (n) { case 0?1;:{2} : z(); break;}}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void f() {switch (n) { case 0?1;:{2} : z(); break;}}\n"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("void f() {switch (n) { case 0?(1?{3:4}):2 : z(); break;}}"), AST); + ASSERT_THROW_INTERNAL(checkCode("void f() {switch (n) { case 0?(1?{3:4}):2 : z(); break;}}\n"), AST); //ticket #4234 - ASSERT_THROW_INTERNAL(checkCode("( ) { switch break ; { switch ( x ) { case } y break ; : } }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("( ) { switch break ; { switch ( x ) { case } y break ; : } }\n"), SYNTAX); //ticket #4267 - ASSERT_THROW_INTERNAL(checkCode("f ( ) { switch break; { switch ( x ) { case } case break; -6: ( ) ; } }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("f ( ) { switch break; { switch ( x ) { case } case break; -6: ( ) ; } }\n"), SYNTAX); // Missing semicolon - ASSERT_THROW_INTERNAL(checkCode("void foo () { switch(0) case 0 : default : }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void foo () { switch(0) case 0 : default : }\n"), SYNTAX); } void garbageCode1() { - (void)checkCode("struct x foo_t; foo_t typedef y;"); + (void)checkCode("struct x foo_t; foo_t typedef y;\n"); } void garbageCode2() { //#4300 (segmentation fault) - TODO_ASSERT_THROW(checkCode("enum { D = 1 struct { } ; } s.b = D;"), InternalError); + TODO_ASSERT_THROW(checkCode("enum { D = 1 struct { } ; } s.b = D;\n"), InternalError); } void garbageCode3() { //#4849 (segmentation fault in Tokenizer::simplifyStructDecl (invalid code)) - TODO_ASSERT_THROW(checkCode("enum { D = 2 s ; struct y { x } ; } { s.a = C ; s.b = D ; }"), InternalError); + TODO_ASSERT_THROW(checkCode("enum { D = 2 s ; struct y { x } ; } { s.a = C ; s.b = D ; }\n"), InternalError); } void garbageCode4() { // #4887 - ASSERT_THROW_INTERNAL(checkCode("void f ( ) { = a ; if ( 1 ) if = ( 0 ) ; }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void f ( ) { = a ; if ( 1 ) if = ( 0 ) ; }\n"), SYNTAX); } void garbageCode5() { // #5168 (segmentation fault) - ASSERT_THROW_INTERNAL(checkCode("( asm : ; void : );"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("( asm : ; void : );\n"), SYNTAX); } void garbageCode6() { // #5214 - ASSERT_THROW_INTERNAL(checkCode("int b = ( 0 ? ? ) 1 : 0 ;"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("int a = int b = ( 0 ? ? ) 1 : 0 ;"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("int b = ( 0 ? ? ) 1 : 0 ;\n"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("int a = int b = ( 0 ? ? ) 1 : 0 ;\n"), SYNTAX); } void garbageCode7() { - ASSERT_THROW_INTERNAL(checkCode("1 (int j) { return return (c) * sizeof } y[1];"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("foo(Args&&...) fn void = { } auto template { { e = T::error }; };\n" "ScopedEnum1 se1; { enum class E : T { e = 0 = e ScopedEnum2 struct UnscopedEnum3 { T{ e = 4 }; };\n" "arr[(int) E::e]; }; UnscopedEnum3 e2 = f()\n" @@ -476,48 +479,48 @@ class TestGarbage : public TestFixture { "namespace UnscopedEnum { template struct UnscopedEnum1 { E{ e = T::error }; }; UnscopedEnum1 { enum E : { e = 0 }; };\n" "UnscopedEnum2 ue3; template struct UnscopedEnum3 { enum { }; }; int arr[E::e]; };\n" "UnscopedEnum3 namespace template int f() { enum E { e }; T::error }; return (int) E(); } int test1 int g() { enum E { e = E };\n" - "E::e; } int test2 = g(); }"), InternalError); + "E::e; } int test2 = g(); }\n"), InternalError); } void garbageCode9() { - TODO_ASSERT_THROW(checkCode("enum { e = { } } ( ) { { enum { } } } { e } "), InternalError); + TODO_ASSERT_THROW(checkCode("enum { e = { } } ( ) { { enum { } } } { e } \n"), InternalError); } void garbageCode10() { // #6127 - ASSERT_THROW_INTERNAL(checkCode("for( rl=reslist; rl!=NULL; rl=rl->next )"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("for( rl=reslist; rl!=NULL; rl=rl->next )\n"), SYNTAX); } void garbageCode12() { // do not crash - (void)checkCode("{ g; S (void) { struct } { } int &g; }"); + (void)checkCode("{ g; S (void) { struct } { } int &g; }\n"); ignore_errout(); // we do not care about the output } void garbageCode13() { // Ticket #2607 - crash - (void)checkCode("struct C {} {} x"); + (void)checkCode("struct C {} {} x\n"); } void garbageCode15() { // Ticket #5203 - ASSERT_THROW_INTERNAL(checkCode("int f ( int* r ) { { int s[2] ; f ( s ) ; if ( ) } }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("int f ( int* r ) { { int s[2] ; f ( s ) ; if ( ) } }\n"), SYNTAX); } void garbageCode16() { // #6080 (segmentation fault) - (void)checkCode("{ } A() { delete }"); // #6080 + (void)checkCode("{ } A() { delete }\n"); // #6080 ignore_errout(); // we do not care about the output } void garbageCode17() { ASSERT_THROW_INTERNAL(checkCode("void h(int l) {\n" " while\n" // Don't crash (#3870) - "}"), SYNTAX); + "}\n"), SYNTAX); } void garbageCode18() { - ASSERT_THROW_INTERNAL(checkCode("switch(){case}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("switch(){case}\n"), SYNTAX); } void garbageCode20() { // #3953 (valgrind errors on garbage code) - ASSERT_EQUALS("void f ( 0 * ) ;", checkCode("void f ( 0 * ) ;")); + ASSERT_EQUALS("void f ( 0 * ) ;", checkCode("void f ( 0 * ) ;\n")); } void garbageCode21() { @@ -528,7 +531,7 @@ class TestGarbage : public TestFixture { " x;\n" " int a, a2, a2*x; if () ;\n" " )\n" - "}"), SYNTAX); + "}\n"), SYNTAX); } void garbageCode22() { @@ -536,7 +539,7 @@ class TestGarbage : public TestFixture { ASSERT_THROW_INTERNAL(checkCode("int f()\n" "{\n" " return if\n" - "}"), SYNTAX); + "}\n"), SYNTAX); } void garbageCode23() { @@ -544,7 +547,7 @@ class TestGarbage : public TestFixture { ASSERT_THROW_INTERNAL_EQUALS(checkCode("{\n" " if (1) = x\n" " else abort s[2]\n" - "}"), + "}\n"), SYNTAX, "syntax error"); } @@ -567,7 +570,7 @@ class TestGarbage : public TestFixture { " switch ( x ) {\n" " case struct Tree : break;\n" " }\n" - "}"), SYNTAX); + "}\n"), SYNTAX); ignore_errout(); // we do not care about the output } @@ -579,13 +582,13 @@ class TestGarbage : public TestFixture { " case 0:\n" " return;\n" " }\n" - "}"), SYNTAX); + "}\n"), SYNTAX); } void garbageCode27() { ASSERT_THROW_INTERNAL(checkCode("int f() {\n" " return if\n" - "}"), SYNTAX); + "}\n"), SYNTAX); } void garbageCode28() { // #5702 (segmentation fault) @@ -593,7 +596,7 @@ class TestGarbage : public TestFixture { (void)checkCode("struct R1 {\n" " int a;\n" " R1 () : a { }\n" - "};"); + "};\n"); ignore_errout(); // we do not care about the output } @@ -601,16 +604,16 @@ class TestGarbage : public TestFixture { // simply survive - a syntax error would be even better (#5867) (void)checkCode("void f(int x) {\n" " x = 42\n" - "}"); + "}\n"); ignore_errout(); // we do not care about the output } void garbageCode31() { - ASSERT_THROW_INTERNAL(checkCode("typedef struct{}x[([],)]typedef e y;(y,x 0){}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("typedef struct{}x[([],)]typedef e y;(y,x 0){}\n"), SYNTAX); } void garbageCode33() { // #6613 (segmentation fault) - (void)checkCode("main(()B{});"); + (void)checkCode("main(()B{});\n"); } // Bug #6626 crash: Token::astOperand2() const ( do while ) @@ -618,13 +621,13 @@ class TestGarbage : public TestFixture { const char code[] = "void foo(void) {\n" " do\n" " while (0);\n" - "}"; + "}\n"; ASSERT_THROW_INTERNAL(checkCode(code), SYNTAX); } void garbageCode35() { // ticket #2604 segmentation fault - ASSERT_THROW_INTERNAL(checkCode("sizeof <= A"), AST); + ASSERT_THROW_INTERNAL(checkCode("sizeof <= A\n"), AST); } void garbageCode36() { // #6334 @@ -638,312 +641,311 @@ class TestGarbage : public TestFixture { void garbageCode37() { // #5166 segmentation fault (invalid code) in lib/checkother.cpp:329 ( void * f { } void b ( ) { * f } ) - (void)checkCode("void * f { } void b ( ) { * f }"); + (void)checkCode("void * f { } void b ( ) { * f }\n"); ignore_errout(); // we do not care about the output } void garbageCode38() { // Ticket #6666 (segmentation fault) - (void)checkCode("{ f2 { } } void f3 () { delete[] } { }"); + (void)checkCode("{ f2 { } } void f3 () { delete[] } { }\n"); ignore_errout(); // we do not care about the output } void garbageCode40() { // #6620 (segmentation fault) - (void)checkCode("{ ( ) () { virtual } ; { } E } A { : { } ( ) } * const ( ) const { }"); + (void)checkCode("{ ( ) () { virtual } ; { } E } A { : { } ( ) } * const ( ) const { }\n"); // test doesn't seem to work on any platform: ASSERT_THROW(checkCode("{ ( ) () { virtual } ; { } E } A { : { } ( ) } * const ( ) const { }", "test.c"), InternalError); } void garbageCode41() { // #6685 (segmentation fault) - (void)checkCode(" { } { return } *malloc(__SIZE_TYPE__ size); *memcpy(void n); static * const () { memcpy (*slot, 3); } { (); } { }"); + (void)checkCode(" { } { return } *malloc(__SIZE_TYPE__ size); *memcpy(void n); static * const () { memcpy (*slot, 3); } { (); } { }\n"); } void garbageCode42() { // #5760 (segmentation fault) - (void)checkCode("{ } * const ( ) { }"); + (void)checkCode("{ } * const ( ) { }\n"); } void garbageCode43() { // #6703 (segmentation fault) - (void)checkCode("int { }; struct A a = { }"); + (void)checkCode("int { }; struct A a = { }\n"); } void garbageCode44() { // #6704 - ASSERT_THROW_INTERNAL(checkCode("{ { }; }; { class A : }; public typedef b;"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{ { }; }; { class A : }; public typedef b;\n"), SYNTAX); } void garbageCode45() { // #6608 - ASSERT_THROW_INTERNAL(checkCode("struct true template < > { = } > struct Types \"s\" ; static_assert < int > ;"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("struct true template < > { = } > struct Types \"s\" ; static_assert < int > ;\n"), SYNTAX); } void garbageCode46() { // #6705 (segmentation fault) - (void)checkCode(" { bar(char *x); void foo (int ...) { struct } va_list ap; va_start(ap, size); va_arg(ap, (d)); }"); + (void)checkCode(" { bar(char *x); void foo (int ...) { struct } va_list ap; va_start(ap, size); va_arg(ap, (d)); }\n"); ignore_errout(); // we do not care about the output } void garbageCode47() { // #6706 (segmentation fault) - (void)checkCode(" { { }; }; * new private: B: B;"); + (void)checkCode(" { { }; }; * new private: B: B;\n"); } void garbageCode48() { // #6712 (segmentation fault) - ASSERT_THROW_INTERNAL(checkCode(" { d\" ) d ...\" } int main ( ) { ( ) catch ( A a ) { { } catch ( ) \"\" } }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode(" { d\" ) d ...\" } int main ( ) { ( ) catch ( A a ) { { } catch ( ) \"\" } }\n"), SYNTAX); } void garbageCode49() { // #6715 - ASSERT_THROW_INTERNAL(checkCode(" ( ( ) ) { } ( { ( __builtin_va_arg_pack ( ) ) ; } ) { ( int { ( ) ( ( ) ) } ( ) { } ( ) ) += ( ) }"), AST); + ASSERT_THROW_INTERNAL(checkCode(" ( ( ) ) { } ( { ( __builtin_va_arg_pack ( ) ) ; } ) { ( int { ( ) ( ( ) ) } ( ) { } ( ) ) += ( ) }\n"), AST); } void garbageCode51() { // #6719 - ASSERT_THROW_INTERNAL(checkCode(" (const \"C\" ...); struct base { int f2; base (int arg1, int arg2); }; global_base(0x55, 0xff); { ((global_base.f1 0x55) (global_base.f2 0xff)) { } } base::base(int arg1, int arg2) { f2 = }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode(" (const \"C\" ...); struct base { int f2; base (int arg1, int arg2); }; global_base(0x55, 0xff); { ((global_base.f1 0x55) (global_base.f2 0xff)) { } } base::base(int arg1, int arg2) { f2 = }\n"), SYNTAX); } void garbageCode53() { // #6721 - ASSERT_THROW_INTERNAL(checkCode("{ { } }; void foo (struct int i) { x->b[i] = = }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{ { } }; void foo (struct int i) { x->b[i] = = }\n"), SYNTAX); } void garbageCode54() { // #6722 - ASSERT_THROW_INTERNAL(checkCode("{ typedef long ((pf) p) (); }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{ typedef long ((pf) p) (); }\n"), SYNTAX); } void garbageCode55() { // #6724 - ASSERT_THROW_INTERNAL(checkCode("() __attribute__((constructor)); { } { }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("() __attribute__((constructor)); { } { }\n"), SYNTAX); } void garbageCode56() { // #6713 - ASSERT_THROW_INTERNAL(checkCode("void foo() { int a = 0; int b = ???; }"), AST); + ASSERT_THROW_INTERNAL(checkCode("void foo() { int a = 0; int b = ???; }\n"), AST); } void garbageCode57() { // #6731 - ASSERT_THROW_INTERNAL(checkCode("{ } if () try { } catch (...) B::~B { }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{ } if () try { } catch (...) B::~B { }\n"), SYNTAX); } void garbageCode58() { // #6732, #6762 - ASSERT_THROW_INTERNAL(checkCode("{ }> {= ~A()^{} }P { }"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("{= ~A()^{} }P { } { }> is"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{ }> {= ~A()^{} }P { }\n"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{= ~A()^{} }P { } { }> is\n"), SYNTAX); } void garbageCode59() { // #6735 - ASSERT_THROW_INTERNAL(checkCode("{ { } }; char font8x8[256][8]"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{ { } }; char font8x8[256][8]\n"), SYNTAX); } void garbageCode60() { // #6736 - ASSERT_THROW_INTERNAL(checkCode("{ } { } typedef int int_array[]; int_array &right ="), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{ } { } typedef int int_array[]; int_array &right =\n"), SYNTAX); } void garbageCode61() { // #6737 - ASSERT_THROW_INTERNAL(checkCode("{ (const U&) }; { }; { }; struct U : virtual public"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{ (const U&) }; { }; { }; struct U : virtual public\n"), SYNTAX); } void garbageCode63() { // #6739 - ASSERT_THROW_INTERNAL(checkCode("{ } { } typedef int u_array[]; typedef u_array &u_array_ref; (u_array_ref arg) { } u_array_ref u_array_ref_gbl_obj0"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{ } { } typedef int u_array[]; typedef u_array &u_array_ref; (u_array_ref arg) { } u_array_ref u_array_ref_gbl_obj0\n"), SYNTAX); } void garbageCode64() { // #6740 - ASSERT_THROW_INTERNAL(checkCode("{ } foo(void (*bar)(void))"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{ } foo(void (*bar)(void))\n"), SYNTAX); } void garbageCode65() { // #6741 (segmentation fault) // TODO write some syntax error - (void)checkCode("{ } { } typedef int u_array[]; typedef u_array &u_array_ref; (u_array_ref arg) { } u_array_ref"); + (void)checkCode("{ } { } typedef int u_array[]; typedef u_array &u_array_ref; (u_array_ref arg) { } u_array_ref\n"); } void garbageCode66() { // #6742 - ASSERT_THROW_INTERNAL(checkCode("{ { } }; { { } }; { }; class bar : public virtual"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{ { } }; { { } }; { }; class bar : public virtual\n"), SYNTAX); } void garbageCode68() { // #6745 (segmentation fault) - (void)checkCode("(int a[3]); typedef void (*fp) (void); fp"); + (void)checkCode("(int a[3]); typedef void (*fp) (void); fp\n"); } void garbageCode69() { // #6746 - ASSERT_THROW_INTERNAL(checkCode("{ (make_mess, aux); } typedef void F(void); aux(void (*x)()) { } (void (*y)()) { } F*"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{ (make_mess, aux); } typedef void F(void); aux(void (*x)()) { } (void (*y)()) { } F*\n"), SYNTAX); } void garbageCode70() { // #6747 - ASSERT_THROW_INTERNAL(checkCode("{ } __attribute__((constructor)) void"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{ } __attribute__((constructor)) void\n"), SYNTAX); } void garbageCode71() { // #6748 - ASSERT_THROW_INTERNAL(checkCode("( ) { } typedef void noattr_t ( ) ; noattr_t __attribute__ ( )"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("( ) { } typedef void noattr_t ( ) ; noattr_t __attribute__ ( )\n"), SYNTAX); } void garbageCode72() { // #6749 - ASSERT_THROW_INTERNAL(checkCode("{ } { } typedef void voidfn(void); = } } unsigned *d = (b b--) --*d"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void foo (int **p) { { { };>= } } unsigned *d = (b b--) --*d\n"), SYNTAX); } void garbageCode78() { // #6756 - ASSERT_THROW_INTERNAL(checkCode("( ) { [ ] } ( ) { } const_array_of_int ( ) { } typedef int A [ ] [ ] ; A a = { { } { } }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("( ) { [ ] } ( ) { } const_array_of_int ( ) { } typedef int A [ ] [ ] ; A a = { { } { } }\n"), SYNTAX); ignore_errout(); // we do not care about the output } void garbageCode79() { // #6757 - ASSERT_THROW_INTERNAL(checkCode("{ } { } typedef void ( func_type ) ( ) ; func_type & ( )"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{ } { } typedef void ( func_type ) ( ) ; func_type & ( )\n"), SYNTAX); } void garbageCode80() { // #6759 - ASSERT_THROW_INTERNAL(checkCode("( ) { ; ( ) ; ( * ) [ ] ; [ ] = ( ( ) ( ) h ) ! ( ( ) ) } { ; } { } head heads [ ] = ; = & heads [ 2 ]"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("( ) { ; ( ) ; ( * ) [ ] ; [ ] = ( ( ) ( ) h ) ! ( ( ) ) } { ; } { } head heads [ ] = ; = & heads [ 2 ]\n"), SYNTAX); } void garbageCode81() { // #6760 - ASSERT_THROW_INTERNAL(checkCode("{ } [ ] { ( ) } { } typedef void ( *fptr1 ) ( ) const"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{ } [ ] { ( ) } { } typedef void ( *fptr1 ) ( ) const\n"), SYNTAX); } void garbageCode82() { // #6761 - ASSERT_THROW_INTERNAL(checkCode("p(\"Hello \" 14) _yn(const size_t) typedef bool pfunk (*pfunk)(const size_t)"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("p(\"Hello \" 14) _yn(const size_t) typedef bool pfunk (*pfunk)(const size_t)\n"), SYNTAX); } void garbageCode83() { // #6771 - ASSERT_THROW_INTERNAL(checkCode("namespace A { class } class A { friend C ; } { } ;"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("namespace A { class } class A { friend C ; } { } ;\n"), SYNTAX); } void garbageCode84() { // #6780 - ASSERT_THROW_INTERNAL(checkCode("int main ( [ ] ) { " " [ ] ; int i = 0 ; do { } ; } ( [ ] ) { }"), SYNTAX); // do not crash + ASSERT_THROW_INTERNAL(checkCode("int main ( [ ] ) { " " [ ] ; int i = 0 ; do { } ; } ( [ ] ) { }\n"), SYNTAX); // do not crash } void garbageCode85() { // #6784 (segmentation fault) - (void)checkCode("{ } { } typedef void ( *VoidFunc() ) ( ) ; VoidFunc"); // do not crash + (void)checkCode("{ } { } typedef void ( *VoidFunc() ) ( ) ; VoidFunc\n"); // do not crash } void garbageCode86() { // #6785 - ASSERT_THROW_INTERNAL(checkCode("{ } typedef char ( *( X ) ( void) , char ) ;"), SYNTAX); // do not crash + ASSERT_THROW_INTERNAL(checkCode("{ } typedef char ( *( X ) ( void) , char ) ;\n"), SYNTAX); // do not crash } void garbageCode87() { // #6788 - ASSERT_THROW_INTERNAL(checkCode("((X (128))) (int a) { v[ = {} (x 42) a] += }"), SYNTAX); // do not crash + ASSERT_THROW_INTERNAL(checkCode("((X (128))) (int a) { v[ = {} (x 42) a] += }\n"), SYNTAX); // do not crash } void garbageCode88() { // #6786 - ASSERT_THROW_INTERNAL(checkCode("( ) { ( 0 ) { ( ) } } g ( ) { i( ( false ?) ( ) : 1 ) ; } ;"), SYNTAX); // do not crash + ASSERT_THROW_INTERNAL(checkCode("( ) { ( 0 ) { ( ) } } g ( ) { i( ( false ?) ( ) : 1 ) ; } ;\n"), SYNTAX); // do not crash } void garbageCode90() { // #6790 - ASSERT_THROW_INTERNAL(checkCode("{ } { } typedef int u_array [[ ] ; typedef u_array & u_array_ref] ( ) { } u_array_ref_gbl_obj0"), SYNTAX); // do not crash + ASSERT_THROW_INTERNAL(checkCode("{ } { } typedef int u_array [[ ] ; typedef u_array & u_array_ref] ( ) { } u_array_ref_gbl_obj0\n"), SYNTAX); // do not crash } void garbageCode91() { // #6791 - ASSERT_THROW_INTERNAL(checkCode("typedef __attribute__((vector_size (16))) { return[ (v2df){ } ;] }"), SYNTAX); // throw syntax error + ASSERT_THROW_INTERNAL(checkCode("typedef __attribute__((vector_size (16))) { return[ (v2df){ } ;] }\n"), SYNTAX); // throw syntax error } void garbageCode92() { // #6792 - ASSERT_THROW_INTERNAL(checkCode("template < typename _Tp ( ( ) ; _Tp ) , decltype > { } { ( ) ( ) }"), SYNTAX); // do not crash + ASSERT_THROW_INTERNAL(checkCode("template < typename _Tp ( ( ) ; _Tp ) , decltype > { } { ( ) ( ) }\n"), SYNTAX); // do not crash } void garbageCode94() { // #6803 //checkCode("typedef long __m256i __attribute__ ( ( ( ) ) )[ ; ( ) { } typedef __m256i __attribute__ ( ( ( ) ) ) < ] ( ) { ; }"); - ASSERT_THROW_INTERNAL(checkCode("typedef long __m256i __attribute__ ( ( ( ) ) )[ ; ( ) { } typedef __m256i __attribute__ ( ( ( ) ) ) < ] ( ) { ; }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("typedef long __m256i __attribute__ ( ( ( ) ) )[ ; ( ) { } typedef __m256i __attribute__ ( ( ( ) ) ) < ] ( ) { ; }\n"), SYNTAX); } void garbageCode95() { // #6804 - ASSERT_THROW_INTERNAL(checkCode("{ } x x ; { } h h [ ] ( ) ( ) { struct x ( x ) ; int __attribute__ ( ) f ( ) { h - > first = & x ; struct x * n = h - > first ; ( ) n > } }"), AST); // do not crash + ASSERT_THROW_INTERNAL(checkCode("{ } x x ; { } h h [ ] ( ) ( ) { struct x ( x ) ; int __attribute__ ( ) f ( ) { h - > first = & x ; struct x * n = h - > first ; ( ) n > } }\n"), SYNTAX); // do not crash } void garbageCode96() { // #6807 - ASSERT_THROW_INTERNAL(checkCode("typedef J J[ ; typedef ( ) ( ) { ; } typedef J J ;] ( ) ( J cx ) { n } ;"), SYNTAX); // throw syntax error + ASSERT_THROW_INTERNAL(checkCode("typedef J J[ ; typedef ( ) ( ) { ; } typedef J J ;] ( ) ( J cx ) { n } ;\n"), SYNTAX); // throw syntax error } void garbageCode97() { // #6808 - ASSERT_THROW_INTERNAL(checkCode("namespace A {> } class A{ { }} class A : T< ;"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("namespace A {> } class A{ { }} class A : T< ;\n"), SYNTAX); } void garbageCode98() { // #6838 ASSERT_THROW_INTERNAL(checkCode("for (cocon To::ta@Taaaaaforconst oken aaaaaaaaaaaa5Dl()\n" "const unsigned in;\n" - "fon *tok = f);.s(Token i = d-)L;"), SYNTAX); + "fon *tok = f);.s(Token i = d-)L;\n"), SYNTAX); } void garbageCode99() { // #6726 ASSERT_THROW_INTERNAL_EQUALS(checkCode("{ xs :: i(:) ! ! x/5 ! !\n" "i, :: a :: b integer, } foo2(x) :: j(:)\n" "b type(*), d(:), a x :: end d(..), foo end\n" - "foo4 b d(..), a a x type(*), b foo2 b"), SYNTAX, "syntax error"); + "foo4 b d(..), a a x type(*), b foo2 b\n"), SYNTAX, "syntax error"); } void garbageCode100() { // #6840 - ASSERT_THROW_INTERNAL(checkCode("( ) { ( i< ) } int foo ( ) { int i ; ( for ( i => 1 ) ; ) }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("( ) { ( i< ) } int foo ( ) { int i ; ( for ( i => 1 ) ; ) }\n"), SYNTAX); } void garbageCode101() { // #6835 // Reported case - ASSERT_THROW_INTERNAL(checkCode("template < class , =( , int) X = 1 > struct A { } ( ) { = } [ { } ] ( ) { A < void > 0 }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("template < class , =( , int) X = 1 > struct A { } ( ) { = } [ { } ] ( ) { A < void > 0 }\n"), SYNTAX); // Reduced case - ASSERT_THROW_INTERNAL(checkCode("template < class =( , ) X = 1> struct A {}; A a;"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("template < class =( , ) X = 1> struct A {}; A a;\n"), SYNTAX); } void garbageCode102() { // #6846 (segmentation fault) - (void)checkCode("struct Object { ( ) ; Object & operator= ( Object ) { ( ) { } if ( this != & b ) } }"); - ignore_errout(); // we do not care about the output + ASSERT_THROW_INTERNAL(checkCode("struct Object { ( ) ; Object & operator= ( Object ) { ( ) { } if ( this != & b ) } }\n"), SYNTAX); } void garbageCode103() { // #6824 - ASSERT_THROW_INTERNAL(checkCode("a f(r) int * r; { { int s[2]; [f(s); if () ] } }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("a f(r) int * r; { { int s[2]; [f(s); if () ] } }\n"), SYNTAX); } void garbageCode104() { // #6847 - ASSERT_THROW_INTERNAL(checkCode("template < Types > struct S {> ( S < ) S >} { ( ) { } } ( ) { return S < void > ( ) } { ( )> >} { ( ) { } } ( ) { ( ) }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("template < Types > struct S {> ( S < ) S >} { ( ) { } } ( ) { return S < void > ( ) } { ( )> >} { ( ) { } } ( ) { ( ) }\n"), SYNTAX); } void garbageCode105() { // #6859 - ASSERT_THROW_INTERNAL(checkCode("void foo (int i) { int a , for (a 1; a( < 4; a++) if (a) (b b++) (b);) n++; }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void foo (int i) { int a , for (a 1; a( < 4; a++) if (a) (b b++) (b);) n++; }\n"), SYNTAX); } void garbageCode106() { // #6880 - ASSERT_THROW_INTERNAL(checkCode("[ ] typedef typedef b_array b_array_ref [ ; ] ( ) b_array_ref b_array_ref_gbl_obj0 { ; { b_array_ref b_array_ref_gbl_obj0 } }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("[ ] typedef typedef b_array b_array_ref [ ; ] ( ) b_array_ref b_array_ref_gbl_obj0 { ; { b_array_ref b_array_ref_gbl_obj0 } }\n"), SYNTAX); } void garbageCode107() { // #6881 - TODO_ASSERT_THROW(checkCode("enum { val = 1{ }; { const} }; { } Bar { const int A = val const } ;"), InternalError); + TODO_ASSERT_THROW(checkCode("enum { val = 1{ }; { const} }; { } Bar { const int A = val const } ;\n"), InternalError); } void garbageCode108() { // #6895 "segmentation fault (invalid code) in CheckCondition::isOppositeCond" - ASSERT_THROW_INTERNAL(checkCode("A( ) { } bool f( ) { ( ) F; ( ) { ( == ) if ( !=< || ( !A( ) && r[2] ) ) ( !A( ) ) ( ) } }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("A( ) { } bool f( ) { ( ) F; ( ) { ( == ) if ( !=< || ( !A( ) && r[2] ) ) ( !A( ) ) ( ) } }\n"), SYNTAX); } void garbageCode109() { // #6900 "segmentation fault (invalid code) in CheckStl::runSimplifiedChecks" - (void)checkCode("( *const<> (( ) ) { } ( *const ( ) ( ) ) { } ( * const<> ( size_t )) ) { } ( * const ( ) ( ) ) { }"); + (void)checkCode("( *const<> (( ) ) { } ( *const ( ) ( ) ) { } ( * const<> ( size_t )) ) { } ( * const ( ) ( ) ) { }\n"); } void garbageCode110() { // #6902 "segmentation fault (invalid code) in CheckStl::string_c_str" - ASSERT_THROW_INTERNAL(checkCode("( *const<> ( size_t ) ; foo ) { } * ( *const ( size_t ) ( ) ;> foo )< { }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("( *const<> ( size_t ) ; foo ) { } * ( *const ( size_t ) ( ) ;> foo )< { }\n"), SYNTAX); } void garbageCode111() { // #6907 - TODO_ASSERT_THROW(checkCode("enum { FOO = 1( ,) } {{ FOO }} ;"), InternalError); + TODO_ASSERT_THROW(checkCode("enum { FOO = 1( ,) } {{ FOO }} ;\n"), InternalError); } void garbageCode112() { // #6909 - TODO_ASSERT_THROW(checkCode("enum { FOO = ( , ) } {{ }}>> enum { FOO< = ( ) } { { } } ;"), InternalError); + TODO_ASSERT_THROW(checkCode("enum { FOO = ( , ) } {{ }}>> enum { FOO< = ( ) } { { } } ;\n"), InternalError); } void garbageCode114() { // #2118 ASSERT_NO_THROW(checkCode("Q_GLOBAL_STATIC_WITH_INITIALIZER(Qt4NodeStaticData, qt4NodeStaticData, {\n" " for (unsigned i = 0 ; i < count; i++) {\n" " }\n" - "});")); + "});\n")); } void garbageCode115() { // #5506 - ASSERT_THROW_INTERNAL(checkCode("A template < int { int = -1 ; } template < int N > struct B { int [ A < N > :: zero ] ; } ; B < 0 > b ;"), UNKNOWN_MACRO); + ASSERT_THROW_INTERNAL(checkCode("A template < int { int = -1 ; } template < int N > struct B { int [ A < N > :: zero ] ; } ; B < 0 > b ;\n"), UNKNOWN_MACRO); } void garbageCode116() { // #5356 - ASSERT_THROW_INTERNAL(checkCode("struct template struct B { }; B < 0 > b;"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("struct template struct B { }; B < 0 > b;\n"), SYNTAX); } void garbageCode117() { // #6121 TODO_ASSERT_THROW(checkCode("enum E { f = {} };\n" - "int a = f;"), InternalError); + "int a = f;\n"), InternalError); } void garbageCode118() { // #5600 - missing include causes invalid enum @@ -953,32 +955,32 @@ class TestGarbage : public TestFixture { "};\n" "struct bytecode {};\n" "jv jq_next() { opcode = ((opcode) +NUM_OPCODES);\n" - "}"), SYNTAX); + "}\n"), SYNTAX); } void garbageCode119() { // #5598 (segmentation fault) - (void)checkCode("{ { void foo() { struct }; template struct S { Used x; void bar() } auto f = [this] { }; } };"); + (void)checkCode("{ { void foo() { struct }; template struct S { Used x; void bar() } auto f = [this] { }; } };\n"); ignore_errout(); // we do not care about the output } void garbageCode120() { // #4927 (segmentation fault) (void)checkCode("int main() {\n" " return 0\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void garbageCode121() { // #2585 ASSERT_THROW_INTERNAL(checkCode("abcdef?" "?<" "123456?" "?>" - "+?" "?="), SYNTAX); + "+?" "?=\n"), SYNTAX); } void garbageCode122() { // #6303 (segmentation fault) (void)checkCode("void foo() {\n" "char *a = malloc(10);\n" "a[0]\n" - "}"); + "}\n"); ignore_errout(); // we do not care about the output } @@ -987,18 +989,18 @@ class TestGarbage : public TestFixture { " class C {\n" " C tpl_mem(T *) { return }\n" " };\n" - "}"); + "}\n"); ignore_errout(); // we do not care about the output } void garbageCode125() { - ASSERT_THROW_INTERNAL(checkCode("{ T struct B : T valueA_AA ; } T : [ T > ( ) { B } template < T > struct A < > : ] { ( ) { return valueA_AC struct { : } } b A < int > AC ( ) a_aa.M ; ( ) ( ) }"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("template < Types > struct S :{ ( S < ) S >} { ( ) { } } ( ) { return S < void > ( ) }"), + ASSERT_THROW_INTERNAL(checkCode("{ T struct B : T valueA_AA ; } T : [ T > ( ) { B } template < T > struct A < > : ] { ( ) { return valueA_AC struct { : } } b A < int > AC ( ) a_aa.M ; ( ) ( ) }\n"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("template < Types > struct S :{ ( S < ) S >} { ( ) { } } ( ) { return S < void > ( ) }\n"), SYNTAX); } void garbageCode126() { - ASSERT_THROW_INTERNAL(checkCode("{ } float __ieee754_sinhf ( float x ) { float t , , do { gf_u ( jx ) { } ( 0 ) return ; ( ) { } t } ( 0x42b17180 ) { } }"), + ASSERT_THROW_INTERNAL(checkCode("{ } float __ieee754_sinhf ( float x ) { float t , , do { gf_u ( jx ) { } ( 0 ) return ; ( ) { } t } ( 0x42b17180 ) { } }\n"), SYNTAX); } @@ -1011,38 +1013,38 @@ class TestGarbage : public TestFixture { " ~A() { printf(\"A d'tor\\n\"); }\n" "};\n" " const A& foo(const A& arg) { return arg; }\n" - " foo(A(12)).Var"); + " foo(A(12)).Var\n"); ignore_errout(); // we do not care about the output } void garbageCode128() { - TODO_ASSERT_THROW(checkCode("enum { FOO = ( , ) } {{ }} enum {{ FOO << = } ( ) } {{ }} ;"), + TODO_ASSERT_THROW(checkCode("enum { FOO = ( , ) } {{ }} enum {{ FOO << = } ( ) } {{ }} ;\n"), InternalError); } void garbageCode129() { - ASSERT_THROW_INTERNAL(checkCode("operator - ( { } typedef typename x ; ( ) ) { ( { { ( ( ) ) } ( { } ) } ) }"), + ASSERT_THROW_INTERNAL(checkCode("operator - ( { } typedef typename x ; ( ) ) { ( { { ( ( ) ) } ( { } ) } ) }\n"), SYNTAX); } void garbageCode130() { - TODO_ASSERT_THROW(checkCode("enum { FOO = ( , ){ } { { } } { { FOO} = } ( ) } { { } } enumL\" ( enumL\" { { FOO } ( ) } { { } } ;"), + TODO_ASSERT_THROW(checkCode("enum { FOO = ( , ){ } { { } } { { FOO} = } ( ) } { { } } enumL\" ( enumL\" { { FOO } ( ) } { { } } ;\n"), InternalError); } void garbageCode131() { - ASSERT_THROW_INTERNAL(checkCode("( void ) { ( ) } ( ) / { ( ) }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("( void ) { ( ) } ( ) / { ( ) }\n"), SYNTAX); // actually the invalid code should trigger an syntax error... } void garbageCode132() { // #7022 - ASSERT_THROW_INTERNAL(checkCode("() () { } { () () ({}) i() } void i(void(*ptr) ()) { ptr(!) () }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("() () { } { () () ({}) i() } void i(void(*ptr) ()) { ptr(!) () }\n"), SYNTAX); } void garbageCode133() { - ASSERT_THROW_INTERNAL(checkCode("void f() {{}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void f() {{}\n"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("void f()) {}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void f()) {}\n"), SYNTAX); ASSERT_THROW_INTERNAL(checkCode("void f()\n" "{\n" @@ -1093,32 +1095,32 @@ class TestGarbage : public TestFixture { void garbageCode134() { // Ticket #5605, #5759, #5762, #5774, #5823, #6059 - ASSERT_THROW_INTERNAL(checkCode("foo() template struct tuple Args> tuple { } main() { foo(); }"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("( ) template < T1 = typename = unused> struct Args { } main ( ) { foo < int > ( ) ; }"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("() template < T = typename = x > struct a {} { f () }"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("template < T = typename = > struct a { f }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("foo() template struct tuple Args> tuple { } main() { foo(); }\n"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("( ) template < T1 = typename = unused> struct Args { } main ( ) { foo < int > ( ) ; }\n"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("() template < T = typename = x > struct a {} { f () }\n"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("template < T = typename = > struct a { f }\n"), SYNTAX); (void)checkCode("struct S { int i, j; }; " "template struct X {}; " "X<&S::i, int> x = X<&S::i, int>(); " - "X<&S::j, int> y = X<&S::j, int>();"); + "X<&S::j, int> y = X<&S::j, int>();\n"); ignore_errout(); // we are not interested in the output (void)checkCode("template struct A {}; " "template <> struct A {}; " - "void foo(const void* f = 0) {}"); + "void foo(const void* f = 0) {}\n"); (void)checkCode("template struct A { " " static const int s = 0; " "}; " - "A a;"); + "A a;\n"); (void)checkCode("template class A {}; " "template > class B {}; " "template > class C { " " C() : _a(0), _b(0) {} " " int _a, _b; " - "};"); + "};\n"); (void)checkCode("template struct A { " " static int i; " "}; " - "void f() { A::i = 0; }"); + "void f() { A::i = 0; }\n"); ignore_errout(); // we are not interested in the output } @@ -1127,17 +1129,17 @@ class TestGarbage : public TestFixture { " return a >> extern\n" "}\n" "long a = 1 ;\n" - "long b = 2 ;"); + "long b = 2 ;\n"); ignore_errout(); // we are not interested in the output } void garbageCode136() { // #7033 - ASSERT_THROW_INTERNAL(checkCode("{ } () { void f() { node_t * n; for (; -n) {} } } { }"), + ASSERT_THROW_INTERNAL(checkCode("{ } () { void f() { node_t * n; for (; -n) {} } } { }\n"), SYNTAX); } void garbageCode137() { // #7034 - ASSERT_THROW_INTERNAL(checkCode("\" \" typedef signed char f; \" \"; void a() { f * s = () &[]; (; ) (; ) }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("\" \" typedef signed char f; \" \"; void a() { f * s = () &[]; (; ) (; ) }\n"), SYNTAX); } void garbageCode138() { // #6660 (segmentation fault) @@ -1149,7 +1151,7 @@ class TestGarbage : public TestFixture { " {};\n" " } halo;\n" "}\n" - "CS_PLUGIN_NAMESPACE_END(csparser)"); + "CS_PLUGIN_NAMESPACE_END(csparser)\n"); ignore_errout(); // we are not interested in the output } @@ -1158,19 +1160,19 @@ class TestGarbage : public TestFixture { " de_ctrl = (nDirection == RIGHT_TO_LEFT) ?\n" " ( (0 & ~(((1 << (1 - (0 ? DE_CONTROL_DIRECTION))) - 1) << (0 ? DE_CONTROL_DIRECTION))) )\n" " : 42;\n" - "}"), SYNTAX); + "}\n"), SYNTAX); } void garbageCode140() { // #7035 - ASSERT_THROW_INTERNAL(checkCode("int foo(int align) { int off(= 0 % align; return off) ? \\ align - off : 0; \\ }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("int foo(int align) { int off(= 0 % align; return off) ? \\ align - off : 0; \\ }\n"), SYNTAX); } void garbageCode141() { // #7043 - TODO_ASSERT_THROW(checkCode("enum { X = << { X } } enum { X = X } = X ;"), InternalError); + TODO_ASSERT_THROW(checkCode("enum { X = << { X } } enum { X = X } = X ;\n"), InternalError); } void garbageCode142() { // #7050 - ASSERT_THROW_INTERNAL(checkCode("{ } ( ) { void mapGraphs ( ) { node_t * n ; for (!oid n ) { } } } { }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{ } ( ) { void mapGraphs ( ) { node_t * n ; for (!oid n ) { } } } { }\n"), SYNTAX); } void garbageCode143() { // #6922 @@ -1184,18 +1186,18 @@ class TestGarbage : public TestFixture { " VGAwCR(0x64,0x?? );\n" " }\n" " }\n" - "}"), AST); + "}\n"), AST); } void garbageCode144() { // #6865 - ASSERT_THROW_INTERNAL(checkCode("template < typename > struct A { } ; template < typename > struct A < INVALID > : A < int[ > { }] ;"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("template < typename > struct A { } ; template < typename > struct A < INVALID > : A < int[ > { }] ;\n"), SYNTAX); } void garbageCode146() { // #7081 ASSERT_THROW_INTERNAL(checkCode("void foo() {\n" " ? std::cout << pow((, 1) << std::endl;\n" " double ( ); }"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("void f() { x = , * [ | + 0xff | > 0xff]; }"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("void f() { x = , | 0xff , 0.1 < ; }"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("void f() { x = [ 1 || ] ; }"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("void f1() { x = name6 1 || ? name3 [ ( 1 || +) ] ; }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void f() { x= name2 & name3 name2 = | 0.1 , | 0.1 , | 0.1 name4 <= >( ); }\n"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void f() { x = , * [ | + 0xff | > 0xff]; }\n"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void f() { x = , | 0xff , 0.1 < ; }\n"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void f() { x = [ 1 || ] ; }\n"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void f1() { x = name6 1 || ? name3 [ ( 1 || +) ] ; }\n"), SYNTAX); } void garbageValueFlow() { @@ -1305,44 +1306,46 @@ class TestGarbage : public TestFixture { } { // 6122 survive garbage code - const char code[] = "; { int i ; for ( i = 0 ; = 123 ; ) - ; }"; + const char code[] = "; { int i ; for ( i = 0 ; = 123 ; ) - ; }\n"; ASSERT_THROW_INTERNAL(checkCode(code), SYNTAX); } { - const char code[] = "void f1() { for (int n = 0 n < 10 n++); }"; + const char code[] = "void f1() { for (int n = 0 n < 10 n++); }\n"; ASSERT_THROW_INTERNAL(checkCode(code), SYNTAX); } } void garbageSymbolDatabase() { - (void)checkCode("void f( { u = 1 ; } ) { }"); + (void)checkCode("void f( { u = 1 ; } ) { }\n"); - ASSERT_THROW_INTERNAL(checkCode("{ }; void namespace A::f; { g() { int } }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{ }; void namespace A::f; { g() { int } }\n"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("class Foo {}; class Bar : public Foo"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("class Foo {}; class Bar : public Foo\n"), SYNTAX); // #5663 (segmentation fault) (void)checkCode("YY_DECL { switch (yy_act) {\n" " case 65: YY_BREAK\n" " case YY_STATE_EOF(block):\n" " yyterminate();\n" - "} }"); + "} }\n"); ignore_errout(); // we are not interested in the output } void garbageAST() { ASSERT_THROW_INTERNAL(checkCode("N 1024 float a[N], b[N + 3], c[N]; void N; (void) i;\n" "int #define for (i = avx_test i < c[i]; i++)\n" - "b[i + 3] = a[i] * {}"), SYNTAX); // Don't hang (#5787) + "b[i + 3] = a[i] * {}\n"), SYNTAX); // Don't hang (#5787) - (void)checkCode("START_SECTION([EXTRA](bool isValid(const String &filename)))"); // Don't crash (#5991) + (void)checkCode("START_SECTION([EXTRA](bool isValid(const String &filename)))\n"); // Don't crash (#5991) // #8352 ASSERT_THROW_INTERNAL(checkCode("else return % name5 name2 - =name1 return enum | { - name3 1 enum != >= 1 >= ++ { { || " - "{ return return { | { - name3 1 enum != >= 1 >= ++ { name6 | ; ++}}}}}}}"), UNKNOWN_MACRO); + "{ return return { | { - name3 1 enum != >= 1 >= ++ { name6 | ; ++}}}}}}}\n"), UNKNOWN_MACRO); ASSERT_THROW_INTERNAL(checkCode("else return % name5 name2 - =name1 return enum | { - name3 1 enum != >= 1 >= ++ { { || " - "{ return return { | { - name3 1 enum != >= 1 >= ++ { { || ; ++}}}}}}}}"), UNKNOWN_MACRO); + "{ return return { | { - name3 1 enum != >= 1 >= ++ { { || ; ++}}}}}}}}\n"), UNKNOWN_MACRO); + + ASSERT_THROW_INTERNAL(checkCode("f(*p, requires(x));\n"), AST); // #14740 } void templateSimplifierCrashes() { @@ -1366,7 +1369,7 @@ class TestGarbage : public TestFixture { " void f() {\n" " s.operator A >();\n" " }\n" - "}"); + "}\n"); ASSERT_NO_THROW(checkCode( // #6034 "template class T, typename... Args>\n" @@ -1380,7 +1383,7 @@ class TestGarbage : public TestFixture { "\n" "int main() {\n" " foo >::value;\n" - "}")); + "}\n")); (void)checkCode( // #6117 (segmentation fault) "template struct something_like_tuple\n" @@ -1398,7 +1401,7 @@ class TestGarbage : public TestFixture { "\n" "typedef something_like_tuple something_like_tuple_t;\n" "SA ((is_last::value == false));\n" - "SA ((is_last::value == false));"); + "SA ((is_last::value == false));\n"); ignore_errout(); // we are not interested in the output (void)checkCode( // #6225 (use-after-free) @@ -1409,7 +1412,7 @@ class TestGarbage : public TestFixture { " template \n" " struct A {};\n" " using AliasA = A;\n" - "}"); + "}\n"); // #3449 ASSERT_EQUALS("template < typename T > struct A ;\n" @@ -1417,72 +1420,72 @@ class TestGarbage : public TestFixture { "{ } ;", checkCode("template struct A;\n" "struct B { template struct C };\n" - "{};")); + "{};\n")); } void garbageCode161() { //7200 - ASSERT_THROW_INTERNAL(checkCode("{ }{ if () try { } catch (...)} B : : ~B { }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{ }{ if () try { } catch (...)} B : : ~B { }\n"), SYNTAX); } void garbageCode162() { //7208 - ASSERT_THROW_INTERNAL(checkCode("return << >> x return << >> x ", false), UNKNOWN_MACRO); + ASSERT_THROW_INTERNAL(checkCode("return << >> x return << >> x \n", false), UNKNOWN_MACRO); } void garbageCode163() { //7228 - ASSERT_THROW_INTERNAL(checkCode("typedef s f[](){typedef d h(;f)}", false), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("typedef s f[](){typedef d h(;f)}\n", false), SYNTAX); } void garbageCode164() { //7234 - ASSERT_THROW_INTERNAL(checkCode("class d{k p;}(){d::d():B<()}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("class d{k p;}(){d::d():B<()}\n"), SYNTAX); } void garbageCode165() { //7235 - ASSERT_THROW_INTERNAL(checkCode("for(;..)", false),SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("for(;..)\n", false),SYNTAX); } void garbageCode167() { //7237 - ASSERT_THROW_INTERNAL(checkCode("class D00i000{:D00i000::}i"),SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("class D00i000{:D00i000::}i\n"),SYNTAX); } void garbageCode168() { // #7246 (segmentation fault) - (void)checkCode("long foo(void) { return *bar; }", false); + (void)checkCode("long foo(void) { return *bar; }\n", false); ignore_errout(); // we do not care about the output } void garbageCode169() { // 6713 ASSERT_THROW_INTERNAL(checkCode("( ) { ( ) ; { return } switch ( ) i\n" - "set case break ; default: ( ) }", false), SYNTAX); + "set case break ; default: ( ) }\n", false), SYNTAX); } void garbageCode170() { // 7255 - ASSERT_THROW_INTERNAL(checkCode("d i(){{f*s=typeid(()0,)}}", false), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("d i(){{f*s=typeid(()0,)}}\n", false), SYNTAX); } void garbageCode171() { // 7270 - ASSERT_THROW_INTERNAL(checkCode("(){case()?():}:", false), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("(){case()?():}:\n", false), SYNTAX); } void garbageCode172() { // #7357 - ASSERT_THROW_INTERNAL(checkCode("p>,"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("p>,\n"), SYNTAX); } void garbageCode173() { // #6781 heap corruption ; TemplateSimplifier::simplifyTemplateInstantiations - ASSERT_THROW_INTERNAL(checkCode(" template < Types > struct S : >( S < ...Types... > S <) > { ( ) { } } ( ) { return S < void > ( ) }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode(" template < Types > struct S : >( S < ...Types... > S <) > { ( ) { } } ( ) { return S < void > ( ) }\n"), SYNTAX); } void garbageCode174() { // #7356 - ASSERT_THROW_INTERNAL(checkCode("{r e() { w*constD = (())D = cast< }}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{r e() { w*constD = (())D = cast< }}\n"), SYNTAX); } void garbageCode175() { // #7027 @@ -1491,32 +1494,32 @@ class TestGarbage : public TestFixture { " for ( i = t3 , i < t1 ; i++ )\n" " for ( j = 0 ; j < = j++ )\n" " return t1 ,\n" - "}"), SYNTAX); + "}\n"), SYNTAX); } void garbageCode176() { // #7257 (segmentation fault) - (void)checkCode("class t { { struct } enum class f : unsigned { q } b ; operator= ( T ) { switch ( b ) { case f::q: } } { assert ( b ) ; } } { ; & ( t ) ( f::t ) ; } ;"); + (void)checkCode("class t { { struct } enum class f : unsigned { q } b ; operator= ( T ) { switch ( b ) { case f::q: } } { assert ( b ) ; } } { ; & ( t ) ( f::t ) ; } ;\n"); ignore_errout(); // we are not interested in the output } void garbageCode181() { - ASSERT_THROW_INTERNAL(checkCode("int test() { int +; }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("int test() { int +; }\n"), SYNTAX); } // #4195 - segfault for "enum { int f ( ) { return = } r = f ( ) ; }" void garbageCode182() { - ASSERT_THROW_INTERNAL(checkCode("enum { int f ( ) { return = } r = f ( ) ; }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("enum { int f ( ) { return = } r = f ( ) ; }\n"), SYNTAX); } // #7505 - segfault void garbageCode183() { - ASSERT_THROW_INTERNAL(checkCode("= { int } enum return { r = f() f(); }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("= { int } enum return { r = f() f(); }\n"), SYNTAX); } void garbageCode184() { // #7699 ASSERT_THROW_INTERNAL(checkCode("unsigned int AquaSalSystem::GetDisplayScreenCount() {\n" " NSArray* pScreens = [NSScreen screens];\n" " return pScreens ? [pScreens count] : 1;\n" - "}"), SYNTAX); + "}\n"), SYNTAX); } void garbageCode185() { // #6011 crash in libreoffice failure to create proper AST @@ -1528,29 +1531,29 @@ class TestGarbage : public TestFixture { " pOut->CreateObject( nIndex, GDI_BRUSH, new WinMtfFillStyle( ReadColor(), ( nStyle == BS_HOLLOW ) ? TRUE : FALSE ) );\n" " return bStatus;\n" " };\n" - "}"); + "}\n"); ignore_errout(); // we are not interested in the output } // #8151 - segfault due to incorrect template syntax void garbageCode186() { - ASSERT_THROW_INTERNAL(checkCode("A<>C"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("A<>C\n"), SYNTAX); } void garbageCode187() { // # 8152 - segfault in handling const char inp[] = "0|\0|0>;\n"; ASSERT_THROW_INTERNAL(checkCode(inp), SYNTAX); - (void)checkCode("template struct S : A< B || C > {};"); // No syntax error: #8390 - (void)checkCode("static_assert(A || B, ab);"); + (void)checkCode("template struct S : A< B || C > {};\n"); // No syntax error: #8390 + (void)checkCode("static_assert(A || B, ab);\n"); } void garbageCode188() { // #8255 - ASSERT_THROW_INTERNAL(checkCode("{z r(){(){for(;<(x);){if(0==0)}}}}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{z r(){(){for(;<(x);){if(0==0)}}}}\n"), SYNTAX); } void garbageCode189() { // #8317 (segmentation fault) - (void)checkCode("t&n(){()()[](){()}}$"); + (void)checkCode("t&n(){()()[](){()}}$\n"); } void garbageCode190() { // #8307 @@ -1558,31 +1561,31 @@ class TestGarbage : public TestFixture { " int i;\n" " i *= 0;\n" " !i <;\n" - "}"), + "}\n"), AST); } void garbageCode191() { // #8333 - ASSERT_THROW_INTERNAL(checkCode("struct A { int f(const); };"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("struct A { int f(int, const, char); };"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("struct A { int f(struct); };"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("struct A { int f(const); };\n"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("struct A { int f(int, const, char); };\n"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("struct A { int f(struct); };\n"), SYNTAX); // The following code is valid and should not trigger any error - ASSERT_NO_THROW(checkCode("struct A { int f ( char ) ; } ;")); + ASSERT_NO_THROW(checkCode("struct A { int f ( char ) ; } ;\n")); } void garbageCode192() { // #8386 (segmentation fault) - ASSERT_THROW_INTERNAL(checkCode("{(()[((0||0xf||))]0[])}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{(()[((0||0xf||))]0[])}\n"), SYNTAX); } // #8740 void garbageCode193() { - ASSERT_THROW_INTERNAL(checkCode("d f(){!=[]&&0()!=0}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("d f(){!=[]&&0()!=0}\n"), SYNTAX); } // #8384 void garbageCode194() { - ASSERT_THROW_INTERNAL(checkCode("{((()))(return 1||);}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{((()))(return 1||);}\n"), SYNTAX); } // #8709 - no garbage but to avoid stability regression (segmentation fault) @@ -1592,19 +1595,19 @@ class TestGarbage : public TestFixture { " switch (d) { case b:; }\n" " double e(b);\n" " if(e <= 0) {}\n" - "}"); + "}\n"); ignore_errout(); // we do not care about the output } // #8265 void garbageCode196() { - ASSERT_THROW_INTERNAL(checkCode("0|,0<= void { ( ()) } 1 name3 return >= >= ( ) >= name5 (\n" " name5 name6 :nam00 [ ()])}))})})})};\n" - "}"), SYNTAX); + "}\n"), SYNTAX); } // #8752 (segmentation fault) void garbageCode199() { - ASSERT_THROW_INTERNAL(checkCode("d f(){e n00e0[]n00e0&" "0+f=0}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("d f(){e n00e0[]n00e0&" "0+f=0}\n"), SYNTAX); } // #8757 void garbageCode200() { - ASSERT_THROW_INTERNAL(checkCode("(){e break,{(case)!{e:[]}}}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("(){e break,{(case)!{e:[]}}}\n"), SYNTAX); } // #8873 void garbageCode201() { - ASSERT_THROW_INTERNAL(checkCode("void f() { std::string s=\"abc\"; return s + }"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void f() { std::string s=\"abc\"; return s + }\n"), SYNTAX); } // #8907 void garbageCode202() { - ASSERT_THROW_INTERNAL(checkCode("void f() { UNKNOWN_MACRO(return); }"), UNKNOWN_MACRO); - ASSERT_THROW_INTERNAL(checkCode("void f() { UNKNOWN_MACRO(throw); }"), UNKNOWN_MACRO); + ASSERT_THROW_INTERNAL(checkCode("void f() { UNKNOWN_MACRO(return); }\n"), UNKNOWN_MACRO); + ASSERT_THROW_INTERNAL(checkCode("void f() { UNKNOWN_MACRO(throw); }\n"), UNKNOWN_MACRO); ignore_errout(); } void garbageCode203() { // #8972 (segmentation fault) - ASSERT_THROW_INTERNAL(checkCode("{ > () {} }"), SYNTAX); - (void)checkCode("template <> a > ::b();"); + ASSERT_THROW_INTERNAL(checkCode("{ > () {} }\n"), SYNTAX); + (void)checkCode("template <> a > ::b();\n"); } void garbageCode204() { - ASSERT_THROW_INTERNAL(checkCode("template ()> c; template a as() {} as>();"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("template ()> c; template a as() {} as>();\n"), SYNTAX); } void garbageCode205() { @@ -1664,55 +1667,55 @@ class TestGarbage : public TestFixture { "CodeSnippetsEvent :: CodeSnippetsEvent ( const CodeSnippetsEvent & Event )\n" ": wxCommandEvent ( Event )\n" ", m_SnippetID ( 0 ) {\n" - "}"), + "}\n"), INTERNAL); } void garbageCode206() { - ASSERT_EQUALS("[test.cpp:1] syntax error: operator", getSyntaxError("void foo() { for (auto operator new : int); }")); - ASSERT_EQUALS("[test.cpp:1] syntax error", getSyntaxError("void foo() { for (a operator== :) }")); + ASSERT_EQUALS("[test.cpp:1] syntax error: operator", getSyntaxError("void foo() { for (auto operator new : int); }\n")); + ASSERT_EQUALS("[test.cpp:1] syntax error", getSyntaxError("void foo() { for (a operator== :) }\n")); } void garbageCode207() { // #8750 - ASSERT_THROW_INTERNAL(checkCode("d f(){(.n00e0(return%n00e0''('')));}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("d f(){(.n00e0(return%n00e0''('')));}\n"), SYNTAX); } void garbageCode208() { // #8753 - ASSERT_THROW_INTERNAL(checkCode("d f(){(for(((((0{t b;((((((((()))))))))}))))))}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("d f(){(for(((((0{t b;((((((((()))))))))}))))))}\n"), SYNTAX); } void garbageCode209() { // #8756 - ASSERT_THROW_INTERNAL(checkCode("{(- -##0xf/-1 0)[]}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{(- -##0xf/-1 0)[]}\n"), SYNTAX); } void garbageCode210() { // #8762 - ASSERT_THROW_INTERNAL(checkCode("{typedef typedef c n00e0[]c000(;n00e0&c000)}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("{typedef typedef c n00e0[]c000(;n00e0&c000)}\n"), SYNTAX); } void garbageCode211() { // #8764 - ASSERT_THROW_INTERNAL(checkCode("{typedef f typedef[]({typedef e e,>;typedef(((typedef;typedef(((typedef struct A {};\n" "template struct A {}; \n" - "A a;"); + "A a;\n"); } void garbageCode217() { // #10011 @@ -1720,11 +1723,11 @@ class TestGarbage : public TestFixture { " auto p;\n" " if (g(p)) {}\n" " assert();\n" - "}"), AST); + "}\n"), AST); } void garbageCode218() { // #8763 - ASSERT_THROW_INTERNAL(checkCode("d f(){t n0000 const[]n0000+0!=n0000,(0)}"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("d f(){t n0000 const[]n0000+0!=n0000,(0)}\n"), SYNTAX); } void garbageCode219() { // #10101 (void)checkCode("typedef void (*func) (addr) ;\n" @@ -1744,100 +1747,111 @@ class TestGarbage : public TestFixture { ASSERT_THROW_INTERNAL(checkCode("template\n"), SYNTAX); // don't crash } void garbageCode223() { // #11639 - ASSERT_THROW_INTERNAL(checkCode("struct{}*"), SYNTAX); // don't crash + ASSERT_THROW_INTERNAL(checkCode("struct{}*\n"), SYNTAX); // don't crash } void garbageCode224() { - ASSERT_THROW_INTERNAL(checkCode("void f(){ auto* b = dynamic_cast int { return 0; }() };")); + ASSERT_NO_THROW(checkCode("void f() { enum { A = [=]() mutable { return 0; }() }; }\n")); + ASSERT_NO_THROW(checkCode("enum { A = [=](void) mutable -> int { return 0; }() };\n")); + } + void garbageCode229() { // #14126 + ASSERT_THROW_INTERNAL(checkCode("void f() {} [[maybe_unused]]\n"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("void f() {} [[unused]]\n"), SYNTAX); + } + void garbageCode230() { // #14432 + ASSERT_THROW_INTERNAL(checkCode("e U U,i\n"), SYNTAX); + } + void garbageCode231() { + ASSERT_THROW_INTERNAL(checkCode("char char* [] = {\"a\" \"b\"}\n"), SYNTAX); } + void syntaxErrorFirstToken() { - ASSERT_THROW_INTERNAL(checkCode("&operator(){[]};"), SYNTAX); // #7818 - ASSERT_THROW_INTERNAL(checkCode("*(*const<> (size_t); foo) { } *(*const (size_t)() ; foo) { }"), SYNTAX); // #6858 - ASSERT_THROW_INTERNAL(checkCode(">{ x while (y) z int = }"), SYNTAX); // #4175 - ASSERT_THROW_INTERNAL(checkCode("&p(!{}e x){({(0?:?){({})}()})}"), SYNTAX); // #7118 - ASSERT_THROW_INTERNAL(checkCode(" { struct { typename D4:typename Base }; };"), SYNTAX); // #3533 + ASSERT_THROW_INTERNAL(checkCode("&operator(){[]};\n"), SYNTAX); // #7818 + ASSERT_THROW_INTERNAL(checkCode("*(*const<> (size_t); foo) { } *(*const (size_t)() ; foo) { }\n"), SYNTAX); // #6858 + ASSERT_THROW_INTERNAL(checkCode(">{ x while (y) z int = }\n"), SYNTAX); // #4175 + ASSERT_THROW_INTERNAL(checkCode("&p(!{}e x){({(0?:?){({})}()})}\n"), SYNTAX); // #7118 + ASSERT_THROW_INTERNAL(checkCode(" { struct { typename D4:typename Base }; };\n"), SYNTAX); // #3533 ASSERT_THROW_INTERNAL(checkCode(" > template < . > struct Y < T > { = } ;\n"), SYNTAX); // #6108 } void syntaxErrorLastToken() { - ASSERT_THROW_INTERNAL(checkCode("int *"), SYNTAX); // #7821 - ASSERT_THROW_INTERNAL(checkCode("x[y]"), SYNTAX); // #2986 - ASSERT_THROW_INTERNAL(checkCode("( ) &"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("|| #if #define <="), SYNTAX); // #2601 - ASSERT_THROW_INTERNAL(checkCode("f::y:y : \n"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("++4++ + + E++++++++++ + ch " "tp.oed5[.]"), SYNTAX); // #7074 - ASSERT_THROW_INTERNAL(checkCode("d a(){f s=0()8[]s?():0}*()?:0", false), SYNTAX); // #7236 - ASSERT_THROW_INTERNAL(checkCode("!2 : #h2 ?:", false), SYNTAX); // #7769 - ASSERT_THROW_INTERNAL(checkCode("--"), SYNTAX); - ASSERT_THROW_INTERNAL(checkCode("volatile true , test < test < #ifdef __ppc__ true ,"), SYNTAX); // #4169 + ASSERT_THROW_INTERNAL(checkCode("++4++ + + E++++++++++ + ch " "tp.oed5[.]\n"), SYNTAX); // #7074 + ASSERT_THROW_INTERNAL(checkCode("d a(){f s=0()8[]s?():0}*()?:0\n", false), SYNTAX); // #7236 + ASSERT_THROW_INTERNAL(checkCode("!2 : #h2 ?:\n", false), SYNTAX); // #7769 + ASSERT_THROW_INTERNAL(checkCode("--\n"), SYNTAX); + ASSERT_THROW_INTERNAL(checkCode("volatile true , test < test < #ifdef __ppc__ true ,\n"), SYNTAX); // #4169 ASSERT_THROW_INTERNAL(checkCode("a,b--\n"), SYNTAX); // #2847 - ASSERT_THROW_INTERNAL(checkCode("x a[0] ="), SYNTAX); // #2682 + ASSERT_THROW_INTERNAL(checkCode("x a[0] =\n"), SYNTAX); // #2682 ASSERT_THROW_INTERNAL(checkCode("auto_ptr\n"), SYNTAX); // #2967 ASSERT_THROW_INTERNAL(checkCode("char a[1]\n"), SYNTAX); // #2865 - ASSERT_THROW_INTERNAL(checkCode("<><<"), SYNTAX); // #2612 - ASSERT_THROW_INTERNAL(checkCode("z"), SYNTAX); // #2831 - ASSERT_THROW_INTERNAL(checkCode("><,f<<\n"), SYNTAX); // #2612 + ASSERT_THROW_INTERNAL(checkCode("z\n"), SYNTAX); // #2831 + ASSERT_THROW_INTERNAL(checkCode("><,f typedef name5 | ( , ;){ } (); }"), SYNTAX); // #9067 - ASSERT_THROW_INTERNAL(checkCode("void f() { x= {}( ) ( 'x')[ ] (); }"), SYNTAX); // #9068 - ASSERT_THROW_INTERNAL(checkCode("void f() { x= y{ } name5 y[ ] + y ^ name5 ^ name5 for ( ( y y y && y y y && name5 ++ int )); }"), SYNTAX); // #9069 + ASSERT_THROW_INTERNAL(checkCode("void f() { x= 'x' > typedef name5 | ( , ;){ } (); }\n"), SYNTAX); // #9067 + ASSERT_THROW_INTERNAL(checkCode("void f() { x= {}( ) ( 'x')[ ] (); }\n"), SYNTAX); // #9068 + ASSERT_THROW_INTERNAL(checkCode("void f() { x= y{ } name5 y[ ] + y ^ name5 ^ name5 for ( ( y y y && y y y && name5 ++ int )); }\n"), SYNTAX); // #9069 } void cliCode() { @@ -1848,12 +1862,12 @@ class TestGarbage : public TestFixture { "bool GetDeviceInformation(String ^ port, LibCECConfiguration ^configuration, uint32_t timeoutMs) {\n" "bool bReturn(false);\n" "}\n" - "};")); + "};\n")); ignore_errout(); // we are not interested in the output } void enumTrailingComma() { - ASSERT_THROW_INTERNAL(checkCode("enum ssl_shutdown_t {ssl_shutdown_none = 0,ssl_shutdown_close_notify = , } ;"), SYNTAX); // #8079 + ASSERT_THROW_INTERNAL(checkCode("enum ssl_shutdown_t {ssl_shutdown_none = 0,ssl_shutdown_close_notify = , } ;\n"), SYNTAX); // #8079 } void nonGarbageCode1() { @@ -1866,25 +1880,31 @@ class TestGarbage : public TestFixture { "template< class T >\n" "template< class Predicate > int\n" "List::DeleteIf( const Predicate &pred )\n" - "{}")); + "{}\n")); ignore_errout(); // we are not interested in the output // #8749 ASSERT_NO_THROW(checkCode( "struct A {\n" " void operator+=(A&) && = delete;\n" - "};")); + "};\n")); // #8788 ASSERT_NO_THROW(checkCode( "struct foo;\n" "void f() {\n" " auto fn = []() -> foo* { return new foo(); };\n" - "}")); + "}\n")); ignore_errout(); // we do not care about the output // #13892 - ASSERT_NO_THROW(checkCode("void foovm(int x[const *]);")); + ASSERT_NO_THROW(checkCode("void foovm(int x[const *]);\n")); + + // #14676 + ASSERT_NO_THROW(checkCode("int main() {\n" + " auto value = m[1 + qRow<>];\n" + "}\n")); + ignore_errout(); } }; diff --git a/test/testimportproject.cpp b/test/testimportproject.cpp index 493689f8a0c..873272030f6 100644 --- a/test/testimportproject.cpp +++ b/test/testimportproject.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,16 +28,21 @@ #include #include #include +#include #include #include #include -class TestImporter : public ImportProject { +class TestImporter final : public ImportProject { public: using ImportProject::importCompileCommands; using ImportProject::importCppcheckGuiProject; using ImportProject::importVcxproj; using ImportProject::SharedItemsProject; + using ImportProject::collectArgs; + using ImportProject::fsSetDefines; + using ImportProject::fsSetIncludePaths; + using ImportProject::setRelativePaths; }; @@ -52,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 @@ -65,29 +71,41 @@ class TestImportProject : public TestFixture { TEST_CASE(importCompileCommands11); // include path order TEST_CASE(importCompileCommands12); // #13040: "directory" is parent directory, relative include paths 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 TEST_CASE(importCompileCommandsDirectoryInvalid); // 'directory' field not a string TEST_CASE(importCppcheckGuiProject); + TEST_CASE(importCppcheckGuiProjectDuplicateSuppressions); TEST_CASE(importCppcheckGuiProjectPremiumMisra); TEST_CASE(ignorePaths); TEST_CASE(testVcxprojUnicode); + TEST_CASE(testCollectArgs1); + TEST_CASE(testCollectArgs2); + TEST_CASE(testCollectArgs3); + TEST_CASE(testCollectArgs4); + TEST_CASE(testCollectArgs5); + TEST_CASE(testCollectArgs6); + TEST_CASE(testCollectArgs7); + TEST_CASE(testVcxprojConditions); } void setDefines() const { FileSettings fs{"test.cpp", Standards::Language::CPP, 0}; - ImportProject::fsSetDefines(fs, "A"); + TestImporter::fsSetDefines(fs, "A"); ASSERT_EQUALS("A=1", fs.defines); - ImportProject::fsSetDefines(fs, "A;B;"); + TestImporter::fsSetDefines(fs, "A;B;"); ASSERT_EQUALS("A=1;B=1", fs.defines); - ImportProject::fsSetDefines(fs, "A;;B;"); + TestImporter::fsSetDefines(fs, "A;;B;"); ASSERT_EQUALS("A=1;B=1", fs.defines); - ImportProject::fsSetDefines(fs, "A;;B"); + TestImporter::fsSetDefines(fs, "A;;B"); ASSERT_EQUALS("A=1;B=1", fs.defines); } @@ -95,7 +113,7 @@ class TestImportProject : public TestFixture { FileSettings fs{"test.cpp", Standards::Language::CPP, 0}; std::list in(1, "../include"); std::map variables; - ImportProject::fsSetIncludePaths(fs, "abc/def/", in, variables); + TestImporter::fsSetIncludePaths(fs, "abc/def/", in, variables); ASSERT_EQUALS(1U, fs.includePaths.size()); ASSERT_EQUALS("abc/include/", fs.includePaths.front()); } @@ -105,7 +123,7 @@ class TestImportProject : public TestFixture { std::list in(1, "$(SolutionDir)other"); std::map variables; variables["SolutionDir"] = "c:/abc/"; - ImportProject::fsSetIncludePaths(fs, "/home/fred", in, variables); + TestImporter::fsSetIncludePaths(fs, "/home/fred", in, variables); ASSERT_EQUALS(1U, fs.includePaths.size()); ASSERT_EQUALS("c:/abc/other/", fs.includePaths.front()); } @@ -115,11 +133,23 @@ class TestImportProject : public TestFixture { std::list in(1, "$(SOLUTIONDIR)other"); std::map variables; variables["SolutionDir"] = "c:/abc/"; - ImportProject::fsSetIncludePaths(fs, "/home/fred", in, variables); + TestImporter::fsSetIncludePaths(fs, "/home/fred", in, variables); ASSERT_EQUALS(1U, fs.includePaths.size()); ASSERT_EQUALS("c:/abc/other/", fs.includePaths.front()); } + 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"([{ @@ -361,8 +391,69 @@ class TestImportProject : public TestFixture { ASSERT_EQUALS(2, importer.fileSettings.size()); const FileSettings &fs1 = importer.fileSettings.front(); const FileSettings &fs2 = importer.fileSettings.back(); - ASSERT_EQUALS(0, fs1.fileIndex); - ASSERT_EQUALS(1, fs2.fileIndex); + ASSERT_EQUALS(0, fs1.file.fsFileId()); + ASSERT_EQUALS(1, fs2.file.fsFileId()); + } + + void importCompileCommands14() const { // #14156 + REDIRECT; + constexpr char json[] = + R"([{ + "arguments": [ + "/usr/bin/g++", + "-DTFS_LINUX_MODULE_NAME=\"tfs_linux\"", + "-g", + "-c", + "cli/main.cpp" + ], + "directory": "/home/daniel/cppcheck", + "file": "/home/daniel/cppcheck/cli/main.cpp", + "output": "/home/daniel/cppcheck/cli/main.o" + }])"; + 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("TFS_LINUX_MODULE_NAME=\"tfs_linux\"", fs.defines); + } + + void importCompileCommands15() const { // #14306 + REDIRECT; + constexpr char json[] = + R"([ + { + "directory": "C:\\Users\\abcd\\efg\\hijk", + "command": "gcc \"-Ipath\\123\" \"-c\" test.c", + "file": "test.c", + "output": "test.obj" + } + ])"; + 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(1, fs.includePaths.size()); + 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 { @@ -385,7 +476,8 @@ class TestImportProject : public TestFixture { TestImporter importer; ASSERT_EQUALS(false, importer.importCompileCommands(istr)); ASSERT_EQUALS(0, importer.fileSettings.size()); - ASSERT_EQUALS("cppcheck: error: no 'arguments' or 'command' field found in compilation database entry\n", GET_REDIRECT_OUTPUT); + ASSERT_EQUALS(1, importer.errors.size()); + ASSERT_EQUALS("no 'arguments' or 'command' field found in compilation database entry", importer.errors[0]); } void importCompileCommandsDirectoryMissing() const { @@ -395,7 +487,8 @@ class TestImportProject : public TestFixture { TestImporter importer; ASSERT_EQUALS(false, importer.importCompileCommands(istr)); ASSERT_EQUALS(0, importer.fileSettings.size()); - ASSERT_EQUALS("cppcheck: error: 'directory' field in compilation database entry missing\n", GET_REDIRECT_OUTPUT); + ASSERT_EQUALS(1, importer.errors.size()); + ASSERT_EQUALS("'directory' field in compilation database entry missing", importer.errors[0]); } void importCompileCommandsDirectoryInvalid() const { @@ -406,7 +499,8 @@ class TestImportProject : public TestFixture { TestImporter importer; ASSERT_EQUALS(false, importer.importCompileCommands(istr)); ASSERT_EQUALS(0, importer.fileSettings.size()); - ASSERT_EQUALS("cppcheck: error: 'directory' field in compilation database entry is not a string\n", GET_REDIRECT_OUTPUT); + ASSERT_EQUALS(1, importer.errors.size()); + ASSERT_EQUALS("'directory' field in compilation database entry is not a string", importer.errors[0]); } void importCppcheckGuiProject() const { @@ -422,6 +516,7 @@ class TestImportProject : public TestFixture { " \n" " \n" " \n" + " gcc-macros.h\n" " \n" " \n" " \n" @@ -432,14 +527,36 @@ class TestImportProject : public TestFixture { Settings s; Suppressions supprs; TestImporter project; - ASSERT_EQUALS(true, project.importCppcheckGuiProject(istr, s, supprs, false)); + ASSERT_EQUALS(true, project.importCppcheckGuiProject(istr, s, supprs)); ASSERT_EQUALS(1, project.guiProject.pathNames.size()); ASSERT_EQUALS("cli/", project.guiProject.pathNames[0]); ASSERT_EQUALS(1, s.includePaths.size()); ASSERT_EQUALS("lib/", s.includePaths.front()); + ASSERT_EQUALS(1, s.userIncludes.size()); + ASSERT_EQUALS("gcc-macros.h", s.userIncludes.front()); ASSERT_EQUALS(true, s.inlineSuppressions); } + void importCppcheckGuiProjectDuplicateSuppressions() const { + REDIRECT; + constexpr char xml[] = "\n" + "\n" + " \n" + " test test\n" + " \n" + " uninitvar\n" + " uninitvar\n" + " \n" + "\n"; + std::istringstream istr(xml); + Settings s; + Suppressions supprs; + TestImporter project; + ASSERT_EQUALS(false, project.importCppcheckGuiProject(istr, s, supprs)); + ASSERT_EQUALS(1, project.errors.size()); + ASSERT_EQUALS("suppression 'uninitvar' already exists", project.errors[0]); + } + void importCppcheckGuiProjectPremiumMisra() const { REDIRECT; constexpr char xml[] = "\n" @@ -453,9 +570,10 @@ class TestImportProject : public TestFixture { ""; std::istringstream istr(xml); Settings s; + s.premium = true; Suppressions supprs; TestImporter project; - ASSERT_EQUALS(true, project.importCppcheckGuiProject(istr, s, supprs, true)); + ASSERT_EQUALS(true, project.importCppcheckGuiProject(istr, s, supprs)); ASSERT_EQUALS("--misra-c-2012", s.premiumArgs); ASSERT(s.addons.empty()); } @@ -530,28 +648,131 @@ class TestImportProject : public TestFixture { ASSERT_EQUALS(project.fileSettings.back().useMfc, true); } + void testCollectArgs1() const + { + std::vector args; + const std::string cmd = " gcc -o main main.c "; + const std::string error = TestImporter::collectArgs(cmd, args); + + ASSERT_EQUALS("", error); + ASSERT_EQUALS(4, args.size()); + ASSERT_EQUALS("gcc", args[0]); + ASSERT_EQUALS("-o", args[1]); + ASSERT_EQUALS("main", args[2]); + ASSERT_EQUALS("main.c", args[3]); + } + + void testCollectArgs2() const + { + std::vector args; + const std::string cmd = "gcc -o main \"directory with space\"/main.c"; + const std::string error = TestImporter::collectArgs(cmd, args); + + ASSERT_EQUALS("", error); + ASSERT_EQUALS(4, args.size()); + ASSERT_EQUALS("gcc", args[0]); + ASSERT_EQUALS("-o", args[1]); + ASSERT_EQUALS("main", args[2]); + ASSERT_EQUALS("directory with space/main.c", args[3]); + } + + void testCollectArgs3() const + { + std::vector args; + const std::string cmd = "gcc -o main directory\\ with\\ space/main.c"; + const std::string error = TestImporter::collectArgs(cmd, args); + + ASSERT_EQUALS("", error); + ASSERT_EQUALS(4, args.size()); + ASSERT_EQUALS("gcc", args[0]); + ASSERT_EQUALS("-o", args[1]); + ASSERT_EQUALS("main", args[2]); + ASSERT_EQUALS("directory with space/main.c", args[3]); + } + + void testCollectArgs4() const + { + std::vector args; + const std::string cmd = "gcc -o main \'directory with space\'/main.c"; + const std::string error = TestImporter::collectArgs(cmd, args); + + ASSERT_EQUALS("", error); + ASSERT_EQUALS(4, args.size()); + ASSERT_EQUALS("gcc", args[0]); + ASSERT_EQUALS("-o", args[1]); + ASSERT_EQUALS("main", args[2]); + ASSERT_EQUALS("directory with space/main.c", args[3]); + } + + void testCollectArgs5() const + { + std::vector args; + const std::string cmd = "gcc -o main directory_with_quote\\\"/main.c"; + const std::string error = TestImporter::collectArgs(cmd, args); + + ASSERT_EQUALS("", error); + ASSERT_EQUALS(4, args.size()); + ASSERT_EQUALS("gcc", args[0]); + ASSERT_EQUALS("-o", args[1]); + ASSERT_EQUALS("main", args[2]); + ASSERT_EQUALS("directory_with_quote\"/main.c", args[3]); + } + + void testCollectArgs6() const + { + std::vector args; + const std::string cmd = "gcc -o main windows\\\\path\\\\main.c"; + const std::string error = TestImporter::collectArgs(cmd, args); + + ASSERT_EQUALS("", error); + ASSERT_EQUALS(4, args.size()); + ASSERT_EQUALS("gcc", args[0]); + ASSERT_EQUALS("-o", args[1]); + ASSERT_EQUALS("main", args[2]); + ASSERT_EQUALS("windows\\path\\main.c", args[3]); + } + + void testCollectArgs7() const + { + std::vector args; + const std::string cmd = "gcc -o main \"non-terminated-quote/main.c"; + const std::string error = TestImporter::collectArgs(cmd, args); + + ASSERT_EQUALS("Missing closing quote in command string", error); + } + + void testVcxprojConditions() const + { + ASSERT(cppcheck::testing::evaluateVcxprojCondition("'$(Configuration)'=='Debug'", "Debug", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition("'$(Platform)'=='Win32'", "Debug", "Win32")); + ASSERT(!cppcheck::testing::evaluateVcxprojCondition("'$(Configuration)'=='Release'", "Debug", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition(" '$(Configuration)' == 'Debug' ", "Debug", "Win32")); + ASSERT(!cppcheck::testing::evaluateVcxprojCondition(" '$(Configuration)' != 'Debug' ", "Debug", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition("'$(Configuration)|$(Platform)' == 'Debug|Win32' ", "Debug", "Win32")); + ASSERT(!cppcheck::testing::evaluateVcxprojCondition("!('$(Configuration)|$(Platform)' == 'Debug|Win32' )", "Debug", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition(" '$(Configuration)' == 'Debug' And '$(Platform)' == 'Win32'", "Debug", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition(" '$(Configuration)' == 'Debug' Or '$(Platform)' == 'Win32'", "Release", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition(" $(Configuration.StartsWith('Debug'))", "Debug-AddressSanitizer", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition(" $(Configuration.EndsWith('AddressSanitizer'))", "Debug-AddressSanitizer", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition(" $(Configuration.Contains('Address'))", "Debug-AddressSanitizer", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition(" $(Configuration.Contains ( 'Address' ) )", "Debug-AddressSanitizer", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition(" $(Configuration.Contains('Address')) And '$(Platform)' == 'Win32'", "Debug-AddressSanitizer", "Win32")); + ASSERT(cppcheck::testing::evaluateVcxprojCondition(" ($(Configuration.Contains('Address')) ) And ( '$(Platform)' == 'Win32')", "Debug-AddressSanitizer", "Win32")); + ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("And", "", ""), std::runtime_error, "Invalid condition: 'And'"); + ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("Or", "", ""), std::runtime_error, "Invalid condition: 'Or'"); + ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("!", "", ""), std::runtime_error, "Invalid condition: '!'"); + ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("'' == '' And ", "", ""), std::runtime_error, "Missing operator"); + ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("('' == ''", "", ""), std::runtime_error, "'(' without closing ')'!"); + ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("'' == '')", "", ""), std::runtime_error, "unmatched ')' in condition '' == '')"); + ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("''", "", ""), std::runtime_error, "Invalid condition: ''''"); + ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("'' == '", "", ""), std::runtime_error, "Can not tokenize condition"); + ASSERT_THROW_EQUALS(cppcheck::testing::evaluateVcxprojCondition("$(Configuration.Lower())", "", ""), std::runtime_error, "Missing operator"); + // invalid expression in => no error. We are ok with that as long as we don't crash + ASSERT(!cppcheck::testing::evaluateVcxprojCondition("' ' && ' '", "", "")); + } + // TODO: test fsParseCommand() - // TODO: test vcxproj conditions - /* - - - - - Debug - x64 - - - - - CPPCHECKLIB_IMPORT - - - - - - - */ }; REGISTER_TEST(TestImportProject) diff --git a/test/testincompletestatement.cpp b/test/testincompletestatement.cpp index 1ac971b3497..8e523e3d06e 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 @@ -22,6 +22,7 @@ #include "settings.h" #include "fixture.h" +#include #include class TestIncompleteStatement : public TestFixture { @@ -34,7 +35,6 @@ class TestIncompleteStatement : public TestFixture { struct CheckOptions { - CheckOptions() = default; bool inconclusive = false; bool cpp = true; }; @@ -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(); } @@ -93,7 +93,7 @@ class TestIncompleteStatement : public TestFixture { "{\n" " const char def[] =\n" " \"abc\";\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -102,7 +102,7 @@ class TestIncompleteStatement : public TestFixture { check("void foo()\n" "{\n" " \"abc\";\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (warning) Redundant code: Found a statement that begins with string constant. [constStatement]\n", errout_str()); } @@ -111,7 +111,7 @@ class TestIncompleteStatement : public TestFixture { check("void foo()\n" "{\n" " const char *str[] = { \"abc\" };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -125,7 +125,7 @@ class TestIncompleteStatement : public TestFixture { "\"more \"\n" "\"world\"\n" "};\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -134,7 +134,7 @@ class TestIncompleteStatement : public TestFixture { check("void foo()\n" "{\n" " 50;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (warning) Redundant code: Found a statement that begins with numeric constant. [constStatement]\n", errout_str()); } @@ -145,7 +145,7 @@ class TestIncompleteStatement : public TestFixture { " 1 == (two + three);\n" " 2 != (two + three);\n" " (one + two) != (two + three);\n" - "}"); + "}\n"); } void test7() { // #9335 @@ -160,7 +160,7 @@ class TestIncompleteStatement : public TestFixture { " for (C c(S); ; ) {\n" " (void)c;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -174,22 +174,38 @@ class TestIncompleteStatement : public TestFixture { " {\n" " { 346.1,114.1 }, { 347.1,111.1 }\n" " };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } 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; }\n"); + 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; }"); + "void f() { X; }\n"); ASSERT_EQUALS("", errout_str()); } void intarray() { - check("int arr[] = { 100/2, 1*100 };"); + check("int arr[] = { 100/2, 1*100 };\n"); ASSERT_EQUALS("", errout_str()); } @@ -197,7 +213,7 @@ class TestIncompleteStatement : public TestFixture { check("struct st arr[] = {\n" " { 100/2, 1*100 }\n" " { 90, 70 }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -205,14 +221,14 @@ class TestIncompleteStatement : public TestFixture { check("struct st arr[] = {\n" " { 100/2, 1*100 }\n" " { 90, 70 }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } void conditionalcall() { check("void f() {\n" " 0==x ? X() : Y();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -220,7 +236,7 @@ class TestIncompleteStatement : public TestFixture { // #2462 - C++11 struct initialization check("void f() {\n" " ABC abc{1,2,3};\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #6260 - C++11 array initialization @@ -228,30 +244,30 @@ class TestIncompleteStatement : public TestFixture { " static const char* a[][2] {\n" " {\"b\", \"\"},\n" " };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #2482 - false positive for empty struct - check("struct A {};"); + check("struct A {};\n"); ASSERT_EQUALS("", errout_str()); // #4387 - C++11 initializer list - check("A::A() : abc{0} {}"); + check("A::A() : abc{0} {}\n"); ASSERT_EQUALS("", errout_str()); // #5042 - C++11 initializer list - check("A::A() : abc::def{0} {}"); + check("A::A() : abc::def{0} {}\n"); ASSERT_EQUALS("", errout_str()); // #4503 - vector init - check("void f() { vector v{1}; }"); + check("void f() { vector v{1}; }\n"); ASSERT_EQUALS("", errout_str()); } void returnstruct() { check("struct s foo() {\n" " return (struct s){0,0};\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #4754 @@ -260,19 +276,19 @@ class TestIncompleteStatement : public TestFixture { " {\"hi\", \"there\"},\n" " {\"happy\", \"sad\"}\n" " };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct s foo() {\n" " return (struct s){0};\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void cast() { check("void f() {\n" " ((struct foo *)(0x1234))->xy = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("bool f(const std::exception& e) {\n" // #10918 @@ -291,14 +307,14 @@ class TestIncompleteStatement : public TestFixture { check("void f() {\n" " int x = 1;\n" " x++, x++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void cpp11init() { check("void f() {\n" " int x{1};\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("std::vector f(int* p) {\n" @@ -310,7 +326,7 @@ class TestIncompleteStatement : public TestFixture { void cpp11init2() { check("x handlers{\n" " { \"mode2\", []() { return 2; } },\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -318,33 +334,33 @@ class TestIncompleteStatement : public TestFixture { check("struct A { void operator()(int); };\n" "void f() {\n" "A{}(0);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("template struct A { void operator()(int); };\n" "void f() {\n" "A{}(0);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void block() { check("void f() {\n" " ({ do_something(); 0; });\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" "out:\n" " ({ do_something(); 0; });\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void mapindex() { check("void f() {\n" " map[{\"1\",\"2\"}]=0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -352,7 +368,7 @@ class TestIncompleteStatement : public TestFixture { check("void foo(int,const char*,int);\n" // #8827 "void f(int value) {\n" " foo(42,\"test\",42),(value&42);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:22]: (warning) Found suspicious operator ',', result is not used. [constStatement]\n", errout_str()); check("int f() {\n" // #11257 @@ -432,22 +448,22 @@ 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()); - check("void f1(int x) { x; }", dinit(CheckOptions, $.inconclusive = true)); + check("void f1(int x) { x; }\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:1:18]: (warning) Unused variable value 'x' [constStatement]\n", errout_str()); - check("void f() { if (Type t; g(t)) {} }"); // #9776 + check("void f() { if (Type t; g(t)) {} }\n"); // #9776 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()); + check("void f(int x) { static_cast(x); }\n"); + 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" @@ -457,7 +473,7 @@ class TestIncompleteStatement : public TestFixture { "}\n"); ASSERT_EQUALS("", errout_str()); - check("void f() { false; }"); // #10856 + check("void f() { false; }\n"); // #10856 ASSERT_EQUALS("[test.cpp:1:12]: (warning) Redundant code: Found a statement that begins with bool constant. [constStatement]\n", errout_str()); check("void f(int i) {\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 '(T)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 @@ -750,59 +766,72 @@ class TestIncompleteStatement : public TestFixture { " g();\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("struct S;\n" // #14664 + "S* a[1];\n" + "void f() {\n" + " a[0];\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:6]: (warning) Redundant code: Found unused array access. [constStatement]\n", + errout_str()); + + check("int f(int i) {\n" // #14889 + " return i ? 8 : ({ int x = 2; x; });\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void vardecl() { // #8984 - check("void f() { a::b *c = d(); }", dinit(CheckOptions, $.inconclusive = true)); + check("void f() { a::b *c = d(); }\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); - check("void f() { std::vector *c; }", dinit(CheckOptions, $.inconclusive = true)); + check("void f() { std::vector *c; }\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); - check("void f() { a::b &c = d(); }", dinit(CheckOptions, $.inconclusive = true)); + check("void f() { a::b &c = d(); }\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); - check("void f() { std::vector &c; }", dinit(CheckOptions, $.inconclusive = true)); + check("void f() { std::vector &c; }\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); - check("void f() { a::b &&c = d(); }", dinit(CheckOptions, $.inconclusive = true)); + check("void f() { a::b &&c = d(); }\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); - check("void f() { std::vector &&c; }", dinit(CheckOptions, $.inconclusive = true)); + check("void f() { std::vector &&c; }\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); - check("void f() { char * const * a, * const * b; }", dinit(CheckOptions, $.inconclusive = true)); + check("void f() { char * const * a, * const * b; }\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); - check("void f() { char * const * a = 0, * volatile restrict * b; }", dinit(CheckOptions, $.inconclusive = true, $.cpp = false)); + check("void f() { char * const * a = 0, * volatile restrict * b; }\n", dinit(CheckOptions, $.inconclusive = true, $.cpp = false)); ASSERT_EQUALS("", errout_str()); - check("void f() { char * const * a = 0, * volatile const * b; }", dinit(CheckOptions, $.inconclusive = true)); + check("void f() { char * const * a = 0, * volatile const * b; }\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } void archive() { check("void f(Archive &ar) {\n" " ar & x;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f(int ar) {\n" " ar & x;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2:6]: (warning, inconclusive) Found suspicious operator '&', result is not used. [constStatement]\n", errout_str()); } void ast() { - check("struct c { void a() const { for (int x=0; x;); } };", dinit(CheckOptions, $.inconclusive = true)); + check("struct c { void a() const { for (int x=0; x;); } };\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } void oror() { check("void foo() {\n" " params_given (params, \"overrides\") || (overrides = \"1\");\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f(std::ifstream& file) {\n" // #10930 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 609edd81fe8..ad95345e1fd 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); @@ -86,7 +89,6 @@ class TestIO : public TestFixture { struct CheckOptions { - CheckOptions() = default; bool inconclusive = false; bool portability = false; Platform::Type platform = Platform::Type::Unspecified; @@ -110,61 +112,62 @@ 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() { check( "void foo() {\n" " std::cout << std::cout;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:3]: (error) Invalid usage of output stream: '<< std::cout'. [coutCerrMisusage]\n", errout_str()); check( "void foo() {\n" " std::cout << (std::cout);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:3]: (error) Invalid usage of output stream: '<< std::cout'. [coutCerrMisusage]\n", errout_str()); check( "void foo() {\n" " std::cout << \"xyz\" << std::cout;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:3]: (error) Invalid usage of output stream: '<< std::cout'. [coutCerrMisusage]\n", errout_str()); check( "void foo(int i) {\n" " std::cout << i << std::cerr;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:3]: (error) Invalid usage of output stream: '<< std::cerr'. [coutCerrMisusage]\n", errout_str()); check( "void foo() {\n" " std::cout << \"xyz\";\n" " std::cout << \"xyz\";\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check( "void foo() {\n" " std::cout << std::cout.good();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check( "void foo() {\n" " unknownObject << std::cout;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check( "void foo() {\n" " MACRO(std::cout <<, << std::cout)\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -177,7 +180,7 @@ class TestIO : public TestFixture { " fread(buffer, 5, 6, f);\n" " rewind(f);\n" " fwrite(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:5]: (error) Write operation on a file that was opened only for reading. [writeReadOnlyFile]\n", errout_str()); check("void foo(FILE*& f) {\n" @@ -185,7 +188,7 @@ class TestIO : public TestFixture { " fread(buffer, 5, 6, f);\n" " rewind(f);\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); ASSERT_EQUALS("[test.cpp:5:5]: (error) Write operation on a file that was opened only for reading. [writeReadOnlyFile]\n", errout_str()); check("void foo(FILE*& f) {\n" @@ -193,7 +196,7 @@ class TestIO : public TestFixture { " fread(buffer, 5, 6, f);\n" " rewind(f);\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32A)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32A)); ASSERT_EQUALS("[test.cpp:5:5]: (error) Write operation on a file that was opened only for reading. [writeReadOnlyFile]\n", errout_str()); check("void foo(FILE*& f) {\n" @@ -201,7 +204,7 @@ class TestIO : public TestFixture { " fread(buffer, 5, 6, f);\n" " rewind(f);\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); ASSERT_EQUALS("[test.cpp:5:5]: (error) Write operation on a file that was opened only for reading. [writeReadOnlyFile]\n", errout_str()); check("void foo(FILE*& f) {\n" @@ -209,7 +212,7 @@ class TestIO : public TestFixture { " fread(buffer, 5, 6, f);\n" " rewind(f);\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); ASSERT_EQUALS("[test.cpp:5:5]: (error) Write operation on a file that was opened only for reading. [writeReadOnlyFile]\n", errout_str()); check("void foo(FILE*& f) {\n" @@ -217,7 +220,7 @@ class TestIO : public TestFixture { " fread(buffer, 5, 6, f);\n" " rewind(f);\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32A)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32A)); ASSERT_EQUALS("[test.cpp:5:5]: (error) Write operation on a file that was opened only for reading. [writeReadOnlyFile]\n", errout_str()); check("void foo(FILE*& f) {\n" @@ -225,55 +228,55 @@ class TestIO : public TestFixture { " fread(buffer, 5, 6, f);\n" " rewind(f);\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); ASSERT_EQUALS("[test.cpp:5:5]: (error) Write operation on a file that was opened only for reading. [writeReadOnlyFile]\n", errout_str()); check("void foo(FILE*& f) {\n" " f = fopen(name, \"r+\");\n" " fwrite(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(FILE*& f) {\n" " f = _wfopen(name, L\"r+\");\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); ASSERT_EQUALS("", errout_str()); check("void foo(FILE*& f) {\n" " f = _tfopen(name, _T(\"r+\"));\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32A)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32A)); ASSERT_EQUALS("", errout_str()); check("void foo(FILE*& f) {\n" " f = _tfopen(name, _T(\"r+\"));\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); ASSERT_EQUALS("", errout_str()); check("void foo(FILE*& f) {\n" " _wfopen_s(&f, name, L\"r+\");\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); ASSERT_EQUALS("", errout_str()); check("void foo(FILE*& f) {\n" " _tfopen_s(&f, name, _T(\"r+\"));\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32A)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32A)); ASSERT_EQUALS("", errout_str()); check("void foo(FILE*& f) {\n" " _tfopen_s(&f, name, _T(\"r+\"));\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); ASSERT_EQUALS("", errout_str()); check("void foo(FILE*& f) {\n" " f = tmpfile();\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); ASSERT_EQUALS("", errout_str()); // Write mode @@ -282,19 +285,19 @@ class TestIO : public TestFixture { " fwrite(buffer, 5, 6, f);\n" " rewind(f);\n" " fread(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:5]: (error) Read operation on a file that was opened only for writing. [readWriteOnlyFile]\n", errout_str()); check("void foo(FILE*& f) {\n" " f = fopen(name, \"w+\");\n" " fread(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(FILE*& f) {\n" " f = tmpfile();\n" " fread(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Append mode @@ -303,14 +306,14 @@ class TestIO : public TestFixture { " fwrite(buffer, 5, 6, f);\n" " rewind(f);\n" " fread(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) Repositioning operation performed on a file opened in append mode has no effect. [seekOnAppendedFile]\n" "[test.cpp:5:5]: (error) Read operation on a file that was opened only for writing. [readWriteOnlyFile]\n", errout_str()); check("void foo(FILE*& f) {\n" " f = fopen(name, \"a+\");\n" " fread(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Variable declared locally @@ -318,7 +321,7 @@ class TestIO : public TestFixture { " FILE* f = fopen(name, \"r\");\n" " fwrite(buffer, 5, 6, f);\n" " fclose(f);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Write operation on a file that was opened only for reading. [writeReadOnlyFile]\n", errout_str()); // Call unknown function @@ -327,60 +330,60 @@ class TestIO : public TestFixture { " fwrite(buffer, 5, 6, f);\n" " bar(f);\n" " fread(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // freopen and tmpfile check("void foo(FILE*& f) {\n" " f = freopen(name, \"r\", f);\n" " fwrite(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Write operation on a file that was opened only for reading. [writeReadOnlyFile]\n", errout_str()); check("void foo(FILE*& f) {\n" " f = _wfreopen(name, L\"r\", f);\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); ASSERT_EQUALS("[test.cpp:3:5]: (error) Write operation on a file that was opened only for reading. [writeReadOnlyFile]\n", errout_str()); check("void foo(FILE*& f) {\n" " f = _tfreopen(name, _T(\"r\"), f);\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32A)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32A)); ASSERT_EQUALS("[test.cpp:3:5]: (error) Write operation on a file that was opened only for reading. [writeReadOnlyFile]\n", errout_str()); check("void foo(FILE*& f) {\n" " f = _tfreopen(name, _T(\"r\"), f);\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); ASSERT_EQUALS("[test.cpp:3:5]: (error) Write operation on a file that was opened only for reading. [writeReadOnlyFile]\n", errout_str()); check("void foo(FILE*& f) {\n" " f = _wfreopen_s(&f, name, L\"r\", f);\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); ASSERT_EQUALS("[test.cpp:3:5]: (error) Write operation on a file that was opened only for reading. [writeReadOnlyFile]\n", errout_str()); check("void foo(FILE*& f) {\n" " f = _tfreopen_s(&f, name, _T(\"r\"), f);\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32A)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32A)); ASSERT_EQUALS("[test.cpp:3:5]: (error) Write operation on a file that was opened only for reading. [writeReadOnlyFile]\n", errout_str()); check("void foo(FILE*& f) {\n" " f = _tfreopen_s(&f, name, _T(\"r\"), f);\n" " fwrite(buffer, 5, 6, f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); ASSERT_EQUALS("[test.cpp:3:5]: (error) Write operation on a file that was opened only for reading. [writeReadOnlyFile]\n", errout_str()); // Crash tests check("void foo(FILE*& f) {\n" " f = fopen(name, mode);\n" // No assertion failure (#3830) " fwrite(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); - check("void fopen(std::string const &filepath, std::string const &mode);"); // #3832 + check("void fopen(std::string const &filepath, std::string const &mode);\n"); // #3832 } void wrongMode_complex() { @@ -389,7 +392,7 @@ class TestIO : public TestFixture { " else f = fopen(name, \"r\");\n" " if(a) fwrite(buffer, 5, 6, f);\n" " else fread(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" @@ -398,14 +401,14 @@ class TestIO : public TestFixture { " else f = fopen(name, \"r\");\n" " if(a) fwrite(buffer, 5, 6, f);\n" " else fread(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " FILE* f = fopen(name, \"w\");\n" " if(a) fwrite(buffer, 5, 6, f);\n" " else fread(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:11]: (error) Read operation on a file that was opened only for writing. [readWriteOnlyFile]\n", errout_str()); } @@ -418,7 +421,7 @@ class TestIO : public TestFixture { " ungetc('a', f);\n" " ungetwc(L'a', f);\n" " rewind(f);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Used file that is not opened. [useClosedFile]\n" "[test.cpp:4:5]: (error) Used file that is not opened. [useClosedFile]\n" "[test.cpp:5:5]: (error) Used file that is not opened. [useClosedFile]\n" @@ -432,40 +435,40 @@ class TestIO : public TestFixture { " return;" " }\n" " fwrite(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(FILE*& f) {\n" " fclose(f);\n" " f = fopen(name, \"r\");\n" " fread(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(FILE*& f) {\n" " f = fopen(name, \"r\");\n" " f = g;\n" " fwrite(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " FILE* f;\n" " fwrite(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Used file that is not opened. [useClosedFile]\n", errout_str()); check("void foo() {\n" " FILE* f(stdout);\n" " fwrite(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" // #3965 " FILE* f[3];\n" " f[0] = fopen(name, mode);\n" " fclose(f[0]);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #4368: multiple functions @@ -488,7 +491,7 @@ class TestIO : public TestFixture { " dump();\n" " close();\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("static FILE *fp = NULL;\n" @@ -502,7 +505,7 @@ class TestIO : public TestFixture { "{\n" " fclose(fp);\n" " fprintf(fp, \"Here's the output.\\n\");\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:11:3]: (error) Used file that is not opened. [useClosedFile]\n", errout_str()); // #4466 @@ -515,7 +518,7 @@ class TestIO : public TestFixture { " fclose(infile);\n" " return;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void chdcd_parse_nero(FILE *infile) {\n" @@ -527,7 +530,7 @@ class TestIO : public TestFixture { " fclose(infile);\n" " return;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #4649 @@ -537,15 +540,37 @@ class TestIO : public TestFixture { " a.f2 = fopen(name,mode);\n" " fclose(a.f1);\n" " fclose(a.f2);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #1473 check("void foo() {\n" " 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()); + "}\n"); + 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" + "}\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" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void foo() {\n" + " FILE *a = fopen(\"aa\", \"r\");\n" + " do {} while (fclose(a));\n" + "}\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" @@ -554,7 +579,7 @@ class TestIO : public TestFixture { " f[1] = fopen(\"2\", \"w\");\n" " fclose(f[0]);\n" " fclose(f[1]);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #12236 @@ -570,13 +595,13 @@ class TestIO : public TestFixture { check("void foo(FILE* f) {\n" " fwrite(buffer, 5, 6, f);\n" " fread(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3: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("void foo(FILE* f) {\n" " fread(buffer, 5, 6, f);\n" " fwrite(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3: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("void foo(FILE* f, bool read) {\n" @@ -584,42 +609,42 @@ class TestIO : public TestFixture { " fread(buffer, 5, 6, f);\n" " else\n" " fwrite(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(FILE* f) {\n" " fread(buffer, 5, 6, f);\n" " fflush(f);\n" " fwrite(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(FILE* f) {\n" " fread(buffer, 5, 6, f);\n" " rewind(f);\n" " fwrite(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(FILE* f) {\n" " fread(buffer, 5, 6, f);\n" " fsetpos(f, pos);\n" " fwrite(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(FILE* f) {\n" " fread(buffer, 5, 6, f);\n" " fseek(f, 0, SEEK_SET);\n" " fwrite(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(FILE* f) {\n" " fread(buffer, 5, 6, f);\n" " long pos = ftell(f);\n" " fwrite(buffer, 5, 6, f);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4: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()); // #6452 - member functions @@ -632,7 +657,7 @@ class TestIO : public TestFixture { " int bytesRead = fread(aboutToOverwrite.data(), 1, bufferLength, d->file);\n" " seek(writePosition);\n" " fwrite(buffer.data(), sizeof(char), buffer.size(), d->file);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class FileStream {\n" @@ -643,7 +668,7 @@ class TestIO : public TestFixture { " int bytesRead = fread(aboutToOverwrite.data(), 1, bufferLength, d->file);\n" " unknown(writePosition);\n" " fwrite(buffer.data(), sizeof(char), buffer.size(), d->file);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class FileStream {\n" @@ -655,7 +680,7 @@ class TestIO : public TestFixture { " int bytesRead = fread(aboutToOverwrite.data(), 1, bufferLength, d->file);\n" " known(writePosition);\n" " fwrite(buffer.data(), sizeof(char), buffer.size(), d->file);\n" - "}"); + "}\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("class FileStream {\n" @@ -667,33 +692,50 @@ class TestIO : public TestFixture { " int bytesRead = fread(X::data(), 1, bufferLength, d->file);\n" " known(writePosition);\n" " fwrite(X::data(), sizeof(char), buffer.size(), d->file);\n" - "}"); + "}\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() { check("void foo() {\n" " FILE* f = fopen(\"\", \"a+\");\n" " fseek(f, 0, SEEK_SET);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " FILE* f = fopen(\"\", \"w\");\n" " fseek(f, 0, SEEK_SET);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " FILE* f = fopen(\"\", \"a\");\n" " fseek(f, 0, SEEK_SET);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (warning) Repositioning operation performed on a file opened in append mode has no effect. [seekOnAppendedFile]\n", errout_str()); check("void foo() {\n" " FILE* f = fopen(\"\", \"a\");\n" " fflush(f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #5578 check("void foo() {\n" @@ -701,38 +743,54 @@ class TestIO : public TestFixture { " fclose(f);\n" " f = fopen(\"\", \"r\");\n" " fseek(f, 0, SEEK_SET);\n" - "}"); + "}\n"); 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" " fflush(stdin);\n" - "}", dinit(CheckOptions, $.portability = true)); + "}\n", dinit(CheckOptions, $.portability = true)); ASSERT_EQUALS("[test.cpp:3:5]: (portability) fflush() called on input stream 'stdin' may result in undefined behaviour on non-linux systems. [fflushOnInputStream]\n", errout_str()); check("void foo()\n" "{\n" " fflush(stdout);\n" - "}", dinit(CheckOptions, $.portability = true)); + "}\n", dinit(CheckOptions, $.portability = true)); ASSERT_EQUALS("", errout_str()); check("void foo(FILE*& f) {\n" " f = fopen(path, \"r\");\n" " fflush(f);\n" - "}", dinit(CheckOptions, $.portability = true)); + "}\n", dinit(CheckOptions, $.portability = true)); ASSERT_EQUALS("[test.cpp:3:5]: (portability) fflush() called on input stream 'f' may result in undefined behaviour on non-linux systems. [fflushOnInputStream]\n", errout_str()); check("void foo(FILE*& f) {\n" " f = fopen(path, \"w\");\n" " fflush(f);\n" - "}", dinit(CheckOptions, $.portability = true)); + "}\n", dinit(CheckOptions, $.portability = true)); ASSERT_EQUALS("", errout_str()); check("void foo(FILE*& f) {\n" " fflush(f);\n" - "}", dinit(CheckOptions, $.portability = true)); + "}\n", dinit(CheckOptions, $.portability = true)); ASSERT_EQUALS("", errout_str()); } @@ -740,10 +798,59 @@ class TestIO : public TestFixture { check("void foo() {\n" " FILE *f1 = fopen(\"tmp\", \"wt\");\n" " FILE *f2 = fopen(\"tmp\", \"rt\");\n" - "}"); + "}\n"); 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" + "}\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" + "}\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" + "}\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" + "}\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" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void testScanf1() { check("void foo() {\n" @@ -755,7 +862,7 @@ class TestIO : public TestFixture { " sscanf(foo, \"%[^~]\", bar);\n" " scanf(\"%dx%s\", &b, bar);\n" " fclose(file);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9]: (warning) fscanf() without field width limits can crash with huge input data. [invalidscanf]\n" "[test.cpp:5:9]: (warning) scanf() without field width limits can crash with huge input data. [invalidscanf]\n" "[test.cpp:6:9]: (warning) scanf() without field width limits can crash with huge input data. [invalidscanf]\n" @@ -771,7 +878,7 @@ class TestIO : public TestFixture { " scanf(\"aa%d\", &a);\n" // No %s " scanf(\"aa%ld\", &a);\n" // No %s " scanf(\"%*[^~]\");\n" // Ignore input - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) scanf format string requires 0 parameters but 1 is given. [wrongPrintfScanfArgNum]\n", errout_str()); } @@ -781,7 +888,7 @@ class TestIO : public TestFixture { " scanf(\"%7c\", str);\n" " scanf(\"%8c\", str);\n" " scanf(\"%9c\", str);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:3]: (error) Width 9 given in format string (no. 1) is larger than destination buffer 'str[8]', use %8c to prevent overflowing it. [invalidScanfFormatWidth]\n", errout_str()); } @@ -790,7 +897,7 @@ class TestIO : public TestFixture { "{\n" " char str [8];\n" " scanf (\"%70s\",str);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:3]: (error) Width 70 given in format string (no. 1) is larger than destination buffer 'str[8]', use %7s to prevent overflowing it. [invalidScanfFormatWidth]\n", errout_str()); } @@ -798,14 +905,22 @@ class TestIO : public TestFixture { check("char s1[42], s2[42];\n" "void test() {\n" " scanf(\"%42s%42[a-z]\", s1, s2);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Width 42 given in format string (no. 1) is larger than destination buffer 's1[42]', use %41s to prevent overflowing it. [invalidScanfFormatWidth]\n" "[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);}" + "void f(){" type " x; scanf(\"" format "\", &x);}\n" #define TEST_SCANF_ERR(format, formatStr, type) \ "[test.c:1]: (warning) " format " in format string (no. 1) requires '" formatStr " *' but the argument type is '" type " *'.\n" @@ -820,7 +935,7 @@ class TestIO : public TestFixture { TEST_SCANF_ERR_AKA_("test.cpp", format, formatStr, type, akaType) #define TEST_PRINTF_CODE(format, type) \ - "void f(" type " x){printf(\"" format "\", x);}" + "void f(" type " x){printf(\"" format "\", x);}\n" #define TEST_PRINTF_ERR(format, requiredType, actualType) \ "[test.c:1]: (warning) " format " in format string (no. 1) requires '" requiredType "' but the argument type is '" actualType "'.\n" @@ -959,7 +1074,7 @@ class TestIO : public TestFixture { " scanf(\"%*1x %1x %29s\", &count, KeyName);\n" // #3373 " fscanf(f, \"%7ms\", &ref);\n" // #3461 " sscanf(ip_port, \"%*[^:]:%4d\", &port);\n" // #3468 - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" @@ -967,7 +1082,7 @@ class TestIO : public TestFixture { " scanf(\"%1d\", &foo, &bar);\n" " fscanf(bar, \"%1d\", &foo, &bar);\n" " scanf(\"%*1x %1x %29s\", &count, KeyName, foo);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) scanf format string requires 0 parameters but 1 is given.\n" "[test.cpp:3]: (warning) scanf format string requires 1 parameter but 2 are given.\n" "[test.cpp:4]: (warning) fscanf format string requires 1 parameter but 2 are given.\n" @@ -978,7 +1093,7 @@ class TestIO : public TestFixture { " scanf(\"%1u%1u\", bar());\n" " sscanf(bar, \"%1d%1d\", &foo);\n" " scanf(\"%*1x %1x %29s\", &count);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (error) scanf format string requires 1 parameter but only 0 are given.\n" "[test.cpp:3]: (error) scanf format string requires 2 parameters but only 1 is given.\n" "[test.cpp:4]: (error) sscanf format string requires 2 parameters but only 1 is given.\n" @@ -990,7 +1105,7 @@ class TestIO : public TestFixture { " sscanf(input, \"%3s\", output);\n" " sscanf(input, \"%4s\", output);\n" " sscanf(input, \"%5s\", output);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6]: (error) Width 5 given in format string (no. 1) is larger than destination buffer 'output[5]', use %4s to prevent overflowing it.\n", errout_str()); check("void foo() {\n" @@ -1000,7 +1115,7 @@ class TestIO : public TestFixture { " sscanf(input, \"%3s\", output);\n" " sscanf(input, \"%4s\", output);\n" " sscanf(input, \"%5s\", output);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:5]: (warning, inconclusive) Width 3 given in format string (no. 1) is smaller than destination buffer 'output[5]'.\n" "[test.cpp:7]: (error) Width 5 given in format string (no. 1) is larger than destination buffer 'output[5]', use %4s to prevent overflowing it.\n" "[test.cpp:4]: (warning) sscanf() without field width limits can crash with huge input data.\n", errout_str()); @@ -1012,7 +1127,7 @@ class TestIO : public TestFixture { " bufT projectId= {0};\n" " const int scanrc=sscanf(line, \"Project(\\\"{%36s}\\\")\", projectId);\n" " sscanf(input, \"%5s\", output);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:6]: (warning, inconclusive) Width 36 given in format string (no. 1) is smaller than destination buffer 'projectId[2048]'.\n", errout_str()); check("void foo(unsigned int i) {\n" @@ -1025,7 +1140,7 @@ class TestIO : public TestFixture { " scanf(\"%t\", &i);\n" " scanf(\"%L\", &i);\n" " scanf(\"%I\", &i);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) 'h' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n" "[test.cpp:3]: (warning) 'hh' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n" "[test.cpp:4]: (warning) 'l' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n" @@ -1081,13 +1196,13 @@ class TestIO : public TestFixture { check("void foo() {\n" " scanf(\"%u\", \"s3\");\n" " scanf(\"%u\", L\"s5W\");\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2]: (warning) %u in format string (no. 1) requires 'unsigned int *' but the argument type is 'const char *'.\n" "[test.cpp:3]: (warning) %u in format string (no. 1) requires 'unsigned int *' but the argument type is 'const wchar_t *'.\n", errout_str()); check("void foo(long l) {\n" " scanf(\"%u\", l);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2]: (warning) %u in format string (no. 1) requires 'unsigned int *' but the argument type is 'signed long'.\n", errout_str()); TEST_SCANF_WARN("%lu","unsigned long","bool"); @@ -1469,13 +1584,13 @@ class TestIO : public TestFixture { check("void foo() {\n" " scanf(\"%Ld\", \"s3\");\n" " scanf(\"%Ld\", L\"s5W\");\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2]: (warning) %Ld in format string (no. 1) requires 'long long *' but the argument type is 'const char *'.\n" "[test.cpp:3]: (warning) %Ld in format string (no. 1) requires 'long long *' but the argument type is 'const wchar_t *'.\n", errout_str()); check("void foo(int i) {\n" " scanf(\"%Ld\", i);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2]: (warning) %Ld in format string (no. 1) requires 'long long *' but the argument type is 'signed int'.\n", errout_str()); TEST_SCANF_WARN("%ju", "uintmax_t", "bool"); @@ -1946,13 +2061,13 @@ class TestIO : public TestFixture { check("void foo() {\n" " scanf(\"%d\", \"s3\");\n" " scanf(\"%d\", L\"s5W\");\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 1) requires 'int *' but the argument type is 'const char *'.\n" "[test.cpp:3]: (warning) %d in format string (no. 1) requires 'int *' but the argument type is 'const wchar_t *'.\n", errout_str()); check("void foo(long l) {\n" " scanf(\"%d\", l);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 1) requires 'int *' but the argument type is 'signed long'.\n", errout_str()); TEST_SCANF_WARN("%x", "unsigned int", "bool"); @@ -1990,13 +2105,13 @@ class TestIO : public TestFixture { check("void foo() {\n" " scanf(\"%x\", \"s3\");\n" " scanf(\"%x\", L\"s5W\");\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2]: (warning) %x in format string (no. 1) requires 'unsigned int *' but the argument type is 'const char *'.\n" "[test.cpp:3]: (warning) %x in format string (no. 1) requires 'unsigned int *' but the argument type is 'const wchar_t *'.\n", errout_str()); check("void foo(long l) {\n" " scanf(\"%x\", l);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2]: (warning) %x in format string (no. 1) requires 'unsigned int *' but the argument type is 'signed long'.\n", errout_str()); TEST_SCANF_WARN("%f", "float", "bool"); @@ -2030,13 +2145,13 @@ class TestIO : public TestFixture { check("void foo() {\n" " scanf(\"%f\", \"s3\");\n" " scanf(\"%f\", L\"s5W\");\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2]: (warning) %f in format string (no. 1) requires 'float *' but the argument type is 'const char *'.\n" "[test.cpp:3]: (warning) %f in format string (no. 1) requires 'float *' but the argument type is 'const wchar_t *'.\n", errout_str()); check("void foo(float f) {\n" " scanf(\"%f\", f);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2]: (warning) %f in format string (no. 1) requires 'float *' but the argument type is 'float'.\n", errout_str()); TEST_SCANF_WARN("%lf", "double", "bool"); @@ -2126,13 +2241,13 @@ class TestIO : public TestFixture { check("void foo() {\n" " scanf(\"%n\", \"s3\");\n" " scanf(\"%n\", L\"s5W\");\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2]: (warning) %n in format string (no. 1) requires 'int *' but the argument type is 'const char *'.\n" "[test.cpp:3]: (warning) %n in format string (no. 1) requires 'int *' but the argument type is 'const wchar_t *'.\n", errout_str()); check("void foo(long l) {\n" " scanf(\"%n\", l);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2]: (warning) %n in format string (no. 1) requires 'int *' but the argument type is 'signed long'.\n", errout_str()); check("void g() {\n" // #5104 @@ -2146,7 +2261,7 @@ class TestIO : public TestFixture { " scanf(\"%lf\",&v4[0]);\n" " myvector v5(1);\n" " scanf(\"%10s\",v5[0]);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); { @@ -2178,7 +2293,7 @@ class TestIO : public TestFixture { check("void g() {\n" " const char c[]=\"42\";\n" " scanf(\"%s\", c);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %s in format string (no. 1) requires a 'char *' but the argument type is 'const char *'.\n" "[test.cpp:3]: (warning) scanf() without field width limits can crash with huge input data.\n", errout_str()); } @@ -2187,6 +2302,12 @@ class TestIO : public TestFixture { " scanf(\"%i\", \"abc\" + 1);\n" "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %i in format string (no. 1) requires 'int *' but the argument type is 'const char *'.\n", errout_str()); + + check("struct S { unsigned char a[1]; };\n" // #14302 + "void f(S s) {\n" + " scanf(\"%hhu\", s.a);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void testPrintfArgument() { @@ -2200,7 +2321,7 @@ class TestIO : public TestFixture { " snprintf(str,10,\"%u%s\");\n" " sprintf(string1, \"%-*.*s\", 32, string2);\n" // #3364 " snprintf(a, 9, \"%s%d\", \"11223344\");\n" // #3655 - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (error) printf format string requires 1 parameter but only 0 are given.\n" "[test.cpp:3]: (error) printf format string requires 2 parameters but only 1 is given.\n" "[test.cpp:4]: (error) printf format string requires 3 parameters but only 2 are given.\n" @@ -2215,7 +2336,7 @@ class TestIO : public TestFixture { " printf(\"\", 0);\n" " printf(\"%i\", 123, bar());\n" " printf(\"%i%s\", 0, bar(), 43123);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) printf format string requires 0 parameters but 1 is given.\n" "[test.cpp:3]: (warning) printf format string requires 1 parameter but 2 are given.\n" "[test.cpp:4]: (warning) printf format string requires 2 parameters but 3 are given.\n", errout_str()); @@ -2225,7 +2346,7 @@ class TestIO : public TestFixture { " swprintf(string1, L\"%s%s\", L\"a\", string2);\n" // MSVC implementation " swprintf(string1, 6, L\"%i\", 32, string2);\n" // Standard implementation " swprintf(string1, 6, L\"%i%s\", 32, string2);\n" // Standard implementation - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) swprintf format string requires 1 parameter but 2 are given.\n" "[test.cpp:4]: (warning) swprintf format string requires 1 parameter but 2 are given.\n", errout_str()); @@ -2242,7 +2363,7 @@ class TestIO : public TestFixture { " printf(\"string: %.*s\", len, string);\n" // #3311 " fprintf(stderr, \"%*cText.\", indent, ' ');\n" // #3313 " sprintf(string1, \"%*\", 32);\n" // #3364 - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(char* s, const char* s2, std::string s3, int i) {\n" @@ -2252,7 +2373,7 @@ class TestIO : public TestFixture { " printf(\"%s\", s3);\n" " printf(\"%s\", \"s4\");\n" " printf(\"%u\", s);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %s in format string (no. 1) requires 'char *' but the argument type is 'signed int'.\n" "[test.cpp:4]: (warning) %s in format string (no. 2) requires 'char *' but the argument type is 'signed int'.\n" "[test.cpp:5]: (warning) %s in format string (no. 1) requires 'char *' but the argument type is 'std::string'.\n" @@ -2265,7 +2386,7 @@ class TestIO : public TestFixture { " printf(\"%jo\", s3);\n" " printf(\"%jx\", i);\n" " printf(\"%jX\", i);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %jd in format string (no. 1) requires 'intmax_t' but the argument type is 'char *'.\n" "[test.cpp:3]: (warning) %ji in format string (no. 1) requires 'intmax_t' but the argument type is 'char *'.\n" "[test.cpp:4]: (warning) %ju in format string (no. 1) requires 'uintmax_t' but the argument type is 'const char *'.\n" @@ -2279,7 +2400,7 @@ class TestIO : public TestFixture { " printf(\"%jd\", ui);\n" " printf(\"%jd\", s3);\n" " printf(\"%jd\", i);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %ju in format string (no. 1) requires 'uintmax_t' but the argument type is 'unsigned int'.\n" "[test.cpp:4]: (warning) %jd in format string (no. 1) requires 'intmax_t' but the argument type is 'unsigned int'.\n" "[test.cpp:5]: (warning) %jd in format string (no. 1) requires 'intmax_t' but the argument type is 'std::string'.\n" @@ -2292,7 +2413,7 @@ class TestIO : public TestFixture { " printf(\"%n\", pi);\n" " printf(\"%n\", s);\n" " printf(\"%n\", \"s4\");\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %n in format string (no. 1) requires 'int *' but the argument type is 'signed int'.\n" "[test.cpp:4]: (warning) %n in format string (no. 1) requires 'int *' but the argument type is 'signed int'.\n" "[test.cpp:6]: (warning) %n in format string (no. 1) requires 'int *' but the argument type is 'std::string'.\n" @@ -2300,7 +2421,7 @@ class TestIO : public TestFixture { check("void foo() {\n" " printf(\"%n\", L\"s5W\");\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %n in format string (no. 1) requires 'int *' but the argument type is 'const wchar_t *'.\n", errout_str()); check("class foo {};\n" @@ -2313,7 +2434,7 @@ class TestIO : public TestFixture { " printf(\"%X\", bp);\n" " printf(\"%X\", u);\n" " printf(\"%X\", i);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %X in format string (no. 1) requires 'unsigned int' but the argument type is 'foo'.\n" "[test.cpp:4]: (warning) %c in format string (no. 1) requires 'unsigned int' but the argument type is 'const char *'.\n" "[test.cpp:5]: (warning) %o in format string (no. 1) requires 'unsigned int' but the argument type is 'double'.\n" @@ -2324,7 +2445,7 @@ class TestIO : public TestFixture { "void foo(const char* cpc, char* pc) {\n" " printf(\"%x\", cpc);\n" " printf(\"%x\", pc);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %x in format string (no. 1) requires 'unsigned int' but the argument type is 'const char *'.\n" "[test.cpp:4]: (warning) %x in format string (no. 1) requires 'unsigned int' but the argument type is 'char *'.\n", errout_str()); @@ -2334,7 +2455,7 @@ class TestIO : public TestFixture { " printf(\"%X\", L\"s5W\");\n" " printf(\"%c\", L\"s5W\");\n" " printf(\"%o\", L\"s5W\");\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %x in format string (no. 1) requires 'unsigned int' but the argument type is 'const wchar_t *'.\n" "[test.cpp:4]: (warning) %X in format string (no. 1) requires 'unsigned int' but the argument type is 'const wchar_t *'.\n" "[test.cpp:5]: (warning) %c in format string (no. 1) requires 'unsigned int' but the argument type is 'const wchar_t *'.\n" @@ -2350,7 +2471,7 @@ class TestIO : public TestFixture { " printf(\"%i\", b);\n" " printf(\"%i\", bp);\n" " printf(\"%i\", uc);\n" // char is smaller than int, so there shouldn't be a problem - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %i in format string (no. 1) requires 'int' but the argument type is 'foo'.\n" "[test.cpp:4]: (warning) %d in format string (no. 1) requires 'int' but the argument type is 'const char *'.\n" "[test.cpp:5]: (warning) %d in format string (no. 1) requires 'int' but the argument type is 'double'.\n" @@ -2362,7 +2483,7 @@ class TestIO : public TestFixture { "void foo() {\n" " printf(\"%i\", L\"s5W\");\n" " printf(\"%d\", L\"s5W\");\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %i in format string (no. 1) requires 'int' but the argument type is 'const wchar_t *'.\n" "[test.cpp:4]: (warning) %d in format string (no. 1) requires 'int' but the argument type is 'const wchar_t *'.\n", errout_str()); @@ -2376,7 +2497,7 @@ class TestIO : public TestFixture { " printf(\"%u\", b);\n" " printf(\"%u\", bp);\n" " printf(\"%u\", bo);\n" // bool shouldn't have a negative sign - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 1) requires 'unsigned int' but the argument type is 'foo'.\n" "[test.cpp:4]: (warning) %u in format string (no. 1) requires 'unsigned int' but the argument type is 'const char *'.\n" "[test.cpp:5]: (warning) %u in format string (no. 1) requires 'unsigned int' but the argument type is 'double'.\n" @@ -2387,7 +2508,7 @@ class TestIO : public TestFixture { check("class foo {};\n" "void foo(const int* cpi, foo f, bar b, bar* bp, double d, int i, bool bo) {\n" " printf(\"%u\", L\"s5W\");\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 1) requires 'unsigned int' but the argument type is 'const wchar_t *'.\n", errout_str()); check("class foo {};\n" @@ -2397,7 +2518,7 @@ class TestIO : public TestFixture { " printf(\"%p\", bp);\n" " printf(\"%p\", cpi);\n" " printf(\"%p\", b);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %p in format string (no. 1) requires an address but the argument type is 'foo'.\n" "[test.cpp:4]: (warning) %p in format string (no. 1) requires an address but the argument type is 'char'.\n", errout_str()); @@ -2409,7 +2530,7 @@ class TestIO : public TestFixture { " printf(\"%p\", cpwc);\n" " printf(\"%p\", \"s4\");\n" " printf(\"%p\", L\"s5W\");\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class foo {};\n" @@ -2421,7 +2542,7 @@ class TestIO : public TestFixture { " printf(\"%f\", d);\n" " printf(\"%f\", b);\n" " printf(\"%f\", (float)cpi);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %e in format string (no. 1) requires 'double' but the argument type is 'foo'.\n" "[test.cpp:4]: (warning) %E in format string (no. 1) requires 'double' but the argument type is 'const char *'.\n" "[test.cpp:5]: (warning) %f in format string (no. 1) requires 'double' but the argument type is 'const signed int *'.\n" @@ -2434,7 +2555,7 @@ class TestIO : public TestFixture { " printf(\"%f\", cpc);\n" " printf(\"%G\", pc);\n" " printf(\"%f\", pc);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %e in format string (no. 1) requires 'double' but the argument type is 'const char *'.\n" "[test.cpp:4]: (warning) %E in format string (no. 1) requires 'double' but the argument type is 'char *'.\n" "[test.cpp:5]: (warning) %f in format string (no. 1) requires 'double' but the argument type is 'const char *'.\n" @@ -2447,7 +2568,7 @@ class TestIO : public TestFixture { " printf(\"%E\", L\"s5W\");\n" " printf(\"%f\", L\"s5W\");\n" " printf(\"%G\", L\"s5W\");\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %e in format string (no. 1) requires 'double' but the argument type is 'const wchar_t *'.\n" "[test.cpp:4]: (warning) %E in format string (no. 1) requires 'double' but the argument type is 'const wchar_t *'.\n" "[test.cpp:5]: (warning) %f in format string (no. 1) requires 'double' but the argument type is 'const wchar_t *'.\n" @@ -2458,7 +2579,7 @@ class TestIO : public TestFixture { " printf(\"%u\", f);\n" " printf(\"%f\", f);\n" " printf(\"%p\", f);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 1) requires 'unsigned int' but the argument type is 'foo'.\n" "[test.cpp:4]: (warning) %f in format string (no. 1) requires 'double' but the argument type is 'foo'.\n" "[test.cpp:5]: (warning) %p in format string (no. 1) requires an address but the argument type is 'foo'.\n", errout_str()); @@ -2468,14 +2589,14 @@ class TestIO : public TestFixture { check("void foo(signed char sc, unsigned char uc, short int si, unsigned short int usi) {\n" " printf(\"%hhx %hhd\", sc, uc);\n" " printf(\"%hd %hu\", si, usi);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %hhx in format string (no. 1) requires 'unsigned char' but the argument type is 'signed char'.\n" "[test.cpp:2]: (warning) %hhd in format string (no. 2) requires 'char' but the argument type is 'unsigned char'.\n", errout_str()); check("void foo(long long int lli, unsigned long long int ulli, long int li, unsigned long int uli) {\n" " printf(\"%llo %llx\", lli, ulli);\n" " printf(\"%ld %lu\", li, uli);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(intmax_t im, uintmax_t uim, size_t s, ptrdiff_t p, long double ld, std::size_t ss, std::ptrdiff_t sp) {\n" @@ -2485,7 +2606,7 @@ class TestIO : public TestFixture { " printf(\"%Lf\", ld);\n" " printf(\"%zx\", ss);\n" " printf(\"%ti\", sp);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Unrecognized (and non-existent in standard library) specifiers. @@ -2497,31 +2618,31 @@ class TestIO : public TestFixture { " printf(\"%La\", ld);\n" " printf(\"%zv\", ss);\n" " printf(\"%tp\", sp);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(long long l, ptrdiff_t p, std::ptrdiff_t sp) {\n" " printf(\"%td\", p);\n" " printf(\"%td\", sp);\n" " printf(\"%td\", l);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4]: (warning) %td in format string (no. 1) requires 'ptrdiff_t' but the argument type is 'signed long long'.\n", errout_str()); check("void foo(int i, long double ld) {\n" " printf(\"%zx %zu\", i, ld);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %zx in format string (no. 1) requires 'size_t' but the argument type is 'signed int'.\n" "[test.cpp:2]: (warning) %zu in format string (no. 2) requires 'size_t' but the argument type is 'long double'.\n", errout_str()); check("void foo(unsigned int ui, long double ld) {\n" " printf(\"%zu %zx\", ui, ld);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %zu in format string (no. 1) requires 'size_t' but the argument type is 'unsigned int'.\n" "[test.cpp:2]: (warning) %zx in format string (no. 2) requires 'size_t' but the argument type is 'long double'.\n", errout_str()); check("void foo(int i, long double ld) {\n" " printf(\"%tx %tu\", i, ld);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %tx in format string (no. 1) requires 'unsigned ptrdiff_t' but the argument type is 'signed int'.\n" "[test.cpp:2]: (warning) %tu in format string (no. 2) requires 'unsigned ptrdiff_t' but the argument type is 'long double'.\n", errout_str()); @@ -2536,7 +2657,7 @@ class TestIO : public TestFixture { " printf(\"%t\", i);\n" " printf(\"%L\", i);\n" " printf(\"%I\", i);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) 'h' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n" "[test.cpp:3]: (warning) 'hh' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n" "[test.cpp:4]: (warning) 'l' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n" @@ -2552,7 +2673,7 @@ class TestIO : public TestFixture { " printf(\"%hhd\", i);\n" " printf(\"%ld\", i);\n" " printf(\"%lld\", i);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %hd in format string (no. 1) requires 'short' but the argument type is 'unsigned int'.\n" "[test.cpp:3]: (warning) %hhd in format string (no. 1) requires 'char' but the argument type is 'unsigned int'.\n" "[test.cpp:4]: (warning) %ld in format string (no. 1) requires 'long' but the argument type is 'unsigned int'.\n" @@ -2561,56 +2682,56 @@ class TestIO : public TestFixture { check("void foo(size_t s, ptrdiff_t p) {\n" " printf(\"%zd\", s);\n" " printf(\"%tu\", p);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Unix32)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Unix32)); ASSERT_EQUALS("[test.cpp:2]: (portability) %zd in format string (no. 1) requires 'ssize_t' but the argument type is 'size_t {aka unsigned long}'.\n" "[test.cpp:3]: (portability) %tu in format string (no. 1) requires 'unsigned ptrdiff_t' but the argument type is 'ptrdiff_t {aka signed long}'.\n", errout_str()); check("void foo(std::size_t s, std::ptrdiff_t p) {\n" " printf(\"%zd\", s);\n" " printf(\"%tu\", p);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Unix32)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Unix32)); ASSERT_EQUALS("[test.cpp:2]: (portability) %zd in format string (no. 1) requires 'ssize_t' but the argument type is 'std::size_t {aka unsigned long}'.\n" "[test.cpp:3]: (portability) %tu in format string (no. 1) requires 'unsigned ptrdiff_t' but the argument type is 'std::ptrdiff_t {aka signed long}'.\n", errout_str()); check("void foo(size_t s, ptrdiff_t p) {\n" " printf(\"%zd\", s);\n" " printf(\"%tu\", p);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Unix64)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Unix64)); ASSERT_EQUALS("[test.cpp:2]: (portability) %zd in format string (no. 1) requires 'ssize_t' but the argument type is 'size_t {aka unsigned long}'.\n" "[test.cpp:3]: (portability) %tu in format string (no. 1) requires 'unsigned ptrdiff_t' but the argument type is 'ptrdiff_t {aka signed long}'.\n", errout_str()); check("void foo(std::size_t s, std::ptrdiff_t p) {\n" " printf(\"%zd\", s);\n" " printf(\"%tu\", p);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Unix64)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Unix64)); ASSERT_EQUALS("[test.cpp:2]: (portability) %zd in format string (no. 1) requires 'ssize_t' but the argument type is 'std::size_t {aka unsigned long}'.\n" "[test.cpp:3]: (portability) %tu in format string (no. 1) requires 'unsigned ptrdiff_t' but the argument type is 'std::ptrdiff_t {aka signed long}'.\n", errout_str()); check("void foo(size_t s, ptrdiff_t p) {\n" " printf(\"%zd\", s);\n" " printf(\"%tu\", p);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win32A)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win32A)); ASSERT_EQUALS("[test.cpp:2]: (portability) %zd in format string (no. 1) requires 'ssize_t' but the argument type is 'size_t {aka unsigned long}'.\n" "[test.cpp:3]: (portability) %tu in format string (no. 1) requires 'unsigned ptrdiff_t' but the argument type is 'ptrdiff_t {aka signed long}'.\n", errout_str()); check("void foo(std::size_t s, std::ptrdiff_t p) {\n" " printf(\"%zd\", s);\n" " printf(\"%tu\", p);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win32A)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win32A)); ASSERT_EQUALS("[test.cpp:2]: (portability) %zd in format string (no. 1) requires 'ssize_t' but the argument type is 'std::size_t {aka unsigned long}'.\n" "[test.cpp:3]: (portability) %tu in format string (no. 1) requires 'unsigned ptrdiff_t' but the argument type is 'std::ptrdiff_t {aka signed long}'.\n", errout_str()); check("void foo(size_t s, ptrdiff_t p) {\n" " printf(\"%zd\", s);\n" " printf(\"%tu\", p);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); ASSERT_EQUALS("[test.cpp:2]: (portability) %zd in format string (no. 1) requires 'ssize_t' but the argument type is 'size_t {aka unsigned long long}'.\n" "[test.cpp:3]: (portability) %tu in format string (no. 1) requires 'unsigned ptrdiff_t' but the argument type is 'ptrdiff_t {aka signed long long}'.\n", errout_str()); check("void foo(std::size_t s, std::ptrdiff_t p) {\n" " printf(\"%zd\", s);\n" " printf(\"%tu\", p);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); ASSERT_EQUALS("[test.cpp:2]: (portability) %zd in format string (no. 1) requires 'ssize_t' but the argument type is 'std::size_t {aka unsigned long long}'.\n" "[test.cpp:3]: (portability) %tu in format string (no. 1) requires 'unsigned ptrdiff_t' but the argument type is 'std::ptrdiff_t {aka signed long long}'.\n", errout_str()); @@ -2619,7 +2740,7 @@ class TestIO : public TestFixture { " printf(\"%lu\", um);\n" " printf(\"%llu\", s);\n" " printf(\"%llu\", um);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); ASSERT_EQUALS("[test.cpp:2]: (portability) %lu in format string (no. 1) requires 'unsigned long' but the argument type is 'size_t {aka unsigned long long}'.\n" "[test.cpp:3]: (portability) %lu in format string (no. 1) requires 'unsigned long' but the argument type is 'uintmax_t {aka unsigned long long}'.\n" "[test.cpp:4]: (portability) %llu in format string (no. 1) requires 'unsigned long long' but the argument type is 'size_t {aka unsigned long long}'.\n" @@ -2632,7 +2753,7 @@ class TestIO : public TestFixture { " printf(\"%llu\", i);\n" " printf(\"%lx\", i);\n" " printf(\"%llx\", i);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %ld in format string (no. 1) requires 'long' but the argument type is 'unsigned int'.\n" "[test.cpp:3]: (warning) %lld in format string (no. 1) requires 'long long' but the argument type is 'unsigned int'.\n" "[test.cpp:4]: (warning) %lu in format string (no. 1) requires 'unsigned long' but the argument type is 'unsigned int'.\n" @@ -2644,13 +2765,13 @@ class TestIO : public TestFixture { " printf(\"%lld\", i);\n" " printf(\"%lld\", im);\n" " printf(\"%lld\", p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %lld in format string (no. 1) requires 'long long' but the argument type is 'signed int'.\n", errout_str()); check("void foo(intmax_t im, ptrdiff_t p) {\n" " printf(\"%lld\", im);\n" " printf(\"%lld\", p);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); ASSERT_EQUALS("[test.cpp:2]: (portability) %lld in format string (no. 1) requires 'long long' but the argument type is 'intmax_t {aka signed long long}'.\n" "[test.cpp:3]: (portability) %lld in format string (no. 1) requires 'long long' but the argument type is 'ptrdiff_t {aka signed long long}'.\n", errout_str()); @@ -2669,7 +2790,7 @@ class TestIO : public TestFixture { " printf(\"%d %f %f %d %f %f\",\n" " foo->d, foo->bar[0].i, a[0],\n" " f[0].d, f[0].baz.i, f[0].bar[0].i);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:13]: (warning) %d in format string (no. 1) requires 'int' but the argument type is 'double'.\n" "[test.cpp:13]: (warning) %f in format string (no. 2) requires 'double' but the argument type is 'signed int'.\n" "[test.cpp:13]: (warning) %f in format string (no. 3) requires 'double' but the argument type is 'int'.\n" @@ -2678,7 +2799,7 @@ class TestIO : public TestFixture { "[test.cpp:13]: (warning) %f in format string (no. 6) requires 'double' but the argument type is 'int'.\n", errout_str()); check("short f() { return 0; }\n" - "void foo() { printf(\"%d %u %lu %I64u %I64d %f %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f()); }"); + "void foo() { printf(\"%d %u %lu %I64u %I64d %f %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f()); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'signed short'.\n" "[test.cpp:2]: (warning) %lu in format string (no. 3) requires 'unsigned long' but the argument type is 'signed short'.\n" "[test.cpp:2]: (warning) %I64u in format string (no. 4) requires 'unsigned __int64' but the argument type is 'signed short'.\n" @@ -2688,7 +2809,7 @@ class TestIO : public TestFixture { "[test.cpp:2]: (warning) %p in format string (no. 8) requires an address but the argument type is 'signed short'.\n", errout_str()); check("unsigned short f() { return 0; }\n" - "void foo() { printf(\"%u %d %ld %I64d %I64u %f %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f()); }"); + "void foo() { printf(\"%u %d %ld %I64d %I64u %f %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f()); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %ld in format string (no. 3) requires 'long' but the argument type is 'unsigned short'.\n" "[test.cpp:2]: (warning) %I64d in format string (no. 4) requires '__int64' but the argument type is 'unsigned short'.\n" "[test.cpp:2]: (warning) %I64u in format string (no. 5) requires 'unsigned __int64' but the argument type is 'unsigned short'.\n" @@ -2697,7 +2818,7 @@ class TestIO : public TestFixture { "[test.cpp:2]: (warning) %p in format string (no. 8) requires an address but the argument type is 'unsigned short'.\n", errout_str()); check("int f() { return 0; }\n" - "void foo() { printf(\"%d %u %lu %I64u %I64d %f %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f()); }"); + "void foo() { printf(\"%d %u %lu %I64u %I64d %f %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f()); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'signed int'.\n" "[test.cpp:2]: (warning) %lu in format string (no. 3) requires 'unsigned long' but the argument type is 'signed int'.\n" "[test.cpp:2]: (warning) %I64u in format string (no. 4) requires 'unsigned __int64' but the argument type is 'signed int'.\n" @@ -2707,7 +2828,7 @@ class TestIO : public TestFixture { "[test.cpp:2]: (warning) %p in format string (no. 8) requires an address but the argument type is 'signed int'.\n", errout_str()); check("unsigned int f() { return 0; }\n" - "void foo() { printf(\"%u %d %ld %I64d %I64u %f %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f()); }"); + "void foo() { printf(\"%u %d %ld %I64d %I64u %f %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f()); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 2) requires 'int' but the argument type is 'unsigned int'.\n" "[test.cpp:2]: (warning) %ld in format string (no. 3) requires 'long' but the argument type is 'unsigned int'.\n" "[test.cpp:2]: (warning) %I64d in format string (no. 4) requires '__int64' but the argument type is 'unsigned int'.\n" @@ -2717,7 +2838,7 @@ class TestIO : public TestFixture { "[test.cpp:2]: (warning) %p in format string (no. 8) requires an address but the argument type is 'unsigned int'.\n", errout_str()); check("long f() { return 0; }\n" - "void foo() { printf(\"%ld %u %lu %I64u %I64d %f %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f()); }"); + "void foo() { printf(\"%ld %u %lu %I64u %I64d %f %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f()); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'signed long'.\n" "[test.cpp:2]: (warning) %lu in format string (no. 3) requires 'unsigned long' but the argument type is 'signed long'.\n" "[test.cpp:2]: (warning) %I64u in format string (no. 4) requires 'unsigned __int64' but the argument type is 'signed long'.\n" @@ -2727,7 +2848,7 @@ class TestIO : public TestFixture { "[test.cpp:2]: (warning) %p in format string (no. 8) requires an address but the argument type is 'signed long'.\n", errout_str()); check("unsigned long f() { return 0; }\n" - "void foo() { printf(\"%lu %d %ld %I64d %I64u %f %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f()); }"); + "void foo() { printf(\"%lu %d %ld %I64d %I64u %f %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f()); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 2) requires 'int' but the argument type is 'unsigned long'.\n" "[test.cpp:2]: (warning) %ld in format string (no. 3) requires 'long' but the argument type is 'unsigned long'.\n" "[test.cpp:2]: (warning) %I64d in format string (no. 4) requires '__int64' but the argument type is 'unsigned long'.\n" @@ -2737,7 +2858,7 @@ class TestIO : public TestFixture { "[test.cpp:2]: (warning) %p in format string (no. 8) requires an address but the argument type is 'unsigned long'.\n", errout_str()); check("long long f() { return 0; }\n" - "void foo() { printf(\"%lld %u %lu %I64u %I64d %f %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f()); }"); + "void foo() { printf(\"%lld %u %lu %I64u %I64d %f %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f()); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'signed long long'.\n" "[test.cpp:2]: (warning) %lu in format string (no. 3) requires 'unsigned long' but the argument type is 'signed long long'.\n" "[test.cpp:2]: (warning) %I64u in format string (no. 4) requires 'unsigned __int64' but the argument type is 'signed long long'.\n" @@ -2746,7 +2867,7 @@ class TestIO : public TestFixture { "[test.cpp:2]: (warning) %p in format string (no. 8) requires an address but the argument type is 'signed long long'.\n", errout_str()); check("unsigned long long f() { return 0; }\n" - "void foo() { printf(\"%llu %d %ld %I64d %I64u %f %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f()); }"); + "void foo() { printf(\"%llu %d %ld %I64d %I64u %f %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f()); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 2) requires 'int' but the argument type is 'unsigned long long'.\n" "[test.cpp:2]: (warning) %ld in format string (no. 3) requires 'long' but the argument type is 'unsigned long long'.\n" "[test.cpp:2]: (warning) %I64d in format string (no. 4) requires '__int64' but the argument type is 'unsigned long long'.\n" @@ -2755,7 +2876,7 @@ class TestIO : public TestFixture { "[test.cpp:2]: (warning) %p in format string (no. 8) requires an address but the argument type is 'unsigned long long'.\n", errout_str()); check("float f() { return 0; }\n" - "void foo() { printf(\"%f %d %ld %u %lu %I64d %I64u %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f(), f()); }"); + "void foo() { printf(\"%f %d %ld %u %lu %I64d %I64u %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f(), f()); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 2) requires 'int' but the argument type is 'float'.\n" "[test.cpp:2]: (warning) %ld in format string (no. 3) requires 'long' but the argument type is 'float'.\n" "[test.cpp:2]: (warning) %u in format string (no. 4) requires 'unsigned int' but the argument type is 'float'.\n" @@ -2766,7 +2887,7 @@ class TestIO : public TestFixture { "[test.cpp:2]: (warning) %p in format string (no. 9) requires an address but the argument type is 'float'.\n", errout_str()); check("double f() { return 0; }\n" - "void foo() { printf(\"%f %d %ld %u %lu %I64d %I64u %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f(), f()); }"); + "void foo() { printf(\"%f %d %ld %u %lu %I64d %I64u %Lf %p\", f(), f(), f(), f(), f(), f(), f(), f(), f()); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 2) requires 'int' but the argument type is 'double'.\n" "[test.cpp:2]: (warning) %ld in format string (no. 3) requires 'long' but the argument type is 'double'.\n" "[test.cpp:2]: (warning) %u in format string (no. 4) requires 'unsigned int' but the argument type is 'double'.\n" @@ -2777,7 +2898,7 @@ class TestIO : public TestFixture { "[test.cpp:2]: (warning) %p in format string (no. 9) requires an address but the argument type is 'double'.\n", errout_str()); check("long double f() { return 0; }\n" - "void foo() { printf(\"%Lf %d %ld %u %lu %I64d %I64u %f %p\", f(), f(), f(), f(), f(), f(), f(), f(), f()); }"); + "void foo() { printf(\"%Lf %d %ld %u %lu %I64d %I64u %f %p\", f(), f(), f(), f(), f(), f(), f(), f(), f()); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 2) requires 'int' but the argument type is 'long double'.\n" "[test.cpp:2]: (warning) %ld in format string (no. 3) requires 'long' but the argument type is 'long double'.\n" "[test.cpp:2]: (warning) %u in format string (no. 4) requires 'unsigned int' but the argument type is 'long double'.\n" @@ -2788,37 +2909,37 @@ class TestIO : public TestFixture { "[test.cpp:2]: (warning) %p in format string (no. 9) requires an address but the argument type is 'long double'.\n", errout_str()); check("int f() { return 0; }\n" - "void foo() { printf(\"%I64d %I64u %I64x %d\", f(), f(), f(), f()); }"); + "void foo() { printf(\"%I64d %I64u %I64x %d\", f(), f(), f(), f()); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %I64d in format string (no. 1) requires '__int64' but the argument type is 'signed int'.\n" "[test.cpp:2]: (warning) %I64u in format string (no. 2) requires 'unsigned __int64' but the argument type is 'signed int'.\n" "[test.cpp:2]: (warning) %I64x in format string (no. 3) requires 'unsigned __int64' but the argument type is 'signed int'.\n", errout_str()); check("long long f() { return 0; }\n" - "void foo() { printf(\"%I32d %I32u %I32x %lld\", f(), f(), f(), f()); }"); + "void foo() { printf(\"%I32d %I32u %I32x %lld\", f(), f(), f(), f()); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %I32d in format string (no. 1) requires '__int32' but the argument type is 'signed long long'.\n" "[test.cpp:2]: (warning) %I32u in format string (no. 2) requires 'unsigned __int32' but the argument type is 'signed long long'.\n" "[test.cpp:2]: (warning) %I32x in format string (no. 3) requires 'unsigned __int32' but the argument type is 'signed long long'.\n", errout_str()); check("unsigned long long f() { return 0; }\n" - "void foo() { printf(\"%I32d %I32u %I32x %llx\", f(), f(), f(), f()); }"); + "void foo() { printf(\"%I32d %I32u %I32x %llx\", f(), f(), f(), f()); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %I32d in format string (no. 1) requires '__int32' but the argument type is 'unsigned long long'.\n" "[test.cpp:2]: (warning) %I32u in format string (no. 2) requires 'unsigned __int32' but the argument type is 'unsigned long long'.\n" "[test.cpp:2]: (warning) %I32x in format string (no. 3) requires 'unsigned __int32' but the argument type is 'unsigned long long'.\n", errout_str()); check("signed char f() { return 0; }\n" - "void foo() { printf(\"%Id %Iu %Ix %hhi\", f(), f(), f(), f()); }"); + "void foo() { printf(\"%Id %Iu %Ix %hhi\", f(), f(), f(), f()); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %Id in format string (no. 1) requires 'ptrdiff_t' but the argument type is 'signed char'.\n" "[test.cpp:2]: (warning) %Iu in format string (no. 2) requires 'size_t' but the argument type is 'signed char'.\n" "[test.cpp:2]: (warning) %Ix in format string (no. 3) requires 'size_t' but the argument type is 'signed char'.\n", errout_str()); check("unsigned char f() { return 0; }\n" - "void foo() { printf(\"%Id %Iu %Ix %hho\", f(), f(), f(), f()); }"); + "void foo() { printf(\"%Id %Iu %Ix %hho\", f(), f(), f(), f()); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %Id in format string (no. 1) requires 'ptrdiff_t' but the argument type is 'unsigned char'.\n" "[test.cpp:2]: (warning) %Iu in format string (no. 2) requires 'size_t' but the argument type is 'unsigned char'.\n" "[test.cpp:2]: (warning) %Ix in format string (no. 3) requires 'size_t' but the argument type is 'unsigned char'.\n", errout_str()); check("namespace bar { int f() { return 0; } }\n" - "void foo() { printf(\"%d %u %lu %f %Lf %p\", bar::f(), bar::f(), bar::f(), bar::f(), bar::f(), bar::f()); }"); + "void foo() { printf(\"%d %u %lu %f %Lf %p\", bar::f(), bar::f(), bar::f(), bar::f(), bar::f(), bar::f()); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'signed int'.\n" "[test.cpp:2]: (warning) %lu in format string (no. 3) requires 'unsigned long' but the argument type is 'signed int'.\n" "[test.cpp:2]: (warning) %f in format string (no. 4) requires 'double' but the argument type is 'signed int'.\n" @@ -2826,7 +2947,7 @@ class TestIO : public TestFixture { "[test.cpp:2]: (warning) %p in format string (no. 6) requires an address but the argument type is 'signed int'.\n", errout_str()); check("struct Fred { int i; } f;\n" - "void foo() { printf(\"%d %u %lu %f %Lf %p\", f.i, f.i, f.i, f.i, f.i, f.i); }"); + "void foo() { printf(\"%d %u %lu %f %Lf %p\", f.i, f.i, f.i, f.i, f.i, f.i); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'signed int'.\n" "[test.cpp:2]: (warning) %lu in format string (no. 3) requires 'unsigned long' but the argument type is 'signed int'.\n" "[test.cpp:2]: (warning) %f in format string (no. 4) requires 'double' but the argument type is 'signed int'.\n" @@ -2834,7 +2955,7 @@ class TestIO : public TestFixture { "[test.cpp:2]: (warning) %p in format string (no. 6) requires an address but the argument type is 'signed int'.\n", errout_str()); check("struct Fred { unsigned int u; } f;\n" - "void foo() { printf(\"%u %d %ld %f %Lf %p\", f.u, f.u, f.u, f.u, f.u, f.u); }"); + "void foo() { printf(\"%u %d %ld %f %Lf %p\", f.u, f.u, f.u, f.u, f.u, f.u); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 2) requires 'int' but the argument type is 'unsigned int'.\n" "[test.cpp:2]: (warning) %ld in format string (no. 3) requires 'long' but the argument type is 'unsigned int'.\n" "[test.cpp:2]: (warning) %f in format string (no. 4) requires 'double' but the argument type is 'unsigned int'.\n" @@ -2842,7 +2963,7 @@ class TestIO : public TestFixture { "[test.cpp:2]: (warning) %p in format string (no. 6) requires an address but the argument type is 'unsigned int'.\n", errout_str()); check("struct Fred { unsigned int ui() { return 0; } } f;\n" - "void foo() { printf(\"%u %d %ld %f %Lf %p\", f.ui(), f.ui(), f.ui(), f.ui(), f.ui(), f.ui()); }"); + "void foo() { printf(\"%u %d %ld %f %Lf %p\", f.ui(), f.ui(), f.ui(), f.ui(), f.ui(), f.ui()); }\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 2) requires 'int' but the argument type is 'unsigned int'.\n" "[test.cpp:2]: (warning) %ld in format string (no. 3) requires 'long' but the argument type is 'unsigned int'.\n" "[test.cpp:2]: (warning) %f in format string (no. 4) requires 'double' but the argument type is 'unsigned int'.\n" @@ -2853,12 +2974,12 @@ class TestIO : public TestFixture { check("void f(int len, int newline) {\n" " printf(\"%s\", newline ? a : str + len);\n" " printf(\"%s\", newline + newline);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %s in format string (no. 1) requires 'char *' but the argument type is 'signed int'.\n", errout_str()); check("struct Fred { int i; } f;\n" "struct Fred & bar() { };\n" - "void foo() { printf(\"%d %u %lu %f %Lf %p\", bar().i, bar().i, bar().i, bar().i, bar().i, bar().i); }"); + "void foo() { printf(\"%d %u %lu %f %Lf %p\", bar().i, bar().i, bar().i, bar().i, bar().i, bar().i); }\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'signed int'.\n" "[test.cpp:3]: (warning) %lu in format string (no. 3) requires 'unsigned long' but the argument type is 'signed int'.\n" "[test.cpp:3]: (warning) %f in format string (no. 4) requires 'double' but the argument type is 'signed int'.\n" @@ -2867,7 +2988,7 @@ class TestIO : public TestFixture { check("struct Fred { int i; } f;\n" "const struct Fred & bar() { };\n" - "void foo() { printf(\"%d %u %lu %f %Lf %p\", bar().i, bar().i, bar().i, bar().i, bar().i, bar().i); }"); + "void foo() { printf(\"%d %u %lu %f %Lf %p\", bar().i, bar().i, bar().i, bar().i, bar().i, bar().i); }\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'signed int'.\n" "[test.cpp:3]: (warning) %lu in format string (no. 3) requires 'unsigned long' but the argument type is 'signed int'.\n" "[test.cpp:3]: (warning) %f in format string (no. 4) requires 'double' but the argument type is 'signed int'.\n" @@ -2876,7 +2997,7 @@ class TestIO : public TestFixture { check("struct Fred { int i; } f;\n" "static const struct Fred & bar() { };\n" - "void foo() { printf(\"%d %u %lu %f %Lf %p\", bar().i, bar().i, bar().i, bar().i, bar().i, bar().i); }"); + "void foo() { printf(\"%d %u %lu %f %Lf %p\", bar().i, bar().i, bar().i, bar().i, bar().i, bar().i); }\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'signed int'.\n" "[test.cpp:3]: (warning) %lu in format string (no. 3) requires 'unsigned long' but the argument type is 'signed int'.\n" "[test.cpp:3]: (warning) %f in format string (no. 4) requires 'double' but the argument type is 'signed int'.\n" @@ -2885,7 +3006,7 @@ class TestIO : public TestFixture { check("struct Fred { int i; } f[2];\n" "struct Fred * bar() { return f; };\n" - "void foo() { printf(\"%d %u %lu %f %Lf %p\", bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i); }"); + "void foo() { printf(\"%d %u %lu %f %Lf %p\", bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i); }\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'signed int'.\n" "[test.cpp:3]: (warning) %lu in format string (no. 3) requires 'unsigned long' but the argument type is 'signed int'.\n" "[test.cpp:3]: (warning) %f in format string (no. 4) requires 'double' but the argument type is 'signed int'.\n" @@ -2894,7 +3015,7 @@ class TestIO : public TestFixture { check("struct Fred { int i; } f[2];\n" "const struct Fred * bar() { return f; };\n" - "void foo() { printf(\"%d %u %lu %f %Lf %p\", bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i); }"); + "void foo() { printf(\"%d %u %lu %f %Lf %p\", bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i); }\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'signed int'.\n" "[test.cpp:3]: (warning) %lu in format string (no. 3) requires 'unsigned long' but the argument type is 'signed int'.\n" "[test.cpp:3]: (warning) %f in format string (no. 4) requires 'double' but the argument type is 'signed int'.\n" @@ -2903,7 +3024,7 @@ class TestIO : public TestFixture { check("struct Fred { int i; } f[2];\n" "static const struct Fred * bar() { return f; };\n" - "void foo() { printf(\"%d %u %lu %f %Lf %p\", bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i); }"); + "void foo() { printf(\"%d %u %lu %f %Lf %p\", bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i); }\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'signed int'.\n" "[test.cpp:3]: (warning) %lu in format string (no. 3) requires 'unsigned long' but the argument type is 'signed int'.\n" "[test.cpp:3]: (warning) %f in format string (no. 4) requires 'double' but the argument type is 'signed int'.\n" @@ -2912,7 +3033,7 @@ class TestIO : public TestFixture { check("struct Fred { int32_t i; } f;\n" "struct Fred & bar() { };\n" - "void foo() { printf(\"%d %ld %u %lu %f %Lf\", bar().i, bar().i, bar().i, bar().i, bar().i, bar().i); }"); + "void foo() { printf(\"%d %ld %u %lu %f %Lf\", bar().i, bar().i, bar().i, bar().i, bar().i, bar().i); }\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %ld in format string (no. 2) requires 'long' but the argument type is 'signed int'.\n" "[test.cpp:3]: (warning) %u in format string (no. 3) requires 'unsigned int' but the argument type is 'signed int'.\n" "[test.cpp:3]: (warning) %lu in format string (no. 4) requires 'unsigned long' but the argument type is 'signed int'.\n" @@ -2923,27 +3044,27 @@ class TestIO : public TestFixture { // #4984 check("void f(double *x) {\n" " printf(\"%f\", x[0]);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int array[10];\n" "int * foo() { return array; }\n" "void f() {\n" " printf(\"%f\", foo()[0]);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4]: (warning) %f in format string (no. 1) requires 'double' but the argument type is 'signed int'.\n", errout_str()); check("struct Base { int length() { } };\n" "struct Derived : public Base { };\n" "void foo(Derived * d) {\n" " printf(\"%f\", d.length());\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4]: (warning) %f in format string (no. 1) requires 'double' but the argument type is 'signed int'.\n", errout_str()); check("std::vector v;\n" "void foo() {\n" " printf(\"%d %u %f\", v[0], v[0], v[0]);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'signed int'.\n" "[test.cpp:3]: (warning) %f in format string (no. 3) requires 'double' but the argument type is 'signed int'.\n", errout_str()); @@ -2951,7 +3072,7 @@ class TestIO : public TestFixture { check("int bar(int a);\n" "void foo() {\n" " printf(\"%d\", bar(0));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("std::vector v;\n" @@ -3197,20 +3318,20 @@ class TestIO : public TestFixture { check("void foo() {\n" " printf(\"%f %d\", static_cast(1.0f), reinterpret_cast(0));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %f in format string (no. 1) requires 'double' but the argument type is 'signed int'.\n" "[test.cpp:2]: (warning) %d in format string (no. 2) requires 'int' but the argument type is 'const void *'.\n", errout_str()); check("void foo() {\n" " UNKNOWN * u;\n" " printf(\"%d %x %u %f\", u[i], u[i], u[i], u[i]);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " long * l;\n" " printf(\"%d %x %u %f\", l[i], l[i], l[i], l[i]);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %d in format string (no. 1) requires 'int' but the argument type is 'signed long'.\n" "[test.cpp:3]: (warning) %x in format string (no. 2) requires 'unsigned int' but the argument type is 'signed long'.\n" "[test.cpp:3]: (warning) %u in format string (no. 3) requires 'unsigned int' but the argument type is 'signed long'.\n" @@ -3231,27 +3352,27 @@ class TestIO : public TestFixture { " printf(\"%u\",v6[0]);\n" " myvector v7(1,0);\n" " printf(\"%s\",v7[0]);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("std::vector v;\n" // #5151 "void foo() {\n" " printf(\"%c %u %f\", v.at(32), v.at(32), v.at(32));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'char'.\n" "[test.cpp:3]: (warning) %f in format string (no. 3) requires 'double' but the argument type is 'char'.\n", errout_str()); // #5195 (segmentation fault) check("void T::a(const std::vector& vx) {\n" " printf(\"%f\", vx.at(0));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #5486 check("void foo() {\n" " ssize_t test = 0;\n" " printf(\"%zd\", test);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #6009 @@ -3259,7 +3380,7 @@ class TestIO : public TestFixture { "extern int IntByReturnValue();\n" "void MyFunction() {\n" " printf( \"%s - %s\", StringByReturnValue(), IntByReturnValue() );\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4]: (warning) %s in format string (no. 1) requires 'char *' but the argument type is 'std::string'.\n" "[test.cpp:4]: (warning) %s in format string (no. 2) requires 'char *' but the argument type is 'signed int'.\n", errout_str()); @@ -3272,7 +3393,7 @@ class TestIO : public TestFixture { " Array array1;\n" " Array array2;\n" " printf(\"%u %u\", array1[0], array2[0]);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:9]: (warning) %u in format string (no. 1) requires 'unsigned int' but the argument type is 'int'.\n" "[test.cpp:9]: (warning) %u in format string (no. 2) requires 'unsigned int' but the argument type is 'float'.\n", errout_str()); @@ -3280,19 +3401,19 @@ class TestIO : public TestFixture { check("struct S { unsigned short x; } s = {0};\n" "void foo() {\n" " printf(\"%d\", s.x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Ticket #7601 check("void foo(int i, unsigned int ui, long long ll, unsigned long long ull) {\n" " printf(\"%Ld %Lu %Ld %Lu\", i, ui, ll, ull);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %Ld in format string (no. 1) requires 'long long' but the argument type is 'signed int'.\n" "[test.cpp:2]: (warning) %Lu in format string (no. 2) requires 'unsigned long long' but the argument type is 'unsigned int'.\n", errout_str()); check("void foo(char c, unsigned char uc, short s, unsigned short us, int i, unsigned int ui, long l, unsigned long ul) {\n" " printf(\"%hhd %hhd %hhd %hhd %hhd %hhd %hhd %hhd\", c, uc, s, us, i, ui, l, ul);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %hhd in format string (no. 2) requires 'char' but the argument type is 'unsigned char'.\n" "[test.cpp:2]: (warning) %hhd in format string (no. 3) requires 'char' but the argument type is 'signed short'.\n" "[test.cpp:2]: (warning) %hhd in format string (no. 4) requires 'char' but the argument type is 'unsigned short'.\n" @@ -3303,7 +3424,7 @@ class TestIO : public TestFixture { check("void foo(char c, unsigned char uc, short s, unsigned short us, int i, unsigned int ui, long l, unsigned long ul) {\n" " printf(\"%hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu\", c, uc, s, us, i, ui, l, ul);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %hhu in format string (no. 1) requires 'unsigned char' but the argument type is 'char'.\n" "[test.cpp:2]: (warning) %hhu in format string (no. 3) requires 'unsigned char' but the argument type is 'signed short'.\n" "[test.cpp:2]: (warning) %hhu in format string (no. 4) requires 'unsigned char' but the argument type is 'unsigned short'.\n" @@ -3314,7 +3435,7 @@ class TestIO : public TestFixture { check("void foo(char c, unsigned char uc, short s, unsigned short us, int i, unsigned int ui, long l, unsigned long ul) {\n" " printf(\"%hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\", c, uc, s, us, i, ui, l, ul);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %hhx in format string (no. 1) requires 'unsigned char' but the argument type is 'char'.\n" "[test.cpp:2]: (warning) %hhx in format string (no. 3) requires 'unsigned char' but the argument type is 'signed short'.\n" "[test.cpp:2]: (warning) %hhx in format string (no. 4) requires 'unsigned char' but the argument type is 'unsigned short'.\n" @@ -3325,7 +3446,7 @@ class TestIO : public TestFixture { check("void foo(char c, unsigned char uc, short s, unsigned short us, int i, unsigned int ui, long l, unsigned long ul) {\n" " printf(\"%hd %hd %hd %hd %hd %hd %hd %hd\", c, uc, s, us, i, ui, l, ul);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %hd in format string (no. 1) requires 'short' but the argument type is 'char'.\n" "[test.cpp:2]: (warning) %hd in format string (no. 2) requires 'short' but the argument type is 'unsigned char'.\n" "[test.cpp:2]: (warning) %hd in format string (no. 4) requires 'short' but the argument type is 'unsigned short'.\n" @@ -3336,7 +3457,7 @@ class TestIO : public TestFixture { check("void foo(char c, unsigned char uc, short s, unsigned short us, int i, unsigned int ui, long l, unsigned long ul) {\n" " printf(\"%hu %hu %hu %hu %hu %hu %hu %hu\", c, uc, s, us, i, ui, l, ul);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %hu in format string (no. 1) requires 'unsigned short' but the argument type is 'char'.\n" "[test.cpp:2]: (warning) %hu in format string (no. 2) requires 'unsigned short' but the argument type is 'unsigned char'.\n" "[test.cpp:2]: (warning) %hu in format string (no. 3) requires 'unsigned short' but the argument type is 'signed short'.\n" @@ -3347,7 +3468,7 @@ class TestIO : public TestFixture { check("void foo(char c, unsigned char uc, short s, unsigned short us, int i, unsigned int ui, long l, unsigned long ul) {\n" " printf(\"%hx %hx %hx %hx %hx %hx %hx %hx\", c, uc, s, us, i, ui, l, ul);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2]: (warning) %hx in format string (no. 1) requires 'unsigned short' but the argument type is 'char'.\n" "[test.cpp:2]: (warning) %hx in format string (no. 2) requires 'unsigned short' but the argument type is 'unsigned char'.\n" "[test.cpp:2]: (warning) %hx in format string (no. 3) requires 'unsigned short' but the argument type is 'signed short'.\n" @@ -3363,9 +3484,23 @@ class TestIO : public TestFixture { "\n" "void foo(struct S x) {\n" " printf(\"%f\", x.f(4.0));\n" - "}"); + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("enum E : uint8_t { E0 }; \n" // #7959 + "void f(E e) {\n" + " printf(\"%hhu\", e);\n" + "}\n"); ASSERT_EQUALS("", errout_str()); + check("enum E : uint8_t { E0 }; \n" + "void f(E e) {\n" + " printf(\"%lu\", e);\n" + "}\n"); + TODO_ASSERT_EQUALS("[test.cpp:3]: (warning) %lu in format string (no. 1) requires 'unsigned long' but the argument type is 'uint8_t'.\n", + "", + errout_str()); + check("void f() {\n" " printf(\"%lu\", sizeof(char));\n" "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); @@ -4124,7 +4259,7 @@ class TestIO : public TestFixture { " printf(\"%1$d\", 1);" " printf(\"%1$d, %d, %1$d\", 1, 2);" " scanf(\"%1$d\", &bar);" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" @@ -4133,7 +4268,7 @@ class TestIO : public TestFixture { " printf(\"%1$d, %d, %4$d\", 1, 2, 3);\n" " scanf(\"%2$d\", &bar);\n" " printf(\"%0$f\", 0.0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:3]: (error) printf format string requires 1 parameter but only 0 are given. [wrongPrintfScanfArgNum]\n" "[test.cpp:4:3]: (warning) printf: referencing parameter 4 while 3 arguments given [wrongPrintfScanfParameterPositionError]\n" "[test.cpp:5:3]: (warning) scanf: referencing parameter 2 while 1 arguments given [wrongPrintfScanfParameterPositionError]\n" @@ -4156,7 +4291,7 @@ class TestIO : public TestFixture { " printf(\"%I32d %I32u %I32x\", u32, u32, u32);\n" " printf(\"%I64d %I64u %I64x\", i64, i64, i64);\n" " printf(\"%I64d %I64u %I64x\", u64, u64, u64);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win32A)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win32A)); ASSERT_EQUALS("[test.cpp:8:5]: (portability) %Id in format string (no. 1) requires 'ptrdiff_t' but the argument type is 'size_t {aka unsigned long}'. [invalidPrintfArgType_sint]\n" "[test.cpp:9:5]: (portability) %Iu in format string (no. 2) requires 'size_t' but the argument type is 'ptrdiff_t {aka signed long}'. [invalidPrintfArgType_uint]\n" "[test.cpp:9:5]: (portability) %Ix in format string (no. 3) requires 'size_t' but the argument type is 'ptrdiff_t {aka signed long}'. [invalidPrintfArgType_uint]\n" @@ -4178,7 +4313,7 @@ class TestIO : public TestFixture { " printf(\"%I32d %I32u %I32x\", u32, u32, u32);\n" " printf(\"%I64d %I64u %I64x\", i64, i64, i64);\n" " printf(\"%I64d %I64u %I64x\", u64, u64, u64);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); ASSERT_EQUALS("[test.cpp:8:5]: (portability) %Id in format string (no. 1) requires 'ptrdiff_t' but the argument type is 'size_t {aka unsigned long long}'. [invalidPrintfArgType_sint]\n" "[test.cpp:9:5]: (portability) %Iu in format string (no. 2) requires 'size_t' but the argument type is 'ptrdiff_t {aka signed long long}'. [invalidPrintfArgType_uint]\n" "[test.cpp:9:5]: (portability) %Ix in format string (no. 3) requires 'size_t' but the argument type is 'ptrdiff_t {aka signed long long}'. [invalidPrintfArgType_uint]\n" @@ -4204,7 +4339,7 @@ class TestIO : public TestFixture { " printf(\"%I16x%i\", s, i);\n" " printf(\"%I32%i\", s, i);\n" " printf(\"%I64%i\", s, i);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) 'I' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier. [invalidLengthModifierError]\n" "[test.cpp:5:5]: (warning) 'I' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier. [invalidLengthModifierError]\n" "[test.cpp:6:5]: (warning) 'I' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier. [invalidLengthModifierError]\n" @@ -4249,7 +4384,7 @@ class TestIO : public TestFixture { " printf(\"%zd\", s);\n" " printf(\"%zd%i\", s, i);\n" " printf(\"%zu\", s);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win32A)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win32A)); ASSERT_EQUALS("[test.cpp:6:5]: (portability) %zu in format string (no. 1) requires 'size_t' but the argument type is 'SSIZE_T {aka signed long}'. [invalidPrintfArgType_uint]\n", errout_str()); check("void foo() {\n" @@ -4258,7 +4393,7 @@ class TestIO : public TestFixture { " printf(\"%zd\", s);\n" " printf(\"%zd%i\", s, i);\n" " printf(\"%zu\", s);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); ASSERT_EQUALS("[test.cpp:6:5]: (portability) %zu in format string (no. 1) requires 'size_t' but the argument type is 'SSIZE_T {aka signed long long}'. [invalidPrintfArgType_uint]\n", errout_str()); check("void foo() {\n" @@ -4267,7 +4402,7 @@ class TestIO : public TestFixture { " printf(\"%zd\", s);\n" " printf(\"%zd%i\", s, i);\n" " printf(\"%zu\", s);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Unix64)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Unix64)); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" @@ -4277,7 +4412,7 @@ class TestIO : public TestFixture { " printf(\"%zd\", s);\n" " printf(\"%zd%i\", s, i);\n" " printf(\"%zu\", s);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); ASSERT_EQUALS("[test.cpp:7:5]: (portability) %zu in format string (no. 1) requires 'size_t' but the argument type is 'SSIZE_T {aka signed long long}'. [invalidPrintfArgType_uint]\n", errout_str()); } @@ -4296,7 +4431,7 @@ class TestIO : public TestFixture { " scanf(\"%I32d %I32u %I32x\", &u32, &u32, &u32);\n" " scanf(\"%I64d %I64u %I64x\", &i64, &i64, &i64);\n" " scanf(\"%I64d %I64u %I64x\", &u64, &u64, &u64);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win32A)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win32A)); ASSERT_EQUALS("[test.cpp:8:5]: (portability) %Id in format string (no. 1) requires 'ptrdiff_t *' but the argument type is 'size_t * {aka unsigned long *}'. [invalidScanfArgType_int]\n" "[test.cpp:9:5]: (portability) %Iu in format string (no. 2) requires 'size_t *' but the argument type is 'ptrdiff_t * {aka signed long *}'. [invalidScanfArgType_int]\n" "[test.cpp:9:5]: (portability) %Ix in format string (no. 3) requires 'size_t *' but the argument type is 'ptrdiff_t * {aka signed long *}'. [invalidScanfArgType_int]\n" @@ -4320,7 +4455,7 @@ class TestIO : public TestFixture { " scanf(\"%I32d %I32u %I32x\", &u32, &u32, &u32);\n" " scanf(\"%I64d %I64u %I64x\", &i64, &i64, &i64);\n" " scanf(\"%I64d %I64u %I64x\", &u64, &u64, &u64);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); ASSERT_EQUALS("[test.cpp:8:5]: (portability) %Id in format string (no. 1) requires 'ptrdiff_t *' but the argument type is 'size_t * {aka unsigned long long *}'. [invalidScanfArgType_int]\n" "[test.cpp:9:5]: (portability) %Iu in format string (no. 2) requires 'size_t *' but the argument type is 'ptrdiff_t * {aka signed long long *}'. [invalidScanfArgType_int]\n" "[test.cpp:9:5]: (portability) %Ix in format string (no. 3) requires 'size_t *' but the argument type is 'ptrdiff_t * {aka signed long long *}'. [invalidScanfArgType_int]\n" @@ -4348,7 +4483,7 @@ class TestIO : public TestFixture { " scanf(\"%I16x%i\", &s, &i);\n" " scanf(\"%I32%i\", &s, &i);\n" " scanf(\"%I64%i\", &s, &i);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning) 'I' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier. [invalidLengthModifierError]\n" "[test.cpp:5:5]: (warning) 'I' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier. [invalidLengthModifierError]\n" "[test.cpp:6:5]: (warning) 'I' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier. [invalidLengthModifierError]\n" @@ -4370,7 +4505,7 @@ class TestIO : public TestFixture { " scanf(\"%zd\", &s);\n" " scanf(\"%zd%i\", &s, &i);\n" " scanf(\"%zu\", &s);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win32A)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win32A)); ASSERT_EQUALS("[test.cpp:6:5]: (portability) %zu in format string (no. 1) requires 'size_t *' but the argument type is 'SSIZE_T * {aka signed long *}'. [invalidScanfArgType_int]\n", errout_str()); check("void foo() {\n" @@ -4379,7 +4514,7 @@ class TestIO : public TestFixture { " scanf(\"%zd\", &s);\n" " scanf(\"%zd%i\", &s, &i);\n" " scanf(\"%zu\", &s);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); ASSERT_EQUALS("[test.cpp:6:5]: (portability) %zu in format string (no. 1) requires 'size_t *' but the argument type is 'SSIZE_T * {aka signed long long *}'. [invalidScanfArgType_int]\n", errout_str()); check("void foo() {\n" @@ -4388,7 +4523,7 @@ class TestIO : public TestFixture { " scanf(\"%zd\", &s);\n" " scanf(\"%zd%i\", &s, &i);\n" " scanf(\"%zu\", &s);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Unix64)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Unix64)); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" @@ -4398,7 +4533,7 @@ class TestIO : public TestFixture { " scanf(\"%zd\", &s);\n" " scanf(\"%zd%i\", &s, &i);\n" " scanf(\"%zu\", &s);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win64)); ASSERT_EQUALS("[test.cpp:7:5]: (portability) %zu in format string (no. 1) requires 'size_t *' but the argument type is 'SSIZE_T * {aka signed long long *}'. [invalidScanfArgType_int]\n", errout_str()); } @@ -4409,7 +4544,7 @@ class TestIO : public TestFixture { " String string;\n" " string.Format(\"%I32d\", u32);\n" " string.AppendFormat(\"%I32d\", u32);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win32A)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win32A)); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" @@ -4417,7 +4552,7 @@ class TestIO : public TestFixture { " CString string;\n" " string.Format(\"%I32d\", u32);\n" " string.AppendFormat(\"%I32d\", u32);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Unix32)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Unix32)); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" @@ -4426,7 +4561,7 @@ class TestIO : public TestFixture { " string.Format(\"%I32d\", u32);\n" " string.AppendFormat(\"%I32d\", u32);\n" " CString::Format(\"%I32d\", u32);\n" - "}", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win32A)); + "}\n", dinit(CheckOptions, $.portability = true, $.platform = Platform::Type::Win32A)); ASSERT_EQUALS("[test.cpp:4:12]: (portability) %I32d in format string (no. 1) requires '__int32' but the argument type is 'unsigned __int32 {aka unsigned int}'. [invalidPrintfArgType_sint]\n" "[test.cpp:5:12]: (portability) %I32d in format string (no. 1) requires '__int32' but the argument type is 'unsigned __int32 {aka unsigned int}'. [invalidPrintfArgType_sint]\n" "[test.cpp:6:14]: (portability) %I32d in format string (no. 1) requires '__int32' but the argument type is 'unsigned __int32 {aka unsigned int}'. [invalidPrintfArgType_sint]\n", errout_str()); @@ -4656,6 +4791,18 @@ class TestIO : public TestFixture { "[test.cpp:17:5]: (warning) %s in format string (no. 5) requires 'char *' but the argument type is 'signed int'. [invalidPrintfArgType_s]\n" "[test.cpp:17:5]: (warning) sprintf_s format string requires 5 parameters but 6 are given. [wrongPrintfScanfArgNum]\n", errout_str()); + check("int main()\n" + "{\n" + " double value = 3.14;\n" + " const size_t buffer_size = 64;\n" + " char buffer[buffer_size];\n" + " int precision = 2;\n" + " _locale_t locale = _create_locale(LC_ALL, \"C\");\n" + " _sprintf_s_l(buffer, buffer_size, \"%.*f\", locale, precision, value);\n" + " _free_locale(locale);\n" + " return 0;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void testMicrosoftSecureScanfArgument() { @@ -4795,26 +4942,33 @@ class TestIO : public TestFixture { " wscanf_s(L\"%4[^-]\", msStr1, _countof(msStr1));\n" "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32W)); ASSERT_EQUALS("", errout_str()); + + check("void f(const char* c) {\n" + " const size_t N = 5;\n" + " char buf[N];\n" + " sscanf_s(c, \"%4[^.]\", buf, N);\n" + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win64)); + ASSERT_EQUALS("", errout_str()); } void testQStringFormatArguments() { check("void foo(float f) {\n" " QString string;\n" " string.sprintf(\"%d\", f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32A)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32A)); ASSERT_EQUALS("[test.cpp:3:12]: (warning) %d in format string (no. 1) requires 'int' but the argument type is 'float'. [invalidPrintfArgType_sint]\n", errout_str()); check("void foo(float f) {\n" " QString string;\n" " string = QString::asprintf(\"%d\", f);\n" - "}", dinit(CheckOptions, $.platform = Platform::Type::Win32A)); + "}\n", dinit(CheckOptions, $.platform = Platform::Type::Win32A)); ASSERT_EQUALS("[test.cpp:3:23]: (warning) %d in format string (no. 1) requires 'int' but the argument type is 'float'. [invalidPrintfArgType_sint]\n", errout_str()); } void testTernary() { // ticket #6182 check("void test(const std::string &val) {\n" " printf(\"%s\", val.empty() ? \"I like to eat bananas\" : val.c_str());\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -4822,30 +4976,30 @@ class TestIO : public TestFixture { check("void test() {\n" " unsigned const x = 5;\n" " printf(\"%u\", x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void testAstType() { // ticket #7014 check("void test() {\n" " printf(\"%c\", \"hello\"[0]);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void test() {\n" " printf(\"%lld\", (long long)1);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void test() {\n" " printf(\"%i\", (short *)x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (warning) %i in format string (no. 1) requires 'int' but the argument type is 'signed short *'. [invalidPrintfArgType_sint]\n", errout_str()); check("int (*fp)();\n" // #7178 - function pointer call "void test() {\n" " printf(\"%i\", fp());\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -4853,7 +5007,7 @@ class TestIO : public TestFixture { check("void foo() {\n" " printf(\"%u %lu %llu\", 0U, 0UL, 0ULL);\n" " printf(\"%u %lu %llu\", 0u, 0ul, 0ull);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -4861,7 +5015,7 @@ class TestIO : public TestFixture { check("void f() {\n" " const char *s = \"0\";\n" " printf(\"%ld%lld\", atol(s), atoll(s));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // 8141 @@ -4880,7 +5034,7 @@ class TestIO : public TestFixture { "PCINT pci;" "void foo() {\n" " printf(\"%d %p %p\", i, pi, pci);\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("using INT = int;\n\n" @@ -4891,7 +5045,7 @@ class TestIO : public TestFixture { "PCINT pci;" "void foo() {\n" " printf(\"%f %f %f\", i, pi, pci);\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:8:5]: (warning) %f in format string (no. 1) requires 'double' but the argument type is 'signed int'. [invalidPrintfArgType_float]\n" "[test.cpp:8:5]: (warning) %f in format string (no. 2) requires 'double' but the argument type is 'signed int *'. [invalidPrintfArgType_float]\n" "[test.cpp:8:5]: (warning) %f in format string (no. 3) requires 'double' but the argument type is 'const signed int *'. [invalidPrintfArgType_float]\n", errout_str()); @@ -4909,17 +5063,17 @@ class TestIO : public TestFixture { void testPrintfParenthesis() { // #8489 check("void f(int a) {\n" " printf(\"%f\", (a >> 24) & 0xff);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (warning) %f in format string (no. 1) requires 'double' but the argument type is 'signed int'. [invalidPrintfArgType_float]\n", errout_str()); check("void f(int a) {\n" " printf(\"%f\", 0xff & (a >> 24));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (warning) %f in format string (no. 1) requires 'double' but the argument type is 'signed int'. [invalidPrintfArgType_float]\n", errout_str()); check("void f(int a) {\n" " printf(\"%f\", ((a >> 24) + 1) & 0xff);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (warning) %f in format string (no. 1) requires 'double' but the argument type is 'signed int'. [invalidPrintfArgType_float]\n", errout_str()); } @@ -4927,7 +5081,7 @@ class TestIO : public TestFixture { check("void foo(const std::vector& IO, const int* pio) {\n" "const auto Idx = std::distance(&IO.front(), pio);\n" "printf(\"Idx = %td\", Idx);\n" - "}", dinit(CheckOptions, $.portability = true)); + "}\n", dinit(CheckOptions, $.portability = true)); ASSERT_EQUALS("", errout_str()); } diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index 043771ce471..cb5f9d53c8a 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,7 +29,7 @@ class TestLeakAutoVar : public TestFixture { TestLeakAutoVar() : TestFixture("TestLeakAutoVar") {} private: - const Settings settings = settingsBuilder().library("std.cfg").build(); + const Settings settings = settingsBuilder().library("std.cfg").checkLibrary().build(); void run() override { mNewTemplate = true; @@ -154,6 +154,7 @@ class TestLeakAutoVar : public TestFixture { TEST_CASE(ifelse27); TEST_CASE(ifelse28); // #11038 TEST_CASE(ifelse29); + TEST_CASE(ifelse30); // switch TEST_CASE(switch1); @@ -181,6 +182,7 @@ class TestLeakAutoVar : public TestFixture { TEST_CASE(return10); TEST_CASE(return11); // #13098 TEST_CASE(return12); // #12238 + TEST_CASE(return13); // General tests: variable type, allocation type, etc TEST_CASE(test1); @@ -209,6 +211,7 @@ class TestLeakAutoVar : public TestFixture { TEST_CASE(inlineFunction); // #3989 TEST_CASE(smartPtrInContainer); // #8262 + TEST_CASE(unconditionalScope); TEST_CASE(functionCallCastConfig); // #9652 TEST_CASE(functionCallLeakIgnoreConfig); // #7923 @@ -216,7 +219,6 @@ class TestLeakAutoVar : public TestFixture { struct CheckOptions { - CheckOptions() = default; bool cpp = false; const Settings *s = nullptr; }; @@ -224,26 +226,18 @@ class TestLeakAutoVar : public TestFixture { #define check(...) check_(__FILE__, __LINE__, __VA_ARGS__) template void check_(const char* file, int line, const char (&code)[size], const CheckOptions& options = make_default_obj()) { - const Settings settings1 = settingsBuilder(options.s ? *options.s : settings).checkLibrary().build(); - - // Tokenize.. - SimpleTokenizer tokenizer(settings1, *this, options.cpp); - ASSERT_LOC(tokenizer.tokenize(code), file, line); - - // Check for leaks.. - runChecks(tokenizer, this); + const Settings& settings1 = options.s ? *options.s : settings; + check_(file, line, code, settings1, options.cpp); } template - void check_(const char* file, int line, const char (&code)[size], const Settings & s) { - const Settings settings0 = settingsBuilder(s).checkLibrary().build(); - + void check_(const char* file, int line, const char (&code)[size], const Settings & s, bool cpp = true) { // Tokenize.. - SimpleTokenizer tokenizer(settings0, *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() { @@ -251,7 +245,7 @@ class TestLeakAutoVar : public TestFixture { " char *p = malloc(10);\n" " p = NULL;\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:3:5]: (error) Memory leak: p [memleak]\n", errout_str()); } @@ -260,7 +254,7 @@ class TestLeakAutoVar : public TestFixture { " char *p = malloc(10);\n" " char *q = p;\n" " free(q);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -269,7 +263,7 @@ class TestLeakAutoVar : public TestFixture { " char *p = malloc(10);\n" " char *q = p + 1;\n" " free(q - 1);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -278,7 +272,7 @@ class TestLeakAutoVar : public TestFixture { " char *a = malloc(10);\n" " a += 10;\n" " free(a - 10);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -287,7 +281,7 @@ class TestLeakAutoVar : public TestFixture { "{\n" " char *p = new char[100];\n" " list += p;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -296,7 +290,7 @@ class TestLeakAutoVar : public TestFixture { " char *p = malloc(10);\n" " p = strcpy(p,q);\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -304,7 +298,7 @@ class TestLeakAutoVar : public TestFixture { check("void foo(struct str *d) {\n" " struct str *p = malloc(10);\n" " d->p = p;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -312,7 +306,7 @@ class TestLeakAutoVar : public TestFixture { check("void foo(struct str *d) {\n" " struct str *p = malloc(10);\n" " d->p = &p->x;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -321,7 +315,7 @@ class TestLeakAutoVar : public TestFixture { " char *p = x();\n" " free(p);\n" " p = NULL;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -331,7 +325,7 @@ class TestLeakAutoVar : public TestFixture { " if (x) { p = malloc(10); }\n" " if (!x) { p = NULL; }\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -339,7 +333,7 @@ class TestLeakAutoVar : public TestFixture { check("void f() {\n" " char *p = malloc(10);\n" " x = a(b(p));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:4:1]: (information) --check-library: Function b() should have / configuration [checkLibraryUseIgnore]\n", errout_str()); } @@ -349,7 +343,7 @@ class TestLeakAutoVar : public TestFixture { " free(p);\n" " bar(&p);\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -359,22 +353,22 @@ class TestLeakAutoVar : public TestFixture { " char * &ref = p;\n" " p = malloc(10);\n" " free(ref);\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); TODO_ASSERT_EQUALS("", "[test.cpp:6:1]: (error) Memory leak: p [memleak]\n", errout_str()); } void assign14() { check("void f(int x) {\n" " char *p;\n" - " if (x && (p = malloc(10))) { }" - "}"); - ASSERT_EQUALS("[test.c:3:35]: (error) Memory leak: p [memleak]\n", errout_str()); + " if (x && (p = malloc(10))) { }\n" + "}\n"); + ASSERT_EQUALS("[test.c:4:1]: (error) Memory leak: p [memleak]\n", errout_str()); check("void f(int x) {\n" " char *p;\n" - " if (x && (p = new char[10])) { }" - "}", dinit(CheckOptions, $.cpp = true)); - ASSERT_EQUALS("[test.cpp:3:37]: (error) Memory leak: p [memleak]\n", errout_str()); + " if (x && (p = new char[10])) { }\n" + "}\n", dinit(CheckOptions, $.cpp = true)); + ASSERT_EQUALS("[test.cpp:4:1]: (error) Memory leak: p [memleak]\n", errout_str()); } void assign15() { @@ -385,7 +379,7 @@ class TestLeakAutoVar : public TestFixture { " free(p);\n" " p = malloc(sizeof *p);\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -394,48 +388,48 @@ class TestLeakAutoVar : public TestFixture { " char *p = malloc(10);\n" " free(p);\n" " if (p=dostuff()) *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void assign17() { // #9047 check("void f() {\n" " char *p = (char*)malloc(10);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:3:1]: (error) Memory leak: p [memleak]\n", errout_str()); check("void f() {\n" " char *p = (char*)(int*)malloc(10);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:3:1]: (error) Memory leak: p [memleak]\n", errout_str()); } void assign18() { check("void f(int x) {\n" " char *p;\n" - " if (x && (p = (char*)malloc(10))) { }" - "}"); - ASSERT_EQUALS("[test.c:3:42]: (error) Memory leak: p [memleak]\n", errout_str()); + " if (x && (p = (char*)malloc(10))) { }\n" + "}\n"); + ASSERT_EQUALS("[test.c:4:1]: (error) Memory leak: p [memleak]\n", errout_str()); check("void f(int x) {\n" " char *p;\n" - " if (x && (p = (char*)(int*)malloc(10))) { }" - "}"); - ASSERT_EQUALS("[test.c:3:48]: (error) Memory leak: p [memleak]\n", errout_str()); + " if (x && (p = (char*)(int*)malloc(10))) { }\n" + "}\n"); + ASSERT_EQUALS("[test.c:4:1]: (error) Memory leak: p [memleak]\n", errout_str()); } void assign19() { check("void f() {\n" " char *p = malloc(10);\n" " free((void*)p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void assign20() { // #9187 check("void f() {\n" " char *p = static_cast(malloc(10));\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:3:1]: (error) Memory leak: p [memleak]\n", errout_str()); } @@ -443,32 +437,32 @@ class TestLeakAutoVar : public TestFixture { check("void f(int **x) {\n" // #10186 " void *p = malloc(10);\n" " *x = (int*)p;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("struct S { int i; };\n" // #10996 "void f() {\n" " S* s = new S();\n" " (void)s;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:5:1]: (error) Memory leak: s [memleak]\n", errout_str()); } void assign22() { // #9139 - const Settings s = settingsBuilder().library("posix.cfg").build(); + const Settings s = settingsBuilder().library("posix.cfg").checkLibrary().build(); check("void f(char tempFileName[256]) {\n" " const int fd = socket(AF_INET, SOCK_PACKET, 0 );\n" - "}", dinit(CheckOptions, $.cpp = true, $.s = &s)); + "}\n", dinit(CheckOptions, $.cpp = true, $.s = &s)); ASSERT_EQUALS("[test.cpp:3:1]: (error) Resource leak: fd [resourceLeak]\n", errout_str()); check("void f() {\n" " const void * const p = malloc(10);\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:3:1]: (error) Memory leak: p [memleak]\n", errout_str()); } void assign23() { - const Settings s = settingsBuilder().library("posix.cfg").build(); + const Settings s = settingsBuilder().library("posix.cfg").checkLibrary().build(); check("void f() {\n" " int n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14;\n" " *&n1 = open(\"xx.log\", O_RDONLY);\n" @@ -571,7 +565,7 @@ class TestLeakAutoVar : public TestFixture { check("void f() {\n" // #11796 " int* p{ new int };\n" " int* q(new int);\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:4:1]: (error) Memory leak: p [memleak]\n" "[test.cpp:4:1]: (error) Memory leak: q [memleak]\n", errout_str()); @@ -635,14 +629,22 @@ class TestLeakAutoVar : public TestFixture { check("void f(int*& x) {\n" // #8235 " int* p = (int*)malloc(10);\n" " x = p ? p : nullptr;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("void f(int*& x) {\n" " int* p = (int*)malloc(10);\n" " x = p != nullptr ? p : nullptr;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); + + check("void f(const char* n) {\n" // #12724 + " FILE* fp = fopen(n, \"r\");\n" + " bool b = (fp == NULL);\n" + " if (b)\n" + " return;\n" + "}\n", dinit(CheckOptions, $.cpp = true)); + ASSERT_EQUALS("[test.cpp:6:1]: (error) Resource leak: fp [resourceLeak]\n", errout_str()); } void memcpy1() { // #11542 @@ -664,17 +666,17 @@ class TestLeakAutoVar : public TestFixture { void isAutoDealloc() { check("void f() {\n" " char *p = new char[100];" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:2:29]: (error) Memory leak: p [memleak]\n", errout_str()); check("void f() {\n" " Fred *fred = new Fred;" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " std::string *str = new std::string;" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:2:40]: (error) Memory leak: str [memleak]\n", errout_str()); check("class TestType {\n" // #9028 @@ -683,13 +685,13 @@ class TestLeakAutoVar : public TestFixture { "};\n" "void f() {\n" " TestType *tt = new TestType();\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:7:1]: (error) Memory leak: tt [memleak]\n", errout_str()); check("void f(Bar& b) {\n" // #7622 " char* data = new char[10];\n" " b = Bar(*new Foo(data));\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:4:1]: (information) --check-library: Function Foo() should have / configuration [checkLibraryUseIgnore]\n", errout_str()); check("class B {};\n" @@ -697,7 +699,7 @@ class TestLeakAutoVar : public TestFixture { " void g() {\n" " auto d = new D();\n" " if (d) {}\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:6:1]: (error) Memory leak: d [memleak]\n", errout_str()); check("struct S {\n" // #12354 @@ -708,7 +710,7 @@ class TestLeakAutoVar : public TestFixture { " if (b)\n" " p = new S();\n" " p->f();\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:9:1]: (error) Memory leak: p [memleak]\n", errout_str()); } @@ -717,7 +719,7 @@ class TestLeakAutoVar : public TestFixture { " void *p = malloc(10);\n" " void *q = realloc(p, 20);\n" " free(q)\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -725,7 +727,7 @@ class TestLeakAutoVar : public TestFixture { check("void f() {\n" " void *p = malloc(10);\n" " void *q = realloc(p, 20);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:4:1]: (error) Memory leak: q [memleak]\n", errout_str()); } @@ -733,7 +735,7 @@ class TestLeakAutoVar : public TestFixture { check("void f() {\n" " char *p = malloc(10);\n" " char *q = (char*) realloc(p, 20);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:4:1]: (error) Memory leak: q [memleak]\n", errout_str()); } @@ -742,7 +744,7 @@ class TestLeakAutoVar : public TestFixture { " void * q = realloc(p, 10);\n" " if (q == NULL)\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:5:1]: (error) Memory leak: q [memleak]\n", errout_str()); } @@ -753,7 +755,7 @@ class TestLeakAutoVar : public TestFixture { " if (size && !datap)\n" " free(ptr);\n" " return datap;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9990 @@ -767,7 +769,7 @@ class TestLeakAutoVar : public TestFixture { " return;\n" " }\n" " free(p2);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -776,7 +778,7 @@ class TestLeakAutoVar : public TestFixture { " void *p = fopen(name,a);\n" " void *q = freopen(name, b, p);\n" " fclose(q)\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -784,7 +786,7 @@ class TestLeakAutoVar : public TestFixture { check("void f() {\n" " void *p = fopen(name,a);\n" " void *q = freopen(name, b, p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:4:1]: (error) Resource leak: q [resourceLeak]\n", errout_str()); } @@ -792,13 +794,13 @@ class TestLeakAutoVar : public TestFixture { check("void f(char *p) {\n" " free(p);\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:3:6]: (error) Dereferencing 'p' after it is deallocated / released [deallocuse]\n", errout_str()); check("void f(char *p) {\n" " free(p);\n" " char c = *p;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:3:15]: (error) Dereferencing 'p' after it is deallocated / released [deallocuse]\n", errout_str()); } @@ -806,7 +808,7 @@ class TestLeakAutoVar : public TestFixture { check("void f(struct str *p) {\n" " free(p);\n" " p = p->next;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:3:9]: (error) Dereferencing 'p' after it is deallocated / released [deallocuse]\n", errout_str()); } @@ -814,25 +816,25 @@ class TestLeakAutoVar : public TestFixture { check("void f(char *p) {\n" " free(p);\n" " return p;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:2:5] -> [test.c:3:5]: (error) Returning/dereferencing 'p' after it is deallocated / released [deallocret]\n", errout_str()); check("void f(char *p) {\n" " if (!p) free(p);\n" " return p;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(char *p) {\n" " if (!p) delete p;\n" " return p;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("void f(char *p) {\n" " if (!p) delete [] p;\n" " return p;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("void f(void* p) {\n" @@ -842,7 +844,7 @@ class TestLeakAutoVar : public TestFixture { " }\n" " g(p);\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -850,7 +852,7 @@ class TestLeakAutoVar : public TestFixture { check("void f(char *p) {\n" " free(p), p = 0;\n" " *p = 0;\n" // <- Make sure pointer info is reset. It is NOT a freed pointer dereference - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -858,7 +860,7 @@ class TestLeakAutoVar : public TestFixture { check("void f(char *p) {\n" " free(p);\n" " x = p = foo();\n" // <- p is not dereferenced - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -867,14 +869,14 @@ class TestLeakAutoVar : public TestFixture { "void f(Foo* foo) {\n" " delete foo->ptr;\n" " foo->ptr = new Foo;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("struct Foo { int* ptr; };\n" "void f(Foo* foo) {\n" " delete foo->ptr;\n" " x = *foo->ptr;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); TODO_ASSERT_EQUALS("[test.cpp:4:6]: (error) Dereferencing 'ptr' after it is deallocated / released [deallocuse]\n", "", errout_str()); check("void parse() {\n" @@ -883,7 +885,7 @@ class TestLeakAutoVar : public TestFixture { " ~Buf() { delete[]m_buf; }\n" " uint8_t *m_buf;\n" " };\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("struct Foo {\n" @@ -895,14 +897,14 @@ class TestLeakAutoVar : public TestFixture { " delete foo->ptr;\n" " foo->ptr = new Foo;\n" " foo->ptr->func();\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("void foo(void (*conv)(char**)) {\n" " char * ptr=(char*)malloc(42);\n" " free(ptr);\n" " (*conv)(&ptr);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -911,7 +913,7 @@ class TestLeakAutoVar : public TestFixture { " int *ptr = new int;\n" " delete(ptr);\n" " *ptr = 0;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:4:6]: (error) Dereferencing 'ptr' after it is deallocated / released [deallocuse]\n", errout_str()); } @@ -962,14 +964,14 @@ class TestLeakAutoVar : public TestFixture { " int *array = new int[42];\n" " delete [] array;\n" " return array[1];" // << - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:3:3] -> [test.cpp:4:3]: (error) Returning/dereferencing 'array' after it is deallocated / released [deallocret]\n", errout_str()); check("int f() {\n" " int *array = (int*)malloc(40);\n" " free(array);\n" " return array[1];" // << - "}"); + "}\n"); ASSERT_EQUALS("[test.c:3:3] -> [test.c:4:3]: (error) Returning/dereferencing 'array' after it is deallocated / released [deallocret]\n", errout_str()); } @@ -980,7 +982,7 @@ class TestLeakAutoVar : public TestFixture { "}\n" "void f2(struct foo *f, int *out) {\n" " *out = f->x;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1118,35 +1120,35 @@ class TestLeakAutoVar : public TestFixture { " else\n" " p = 0;\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:3:9] -> [test.c:6:5]: (error) Memory pointed to by 'p' is freed twice. [doubleFree]\n", errout_str()); check( "void foo(char *p) {\n" " free(p);\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:2:3] -> [test.c:3:3]: (error) Memory pointed to by 'p' is freed twice. [doubleFree]\n", errout_str()); check( "void foo(char *p, char *r) {\n" " free(p);\n" " free(r);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check( "void foo() {\n" " free(p);\n" " free(r);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check( "void foo(char *p) {\n" " if (x < 3) free(p);\n" " else { if (x > 9) free(p); }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check( @@ -1154,7 +1156,7 @@ class TestLeakAutoVar : public TestFixture { " free(p);\n" " getNext(&p);\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check( @@ -1162,7 +1164,7 @@ class TestLeakAutoVar : public TestFixture { " free(p);\n" " bar();\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:2:3] -> [test.c:4:3]: (error) Memory pointed to by 'p' is freed twice. [doubleFree]\n", errout_str()); check( @@ -1170,7 +1172,7 @@ class TestLeakAutoVar : public TestFixture { " free(p);\n" " printf(\"Freed memory at location %x\", p);\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:3:41]: (error) Dereferencing 'p' after it is deallocated / released [deallocuse]\n" "[test.c:2:3] -> [test.c:4:3]: (error) Memory pointed to by 'p' is freed twice. [doubleFree]\n", errout_str()); @@ -1179,21 +1181,21 @@ class TestLeakAutoVar : public TestFixture { "void foo(FILE *p) {\n" " fclose(p);\n" " fclose(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:2:3] -> [test.c:3:3]: (error) Resource handle 'p' freed twice. [doubleFree]\n", errout_str()); check( "void foo(FILE *p, FILE *r) {\n" " fclose(p);\n" " fclose(r);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check( "void foo(FILE *p) {\n" " if (x < 3) fclose(p);\n" " else { if (x > 9) fclose(p); }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check( @@ -1201,7 +1203,7 @@ class TestLeakAutoVar : public TestFixture { " fclose(p);\n" " gethandle(&p);\n" " fclose(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check( @@ -1209,14 +1211,14 @@ class TestLeakAutoVar : public TestFixture { " fclose(p);\n" " gethandle();\n" " fclose(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:2:3] -> [test.c:4:3]: (error) Resource handle 'p' freed twice. [doubleFree]\n", errout_str()); check( "void foo(Data* p) {\n" " free(p->a);\n" " free(p->b);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check( @@ -1227,7 +1229,7 @@ class TestLeakAutoVar : public TestFixture { " exit();\n" " }\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check( @@ -1238,7 +1240,7 @@ class TestLeakAutoVar : public TestFixture { " x = 0;\n" " }\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:4:9] -> [test.c:7:5]: (error) Memory pointed to by 'p' is freed twice. [doubleFree]\n", errout_str()); check( @@ -1247,35 +1249,35 @@ class TestLeakAutoVar : public TestFixture { " free(p);\n" " p = do_something();\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check( "void foo(char *p) {\n" " delete p;\n" " delete p;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:2:10] -> [test.cpp:3:10]: (error) Memory pointed to by 'p' is freed twice. [doubleFree]\n", errout_str()); check( "void foo(char *p, char *r) {\n" " delete p;\n" " delete r;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check( "void foo(P p) {\n" " delete p.x;\n" " delete p;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check( "void foo(char **p) {\n" " delete p[0];\n" " delete p[1];\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check( @@ -1283,7 +1285,7 @@ class TestLeakAutoVar : public TestFixture { " delete p;\n" " getNext(&p);\n" " delete p;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check( @@ -1291,21 +1293,21 @@ class TestLeakAutoVar : public TestFixture { " delete p;\n" " bar();\n" " delete p;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:2:10] -> [test.cpp:4:10]: (error) Memory pointed to by 'p' is freed twice. [doubleFree]\n", errout_str()); check( "void foo(char *p) {\n" " delete[] p;\n" " delete[] p;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:2:12] -> [test.cpp:3:12]: (error) Memory pointed to by 'p' is freed twice. [doubleFree]\n", errout_str()); check( "void foo(char *p, char *r) {\n" " delete[] p;\n" " delete[] r;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check( @@ -1313,7 +1315,7 @@ class TestLeakAutoVar : public TestFixture { " delete[] p;\n" " getNext(&p);\n" " delete[] p;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check( @@ -1321,7 +1323,7 @@ class TestLeakAutoVar : public TestFixture { " delete[] p;\n" " bar();\n" " delete[] p;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:2:12] -> [test.cpp:4:12]: (error) Memory pointed to by 'p' is freed twice. [doubleFree]\n", errout_str()); check( @@ -1332,7 +1334,7 @@ class TestLeakAutoVar : public TestFixture { " delete pxpm;\n" " pxpm = NULL;\n" " return *this;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check( @@ -1349,7 +1351,7 @@ class TestLeakAutoVar : public TestFixture { " throw;\n" " }\n" " delete ptr;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check( @@ -1365,7 +1367,7 @@ class TestLeakAutoVar : public TestFixture { " if(doDelete)\n" " delete a;\n" " return 0;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); TODO_ASSERT_EQUALS("", "[test.cpp:8:8] -> [test.cpp:11:15]: (error) Memory pointed to by 'a' is freed twice. [doubleFree]\n", errout_str()); check( @@ -1379,7 +1381,7 @@ class TestLeakAutoVar : public TestFixture { " delete[] x;\n" " }\n" " delete[] x;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check( @@ -1391,7 +1393,7 @@ class TestLeakAutoVar : public TestFixture { " delete[] x;\n" " }\n" " delete[] x;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); TODO_ASSERT_EQUALS("[test.cpp:8]: (error) Memory pointed to by 'x' is freed twice.\n", "", errout_str()); check( @@ -1403,7 +1405,7 @@ class TestLeakAutoVar : public TestFixture { " delete[] x;\n" " }\n" " delete[] x;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); TODO_ASSERT_EQUALS("[test.cpp:8]: (error) Memory pointed to by 'x' is freed twice.\n", "", errout_str()); check( @@ -1415,7 +1417,7 @@ class TestLeakAutoVar : public TestFixture { " free(x);\n" " }\n" " free(x);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.c:8]: (error) Memory pointed to by 'x' is freed twice.\n", "", errout_str()); check( @@ -1429,7 +1431,7 @@ class TestLeakAutoVar : public TestFixture { " delete[] x;\n" " }\n" " delete[] x;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check( @@ -1443,7 +1445,7 @@ class TestLeakAutoVar : public TestFixture { " delete[] x;\n" " } while (true);\n" " delete[] x;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check( @@ -1455,7 +1457,7 @@ class TestLeakAutoVar : public TestFixture { " free(p);\n" " }\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:6:9] -> [test.c:8:5]: (error) Memory pointed to by 'p' is freed twice. [doubleFree]\n", errout_str()); check( @@ -1476,7 +1478,7 @@ class TestLeakAutoVar : public TestFixture { "void MyThrow(err)\n" "{\n" " throw(err);\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check( @@ -1497,7 +1499,7 @@ class TestLeakAutoVar : public TestFixture { "void MyExit(err)\n" "{\n" " exit(err);\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check( // #6252 @@ -1512,14 +1514,14 @@ class TestLeakAutoVar : public TestFixture { " delete m_thing;\n" " m_thing = new Thing;\n" " }\n" - "};", dinit(CheckOptions, $.cpp = true)); + "};\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); // #7401 check("void pCodeLabelDestruct(pCode *pc) {\n" " free(PCL(pc)->label);\n" " free(pc);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1529,7 +1531,7 @@ class TestLeakAutoVar : public TestFixture { " if (a == 2) { free(p); return ((void*)1); }\n" " free(p);\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1546,7 +1548,7 @@ class TestLeakAutoVar : public TestFixture { " free(bar)\n" " } while(!done);\n" " return;" - "}" + "}\n" ); ASSERT_EQUALS("", errout_str()); } @@ -1558,7 +1560,7 @@ class TestLeakAutoVar : public TestFixture { " exit(1);\n" " }\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(void* p, int i) {\n" // #11391 @@ -1578,7 +1580,7 @@ class TestLeakAutoVar : public TestFixture { " free(p);\n" " x = (q == p);\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:2:3] -> [test.c:4:3]: (error) Memory pointed to by 'p' is freed twice. [doubleFree]\n", errout_str()); } @@ -1586,7 +1588,7 @@ class TestLeakAutoVar : public TestFixture { check("void do_wordexp(FILE *f) {\n" " free(getword(f));\n" " fclose(f);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1595,14 +1597,14 @@ class TestLeakAutoVar : public TestFixture { " free(p);\n" " if (x && (p = malloc(10)))\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(char *p, int x) {\n" " delete[] p;\n" " if (x && (p = new char[10]))\n" " delete[] p;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); } @@ -1715,7 +1717,7 @@ class TestLeakAutoVar : public TestFixture { " if (q == NULL)\n" " return;\n" " free(q);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:3:16] -> [test.c:8:5]: (error) Memory pointed to by 'p' is freed twice. [doubleFree]\n", errout_str()); } @@ -1751,7 +1753,7 @@ class TestLeakAutoVar : public TestFixture { " int *i = new int;\n" " unique_ptr x(i);\n" " delete i;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:6:5] -> [test.cpp:7:12]: (error) Memory pointed to by 'i' is freed twice. [doubleFree]\n", errout_str()); check("using namespace std;\n" @@ -1760,14 +1762,14 @@ class TestLeakAutoVar : public TestFixture { "{\n" " int *i = new int;\n" " unique_ptr x(i);\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); } void doublefree15() { // #11966 check("void f(FILE* fp) {\n" " static_cast(fclose(fp));\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); } @@ -1829,7 +1831,7 @@ class TestLeakAutoVar : public TestFixture { check("void f() {\n" " char *p = malloc(10);\n" " exit(0);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1837,7 +1839,7 @@ class TestLeakAutoVar : public TestFixture { check("void f() {\n" " char *p = malloc(10);\n" " fatal_error();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:3:18]: (information) --check-library: Function fatal_error() should have configuration [checkLibraryNoReturn]\n", errout_str()); } @@ -1848,9 +1850,9 @@ class TestLeakAutoVar : public TestFixture { " if (x) {\n" " free(p);\n" " ::exit(0);\n" - " }" + " }\n" " free(p);\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -1858,9 +1860,9 @@ class TestLeakAutoVar : public TestFixture { " if (x) {\n" " free(p);\n" " std::exit(0);\n" - " }" + " }\n" " free(p);\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); } @@ -1873,7 +1875,7 @@ class TestLeakAutoVar : public TestFixture { " func_notret();\n" " }\n" " free(ptr);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1882,7 +1884,7 @@ class TestLeakAutoVar : public TestFixture { " p->x = malloc(10);\n" " free(p->x);\n" " p->x = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(s_t s) {\n" // #11061 @@ -1904,7 +1906,7 @@ class TestLeakAutoVar : public TestFixture { check("void g(size_t len) {\n" // #12365 " char* b = new char[len + 1]{};\n" " std::string str = std::string(b);\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:4:1]: (error) Memory leak: b [memleak]\n", errout_str()); } @@ -1915,7 +1917,7 @@ class TestLeakAutoVar : public TestFixture { " if (err) {\n" " free(reg);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1928,7 +1930,7 @@ class TestLeakAutoVar : public TestFixture { " goto x;\n" " }\n" " return p;\n" // no error since there is a goto - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1953,7 +1955,7 @@ class TestLeakAutoVar : public TestFixture { " if (x) { p = malloc(10); }\n" " else { return 0; }\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1962,7 +1964,7 @@ class TestLeakAutoVar : public TestFixture { " char *p = NULL;\n" " if (x) { p = malloc(10); }\n" " else { return 0; }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:5:1]: (error) Memory leak: p [memleak]\n", errout_str()); } @@ -1971,7 +1973,7 @@ class TestLeakAutoVar : public TestFixture { " char *p = malloc(10);\n" " if (!p) { return; }\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("char * f(size_t size) {" @@ -1979,14 +1981,14 @@ class TestLeakAutoVar : public TestFixture { " if (!p && size != 0)" " return NULL;" " return p;" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " char *p = malloc(10);\n" " if (p) { } else { return; }\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #3866 - UNLIKELY @@ -1994,7 +1996,7 @@ class TestLeakAutoVar : public TestFixture { " char *p = malloc(10);\n" " if (UNLIKELY(!p)) { return; }\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2003,7 +2005,7 @@ class TestLeakAutoVar : public TestFixture { " char *p;\n" " if (x) { p = malloc(10); }\n" " if (x) { free(p); }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" @@ -2011,7 +2013,7 @@ class TestLeakAutoVar : public TestFixture { " if (x) { p = malloc(10); }\n" " if (!x) { return; }\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2020,7 +2022,7 @@ class TestLeakAutoVar : public TestFixture { " char *p = malloc(10);\n" " if (!p && x) { p = malloc(10); }\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2031,7 +2033,7 @@ class TestLeakAutoVar : public TestFixture { " free(a);\n" " else\n" " a = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:6:9]: (error) Memory leak: a [memleak]\n", errout_str()); } @@ -2041,7 +2043,7 @@ class TestLeakAutoVar : public TestFixture { " if (x < 0)\n" // assume negative value indicates its unallocated " return;\n" " free(x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2051,7 +2053,7 @@ class TestLeakAutoVar : public TestFixture { " if (fd == -1)\n" " return -1;\n" " return fd;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f() {\n" @@ -2059,7 +2061,7 @@ class TestLeakAutoVar : public TestFixture { " if (fd != -1)\n" " return fd;\n" " return -1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2069,7 +2071,7 @@ class TestLeakAutoVar : public TestFixture { " if (dostuff(p==NULL,0))\n" " return;\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2079,7 +2081,7 @@ class TestLeakAutoVar : public TestFixture { " if (!(x != NULL))\n" " return;\n" " free(x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2089,7 +2091,7 @@ class TestLeakAutoVar : public TestFixture { " if (NULL == (p = malloc(4)))\n" " return;\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2097,7 +2099,7 @@ class TestLeakAutoVar : public TestFixture { check("void f(char **p) {\n" " if ((*p = malloc(4)) == NULL)\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2108,7 +2110,7 @@ class TestLeakAutoVar : public TestFixture { " return 1;\n" " free(path);\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f(int fd, const char *mode) {\n" @@ -2117,7 +2119,7 @@ class TestLeakAutoVar : public TestFixture { " return 1;\n" // <- memory leak " free(path);\n" " return 0;\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4] memory leak", "", errout_str()); } @@ -2127,7 +2129,7 @@ class TestLeakAutoVar : public TestFixture { " if (buf == (char*)NULL)\n" " return NULL;\n" " return buf;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2137,14 +2139,14 @@ class TestLeakAutoVar : public TestFixture { "void test_alloc() {\n" " if ( global_ptr = new SSS()) {}\n" " return;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("FILE* hFile;\n" "int openFile( void ) {\n" " if ((hFile = fopen(\"1.txt\", \"wb\" )) == NULL) return 0;\n" " return 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2155,7 +2157,7 @@ class TestLeakAutoVar : public TestFixture { " return;\n" " free(p);\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(void) {\n" @@ -2164,7 +2166,7 @@ class TestLeakAutoVar : public TestFixture { " return;\n" " free(p);\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2174,7 +2176,7 @@ class TestLeakAutoVar : public TestFixture { " if (!p)\n" " return NULL;\n" " return p;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int *f() {\n" @@ -2182,7 +2184,7 @@ class TestLeakAutoVar : public TestFixture { " if (!!(!p))\n" " return NULL;\n" " return p;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2193,7 +2195,7 @@ class TestLeakAutoVar : public TestFixture { " if (q == 0)\n" " return;\n" " free(q);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:5:9]: (error) Memory leak: p [memleak]\n", errout_str()); check("void f() {\n" @@ -2204,7 +2206,7 @@ class TestLeakAutoVar : public TestFixture { " return;\n" " } else\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:8:9]: (error) Memory leak: p [memleak]\n", errout_str()); } @@ -2215,7 +2217,7 @@ class TestLeakAutoVar : public TestFixture { " if (!b)\n" " return;\n" " a = b;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2226,7 +2228,7 @@ class TestLeakAutoVar : public TestFixture { " else\n" " void * p2 = malloc(2);\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:3:30]: (error) Memory leak: p1 [memleak]\n" "[test.c:5:30]: (error) Memory leak: p2 [memleak]\n", errout_str()); @@ -2235,7 +2237,7 @@ class TestLeakAutoVar : public TestFixture { " void * p1 = malloc(5);\n" " else\n" " void * p2 = malloc(2);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:3:30]: (error) Memory leak: p1 [memleak]\n" "[test.c:5:30]: (error) Memory leak: p2 [memleak]\n", errout_str()); } @@ -2248,7 +2250,7 @@ class TestLeakAutoVar : public TestFixture { " p = malloc(5);\n" " }\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:6:5]: (error) Memory leak: p [memleak]\n", errout_str()); } @@ -2258,7 +2260,7 @@ class TestLeakAutoVar : public TestFixture { " if (fd >= 0)\n" " return fd;\n" " return -1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f(const char * pathname, int flags) {\n" @@ -2266,7 +2268,7 @@ class TestLeakAutoVar : public TestFixture { " if (fd <= -1)\n" " return -1;\n" " return fd;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2278,7 +2280,7 @@ class TestLeakAutoVar : public TestFixture { } void ifelse24() { // #1733 - const Settings s = settingsBuilder().library("std.cfg").library("posix.cfg").build(); + const Settings s = settingsBuilder().library("std.cfg").library("posix.cfg").checkLibrary().build(); check("void f() {\n" " char* temp = strdup(\"temp.txt\");\n" @@ -2384,6 +2386,22 @@ class TestLeakAutoVar : public TestFixture { ASSERT_EQUALS("", errout_str()); // don't crash } + void ifelse30() { + check("void f(void** pp) {\n" // #14709 + " void* p = malloc(8);\n" + " if ((void*)p == 0)\n" + " return;\n" + " *pp = p;\n" + "}\n" + "void g(void** pp) {\n" + " void* p = malloc(8);\n" + " if (static_cast(p) == 0)\n" + " return;\n" + " *pp = p;\n" + "}\n", dinit(CheckOptions, $.cpp = true)); + ASSERT_EQUALS("", errout_str()); + } + void switch1() { check("void f() {\n" " char *p = 0;\n" @@ -2392,7 +2410,7 @@ class TestLeakAutoVar : public TestFixture { " default: return;\n" " }\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2403,7 +2421,7 @@ class TestLeakAutoVar : public TestFixture { " for (i=0;i<5;i++) { }\n" " if (x) { free(p) }\n" " else { a = p; }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2438,13 +2456,13 @@ class TestLeakAutoVar : public TestFixture { check("void f() {\n" " FILE*f=fopen(fname,a);\n" " free(f);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:2:12] -> [test.c:3:5]: (error) Mismatching allocation and deallocation: f [mismatchAllocDealloc]\n", errout_str()); check("void f() {\n" " FILE*f=fopen(fname,a);\n" " free((void*)f);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:2:12] -> [test.c:3:5]: (error) Mismatching allocation and deallocation: f [mismatchAllocDealloc]\n", errout_str()); check("void f() {\n" @@ -2454,18 +2472,18 @@ class TestLeakAutoVar : public TestFixture { " delete[] cPtr;\n" " cPtr = new char[100];\n" " delete cPtr;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:6:12] -> [test.cpp:7:12]: (error) Mismatching allocation and deallocation: cPtr [mismatchAllocDealloc]\n", errout_str()); check("void f() {\n" " char *cPtr = new char[100];\n" " free(cPtr);\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:2:18] -> [test.cpp:3:5]: (error) Mismatching allocation and deallocation: cPtr [mismatchAllocDealloc]\n", errout_str()); check("void f() {\n" " char *cPtr = new (buf) char[100];\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -2484,7 +2502,7 @@ class TestLeakAutoVar : public TestFixture { " void* a = malloc(1);\n" " void* b = freopen(f, p, a);\n" " free(b);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:2:14] -> [test.c:3:14]: (error) Mismatching allocation and deallocation: a [mismatchAllocDealloc]\n" "[test.c:3:14] -> [test.c:4:4]: (error) Mismatching allocation and deallocation: b [mismatchAllocDealloc]\n", errout_str()); @@ -2492,14 +2510,14 @@ class TestLeakAutoVar : public TestFixture { " void* a;\n" " void* b = realloc(a, 10);\n" " free(b);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " int * i = new int;\n" " int * j = realloc(i, 2 * sizeof(int));\n" " delete[] j;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:2:14] -> [test.cpp:3:14]: (error) Mismatching allocation and deallocation: i [mismatchAllocDealloc]\n" "[test.cpp:3:14] -> [test.cpp:4:13]: (error) Mismatching allocation and deallocation: j [mismatchAllocDealloc]\n", errout_str()); @@ -2529,26 +2547,26 @@ class TestLeakAutoVar : public TestFixture { check("void f() {\n" " FILE*f=fopen(fname,a);\n" " std::unique_ptr fp{f};\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:2:12] -> [test.cpp:3:30]: (error) Mismatching allocation and deallocation: f [mismatchAllocDealloc]\n", errout_str()); check("void f() {\n" " FILE*f=fopen(fname,a);\n" " std::unique_ptr fp{f, &fclose};\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " FILE*f=fopen(fname,a);\n" " std::shared_ptr fp{f, &fclose};\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("struct deleter { void operator()(FILE* f) { fclose(f); }};\n" "void f() {\n" " FILE*f=fopen(fname,a);\n" " std::unique_ptr fp{f};\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("int * create();\n" @@ -2570,39 +2588,39 @@ class TestLeakAutoVar : public TestFixture { check("void f() {\n" " FILE*f=fopen(fname,a);\n" " std::shared_ptr fp{f, [](FILE* x) { fclose(x); }};\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " FILE*f=fopen(fname,a);\n" " std::shared_ptr fp{f, +[](FILE* x) { fclose(x); }};\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " FILE*f=fopen(fname,a);\n" " std::shared_ptr fp{f, [](FILE* x) { free(f); }};\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:2:12] -> [test.cpp:3:30]: (error) Mismatching allocation and deallocation: f [mismatchAllocDealloc]\n", errout_str()); check("void f() {\n" " FILE*f=fopen(fname,a);\n" " std::shared_ptr fp{f, [](FILE* x) {}};\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:2:12] -> [test.cpp:3:30]: (error) Mismatching allocation and deallocation: f [mismatchAllocDealloc]\n", errout_str()); check("class C;\n" "void f() {\n" " C* c = new C{};\n" " std::shared_ptr a{c, [](C*) {}};\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("class C;\n" "void f() {\n" " C* c = new C{};\n" " std::shared_ptr a{c, [](C* x) { delete x; }};\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("struct DirDeleter {\n" // #12544 @@ -2634,7 +2652,7 @@ class TestLeakAutoVar : public TestFixture { check("int f() {\n" " char *p = malloc(100);\n" " return 123;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:3:5]: (error) Memory leak: p [memleak]\n", errout_str()); } @@ -2642,7 +2660,7 @@ class TestLeakAutoVar : public TestFixture { check("char *f() {\n" " char *p = malloc(100);\n" " return p;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2650,7 +2668,7 @@ class TestLeakAutoVar : public TestFixture { check("struct dev * f() {\n" " struct ABC *abc = malloc(100);\n" " return &abc->dev;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2662,7 +2680,7 @@ class TestLeakAutoVar : public TestFixture { " throw 1;\n" " }\n" " free(p);\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("void f(char *p, int x) {\n" @@ -2671,7 +2689,7 @@ class TestLeakAutoVar : public TestFixture { " throw 1;\n" " }\n" " delete p;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("void f(char *p, int x) {\n" @@ -2680,7 +2698,7 @@ class TestLeakAutoVar : public TestFixture { " throw 1;\n" " }\n" " delete [] p;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); } @@ -2694,7 +2712,7 @@ class TestLeakAutoVar : public TestFixture { " return;\n" " }\n" " *p = 0;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); } @@ -2702,7 +2720,7 @@ class TestLeakAutoVar : public TestFixture { check("std::pair f(size_t n) {\n" " char* p = (char* )malloc(n);\n" " return {p, p};\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); } @@ -2710,43 +2728,43 @@ class TestLeakAutoVar : public TestFixture { check("uint8_t *f() {\n" " void *x = malloc(1);\n" " return (uint8_t *)x;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("uint8_t f() {\n" " void *x = malloc(1);\n" " return (uint8_t)x;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:3:5]: (error) Memory leak: x [memleak]\n", errout_str()); check("void** f() {\n" " void *x = malloc(1);\n" " return (void**)x;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("void* f() {\n" " void *x = malloc(1);\n" " return (long long)x;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("void* f() {\n" " void *x = malloc(1);\n" " return (void*)(short)x;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:3:5]: (error) Memory leak: x [memleak]\n", errout_str()); check("void* f() {\n" " void *x = malloc(1);\n" " return (mytype)x;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("void* f() {\n" // Do not crash " void *x = malloc(1);\n" " return (mytype)y;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:3:5]: (error) Memory leak: x [memleak]\n", errout_str()); } @@ -2754,25 +2772,25 @@ class TestLeakAutoVar : public TestFixture { check("void* f() {\n" " void *x = malloc(1);\n" " return (x);\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("void* f() {\n" " void *x = malloc(1);\n" " return ((x));\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("void* f() {\n" " void *x = malloc(1);\n" " return ((((x))));\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("char* f() {\n" " void *x = malloc(1);\n" " return (char*)(x);\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); } @@ -2780,7 +2798,7 @@ class TestLeakAutoVar : public TestFixture { check("void* f() {\n" " void *x = malloc (sizeof (struct alloc));\n" " return x + sizeof (struct alloc);\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); } @@ -2789,7 +2807,7 @@ class TestLeakAutoVar : public TestFixture { " char* p = (char*)malloc(1);\n" " p[0] = 'x';\n" " return p[0];\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:4:5]: (error) Memory leak: p [memleak]\n", errout_str()); check("struct S { int f(); };\n" // #11746 @@ -2797,14 +2815,14 @@ class TestLeakAutoVar : public TestFixture { " S* s = new S;\n" " delete s;\n" " return s->f();\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:4:5] -> [test.cpp:5:5]: (error) Returning/dereferencing 's' after it is deallocated / released [deallocret]\n", errout_str()); check("int f() {\n" " int* p = new int(3);\n" " delete p;\n" " return *p;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:3:5] -> [test.cpp:4:5]: (error) Returning/dereferencing 'p' after it is deallocated / released [deallocret]\n", errout_str()); } @@ -2841,10 +2859,26 @@ class TestLeakAutoVar : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void return13() { // #4638 + CheckOptions options; + options.cpp = true; + check("bool f() {\n" + " int* p = new int;\n" + " return p;\n" + "}\n" + "bool g() {\n" + " void* p = malloc(4);\n" + " return p;\n" + "}\n", options); + ASSERT_EQUALS("[test.cpp:3:5]: (error) Memory leak: p [memleak]\n" + "[test.cpp:7:5]: (error) Memory leak: p [memleak]\n", + errout_str()); + } + void test1() { check("void f(double*&p) {\n" // 3809 " p = malloc(0x100);\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); check("void f(int*& p) {\n" // #4400 @@ -2873,7 +2907,7 @@ class TestLeakAutoVar : public TestFixture { check("struct Fred {\n" " char *p;\n" " void f1() { free(p); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -2881,7 +2915,7 @@ class TestLeakAutoVar : public TestFixture { check("void f() {\n" " char *&p = x();\n" " p = malloc(10);\n" - "};", dinit(CheckOptions, $.cpp = true)); + "};\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); } @@ -2890,21 +2924,21 @@ class TestLeakAutoVar : public TestFixture { " static char *p;\n" " if (!p) p = malloc(10);\n" " if (x) { free(p); p = 0; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } void test5() { // unknown type - check("void f() { Fred *p = malloc(10); }", dinit(CheckOptions, $.cpp = true)); + check("void f() { Fred *p = malloc(10); }\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:1:34]: (error) Memory leak: p [memleak]\n", errout_str()); - check("void f() { Fred *p = malloc(10); }"); + check("void f() { Fred *p = malloc(10); }\n"); ASSERT_EQUALS("[test.c:1:34]: (error) Memory leak: p [memleak]\n", errout_str()); - check("void f() { Fred *p = new Fred; }", dinit(CheckOptions, $.cpp = true)); + check("void f() { Fred *p = new Fred; }\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); - check("void f() { Fred fred = malloc(10); }", dinit(CheckOptions, $.cpp = true)); + check("void f() { Fred fred = malloc(10); }\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); } @@ -2912,7 +2946,7 @@ class TestLeakAutoVar : public TestFixture { check("void f() {\n" " char *p = malloc(10);\n" " throw 123;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:3:5]: (error) Memory leak: p [memleak]\n", errout_str()); check("void f() {\n" @@ -2922,7 +2956,7 @@ class TestLeakAutoVar : public TestFixture { " throw 123;\n" " } catch (...) { }\n" " free(p);\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); } @@ -2939,7 +2973,7 @@ class TestLeakAutoVar : public TestFixture { " throw ::NS::Except();\n" " }\n" " delete pi;\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); } @@ -2952,7 +2986,7 @@ class TestLeakAutoVar : public TestFixture { check("void f() {\n" " char *p = malloc(10);\n" " x(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:3:9]: (information) --check-library: Function x() should have configuration [checkLibraryNoReturn]\n" "[test.c:4:1]: (information) --check-library: Function x() should have / configuration [checkLibraryUseIgnore]\n", errout_str()); @@ -2970,7 +3004,7 @@ class TestLeakAutoVar : public TestFixture { check("void f() {\n" " char *p = malloc(10);\n" " x(&p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:3:10]: (information) --check-library: Function x() should have configuration [checkLibraryNoReturn]\n" "[test.c:4:1]: (information) --check-library: Function x() should have / configuration [checkLibraryUseIgnore]\n", errout_str()); @@ -2981,7 +3015,7 @@ class TestLeakAutoVar : public TestFixture { const char code[] = "void f() {\n" " char *p = malloc(10);\n" " if (set_data(p)) { }\n" - "}"; + "}\n"; check(code); ASSERT_EQUALS("[test.c:4:1]: (information) --check-library: Function set_data() should have / configuration [checkLibraryUseIgnore]\n", errout_str()); check(code, dinit(CheckOptions, $.cpp = true)); @@ -2992,7 +3026,7 @@ class TestLeakAutoVar : public TestFixture { const char code[] = "void f() {\n" " char *p = malloc(10);\n" " if (set_data(p)) { return; }\n" - "}"; + "}\n"; check(code); ASSERT_EQUALS("[test.c:3:24]: (information) --check-library: Function set_data() should have / configuration [checkLibraryUseIgnore]\n" "[test.c:4:1]: (information) --check-library: Function set_data() should have / configuration [checkLibraryUseIgnore]\n" @@ -3009,7 +3043,7 @@ class TestLeakAutoVar : public TestFixture { " char *p = malloc(10);\n" " int ret = set_data(p);\n" " return ret;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:4:5]: (information) --check-library: Function set_data() should have / configuration [checkLibraryUseIgnore]\n", errout_str()); } @@ -3087,7 +3121,7 @@ class TestLeakAutoVar : public TestFixture { void ptrptr() { check("void f() {\n" " char **p = malloc(10);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.c:3:1]: (error) Memory leak: p [memleak]\n", errout_str()); } @@ -3095,19 +3129,19 @@ class TestLeakAutoVar : public TestFixture { check("void QueueDSMCCPacket(unsigned char *data, int length) {\n" " unsigned char *dataCopy = malloc(length * sizeof(unsigned char));\n" " m_dsmccQueue.enqueue(new DSMCCPacket(dataCopy));\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:4:1]: (information) --check-library: Function DSMCCPacket() should have / configuration [checkLibraryUseIgnore]\n", errout_str()); check("void QueueDSMCCPacket(unsigned char *data, int length) {\n" " unsigned char *dataCopy = malloc(length * sizeof(unsigned char));\n" " m_dsmccQueue.enqueue(new DSMCCPacket(somethingunrelated));\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:4:1]: (error) Memory leak: dataCopy [memleak]\n", errout_str()); check("void f() {\n" " char *buf = new char[1000];\n" " clist.push_back(new (std::nothrow) C(buf));\n" - "}", dinit(CheckOptions, $.cpp = true)); + "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:4:1]: (information) --check-library: Function C() should have / configuration [checkLibraryUseIgnore]\n", errout_str()); } @@ -3116,7 +3150,7 @@ class TestLeakAutoVar : public TestFixture { " double *new = malloc(1*sizeof(double));\n" " free(new);\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -3129,7 +3163,7 @@ class TestLeakAutoVar : public TestFixture { " }\n" " c = malloc(128);\n" " return ret();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -3145,6 +3179,34 @@ class TestLeakAutoVar : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void unconditionalScope() { + check("void f() {\n" // #14945 + " {\n" + " int* p = new int;\n" + " *p = 1;\n" + " }\n" + " {\n" + " int* q = new int;\n" + " *q = 2;\n" + " delete q;\n" + " }\n" + " int* r = new int;\n" + " *r = 3;\n" + " delete r;\n" + "}\n", dinit(CheckOptions, $.cpp = true)); + ASSERT_EQUALS("[test.cpp:5:5]: (error) Memory leak: p [memleak]\n", errout_str()); + + check("void f() {\n" + " int* p = new int;\n" + " {\n" + " (void)p;\n" + " }\n" + " *p = 1;\n" + " delete p;\n" + "}\n", dinit(CheckOptions, $.cpp = true)); + ASSERT_EQUALS("", errout_str()); + } + void functionCallCastConfig() { // #9652 constexpr char xmldata[] = "\n" "\n" @@ -3164,7 +3226,7 @@ class TestLeakAutoVar : public TestFixture { "{\n" " char * buf = malloc(4);\n" " free_func((void *)(1), buf);\n" - "}", settingsFunctionCall); + "}\n", settingsFunctionCall); ASSERT_EQUALS("[test.cpp:5:1]: (information) --check-library: Function free_func() should have / configuration [checkLibraryUseIgnore]\n", errout_str()); check("void g(void*);\n" @@ -3191,7 +3253,7 @@ class TestLeakAutoVar : public TestFixture { " \n" " \n" "\n"; - const Settings settingsLeakIgnore = settingsBuilder().libraryxml(xmldata).build(); + const Settings settingsLeakIgnore = settingsBuilder().libraryxml(xmldata).checkLibrary().build(); check("void f() {\n" " double* a = new double[1024];\n" " SomeClass::someMethod(a);\n" @@ -3227,14 +3289,14 @@ class TestLeakAutoVarRecursiveCountLimit : public TestFixture { #define checkP(...) checkP_(__FILE__, __LINE__, __VA_ARGS__) template - void checkP_(const char* file, int line, const char (&code)[size], bool cpp = false) { - SimpleTokenizer2 tokenizer(settings, *this, code, cpp?"test.cpp":"test.c"); + void checkP_(const char* file, int line, const char (&code)[size]) { + SimpleTokenizer2 tokenizer(settings, *this, code, "test.c"); // Tokenizer.. ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); - // Check for leaks.. - runChecks(tokenizer, this); + CheckLeakAutoVar check; + runChecks(check, tokenizer, *this); } void run() override { @@ -3250,7 +3312,7 @@ class TestLeakAutoVarRecursiveCountLimit : public TestFixture { "void foo() {\n" " if (0) { }\n" " THOU THOU\n" - "}"), LIMIT, "Internal limit: CheckLeakAutoVar::checkScope() Maximum recursive count of 1000 reached."); + "}\n"), LIMIT, "Internal limit: CheckLeakAutoVar::checkScope() Maximum recursive count of 1000 reached."); ASSERT_NO_THROW(checkP("#define ONE if (0) { }\n" "#define TEN ONE ONE ONE ONE ONE ONE ONE ONE ONE ONE\n" "#define HUN TEN TEN TEN TEN TEN TEN TEN TEN TEN TEN\n" @@ -3258,7 +3320,7 @@ class TestLeakAutoVarRecursiveCountLimit : public TestFixture { "void foo() {\n" " if (0) { }\n" " THOU THOU\n" - "}")); + "}\n")); } }; @@ -3280,8 +3342,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 { @@ -3300,7 +3362,7 @@ class TestLeakAutoVarStrcpy : public TestFixture { "{\n" " char* ptr = new char[strlen(str)+1];\n" " m = strcpy(ptr, str);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -3308,7 +3370,7 @@ class TestLeakAutoVarStrcpy : public TestFixture { check("void f(char *p) {\n" " free(p);\n" " strcpy(a, p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:15]: (error) Dereferencing 'p' after it is deallocated / released [deallocuse]\n", errout_str()); check("void f(char *p, const char *q) {\n" // #11665 @@ -3321,12 +3383,12 @@ class TestLeakAutoVarStrcpy : public TestFixture { check("void f(char *p) {\n" // #3041 - assigning pointer when it's used " free(p);\n" " strcpy(a, p=b());\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void fclose_false_positive() { // #9575 - check("int f(FILE *fp) { return fclose(fp); }"); + check("int f(FILE *fp) { return fclose(fp); }\n"); ASSERT_EQUALS("", errout_str()); } @@ -3356,7 +3418,7 @@ class TestLeakAutoVarStrcpy : public TestFixture { " if (b)\n" " p = new S();\n" " p->f();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:9:1]: (error) Memory leak: p [memleak]\n", errout_str()); check("class B { std::string s; };\n" // #12062 @@ -3385,8 +3447,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 { @@ -3458,8 +3520,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/testlibrary.cpp b/test/testlibrary.cpp index 44b1b6660a7..28264a02a53 100644 --- a/test/testlibrary.cpp +++ b/test/testlibrary.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -110,7 +109,7 @@ class TestLibrary : public TestFixture { " \n" ""; - const char code[] = "foo();"; + const char code[] = "foo();\n"; SimpleTokenList tokenList(code); tokenList.front()->next()->astOperand1(tokenList.front()); @@ -132,13 +131,13 @@ class TestLibrary : public TestFixture { Library library; ASSERT(LibraryHelper::loadxmldata(library, xmldata, sizeof(xmldata))); { - const char code[] = "fred.foo(123);"; // <- wrong scope, not library function + const char code[] = "fred.foo(123);\n"; // <- wrong scope, not library function const SimpleTokenList tokenList(code); ASSERT(library.isNotLibraryFunction(tokenList.front()->tokAt(2))); } { - const char code[] = "Fred::foo(123);"; // <- wrong scope, not library function + const char code[] = "Fred::foo(123);\n"; // <- wrong scope, not library function const SimpleTokenList tokenList(code); ASSERT(library.isNotLibraryFunction(tokenList.front()->tokAt(2))); @@ -154,7 +153,7 @@ class TestLibrary : public TestFixture { ""; TokenList tokenList(settingsDefault, Standards::Language::CPP); - const char code[] = "foo();"; // <- too few arguments, not library function + const char code[] = "foo();\n"; // <- too few arguments, not library function ASSERT(tokenList.createTokensFromString(code)); Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous()); tokenList.createAst(); @@ -178,7 +177,7 @@ class TestLibrary : public TestFixture { { TokenList tokenList(settingsDefault, Standards::Language::CPP); - const char code[] = "foo();"; // <- too few arguments, not library function + const char code[] = "foo();\n"; // <- too few arguments, not library function ASSERT(tokenList.createTokensFromString(code)); Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous()); tokenList.createAst(); @@ -187,7 +186,7 @@ class TestLibrary : public TestFixture { } { TokenList tokenList(settingsDefault, Standards::Language::CPP); - const char code[] = "foo(a);"; // <- library function + const char code[] = "foo(a);\n"; // <- library function ASSERT(tokenList.createTokensFromString(code)); Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous()); tokenList.createAst(); @@ -198,7 +197,7 @@ class TestLibrary : public TestFixture { } { TokenList tokenList(settingsDefault, Standards::Language::CPP); - const char code[] = "foo(a, b);"; // <- library function + const char code[] = "foo(a, b);\n"; // <- library function ASSERT(tokenList.createTokensFromString(code)); Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous()); tokenList.createAst(); @@ -209,7 +208,7 @@ class TestLibrary : public TestFixture { } { TokenList tokenList(settingsDefault, Standards::Language::CPP); - const char code[] = "foo(a, b, c);"; // <- too much arguments, not library function + const char code[] = "foo(a, b, c);\n"; // <- too much arguments, not library function ASSERT(tokenList.createTokensFromString(code)); Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous()); tokenList.createAst(); @@ -226,7 +225,7 @@ class TestLibrary : public TestFixture { " \n" ""; - const char code[] = "Fred foo(123);"; // <- Variable declaration, not library function + const char code[] = "Fred foo(123);\n"; // <- Variable declaration, not library function SimpleTokenList tokenList(code); tokenList.front()->next()->astOperand1(tokenList.front()); tokenList.front()->next()->varId(1); @@ -286,7 +285,7 @@ class TestLibrary : public TestFixture { ASSERT(LibraryHelper::loadxmldata(library, xmldata, sizeof(xmldata))); ASSERT_EQUALS(0, library.functions().at("foo").argumentChecks.at(-1).notuninit); - const char code[] = "foo(a,b,c,d,e);"; + const char code[] = "foo(a,b,c,d,e);\n"; SimpleTokenList tokenList(code); tokenList.front()->next()->astOperand1(tokenList.front()); @@ -310,7 +309,7 @@ class TestLibrary : public TestFixture { Library library; ASSERT(LibraryHelper::loadxmldata(library, xmldata, sizeof(xmldata))); - const char code[] = "foo(a,b,c,d);"; + const char code[] = "foo(a,b,c,d);\n"; SimpleTokenList tokenList(code); tokenList.front()->next()->astOperand1(tokenList.front()); @@ -341,7 +340,7 @@ class TestLibrary : public TestFixture { Library library; ASSERT(LibraryHelper::loadxmldata(library, xmldata, sizeof(xmldata))); - const char code[] = "foo(a,b,c,d,e,f,g,h,i,j,k);"; + const char code[] = "foo(a,b,c,d,e,f,g,h,i,j,k);\n"; SimpleTokenList tokenList(code); tokenList.front()->next()->astOperand1(tokenList.front()); @@ -482,7 +481,7 @@ class TestLibrary : public TestFixture { Library library; ASSERT(LibraryHelper::loadxmldata(library, xmldata, sizeof(xmldata))); - const char code[] = "foo(a,b,c,d,e);"; + const char code[] = "foo(a,b,c,d,e);\n"; SimpleTokenList tokenList(code); tokenList.front()->next()->astOperand1(tokenList.front()); @@ -544,13 +543,13 @@ class TestLibrary : public TestFixture { ASSERT(library.functions().at("bar").argumentChecks.empty()); { - const char code[] = "Foo::foo();"; + const char code[] = "Foo::foo();\n"; const SimpleTokenList tokenList(code); ASSERT(library.isnotnoreturn(tokenList.front()->tokAt(2))); } { - const char code[] = "bar();"; + const char code[] = "bar();\n"; const SimpleTokenList tokenList(code); ASSERT(library.isnotnoreturn(tokenList.front())); } @@ -570,14 +569,14 @@ class TestLibrary : public TestFixture { { SimpleTokenizer tokenizer(settingsDefault, *this); - const char code[] = "CString str; str.Format();"; + const char code[] = "CString str; str.Format();\n"; ASSERT(tokenizer.tokenize(code)); ASSERT(library.isnotnoreturn(Token::findsimplematch(tokenizer.tokens(), "Format"))); } { SimpleTokenizer tokenizer(settingsDefault, *this); - const char code[] = "HardDrive hd; hd.Format();"; + const char code[] = "HardDrive hd; hd.Format();\n"; ASSERT(tokenizer.tokenize(code)); ASSERT(!library.isnotnoreturn(Token::findsimplematch(tokenizer.tokens(), "Format"))); } @@ -596,14 +595,14 @@ class TestLibrary : public TestFixture { { SimpleTokenizer tokenizer(settingsDefault, *this); - const char code[] = "struct X : public Base { void dostuff() { f(0); } };"; + const char code[] = "struct X : public Base { void dostuff() { f(0); } };\n"; ASSERT(tokenizer.tokenize(code)); ASSERT(library.isnullargbad(Token::findsimplematch(tokenizer.tokens(), "f"),1)); } { SimpleTokenizer tokenizer(settingsDefault, *this); - const char code[] = "struct X : public Base { void dostuff() { f(1,2); } };"; + const char code[] = "struct X : public Base { void dostuff() { f(1,2); } };\n"; ASSERT(tokenizer.tokenize(code)); ASSERT(!library.isnullargbad(Token::findsimplematch(tokenizer.tokens(), "f"),1)); } @@ -623,7 +622,7 @@ class TestLibrary : public TestFixture { Library library; ASSERT(LibraryHelper::loadxmldata(library, xmldata, sizeof(xmldata))); - const char code[] = "a(); b();"; + const char code[] = "a(); b();\n"; const SimpleTokenList tokenList(code); const Library::WarnInfo* a = library.getWarnInfo(tokenList.front()); @@ -873,7 +872,7 @@ class TestLibrary : public TestFixture { { SimpleTokenizer var(*this); - ASSERT(var.tokenize("std::A a;")); + ASSERT(var.tokenize("std::A a;\n")); ASSERT_EQUALS(&A, library.detectContainer(var.tokens())); ASSERT(!library.detectIterator(var.tokens())); bool isIterator; @@ -883,7 +882,7 @@ class TestLibrary : public TestFixture { { SimpleTokenizer var(*this); - ASSERT(var.tokenize("std::A::size_type a_s;")); + ASSERT(var.tokenize("std::A::size_type a_s;\n")); ASSERT(!library.detectContainer(var.tokens())); ASSERT(!library.detectIterator(var.tokens())); ASSERT(!library.detectContainerOrIterator(var.tokens())); @@ -891,7 +890,7 @@ class TestLibrary : public TestFixture { { SimpleTokenizer var(*this); - ASSERT(var.tokenize("std::A::iterator a_it;")); + ASSERT(var.tokenize("std::A::iterator a_it;\n")); ASSERT(!library.detectContainer(var.tokens())); ASSERT_EQUALS(&A, library.detectIterator(var.tokens())); bool isIterator; @@ -901,7 +900,7 @@ class TestLibrary : public TestFixture { { SimpleTokenizer var(*this); - ASSERT(var.tokenize("std::B b;")); + ASSERT(var.tokenize("std::B b;\n")); ASSERT_EQUALS(&B, library.detectContainer(var.tokens())); ASSERT(!library.detectIterator(var.tokens())); bool isIterator; @@ -911,7 +910,7 @@ class TestLibrary : public TestFixture { { SimpleTokenizer var(*this); - ASSERT(var.tokenize("std::B::size_type b_s;")); + ASSERT(var.tokenize("std::B::size_type b_s;\n")); ASSERT(!library.detectContainer(var.tokens())); ASSERT(!library.detectIterator(var.tokens())); ASSERT(!library.detectContainerOrIterator(var.tokens())); @@ -919,7 +918,7 @@ class TestLibrary : public TestFixture { { SimpleTokenizer var(*this); - ASSERT(var.tokenize("std::B::iterator b_it;")); + ASSERT(var.tokenize("std::B::iterator b_it;\n")); ASSERT(!library.detectContainer(var.tokens())); ASSERT_EQUALS(&B, library.detectIterator(var.tokens())); bool isIterator; @@ -929,7 +928,7 @@ class TestLibrary : public TestFixture { { SimpleTokenizer var(*this); - ASSERT(var.tokenize("C c;")); + ASSERT(var.tokenize("C c;\n")); ASSERT(!library.detectContainer(var.tokens())); ASSERT(!library.detectIterator(var.tokens())); ASSERT(!library.detectContainerOrIterator(var.tokens())); @@ -937,7 +936,7 @@ class TestLibrary : public TestFixture { { SimpleTokenizer var(*this); - ASSERT(var.tokenize("D d;")); + ASSERT(var.tokenize("D d;\n")); ASSERT(!library.detectContainer(var.tokens())); ASSERT(!library.detectIterator(var.tokens())); ASSERT(!library.detectContainerOrIterator(var.tokens())); @@ -945,7 +944,7 @@ class TestLibrary : public TestFixture { { SimpleTokenizer var(*this); - ASSERT(var.tokenize("std::E e;")); + ASSERT(var.tokenize("std::E e;\n")); ASSERT(library.detectContainer(var.tokens())); ASSERT(!library.detectIterator(var.tokens())); bool isIterator; @@ -956,7 +955,7 @@ class TestLibrary : public TestFixture { { SimpleTokenizer var(*this); - ASSERT(var.tokenize("E e;")); + ASSERT(var.tokenize("E e;\n")); ASSERT(!library.detectContainer(var.tokens())); ASSERT(!library.detectIterator(var.tokens())); ASSERT(!library.detectContainerOrIterator(var.tokens())); @@ -965,7 +964,7 @@ class TestLibrary : public TestFixture { { SimpleTokenizer var(*this); - ASSERT(var.tokenize("std::E::iterator I;")); + ASSERT(var.tokenize("std::E::iterator I;\n")); ASSERT(!library.detectContainer(var.tokens())); ASSERT(!library.detectIterator(var.tokens())); ASSERT(!library.detectContainerOrIterator(var.tokens())); @@ -974,7 +973,7 @@ class TestLibrary : public TestFixture { { SimpleTokenizer var(*this); - ASSERT(var.tokenize("std::E::size_type p;")); + ASSERT(var.tokenize("std::E::size_type p;\n")); ASSERT(!library.detectContainer(var.tokens())); ASSERT(!library.detectIterator(var.tokens())); ASSERT(!library.detectContainerOrIterator(var.tokens())); @@ -983,7 +982,7 @@ class TestLibrary : public TestFixture { { SimpleTokenizer var(*this); - ASSERT(var.tokenize("std::F f;")); + ASSERT(var.tokenize("std::F f;\n")); ASSERT(library.detectContainer(var.tokens())); ASSERT(!library.detectIterator(var.tokens())); bool isIterator; @@ -993,7 +992,7 @@ class TestLibrary : public TestFixture { { SimpleTokenizer var(*this); - ASSERT(var.tokenize("std::F::iterator I;")); + ASSERT(var.tokenize("std::F::iterator I;\n")); ASSERT(!library.detectContainer(var.tokens())); TODO_ASSERT(library.detectIterator(var.tokens())); bool isIterator = false; @@ -1003,7 +1002,7 @@ class TestLibrary : public TestFixture { { SimpleTokenizer var(*this); - ASSERT(var.tokenize("F::iterator I;")); + ASSERT(var.tokenize("F::iterator I;\n")); ASSERT(!library.detectContainer(var.tokens())); ASSERT(!library.detectIterator(var.tokens())); ASSERT(!library.detectContainerOrIterator(var.tokens())); @@ -1013,7 +1012,14 @@ class TestLibrary : public TestFixture { } } -#define LOADLIBERROR(xmldata, errorcode) loadLibError(xmldata, errorcode, __FILE__, __LINE__) +#define LOADLIBERROR(...) loadLibError(__FILE__, __LINE__, __VA_ARGS__) + template + void loadLibError(const char* file, unsigned line, const char (&xmldata)[size], Library::ErrorCode errorcode) const { + Library library; + Library::Error liberr; + assertEquals(file, line, true, LibraryHelper::loadxmldata(library, liberr, xmldata, size-1)); + assertEquals(file, line, true, errorcode == liberr.errorcode); + } void version() const { { @@ -1054,14 +1060,6 @@ class TestLibrary : public TestFixture { } } - template - void loadLibError(const char (&xmldata)[size], Library::ErrorCode errorcode, const char* file, unsigned line) const { - Library library; - Library::Error liberr; - assertEquals(file, line, true, LibraryHelper::loadxmldata(library, liberr, xmldata, size-1)); - assertEquals(file, line, true, errorcode == liberr.errorcode); - } - #define LOADLIB_ERROR_INVALID_RANGE(valid) LOADLIBERROR("\n" \ "\n" \ "\n" \ diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index 6a0ba4c0871..8cbe5b50019 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -167,7 +167,7 @@ class TestMathLib : public TestFixture { ASSERT_EQUALS("1", MathLib::calculate("0", "1", '^')); // Unknown action should throw exception - ASSERT_THROW_INTERNAL_EQUALS(MathLib::calculate("1","2",'j'),INTERNAL, "Unexpected action 'j' in MathLib::calculate(). Please report this to Cppcheck developers."); + ASSERT_THROW_INTERNAL_EQUALS(MathLib::calculate("1","2",'j'),INTERNAL, "Unexpected action 'j' in MathLib::calculate()."); } void calculate1() const { @@ -416,6 +416,8 @@ class TestMathLib : public TestFixture { TokenList::deleteTokens(tok); } + ASSERT_THROW_INTERNAL_EQUALS(MathLib::toBigNumber("''"), INTERNAL, "Internal Error. MathLib::toBigNumber: characterLiteralToLL('') => empty character literal"); + // TODO: test binary // TODO: test floating point @@ -588,6 +590,8 @@ class TestMathLib : public TestFixture { TokenList::deleteTokens(tok); } + ASSERT_THROW_INTERNAL_EQUALS(MathLib::toBigUNumber("''"), INTERNAL, "Internal Error. MathLib::toBigUNumber: characterLiteralToLL('') => empty character literal"); + // TODO: test binary // TODO: test floating point @@ -736,6 +740,8 @@ class TestMathLib : public TestFixture { ASSERT_EQUALS("0.0", MathLib::toString(MathLib::toDoubleNumber("-0"))); ASSERT_EQUALS("0.0", MathLib::toString(MathLib::toDoubleNumber("-0."))); ASSERT_EQUALS("0.0", MathLib::toString(MathLib::toDoubleNumber("-0.0"))); + + ASSERT_THROW_INTERNAL_EQUALS(MathLib::toDoubleNumber("''"), INTERNAL, "Internal Error. MathLib::toDoubleNumber: characterLiteralToLL('') => empty character literal"); } void isint() const { diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index a6a7abb51c0..e05698ae23e 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,33 +39,32 @@ 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()); } void testFunctionReturnType() { { const char code[] = "const char *foo()\n" - "{ return 0; }"; - ASSERT_EQUALS(CheckMemoryLeak::No, functionReturnType(code)); + "{ return 0; }\n"; + ASSERT_EQUALS(CheckMemoryLeakImpl::No, functionReturnType(code)); } { const char code[] = "Fred *newFred()\n" - "{ return new Fred; }"; - ASSERT_EQUALS(CheckMemoryLeak::New, functionReturnType(code)); + "{ return new Fred; }\n"; + ASSERT_EQUALS(CheckMemoryLeakImpl::New, functionReturnType(code)); } { const char code[] = "char *foo()\n" - "{ return new char[100]; }"; - ASSERT_EQUALS(CheckMemoryLeak::NewArray, functionReturnType(code)); + "{ return new char[100]; }\n"; + ASSERT_EQUALS(CheckMemoryLeakImpl::NewArray, functionReturnType(code)); } { @@ -73,8 +72,8 @@ class TestMemleak : public TestFixture { "{\n" " char *p = new char[100];\n" " return p;\n" - "}"; - ASSERT_EQUALS(CheckMemoryLeak::NewArray, functionReturnType(code)); + "}\n"; + 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(); } @@ -150,6 +149,7 @@ class TestMemleakInFunction : public TestFixture { TEST_CASE(realloc22); TEST_CASE(realloc23); TEST_CASE(realloc24); // #9228 + TEST_CASE(realloc25); } void realloc1() { @@ -157,7 +157,7 @@ class TestMemleakInFunction : public TestFixture { "{\n" " char *a = (char *)malloc(10);\n" " a = realloc(a, 100);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:5]: (error) Common realloc mistake: \'a\' nulled but not freed upon failure [memleakOnRealloc]\n", errout_str()); } @@ -167,7 +167,7 @@ class TestMemleakInFunction : public TestFixture { " char *a = (char *)malloc(10);\n" " a = (char *)realloc(a, 100);\n" " free(a);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:5]: (error) Common realloc mistake: \'a\' nulled but not freed upon failure [memleakOnRealloc]\n", errout_str()); } @@ -179,7 +179,7 @@ class TestMemleakInFunction : public TestFixture { " if ((a = realloc(a, 100)) == NULL)\n" " return;\n" " free(a);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -191,7 +191,7 @@ class TestMemleakInFunction : public TestFixture { " if ((a = realloc(a, 100)) == NULL)\n" " return;\n" " free(a);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: a\n", "[test.cpp:4:10]: (error) Common realloc mistake: \'a\' nulled but not freed upon failure [memleakOnRealloc]\n", @@ -209,7 +209,7 @@ class TestMemleakInFunction : public TestFixture { " free(buf);\n" " else\n" " free(new_buf);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -223,7 +223,7 @@ class TestMemleakInFunction : public TestFixture { " }\n" " free(pData);\n" " return true;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -235,7 +235,7 @@ class TestMemleakInFunction : public TestFixture { " if (!m_buf) {\n" " m_buf = origBuf;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -243,7 +243,7 @@ class TestMemleakInFunction : public TestFixture { check("void foo()\n" "{\n" " x = realloc(x,100);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -253,7 +253,7 @@ class TestMemleakInFunction : public TestFixture { " pa = pb = malloc(10);\n" " pa = realloc(pa, 20);" " exit();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -264,7 +264,7 @@ class TestMemleakInFunction : public TestFixture { " if (!p)\n" " error();\n" " usep(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -275,7 +275,7 @@ class TestMemleakInFunction : public TestFixture { " if ((a = realloc(a, x + 100)) == NULL)\n" " return;\n" " free(a);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -285,7 +285,7 @@ class TestMemleakInFunction : public TestFixture { " char **str;\n" " *str = realloc(*str,100);\n" " free (*str);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:6]: (error) Common realloc mistake: \'str\' nulled but not freed upon failure [memleakOnRealloc]\n", errout_str()); } @@ -296,7 +296,7 @@ class TestMemleakInFunction : public TestFixture { " if (!p)\n" " error();\n" " usep(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -307,7 +307,7 @@ class TestMemleakInFunction : public TestFixture { " if( m_options == NULL )\n" " return false;\n" " return true;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Common realloc mistake: \'m_options\' nulled but not freed upon failure [memleakOnRealloc]\n", errout_str()); } @@ -317,7 +317,7 @@ class TestMemleakInFunction : public TestFixture { " if (zLine) {\n" " free(zLine);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -326,7 +326,7 @@ class TestMemleakInFunction : public TestFixture { "{\n" " void ***a = malloc(sizeof(a));\n" " ***a = realloc(***(a), sizeof(a) * 2);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:8]: (error) Common realloc mistake: \'a\' nulled but not freed upon failure [memleakOnRealloc]\n", errout_str()); } @@ -335,7 +335,7 @@ class TestMemleakInFunction : public TestFixture { "{\n" " void *a = malloc(sizeof(a));\n" " a = realloc((void*)a, sizeof(a) * 2);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:5]: (error) Common realloc mistake: \'a\' nulled but not freed upon failure [memleakOnRealloc]\n", errout_str()); } @@ -344,7 +344,7 @@ class TestMemleakInFunction : public TestFixture { "{\n" " void *a = malloc(sizeof(a));\n" " a = (realloc((void*)((a)), sizeof(a) * 2));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:5]: (error) Common realloc mistake: \'a\' nulled but not freed upon failure [memleakOnRealloc]\n", errout_str()); } @@ -353,7 +353,7 @@ class TestMemleakInFunction : public TestFixture { "{\n" " void *a = malloc(sizeof(a));\n" " a = realloc((a) + 1, sizeof(a) * 2);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -364,7 +364,7 @@ class TestMemleakInFunction : public TestFixture { " bs = realloc(bs, 100);\n" " if (bs == NULL) return bs0;\n" " return bs;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -375,7 +375,7 @@ class TestMemleakInFunction : public TestFixture { " bs = realloc(bs, 100);\n" " if (bs == NULL) return;\n" " *bsp = bs;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -386,7 +386,7 @@ class TestMemleakInFunction : public TestFixture { " if (!(cigar = realloc(cigar, 100 * sizeof(*cigar))))\n" " return;\n" " s->cigar = cigar;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -394,28 +394,82 @@ class TestMemleakInFunction : public TestFixture { check("void f() {\n" "void *a = NULL;\n" "a = realloc(a, 20);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" "void *a = NULL;\n" "a = malloc(10);\n" "a = realloc(a, 20);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:1]: (error) Common realloc mistake: \'a\' nulled but not freed upon failure [memleakOnRealloc]\n", errout_str()); check("void f() {\n" "void *a = nullptr;\n" "a = malloc(10);\n" "a = realloc(a, 20);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:1]: (error) Common realloc mistake: \'a\' nulled but not freed upon failure [memleakOnRealloc]\n", errout_str()); check("void f(char *b) {\n" "void *a = NULL;\n" "a = b;\n" "a = realloc(a, 20);\n" - "}"); + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + + void realloc25() { + check("struct T {\n" + " char* ptr;\n" + " size_t len;\n" + "};\n" + "struct S {\n" + " struct T t;\n" + "};\n" + "void f(struct S* s, size_t len) {\n" + " char* p = s->t.ptr;\n" + " p = realloc(p, len);\n" + " if (p) {\n" + " s->t.ptr = p;\n" + " s->t.len = len;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct T {\n" + " char* ptr;\n" + " size_t len;\n" + "};\n" + "struct S {\n" + " struct T t[1];\n" + "};\n" + "void f(struct S* s, size_t len) {\n" + " char* p = s->t[0].ptr;\n" + " p = realloc(p, len);\n" + " if (p) {\n" + " s->t[0].ptr = p;\n" + " s->t[0].len = len;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct T {\n" // #14718 + " char* ptr;\n" + " size_t len;\n" + "};\n" + "struct S {\n" + " struct T t;\n" + "};\n" + "char* get(struct T t) { return t.ptr; };\n" + "void f(struct S* s, size_t len) {\n" + " char* p = get(s->t);\n" + " p = realloc(p, len);\n" + " if (p) {\n" + " s->t.ptr = p;\n" + " s->t.len = len;\n" + " }\n" + "}\n"); ASSERT_EQUALS("", errout_str()); } }; @@ -434,7 +488,7 @@ class TestMemleakInClass : public TestFixture { TestMemleakInClass() : TestFixture("TestMemleakInClass") {} private: - const Settings settings = settingsBuilder().severity(Severity::warning).severity(Severity::style).library("std.cfg").build(); + const Settings settings = settingsBuilder().severity(Severity::warning).severity(Severity::style).library("std.cfg").library("posix.cfg").build(); /** * Tokenize and execute leak check for given code @@ -447,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)(); } @@ -479,6 +533,7 @@ class TestMemleakInClass : public TestFixture { TEST_CASE(class25); // ticket #4367 - false positive implementation for destructor is not seen TEST_CASE(class26); // ticket #10789 TEST_CASE(class27); // ticket #8126 + TEST_CASE(class28); // ticket #14954 TEST_CASE(staticvar); @@ -513,7 +568,7 @@ class TestMemleakInClass : public TestFixture { "Fred::~Fred()\n" "{\n" " delete [] str2;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:11]: (style) Class 'Fred' is unsafe, 'Fred::str1' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); check("class Fred\n" @@ -531,7 +586,7 @@ class TestMemleakInClass : public TestFixture { " {\n" " delete [] str2;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:11]: (style) Class 'Fred' is unsafe, 'Fred::str1' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); } @@ -553,7 +608,7 @@ class TestMemleakInClass : public TestFixture { "Fred::~Fred()\n" "{\n" " free(str1);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:17:5]: (error) Mismatching allocation and deallocation: Fred::str1 [mismatchAllocDealloc]\n", errout_str()); check("class Fred\n" @@ -569,7 +624,7 @@ class TestMemleakInClass : public TestFixture { " {\n" " free(str1);\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:12:9]: (error) Mismatching allocation and deallocation: Fred::str1 [mismatchAllocDealloc]\n", errout_str()); } @@ -605,7 +660,7 @@ class TestMemleakInClass : public TestFixture { " delete tok;\n" " tok = next;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); @@ -634,7 +689,7 @@ class TestMemleakInClass : public TestFixture { " tok = next;\n" " }\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -658,7 +713,7 @@ class TestMemleakInClass : public TestFixture { "{\n" " ABC *p = new ABC;\n" " addAbc( p );\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct ABC;\n" @@ -675,7 +730,7 @@ class TestMemleakInClass : public TestFixture { " ABC *p = new ABC;\n" " addAbc( p );\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -691,7 +746,7 @@ class TestMemleakInClass : public TestFixture { " char *str = new char[100];\n" " delete [] str;\n" " hello();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class Fred\n" @@ -703,7 +758,7 @@ class TestMemleakInClass : public TestFixture { " delete [] str;\n" " hello();\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -723,7 +778,7 @@ class TestMemleakInClass : public TestFixture { "Fred::~Fred()\n" "{\n" " delete this->i;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class Fred\n" @@ -738,7 +793,7 @@ class TestMemleakInClass : public TestFixture { " {\n" " delete this->i;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -755,7 +810,7 @@ class TestMemleakInClass : public TestFixture { " int* c = new int(1);\n" " delete c;\n" " doNothing(c);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class A\n" @@ -768,7 +823,7 @@ class TestMemleakInClass : public TestFixture { " doNothing(c);\n" " }\n" " void doNothing() { }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -785,7 +840,7 @@ class TestMemleakInClass : public TestFixture { "{ p = new int; }\n" "\n" "A::~A()\n" - "{ delete (p); }"); + "{ delete (p); }\n"); ASSERT_EQUALS("", errout_str()); check("class A\n" @@ -796,7 +851,7 @@ class TestMemleakInClass : public TestFixture { " { p = new int; }\n" " ~A()\n" " { delete (p); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -808,7 +863,7 @@ class TestMemleakInClass : public TestFixture { " A();\n" "};\n" "A::A()\n" - "{ p = new int; }"); + "{ p = new int; }\n"); ASSERT_EQUALS("[test.cpp:4:11]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); check("class A\n" @@ -816,7 +871,7 @@ class TestMemleakInClass : public TestFixture { "public:\n" " int * p;\n" " A() { p = new int; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:11]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); } @@ -826,8 +881,8 @@ class TestMemleakInClass : public TestFixture { "public:\n" " int * p;\n" " A() : p(new int[10])\n" - " { }" - "};"); + " { }\n" + "};\n"); ASSERT_EQUALS("[test.cpp:4:11]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); check("class A\n" @@ -837,7 +892,7 @@ class TestMemleakInClass : public TestFixture { " A();\n" "};\n" "A::A() : p(new int[10])\n" - "{ }"); + "{ }\n"); ASSERT_EQUALS("[test.cpp:4:11]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); } @@ -859,7 +914,7 @@ class TestMemleakInClass : public TestFixture { "{ }\n" "\n" "void A::cleanup()\n" - "{ delete [] p; }"); + "{ delete [] p; }\n"); ASSERT_EQUALS("[test.cpp:4:10]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); check("class A\n" @@ -873,7 +928,7 @@ class TestMemleakInClass : public TestFixture { " { }\n" " void cleanup()\n" " { delete [] p; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:4:10]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); } @@ -895,7 +950,7 @@ class TestMemleakInClass : public TestFixture { "{ }\n" "\n" "void A::foo()\n" - "{ p = new int[10]; delete [] p; }"); + "{ p = new int[10]; delete [] p; }\n"); ASSERT_EQUALS("[test.cpp:17:3]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated. [publicAllocationError]\n", errout_str()); check("class A\n" @@ -909,7 +964,7 @@ class TestMemleakInClass : public TestFixture { " { }\n" " void foo()\n" " { p = new int[10]; delete [] p; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:11:7]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated. [publicAllocationError]\n", errout_str()); } @@ -922,7 +977,7 @@ class TestMemleakInClass : public TestFixture { "};\n" "\n" "void A::init()\n" - "{ p = new int[10]; }"); + "{ p = new int[10]; }\n"); ASSERT_EQUALS("[test.cpp:9:3]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated. [publicAllocationError]\n" "[test.cpp:3:10]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); @@ -932,7 +987,7 @@ class TestMemleakInClass : public TestFixture { "public:\n" " void init()\n" " { p = new int[10]; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:7]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated. [publicAllocationError]\n" "[test.cpp:3:10]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); @@ -945,7 +1000,7 @@ class TestMemleakInClass : public TestFixture { "};\n" "\n" "void A::init()\n" - "{ p = new int; }"); + "{ p = new int; }\n"); ASSERT_EQUALS("[test.cpp:9:3]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated. [publicAllocationError]\n" "[test.cpp:3:10]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); @@ -955,7 +1010,7 @@ class TestMemleakInClass : public TestFixture { "public:\n" " void init()\n" " { p = new int; }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:7]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated. [publicAllocationError]\n" "[test.cpp:3:10]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); @@ -968,7 +1023,7 @@ class TestMemleakInClass : public TestFixture { "};\n" "\n" "void A::init()\n" - "{ p = malloc(sizeof(int)*10); }"); + "{ p = malloc(sizeof(int)*10); }\n"); ASSERT_EQUALS("[test.cpp:9:3]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated. [publicAllocationError]\n" "[test.cpp:3:10]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); @@ -978,7 +1033,7 @@ class TestMemleakInClass : public TestFixture { "public:\n" " void init()\n" " { p = malloc(sizeof(int)*10); }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:7]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated. [publicAllocationError]\n" "[test.cpp:3:10]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); } @@ -992,7 +1047,7 @@ class TestMemleakInClass : public TestFixture { " ~A() { delete [] p; }\n" "};\n" "A::A()\n" - "{ p = new int[10]; }"); + "{ p = new int[10]; }\n"); ASSERT_EQUALS("", errout_str()); check("class A\n" @@ -1002,7 +1057,7 @@ class TestMemleakInClass : public TestFixture { " A()\n" " { p = new int[10]; }\n" " ~A() { delete [] p; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); @@ -1014,7 +1069,7 @@ class TestMemleakInClass : public TestFixture { " ~A() { delete p; }\n" "};\n" "A::A()\n" - "{ p = new int; }"); + "{ p = new int; }\n"); ASSERT_EQUALS("", errout_str()); check("class A\n" @@ -1024,7 +1079,7 @@ class TestMemleakInClass : public TestFixture { " A()\n" " { p = new int; }\n" " ~A() { delete p; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); @@ -1036,7 +1091,7 @@ class TestMemleakInClass : public TestFixture { " ~A() { free(p); }\n" "};\n" "A::A()\n" - "{ p = malloc(sizeof(int)*10); }"); + "{ p = malloc(sizeof(int)*10); }\n"); ASSERT_EQUALS("", errout_str()); check("class A\n" @@ -1046,7 +1101,7 @@ class TestMemleakInClass : public TestFixture { " A()\n" " { p = malloc(sizeof(int)*10); }\n" " ~A() { free(p); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1059,7 +1114,7 @@ class TestMemleakInClass : public TestFixture { "public:\n" " A() { a = b = new int[10]; }\n" " ~A() { delete [] a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1076,7 +1131,7 @@ class TestMemleakInClass : public TestFixture { "{\n" " A::pd = new char[12];\n" " delete [] A::pd;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:10:5]: (warning) Possible leak in public function. The pointer 'pd' is not deallocated before it is allocated. [publicAllocationError]\n", errout_str()); check("class A {\n" @@ -1088,7 +1143,7 @@ class TestMemleakInClass : public TestFixture { " pd = new char[12];\n" " delete [] pd;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:7:9]: (warning) Possible leak in public function. The pointer 'pd' is not deallocated before it is allocated. [publicAllocationError]\n", errout_str()); check("class A {\n" @@ -1102,7 +1157,7 @@ class TestMemleakInClass : public TestFixture { "{\n" " pd = new char[12];\n" " delete [] pd;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:10:5]: (warning) Possible leak in public function. The pointer 'pd' is not deallocated before it is allocated. [publicAllocationError]\n", errout_str()); } @@ -1118,7 +1173,7 @@ class TestMemleakInClass : public TestFixture { " }\n" "private:\n" " char *a;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class A : public x\n" @@ -1132,7 +1187,7 @@ class TestMemleakInClass : public TestFixture { "{\n" " a = new char[10];\n" " foo(a);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1150,7 +1205,7 @@ class TestMemleakInClass : public TestFixture { "{\n" " rp1 = new TRadioButton(this);\n" " rp2 = new TRadioButton(this);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class TRadioButton { };\n" @@ -1166,7 +1221,7 @@ class TestMemleakInClass : public TestFixture { "{\n" " rp1 = new TRadioButton;\n" " rp2 = new TRadioButton;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:19]: (style) Class 'Foo' is unsafe, 'Foo::rp1' can leak by wrong usage. [unsafeClassCanLeak]\n" "[test.cpp:6:19]: (style) Class 'Foo' is unsafe, 'Foo::rp2' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); @@ -1189,7 +1244,7 @@ class TestMemleakInClass : public TestFixture { "{\n" " delete rp1;\n" " delete rp2;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1211,7 +1266,7 @@ class TestMemleakInClass : public TestFixture { " delete [] str2;\n" " }\n" " };\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:15]: (style) Class 'Fred' is unsafe, 'Fred::str1' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); check("namespace ns1 {\n" @@ -1235,7 +1290,7 @@ class TestMemleakInClass : public TestFixture { " {\n" " delete [] str2;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:15]: (style) Class 'Fred' is unsafe, 'Fred::str1' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); check("namespace ns1 {\n" @@ -1258,7 +1313,7 @@ class TestMemleakInClass : public TestFixture { "ns1::Fred::~Fred()\n" "{\n" " delete [] str2;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:15]: (style) Class 'Fred' is unsafe, 'Fred::str1' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); check("namespace ns1 {\n" @@ -1283,7 +1338,7 @@ class TestMemleakInClass : public TestFixture { "ns1::ns2::Fred::~Fred()\n" "{\n" " delete [] str2;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:19]: (style) Class 'Fred' is unsafe, 'Fred::str1' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); check("namespace ns1 {\n" @@ -1310,7 +1365,7 @@ class TestMemleakInClass : public TestFixture { "ns1::ns2::ns3::Fred::~Fred()\n" "{\n" " delete [] str2;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:23]: (style) Class 'Fred' is unsafe, 'Fred::str1' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); } @@ -1327,7 +1382,7 @@ class TestMemleakInClass : public TestFixture { " C *c;\n" "public:\n" " A() : b(new B()), c(new C(b)) { }\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:9:8]: (style) Class 'A' is unsafe, 'A::b' can leak by wrong usage. [unsafeClassCanLeak]\n" "[test.cpp:10]: (style) Class 'A' is unsafe, 'A::c' can leak by wrong usage.\n", "[test.cpp:9:8]: (style) Class 'A' is unsafe, 'A::b' can leak by wrong usage. [unsafeClassCanLeak]\n", @@ -1349,7 +1404,7 @@ class TestMemleakInClass : public TestFixture { " b = new B();\n" " c = new C(b);\n" " }\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:9:8]: (style) Class 'A' is unsafe, 'A::b' can leak by wrong usage. [unsafeClassCanLeak]\n" "[test.cpp:10]: (style) Class 'A' is unsafe, 'A::c' can leak by wrong usage.\n", "[test.cpp:9:8]: (style) Class 'A' is unsafe, 'A::b' can leak by wrong usage. [unsafeClassCanLeak]\n", @@ -1363,7 +1418,7 @@ class TestMemleakInClass : public TestFixture { "private:\n" " Fred() { a = new int; }\n" " ~Fred() { (delete(a), (a)=NULL); }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1382,7 +1437,7 @@ class TestMemleakInClass : public TestFixture { " ~CData() { if (m_impl) m_impl->Release(); }\n" "private:\n" " CDataImpl *m_impl;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1393,7 +1448,7 @@ class TestMemleakInClass : public TestFixture { "public:\n" " Fred(const Fred &fred) { a = new int; }\n" " ~Fred() { delete a; }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1404,7 +1459,7 @@ class TestMemleakInClass : public TestFixture { "public:\n" " Fred() { a = new int; }\n" " ~Fred();\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1430,6 +1485,15 @@ class TestMemleakInClass : public TestFixture { ASSERT_EQUALS("[test.cpp:6:11]: (style) Class 'S' is unsafe, 'S::a' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); } + void class28() { // ticket #14954 + check("struct S {\n" + " explicit S(char *name) { m_fd = mkstemp(name); }\n" + " ~S() { /* close(m_fd); */ }\n" + " int m_fd;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:4:9]: (style) Class 'S' is unsafe, 'S::m_fd' can leak by wrong usage. [unsafeClassCanLeak]\n", errout_str()); + } + void staticvar() { check("class A\n" "{\n" @@ -1441,7 +1505,7 @@ class TestMemleakInClass : public TestFixture { " if (!p)\n" " p = new int[100];\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -1473,7 +1537,7 @@ class TestMemleakInClass : public TestFixture { "void Tokenizer::deleteTokens(int *tok)\n" "{\n" " delete tok;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Global function @@ -1500,7 +1564,7 @@ class TestMemleakInClass : public TestFixture { "{\n" " deleteTokens(_tokens);\n" " _tokens = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1525,7 +1589,7 @@ class TestMemleakInClass : public TestFixture { "\n" "A::~A() {\n" " delete [] pkt_buffer;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:14:9]: (error) Mismatching allocation and deallocation: A::pkt_buffer [mismatchAllocDealloc]\n", errout_str()); check("struct S {\n" // 5678 @@ -1561,7 +1625,7 @@ class TestMemleakInClass : public TestFixture { " data_ = new char[42];\n" " delete data_;\n" " data_ = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:17:3]: (warning) Possible leak in public function. The pointer 'data_' is not deallocated before it is allocated. [publicAllocationError]\n" "[test.cpp:18:3]: (error) Mismatching allocation and deallocation: Foo::data_ [mismatchAllocDealloc]\n", errout_str()); @@ -1584,7 +1648,7 @@ class TestMemleakInClass : public TestFixture { " data_ = new char[42];\n" " delete data_;\n" " data_ = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:17:3]: (warning) Possible leak in public function. The pointer 'data_' is not deallocated before it is allocated. [publicAllocationError]\n" "[test.cpp:18:3]: (error) Mismatching allocation and deallocation: Foo::data_ [mismatchAllocDealloc]\n", errout_str()); } @@ -1599,7 +1663,7 @@ class TestMemleakInClass : public TestFixture { " ~Fred() { free(s); }\n" " void xy()\n" " { s = malloc(100); }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:9:7]: (warning) Possible leak in public function. The pointer 's' is not deallocated before it is allocated. [publicAllocationError]\n", errout_str()); check("class Fred\n" @@ -1611,7 +1675,7 @@ class TestMemleakInClass : public TestFixture { " { s = malloc(100); }\n" "private:\n" " char *s;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:7:7]: (warning) Possible leak in public function. The pointer 's' is not deallocated before it is allocated. [publicAllocationError]\n", errout_str()); } @@ -1625,7 +1689,7 @@ class TestMemleakInClass : public TestFixture { " ~Fred() { free(s); }\n" " const Fred & operator = (const Fred &f)\n" " { s = malloc(100); }\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:9:7]: (warning) Possible leak in public function. The pointer 's' is not deallocated before it is allocated. [publicAllocationError]\n", errout_str()); } }; @@ -1652,7 +1716,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)(); } @@ -1673,6 +1737,8 @@ class TestMemleakStructMember : public TestFixture { TEST_CASE(assign2); TEST_CASE(assign3); TEST_CASE(assign4); // #11019 + TEST_CASE(assign5); + TEST_CASE(assign6); // Failed allocation TEST_CASE(failedAllocation); @@ -1682,6 +1748,7 @@ class TestMemleakStructMember : public TestFixture { TEST_CASE(function3); // #3024: kernel list TEST_CASE(function4); // #3038: Deallocating in function TEST_CASE(function5); // #10381, #10382, #10158 + TEST_CASE(function6); // Handle if-else TEST_CASE(ifelse); @@ -1715,14 +1782,14 @@ class TestMemleakStructMember : public TestFixture { " struct ABC *abc = malloc(sizeof(struct ABC));\n" " abc->a = malloc(10);\n" " free(abc);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:5]: (error) Memory leak: abc.a [memleak]\n", errout_str()); check("static void foo()\n" "{\n" " struct ABC *abc = malloc(sizeof(struct ABC));\n" " abc->a = malloc(10);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:1]: (error) Memory leak: abc.a [memleak]\n", errout_str()); check("static ABC * foo()\n" @@ -1735,7 +1802,7 @@ class TestMemleakStructMember : public TestFixture { " return 0;\n" " }\n" " return abc;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:9]: (error) Memory leak: abc.a [memleak]\n", errout_str()); check("static void foo(int a)\n" @@ -1747,7 +1814,7 @@ class TestMemleakStructMember : public TestFixture { " free(abc->a);\n" " return;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:10:1]: (error) Memory leak: abc.a [memleak]\n", errout_str()); } @@ -1763,7 +1830,7 @@ class TestMemleakStructMember : public TestFixture { "out:\n" " free(abc->a);\n" " free(abc);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1773,13 +1840,13 @@ class TestMemleakStructMember : public TestFixture { " struct ABC *abc = malloc(sizeof(struct ABC));\n" " abc->a = malloc(10);\n" " return abc;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("static void foo(struct ABC *abc)\n" "{\n" " abc->a = malloc(10);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #7302 @@ -1787,14 +1854,14 @@ class TestMemleakStructMember : public TestFixture { " struct ABC abc;\n" " abc.a = malloc(10);\n" " return abc.a;\n" - "}", false); + "}\n", false); ASSERT_EQUALS("", errout_str()); check("void* foo() {\n" " struct ABC abc;\n" " abc.a = malloc(10);\n" " return abc.b;\n" - "}", false); + "}\n", false); ASSERT_EQUALS("[test.c:4:5]: (error) Memory leak: abc.a [memleak]\n", errout_str()); } @@ -1804,7 +1871,7 @@ class TestMemleakStructMember : public TestFixture { " struct ABC *abc = malloc(sizeof(struct ABC));\n" " abc->a = malloc(10);\n" " return &abc->self;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1813,7 +1880,7 @@ class TestMemleakStructMember : public TestFixture { "{\n" " struct ABC *abc = abc1;\n" " abc->a = malloc(10);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("static void foo()\n" @@ -1821,7 +1888,7 @@ class TestMemleakStructMember : public TestFixture { " struct ABC *abc;\n" " abc1 = abc = malloc(sizeof(ABC));\n" " abc->a = malloc(10);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("static void foo()\n" @@ -1830,7 +1897,7 @@ class TestMemleakStructMember : public TestFixture { " ptr = malloc(sizeof(struct msn_entry));\n" " ptr->msn = malloc(100);\n" " back = ptr;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1839,7 +1906,7 @@ class TestMemleakStructMember : public TestFixture { check("static void foo() {\n" " struct ABC *abc = malloc(123);\n" " abc->a = abc->b = malloc(10);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1848,7 +1915,7 @@ class TestMemleakStructMember : public TestFixture { " struct s f2;\n" " f2.a = malloc(100);\n" " *f1 = f2;\n" - "}", false); + "}\n", false); ASSERT_EQUALS("", errout_str()); } @@ -1919,6 +1986,50 @@ class TestMemleakStructMember : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void assign5() { + check("struct S { int fd; };\n" + "void f() {\n" + " struct S* s = (struct S*)malloc(sizeof(struct S));\n" + " s->fd = open(\"abc\", O_RDWR | O_NOCTTY);\n" + " free(s);\n" + "}\n" + "void g() {\n" + " struct S* s = static_cast(malloc(sizeof(struct S)));\n" + " s->fd = open(\"abc\", O_RDWR | O_NOCTTY);\n" + " free(s);\n" + "}\n" + "void h() {\n" + " S* s = new S;\n" + " s->fd = open(\"abc\", O_RDWR | O_NOCTTY);\n" + " delete s;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:5]: (error) Resource leak: s.fd [resourceLeak]\n" + "[test.cpp:10:5]: (error) Resource leak: s.fd [resourceLeak]\n" + "[test.cpp:16:1]: (error) Resource leak: s.fd [resourceLeak]\n", + errout_str()); + + check("struct S { int fd; };\n" // #13031 + "void f() {\n" + " struct S* s = malloc(sizeof(struct S));\n" + " s->fd = open(\"abc\", O_RDWR | O_NOCTTY);\n" + " if (s->fd < 0) {\n" + " free(s);\n" + " return NULL;\n" + " }\n" + " return s;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + + void assign6() { + check("struct S { S* p; };\n" // #14524 + "void f() {\n" + " S s;\n" + " s.p = static_cast(malloc(sizeof(S)));\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:1]: (error) Memory leak: s.p [memleak]\n", errout_str()); + } + void failedAllocation() { check("static struct ABC * foo()\n" "{\n" @@ -1930,7 +2041,7 @@ class TestMemleakStructMember : public TestFixture { " return 0;\n" " }\n" " return abc;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1941,7 +2052,7 @@ class TestMemleakStructMember : public TestFixture { " struct ABC *abc = malloc(sizeof(struct ABC));\n" " abc->a = malloc(10);\n" " func(abc);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("static void foo()\n" @@ -1949,7 +2060,7 @@ class TestMemleakStructMember : public TestFixture { " struct ABC *abc = malloc(sizeof(struct ABC));\n" " abclist.push_back(abc);\n" " abc->a = malloc(10);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1959,7 +2070,7 @@ class TestMemleakStructMember : public TestFixture { " A a = { 0 };\n" " a.foo = (char *) malloc(10);\n" " assign(&a);\n" - "}", false); + "}\n", false); ASSERT_EQUALS("", errout_str()); } @@ -1969,7 +2080,7 @@ class TestMemleakStructMember : public TestFixture { " struct ABC *abc = malloc(100);\n" " abc.a = (char *) malloc(10);\n" " list_add_tail(&abc->list, head);\n" - "}", false); + "}\n", false); ASSERT_EQUALS("", errout_str()); } @@ -1980,7 +2091,7 @@ class TestMemleakStructMember : public TestFixture { " struct ABC abc;\n" " abc.a = (char *) malloc(10);\n" " a(abc.a);\n" - "}", false); + "}\n", false); ASSERT_EQUALS("", errout_str()); } @@ -1989,14 +2100,14 @@ class TestMemleakStructMember : public TestFixture { " struct s s1;\n" " s1->x = malloc(1);\n" " return (s1);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct nc_rpc nc_rpc_getconfig() {\n" // #10382 " struct nc_rpc rpc;\n" " rpc->filter = malloc(1);\n" " return (nc_rpc)rpc;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("T* f(const char *str) {\n" // #10158 @@ -2018,7 +2129,33 @@ class TestMemleakStructMember : public TestFixture { " }\n" " return g(&a);\n" "}\n"); - TODO_ASSERT_EQUALS("", "[test.cpp:9:9]: (error) Memory leak: a.str [memleak]\n", errout_str()); + ASSERT_EQUALS("", errout_str()); + + check("struct S { int *p; };\n" + "S f(int i) {\n" + " S s;\n" + " switch(i) {\n" + " case 1:\n" + " s.p = new int;\n" + " break;\n" + " default: {\n" + " return {};\n" + " }\n" + " }\n" + " return s;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + + void function6() { + check("struct S { int* p; };\n" // #14706 + "void g(void*);\n" + "void f() {\n" + " S* s = new S();\n" + " s->p = new int();\n" + " g((void*)s);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void ifelse() { @@ -2036,7 +2173,7 @@ class TestMemleakStructMember : public TestFixture { " }\n" " free(abc->a);\n" " free(abc);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2052,7 +2189,7 @@ class TestMemleakStructMember : public TestFixture { " free(abc);\n" " abc = next;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2064,7 +2201,7 @@ class TestMemleakStructMember : public TestFixture { " abc = malloc(sizeof(struct ABC));\n" " abc->a = malloc(10);\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2082,7 +2219,7 @@ class TestMemleakStructMember : public TestFixture { " a.f = fopen(\"test\", \"r\");\n" " a.c = new char[12];\n" " a.m = malloc(12);\n" - "}"; + "}\n"; check(code1, true); ASSERT_EQUALS("[test.cpp:12:1]: (error) Resource leak: a.f [resourceLeak]\n" @@ -2107,7 +2244,7 @@ class TestMemleakStructMember : public TestFixture { " fclose(a.f);\n" " delete [] a.c;\n" " free(a.m);\n" - "}"; + "}\n"; check(code2, true); ASSERT_EQUALS("", errout_str()); @@ -2116,7 +2253,7 @@ class TestMemleakStructMember : public TestFixture { const char code3[] = "void func() {\n" " struct A a;\n" " a.f = fopen(\"test\", \"r\");\n" - "}"; + "}\n"; check(code3, true); ASSERT_EQUALS("", errout_str()); @@ -2131,7 +2268,7 @@ class TestMemleakStructMember : public TestFixture { "void func() {\n" " struct A a;\n" " a.f = fopen(\"test\", \"r\");\n" - "}"; + "}\n"; check(code4, true); ASSERT_EQUALS("", errout_str()); @@ -2147,7 +2284,7 @@ class TestMemleakStructMember : public TestFixture { "{\n" " Test& y = *x;\n" " y.data = malloc(10);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2157,7 +2294,7 @@ class TestMemleakStructMember : public TestFixture { "unique_ptrotherbuffer{new char[otherbufsize+1]};\n" "char *const oldbuffer = otherbuffer.get();\n" "int const oldbufsize = otherbufsize;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2170,7 +2307,7 @@ class TestMemleakStructMember : public TestFixture { " (s).state_check_buff = (void* )malloc(1);\n" " if (s.state_check_buff == 0)\n" " return;\n" - "}", false); + "}\n", false); ASSERT_EQUALS("[test.c:9:1]: (error) Memory leak: s.state_check_buff [memleak]\n", errout_str()); } @@ -2180,7 +2317,7 @@ class TestMemleakStructMember : public TestFixture { " foo f;\n" " ((f)->realm) = strdup(realm);\n" " if(f->realm == NULL) {}\n" - "}", false); + "}\n", false); ASSERT_EQUALS("[test.c:6:1]: (error) Memory leak: f.realm [memleak]\n", errout_str()); } @@ -2191,7 +2328,7 @@ class TestMemleakStructMember : public TestFixture { "void func() {\n" " struct ABC abc;\n" " abc.a = myalloc();\n" - "}", false); + "}\n", false); ASSERT_EQUALS("[test.c:7:1]: (error) Memory leak: abc.a [memleak]\n", errout_str()); } @@ -2207,7 +2344,7 @@ class TestMemleakStructMember : public TestFixture { " }\n" " delete[] s.p;\n" " return 0;\n" - "}", true); + "}\n", true); ASSERT_EQUALS("", errout_str()); check( @@ -2261,7 +2398,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)(); } @@ -2288,23 +2425,23 @@ class TestMemleakNoVar : public TestFixture { // standard function.. check("void x() {\n" " strcpy(a, strdup(p));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (error) Allocation with strdup, strcpy doesn't release it. [leakNoVarFunctionCall]\n", errout_str()); check("char *x() {\n" " char *ret = strcpy(malloc(10), \"abc\");\n" " return ret;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("char *x() {\n" " return strcpy(malloc(10), \"abc\");\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void x() {\n" " free(malloc(10));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // user function.. @@ -2313,76 +2450,76 @@ class TestMemleakNoVar : public TestFixture { "\n" "void x() {\n" " set_error(strdup(p));\n" - "}"); - TODO_ASSERT_EQUALS("[test.cpp:5]: (error) Allocation with strdup, set_error doesn't release it.\n", "", errout_str()); + "}\n"); + TODO_ASSERT_EQUALS("[test.cpp:5:15]: (error) Allocation with strdup, set_error doesn't release it. [leakNoVarFunctionCall]\n", "", errout_str()); check("void f()\n" "{\n" " int fd;\n" " fd = mkstemp(strdup(\"/tmp/file.XXXXXXXX\"));\n" " close(fd);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Allocation with strdup, mkstemp doesn't release it.\n", "", errout_str()); check("void f()\n" "{\n" " if(TRUE || strcmp(strdup(a), b));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:23]: (error) Allocation with strdup, strcmp doesn't release it. [leakNoVarFunctionCall]\n", errout_str()); check("void f()\n" "{\n" " if(!strcmp(strdup(a), b) == 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:16]: (error) Allocation with strdup, strcmp doesn't release it. [leakNoVarFunctionCall]\n", errout_str()); check("void f()\n" "{\n" " 42, strcmp(strdup(a), b);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:16]: (error) Allocation with strdup, strcmp doesn't release it. [leakNoVarFunctionCall]\n", errout_str()); check("void f() {\n" " assert(freopen(\"/dev/null\", \"r\", stdin));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void x() {\n" " strcpy(a, (void*)strdup(p));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:22]: (error) Allocation with strdup, strcpy doesn't release it. [leakNoVarFunctionCall]\n", errout_str()); check("void* malloc1() {\n" " return (malloc(1));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("char *x() {\n" " char *ret = (char*)strcpy(malloc(10), \"abc\");\n" " return ret;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " free(malloc(1));\n" " strcpy(a, strdup(p));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:15]: (error) Allocation with strdup, strcpy doesn't release it. [leakNoVarFunctionCall]\n", errout_str()); check("void f() {\n" " memcmp(calloc(10, 10), strdup(q), 100);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:12]: (error) Allocation with calloc, memcmp doesn't release it. [leakNoVarFunctionCall]\n" "[test.cpp:2:28]: (error) Allocation with strdup, memcmp doesn't release it. [leakNoVarFunctionCall]\n", errout_str()); check("void* f(int size) {\n" " return (void*) malloc(size);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int* f(int size) {\n" " return static_cast(malloc(size));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() { if (new int[42]) {} }\n" // #10857 @@ -2466,31 +2603,66 @@ class TestMemleakNoVar : public TestFixture { " f(new U());\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("struct A {\n" // #14339 + " void g(int* p) { p_ = p; }\n" + " int *p_;\n" + "};\n" + "void f(A& a) {\n" + " 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() { check("void x()\n" "{\n" " malloc(10);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Return value of allocation function 'malloc' is not stored. [leakReturnValNotUsed]\n", errout_str()); check("void x()\n" "{\n" " calloc(10, 1);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Return value of allocation function 'calloc' is not stored. [leakReturnValNotUsed]\n", errout_str()); check("void x()\n" "{\n" " strdup(\"Test\");\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Return value of allocation function 'strdup' is not stored. [leakReturnValNotUsed]\n", errout_str()); check("void x()\n" "{\n" " (char*) malloc(10);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:13]: (error) Return value of allocation function 'malloc' is not stored. [leakReturnValNotUsed]\n", errout_str()); check("void x()\n" @@ -2498,7 +2670,7 @@ class TestMemleakNoVar : public TestFixture { " char* ptr = malloc(10);\n" " foo(ptr);\n" " free(ptr);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f( void ) {\n" // FP: #11246 @@ -2507,19 +2679,19 @@ class TestMemleakNoVar : public TestFixture { " if ( ok )\n" " free( address ), address = 0;\n" " return 0;\n" - "} "); + "} \n"); ASSERT_EQUALS("", errout_str()); check("char** x(const char* str) {\n" " char* ptr[] = { malloc(10), malloc(5), strdup(str) };\n" " return ptr;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void x()\n" "{\n" " 42,malloc(42);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8]: (error) Return value of allocation function 'malloc' is not stored. [leakReturnValNotUsed]\n", errout_str()); check("void *f()\n" @@ -2529,7 +2701,7 @@ class TestMemleakNoVar : public TestFixture { "void x()\n" "{\n" " f();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:5]: (error) Return value of allocation function 'f' is not stored. [leakReturnValNotUsed]\n", errout_str()); check("void f()\n" // #8100 @@ -2539,7 +2711,7 @@ class TestMemleakNoVar : public TestFixture { "void x()\n" "{\n" " f();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void *f() {\n" // #8848 @@ -2548,26 +2720,26 @@ class TestMemleakNoVar : public TestFixture { "void x()\n" "{\n" " f();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void x()\n" "{\n" " if(!malloc(5)) fail();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9]: (error) Return value of allocation function 'malloc' is not stored. [leakReturnValNotUsed]\n", errout_str()); check("FOO* factory() {\n" " FOO* foo = new (std::nothrow) FOO;\n" " return foo;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Ticket #6536 check("struct S { S(int) {} };\n" "void foo(int i) {\n" " S socket(i);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Ticket #6693 @@ -2577,12 +2749,12 @@ class TestMemleakNoVar : public TestFixture { "};\n" "void CTest::Initialise() {\n" " malloc();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" // #7348 - cast " p = (::X*)malloc(42);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #7182 "crash: CheckMemoryLeak::functionReturnType()" @@ -2590,7 +2762,7 @@ class TestMemleakNoVar : public TestFixture { "template auto binary_left_comma (T x, Ts... ts) { return (x , ... , ts); }\n" "int main() {\n" " unary_right_comma (a);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -2606,7 +2778,7 @@ class TestMemleakNoVar : public TestFixture { " new int{};\n" " new int{ 1 };\n" " new uint8_t[4];\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (error) Return value of allocation function 'new' is not stored. [leakReturnValNotUsed]\n" "[test.cpp:3:5]: (error) Return value of allocation function 'new' is not stored. [leakReturnValNotUsed]\n" "[test.cpp:4:5]: (error) Return value of allocation function 'new' is not stored. [leakReturnValNotUsed]\n" @@ -2624,7 +2796,7 @@ class TestMemleakNoVar : public TestFixture { check("void f(int* p) {\n" " new auto('c');\n" " new(p) int;\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:1:29]: (error) Return value of allocation function 'new' is not stored. [leakReturnValNotUsed]\n" "[test.cpp:3]: (error) Return value of allocation function 'new' is not stored.\n", "", @@ -2661,7 +2833,7 @@ class TestMemleakNoVar : public TestFixture { " C{ new int(1), 1 };\n" " C{ new(p) int, 1 };\n" " C{ new QWidget, 1 };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(bool b) { if (b && malloc(42)) {} }\n" // // #10858 @@ -2701,59 +2873,77 @@ class TestMemleakNoVar : public TestFixture { " delete[] &p[-1];\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("void f(FILE* fp1, FILE* fp2) {\n" // #14171 + " if (freopen(NULL, \"w+b\", fp1) == NULL) {}\n" + " if (std::freopen(NULL, \"w+b\", fp2) == NULL) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" // #14172 + " if (malloc(4) == nullptr) {}\n" + " if (::malloc(4) == nullptr) {}\n" + " if (std::malloc(4) == nullptr) {}\n" + " if (::std::malloc(4) == nullptr) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:9]: (error) Return value of allocation function 'malloc' is not stored. [leakReturnValNotUsed]\n" + "[test.cpp:3:11]: (error) Return value of allocation function 'malloc' is not stored. [leakReturnValNotUsed]\n" + "[test.cpp:4:14]: (error) Return value of allocation function 'malloc' is not stored. [leakReturnValNotUsed]\n" + "[test.cpp:5:16]: (error) Return value of allocation function 'malloc' is not stored. [leakReturnValNotUsed]\n", + errout_str()); } void smartPointerFunctionParam() { check("void x() {\n" " f(shared_ptr(new int(42)), g());\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (warning, inconclusive) Unsafe allocation. If g() throws, memory could be leaked. Use make_shared() instead. [leakUnsafeArgAlloc]\n", errout_str()); check("void x() {\n" " h(12, f(shared_ptr(new int(42)), g()));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (warning, inconclusive) Unsafe allocation. If g() throws, memory could be leaked. Use make_shared() instead. [leakUnsafeArgAlloc]\n", errout_str()); check("void x() {\n" " f(unique_ptr(new int(42)), g());\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (warning, inconclusive) Unsafe allocation. If g() throws, memory could be leaked. Use make_unique() instead. [leakUnsafeArgAlloc]\n", errout_str()); check("void x() {\n" " f(g(), shared_ptr(new int(42)));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (warning, inconclusive) Unsafe allocation. If g() throws, memory could be leaked. Use make_shared() instead. [leakUnsafeArgAlloc]\n", errout_str()); check("void x() {\n" " f(g(), unique_ptr(new int(42)));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (warning, inconclusive) Unsafe allocation. If g() throws, memory could be leaked. Use make_unique() instead. [leakUnsafeArgAlloc]\n", errout_str()); check("void x() {\n" " f(shared_ptr(new char), make_unique(32));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (warning, inconclusive) Unsafe allocation. If make_unique() throws, memory could be leaked. Use make_shared() instead. [leakUnsafeArgAlloc]\n", errout_str()); check("void x() {\n" " f(g(124), h(\"test\", 234), shared_ptr(new char));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (warning, inconclusive) Unsafe allocation. If h() throws, memory could be leaked. Use make_shared() instead. [leakUnsafeArgAlloc]\n", errout_str()); check("void x() {\n" " f(shared_ptr(new std::string(\"\")), g());\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (warning, inconclusive) Unsafe allocation. If g() throws, memory could be leaked. Use make_shared() instead. [leakUnsafeArgAlloc]\n", errout_str()); check("void g(int x) throw() { }\n" "void x() {\n" " f(g(124), shared_ptr(new char));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void __declspec(nothrow) g(int x) { }\n" "void x() {\n" " f(g(124), shared_ptr(new char));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void resourceLeak() { @@ -2764,23 +2954,23 @@ class TestMemleakNoVar : public TestFixture { " if (result) return !result;\n" " fclose(fp);\n" " return result;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " fopen(\"file.txt\", \"r\");\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:3]: (error) Return value of allocation function 'fopen' is not stored. [leakReturnValNotUsed]\n", errout_str()); check("void foo() {\n" " FILE *f = fopen(\"file.txt\", \"r\");\n" " freopen(\"file.txt\", \"r\", f);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:3]: (error) Return value of allocation function 'freopen' is not stored. [leakReturnValNotUsed]\n", errout_str()); check("void foo() {\n" " freopen(\"file.txt\", \"r\", stdin);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct Holder {\n" @@ -2790,7 +2980,7 @@ class TestMemleakNoVar : public TestFixture { "};\n" "void foo() {\n" " Holder h ( fopen(\"file.txt\", \"r\"));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct Holder {\n" @@ -2800,7 +2990,7 @@ class TestMemleakNoVar : public TestFixture { "};\n" "void foo() {\n" " Holder ( fopen(\"file.txt\", \"r\"));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct Holder {\n" @@ -2810,7 +3000,7 @@ class TestMemleakNoVar : public TestFixture { "};\n" "void foo() {\n" " Holder h { fopen(\"file.txt\", \"r\")};\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct Holder {\n" @@ -2820,7 +3010,7 @@ class TestMemleakNoVar : public TestFixture { "};\n" "void foo() {\n" " Holder h = fopen(\"file.txt\", \"r\");\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct Holder {\n" @@ -2830,7 +3020,7 @@ class TestMemleakNoVar : public TestFixture { "};\n" "void foo() {\n" " Holder { fopen(\"file.txt\", \"r\")};\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct Holder {\n" @@ -2840,7 +3030,7 @@ class TestMemleakNoVar : public TestFixture { "};\n" "void foo() {\n" " Holder { 0, fopen(\"file.txt\", \"r\")};\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2851,7 +3041,7 @@ class TestMemleakNoVar : public TestFixture { "\n" "void f() {\n" " makeThing();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #10631 @@ -2878,12 +3068,12 @@ class TestMemleakNoVar : public TestFixture { void crash1() { // #10729 check("void foo() {\n" " extern void *realloc (void *ptr, size_t size);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " extern void *malloc (size_t size);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 88338447ade..81c44d58811 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,6 +37,7 @@ class TestNullPointer : public TestFixture { private: const Settings settings = settingsBuilder().library("std.cfg").severity(Severity::warning).build(); + const Settings settings_i = settingsBuilder(settings).certainty(Certainty::inconclusive).build(); void run() override { mNewTemplate = true; @@ -142,6 +143,11 @@ 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(nullpointer110); // #14937 TEST_CASE(nullpointer_addressOf); // address of TEST_CASE(nullpointerSwitch); // #2626 TEST_CASE(nullpointer_cast); // #4692 @@ -166,6 +172,7 @@ class TestNullPointer : public TestFixture { TEST_CASE(nullpointerStdStream); TEST_CASE(nullpointerSmartPointer); TEST_CASE(nullpointerOutOfMemory); + TEST_CASE(nullpointerOutOfResources); TEST_CASE(functioncall); TEST_CASE(functioncalllibrary); // use Library to parse function call TEST_CASE(functioncallDefaultArguments); @@ -180,23 +187,25 @@ class TestNullPointer : public TestFixture { struct CheckOptions { - CheckOptions() = default; bool inconclusive = false; bool cpp = true; - Standards::cstd_t cstd = Standards::CLatest; }; #define check(...) check_(__FILE__, __LINE__, __VA_ARGS__) template void check_(const char* file, int line, const char (&code)[size], const CheckOptions& options = make_default_obj()) { - const Settings settings1 = settingsBuilder(settings).certainty(Certainty::inconclusive, options.inconclusive).c(options.cstd).build(); + const Settings& settings1 = options.inconclusive ? settings_i : settings; + check_(file, line, code, settings1, options.cpp); + } + template + void check_(const char* file, int line, const char (&code)[size], const Settings& s, bool cpp = true) { // Tokenize.. - SimpleTokenizer tokenizer(settings1, *this, options.cpp); + SimpleTokenizer tokenizer(s, *this, cpp); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check for null pointer dereferences.. - runChecks(tokenizer, this); + CheckNullPointer check; + runChecks(check, tokenizer, *this); } #define checkP(...) checkP_(__FILE__, __LINE__, __VA_ARGS__) @@ -207,8 +216,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); } @@ -219,7 +228,7 @@ class TestNullPointer : public TestFixture { "{\n" " while (tok);\n" " tok = tok->next();\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:3:12] -> [test.cpp:4:11]: (warning) Either the condition 'tok' is redundant or there is possible null pointer dereference: tok. [nullPointerRedundantCheck]\n", errout_str()); // #2681 @@ -244,7 +253,7 @@ class TestNullPointer : public TestFixture { " while (tok && tok->str() != \";\")\n" " tok = tok->next();\n" " }\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:5] -> [test.cpp:3]: (warning) Either the condition 'while' is redundant or there is possible null pointer dereference: tok.\n", "", errout_str()); check("void foo(Token &tok)\n" @@ -254,7 +263,7 @@ class TestNullPointer : public TestFixture { " while (!tok)\n" " char c = tok.read();\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" @@ -265,7 +274,7 @@ class TestNullPointer : public TestFixture { " tok = tok->next();\n" " if( !tok ) break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" @@ -275,7 +284,7 @@ class TestNullPointer : public TestFixture { " while (tok && tok->str() != \";\")\n" " tok = tok->next();\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(A*a)\n" @@ -290,7 +299,7 @@ class TestNullPointer : public TestFixture { " a->b();\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // dereference in outer scope.. @@ -299,7 +308,7 @@ class TestNullPointer : public TestFixture { " while (tok) tok = tok->next();\n" " }\n" " tok->str();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:16] -> [test.cpp:5:5]: (warning) Either the condition 'tok' is redundant or there is possible null pointer dereference: tok. [nullPointerRedundantCheck]\n", errout_str()); check("int foo(const Token *tok)\n" @@ -324,7 +333,7 @@ class TestNullPointer : public TestFixture { " while (d && d->i == 0)\n" " d = d->c;\n" " if (!d) throw;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct b {\n" @@ -349,7 +358,7 @@ class TestNullPointer : public TestFixture { " }\n" " else if (a->x == 2) { }\n" " if (a) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // ticket #2134 - sizeof doesn't dereference @@ -359,7 +368,7 @@ class TestNullPointer : public TestFixture { " sizeof(*list);\n" " if (!list)\n" " ;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // ticket #2245 - sizeof doesn't dereference @@ -367,7 +376,7 @@ class TestNullPointer : public TestFixture { " if (!p) {\n" " int sz = sizeof(p->x);\n" " }\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } @@ -379,7 +388,7 @@ class TestNullPointer : public TestFixture { " Fred fred;\n" " while (fred);\n" " fred.hello();\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } @@ -395,7 +404,7 @@ class TestNullPointer : public TestFixture { " int a = abc->a;\n" " if (!abc)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9] -> [test.cpp:3:13]: (warning) Either the condition '!abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(struct ABC *abc) {\n" @@ -404,7 +413,7 @@ class TestNullPointer : public TestFixture { " bar(x, y, abc->a);\n" " if (!abc)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:9] -> [test.cpp:2:9]: (warning) Either the condition '!abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n" "[test.cpp:5:9] -> [test.cpp:3:12]: (warning) Either the condition '!abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n" "[test.cpp:5:9] -> [test.cpp:4:15]: (warning) Either the condition '!abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n", errout_str()); @@ -414,7 +423,7 @@ class TestNullPointer : public TestFixture { " return;\n" " }\n" " if (abc) {}\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:5:9] -> [test.cpp:2:9]: (warning) Either the condition 'abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n", errout_str()); @@ -424,7 +433,7 @@ class TestNullPointer : public TestFixture { " return;\n" " }\n" " if (!abc);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:9] -> [test.cpp:2:9]: (warning) Either the condition '!abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n", errout_str()); // TODO: False negative if member of member is dereferenced @@ -432,14 +441,14 @@ class TestNullPointer : public TestFixture { " abc->next->a = 0;\n" " if (abc->next)\n" " ;\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:2]: (warning) Possible null pointer dereference: abc - otherwise it is redundant to check it against null.\n", "", errout_str()); check("void foo(ABC *abc) {\n" " abc->a = 0;\n" " if (abc && abc->b == 0)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:3:9] -> [test.cpp:2:5]: (warning) Either the condition 'abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n", errout_str()); @@ -450,13 +459,13 @@ class TestNullPointer : public TestFixture { " if (abc && abc->a);\n" " if (!abc)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(struct ABC *abc) {\n" " int x = abc && a(abc->x);\n" " if (abc) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // ok to use a linked list.. @@ -465,13 +474,13 @@ class TestNullPointer : public TestFixture { " abc = abc->next;\n" " if (!abc)\n" " ;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f(struct ABC *abc) {\n" " abc = (ABC *)(abc->_next);\n" - " if (abc) { }" - "}", dinit(CheckOptions, $.inconclusive = true)); + " if (abc) { }\n" + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // reassign struct.. @@ -481,7 +490,7 @@ class TestNullPointer : public TestFixture { " abc = abc->next;\n" " if (!abc)\n" " ;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void foo(struct ABC *abc)\n" @@ -490,7 +499,7 @@ class TestNullPointer : public TestFixture { " f(&abc);\n" " if (!abc)\n" " ;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // goto.. @@ -504,7 +513,7 @@ class TestNullPointer : public TestFixture { "out:\n" " if (!abc)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // loops.. @@ -518,7 +527,7 @@ class TestNullPointer : public TestFixture { " --a;\n" " }\n" " while (a > 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f()\n" @@ -530,7 +539,7 @@ class TestNullPointer : public TestFixture { " if (!tok)\n" " return;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // dynamic_cast.. @@ -539,7 +548,7 @@ class TestNullPointer : public TestFixture { " int a = abc->a;\n" " if (!dynamic_cast(abc))\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #2641 - global pointer, function call @@ -548,14 +557,14 @@ class TestNullPointer : public TestFixture { " abc->a = 0;\n" " do_stuff();\n" " if (abc) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("",errout_str()); check("Fred *fred;\n" "void f() {\n" " fred->foo();\n" " if (fred) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("",errout_str()); // #2641 - local pointer, function call @@ -564,7 +573,7 @@ class TestNullPointer : public TestFixture { " abc->a = 0;\n" " do_stuff();\n" " if (abc) { }\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:5:9] -> [test.cpp:3:5]: (warning) Either the condition 'abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n", errout_str()); @@ -574,7 +583,7 @@ class TestNullPointer : public TestFixture { " abc->a = 0;\n" " do_stuff();\n" " if (abc) { }\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:4:9] -> [test.cpp:2:5]: (warning) Either the condition 'abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n", errout_str()); @@ -589,32 +598,32 @@ class TestNullPointer : public TestFixture { " if ( abc ) {}\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #3128 check("void f(ABC *abc) {\n" " x(!abc || y(abc->a));\n" " if (abc) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(ABC *abc) {\n" " x(def || !abc || y(def, abc->a));\n" " if (abc) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(ABC *abc) {\n" " x(abc && y(def, abc->a));\n" " if (abc) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(ABC *abc) {\n" " x(def && abc && y(def, abc->a));\n" " if (abc) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #3228 - calling function with null object @@ -622,7 +631,7 @@ class TestNullPointer : public TestFixture { const char code[] = "void f(Fred *fred) {\n" " fred->x();\n" " if (fred) { }\n" - "}"; + "}\n"; check(code); ASSERT_EQUALS( "[test.cpp:3:9] -> [test.cpp:2:5]: (warning) Either the condition 'fred' is redundant or there is possible null pointer dereference: fred. [nullPointerRedundantCheck]\n", @@ -634,7 +643,7 @@ class TestNullPointer : public TestFixture { "void f(struct FRED *fred) {\n" " fred->x = 0;\n" " IF(!fred){}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" @@ -642,7 +651,7 @@ class TestNullPointer : public TestFixture { " if (!buffer)\n" " uv_fatal_error();\n" " buffer->x = 11;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -656,14 +665,14 @@ class TestNullPointer : public TestFixture { " *p = 0;\n" " if (!p)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9] -> [test.cpp:3:6]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(int *p)\n" "{\n" " *p = 0;\n" " if (p) { }\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:4:9] -> [test.cpp:3:6]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); @@ -672,7 +681,7 @@ class TestNullPointer : public TestFixture { "{\n" " *p = 0;\n" " if (p || q) { }\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:4:9] -> [test.cpp:3:6]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); @@ -682,7 +691,7 @@ class TestNullPointer : public TestFixture { " bar(*p);\n" " if (!p)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9] -> [test.cpp:3:10]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(char *p)\n" @@ -690,14 +699,14 @@ class TestNullPointer : public TestFixture { " strcpy(p, \"abc\");\n" " if (!p)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9] -> [test.cpp:3:12]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(char *p)\n" "{\n" " if (*p == 0) { }\n" " if (!p) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9] -> [test.cpp:3:10]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); // no error @@ -707,7 +716,7 @@ class TestNullPointer : public TestFixture { " f(&p);\n" " if (!p)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" @@ -715,7 +724,7 @@ class TestNullPointer : public TestFixture { " int **p = f();\n" " if (!p)\n" " ;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void foo(int *p)\n" @@ -726,7 +735,7 @@ class TestNullPointer : public TestFixture { " *p = 0;\n" " if (!p)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int x)\n" @@ -734,7 +743,7 @@ class TestNullPointer : public TestFixture { " int a = 2 * x;" " if (x == 0)\n" " ;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void foo(int *p)\n" @@ -742,7 +751,7 @@ class TestNullPointer : public TestFixture { " int var1 = p ? *p : 0;\n" " if (!p)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int *p, bool x)\n" @@ -750,7 +759,7 @@ class TestNullPointer : public TestFixture { " int var1 = x ? *p : 5;\n" " if (!p)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:4:9] -> [test.cpp:3:21]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); @@ -759,13 +768,13 @@ class TestNullPointer : public TestFixture { check("void f(int *p) {\n" " *p = 0;\n" " while (p) { p = 0; }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int *p) {\n" " *p = 0;\n" " while (p) { }\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:3:12] -> [test.cpp:2:6]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); @@ -776,7 +785,7 @@ class TestNullPointer : public TestFixture { " int var1 = p ? (p->a) : 0;\n" " if (!p)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(ABC *p)\n" @@ -784,7 +793,7 @@ class TestNullPointer : public TestFixture { " int var1 = p ? (1 + p->a) : 0;\n" " if (!p)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -816,7 +825,7 @@ class TestNullPointer : public TestFixture { " break;\n" " else\n" " p = p->next();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(Document *doc) {\n" @@ -824,27 +833,27 @@ class TestNullPointer : public TestFixture { " if (!doc) {\n" " return;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #3128 - false positive check("void f(int *p) {\n" " assert(!p || (*p<=6));\n" " if (p) { *p = 0; }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int *p) {\n" " assert(p && (*p<=6));\n" " if (p) { *p = 0; }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int *p) {\n" " *p = 12;\n" " assert(p && (*p<=6));\n" " if (p) { *p = 0; }\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:3:12] -> [test.cpp:2:6]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); @@ -854,7 +863,7 @@ class TestNullPointer : public TestFixture { " p = p->next;\n" " if (!p)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(x *p)\n" @@ -862,7 +871,7 @@ class TestNullPointer : public TestFixture { " p = bar(p->next);\n" " if (!p)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(x *p)\n" @@ -870,7 +879,7 @@ class TestNullPointer : public TestFixture { " p = aa->bar(p->next);\n" " if (!p)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(x *p)\n" @@ -878,7 +887,7 @@ class TestNullPointer : public TestFixture { " p = *p2 = p->next;\n" " if (!p)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(struct ABC *abc)\n" @@ -886,32 +895,32 @@ class TestNullPointer : public TestFixture { " abc = abc ? abc->next : 0;\n" " if (!abc)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(struct ABC *abc) {\n" // #4523 " abc = (*abc).next;\n" " if (abc) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(struct ABC *abc) {\n" // #4523 " abc = (*abc->ptr);\n" " if (abc) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f(Item *item) {\n" " x = item ? ab(item->x) : 0;\n" " if (item) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f(Item *item) {\n" " item->x = 0;\n" " a = b ? c : d;\n" " if (item) { }\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:4:9] -> [test.cpp:2:5]: (warning) Either the condition 'item' is redundant or there is possible null pointer dereference: item. [nullPointerRedundantCheck]\n", errout_str()); @@ -925,7 +934,7 @@ class TestNullPointer : public TestFixture { "\n" " if( !pFrm )\n" " return FALSE;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Ticket #2463 @@ -945,7 +954,7 @@ class TestNullPointer : public TestFixture { " break;\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #2525 - sizeof @@ -954,26 +963,26 @@ class TestNullPointer : public TestFixture { " int c = sizeof(test[0]);\n" " if (!test)\n" " ;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f(type* p) {\n" // #4983 " x(sizeof p[0]);\n" " if (!p)\n" " ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #3023 - checked deref check("void f(struct ABC *abc) {\n" " WARN_ON(!abc || abc->x == 0);\n" " if (!abc) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(struct ABC *abc) {\n" " WARN_ON(!abc || abc->x == 7);\n" " if (!abc) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #3425 - false positives when there are macros @@ -981,20 +990,28 @@ class TestNullPointer : public TestFixture { "void f(int *p) {\n" " *p = 0;\n" " IF(!p){}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" // #3914 - false positive " int *p;\n" " ((p=ret()) && (x=*p));\n" " if (p);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct S { struct T { char c; } *p; };\n" // #6541 "char f(S* s) { return s->p ? 'a' : s->p->c; }\n"); ASSERT_EQUALS("[test.cpp:2:24] -> [test.cpp:2:37]: (warning) Either the condition 's->p' is redundant or there is possible null pointer dereference: s->p. [nullPointerRedundantCheck]\n", errout_str()); + + check("int f(const int a[]) {\n" // #14544 + " int i = 0;\n" + " if (!a)\n" + " a = &i;\n" + " return *a;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void nullpointer5() { @@ -1004,7 +1021,7 @@ class TestNullPointer : public TestFixture { " char c = a.c();\n" " if (!a)\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1019,18 +1036,18 @@ class TestNullPointer : public TestFixture { " } else { if (a == 2) {\n" " p = new FooCar; } }\n" " p->abcd();\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:8]: (error) Possible null pointer dereference: p\n", "", errout_str()); check("static void foo() {\n" " int &r = *(int*)0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (error) Null pointer dereference: (int*)0 [nullPointer]\n", errout_str()); check("static void foo(int x) {\n" " int y = 5 + *(int*)0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:18]: (error) Null pointer dereference: (int*)0 [nullPointer]\n", errout_str()); { @@ -1045,7 +1062,7 @@ class TestNullPointer : public TestFixture { check("static void foo() {\n" " std::cout << *(int*)0;" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:19]: (error) Null pointer dereference: (int*)0 [nullPointer]\n", errout_str()); check("void f()\n" @@ -1055,12 +1072,12 @@ class TestNullPointer : public TestFixture { " delete c;\n" " }\n" " c[0] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:5]: (error) Null pointer dereference: c [nullPointer]\n", errout_str()); check("static void foo() {\n" " if (3 > *(int*)0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:14]: (error) Null pointer dereference: (int*)0 [nullPointer]\n", errout_str()); // no false positive.. @@ -1069,20 +1086,20 @@ class TestNullPointer : public TestFixture { " Foo *p = 0;\n" " p = new Foo;\n" " p->abcd();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" " int sz = sizeof((*(struct dummy *)0).x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void get_offset(long &offset)\n" "{\n" " mystruct * temp; temp = 0;\n" " offset = (long)(&(temp->z));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Ticket #1893 - try/catch inside else @@ -1101,7 +1118,7 @@ class TestNullPointer : public TestFixture { " }\n" " *Q=1;\n" " return Q;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int *test(int *Z)\n" @@ -1117,7 +1134,7 @@ class TestNullPointer : public TestFixture { " }\n" " *Q=1;\n" " return Q;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:12:6]: (warning) Possible null pointer dereference: Q [nullPointer]\n", errout_str()); // Ticket #2052 (false positive for 'else continue;') @@ -1128,7 +1145,7 @@ class TestNullPointer : public TestFixture { " else continue;\n" " *p = 0;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // function pointer.. @@ -1137,7 +1154,7 @@ class TestNullPointer : public TestFixture { " void (*f)();\n" " f = 0;\n" " f();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:5]: (error) Null pointer dereference: f [nullPointer]\n", errout_str()); check("int* g();\n" // #11007 @@ -1155,7 +1172,7 @@ class TestNullPointer : public TestFixture { " for (int i = 0; i < 10; ++i) {\n" " int x = *p + 1;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:18]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); check("void f(int a) {\n" @@ -1166,21 +1183,21 @@ class TestNullPointer : public TestFixture { " for (int i = 0; i < 3; i++) {\n" " if (a && (p[i] == '1'));\n" " }\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // ticket #2251: taking the address of member check("void f() {\n" " Fred *fred = 0;\n" " int x = &fred->x;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // ticket #3220: dereferencing a null pointer is UB check("void f() {\n" " Fred *fred = NULL;\n" " fred->do_something();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Null pointer dereference: fred [nullPointer]\n", errout_str()); // ticket #3570 - parsing of conditions @@ -1190,21 +1207,21 @@ class TestNullPointer : public TestFixture { " if (x)\n" " p = q;\n" " if (p && *p) { }\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " int *p = NULL;\n" " if (x)\n" " p = q;\n" " if (!p || *p) { }\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " int *p = NULL;\n" " if (x)\n" " p = q;\n" " if (p || *p) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:15]: (warning) Possible null pointer dereference: p [nullPointer]\n", errout_str()); } @@ -1220,7 +1237,7 @@ class TestNullPointer : public TestFixture { "\n" "void g() {\n" " f(NULL, NULL);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } @@ -1245,7 +1262,7 @@ class TestNullPointer : public TestFixture { " for (int i = 0; i < n; i++) {\n" " argv32[i] = 0;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // No false negative: @@ -1260,7 +1277,7 @@ class TestNullPointer : public TestFixture { " for (int i = 0; i < n; i++) {\n" " argv32[i] = 0;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:10:9]: (warning) Possible null pointer dereference: argv32 [nullPointer]\n", errout_str()); // #2231 - error if assignment in loop is not used @@ -1276,7 +1293,7 @@ class TestNullPointer : public TestFixture { " }\n" "\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:11:6]: (warning) Possible null pointer dereference: p [nullPointer]\n", errout_str()); } @@ -1285,7 +1302,7 @@ class TestNullPointer : public TestFixture { "{\n" " wxLongLong x = 0;\n" " int y = x.GetValue();\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } @@ -1294,7 +1311,7 @@ class TestNullPointer : public TestFixture { "{\n" " std::string * x = 0;\n" " *x = \"test\";\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:4]: (error) Null pointer dereference: x [nullPointer]\n", errout_str()); } @@ -1304,7 +1321,7 @@ class TestNullPointer : public TestFixture { "{\n" " struct my_type* p = 0;\n" " p->x = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:3]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); } @@ -1316,7 +1333,7 @@ class TestNullPointer : public TestFixture { " struct my_type* p;\n" " p = 0;\n" " return p->x;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:10]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); } @@ -1330,7 +1347,8 @@ class TestNullPointer : public TestFixture { check(code); // C++ file => nullptr means NULL ASSERT_EQUALS("[test.cpp:4:11]: (error) Null pointer dereference: i [nullPointer]\n", errout_str()); - check(code, dinit(CheckOptions, $.cpp = false, $.cstd = Standards::C17)); // C17 file => nullptr does not mean NULL + const Settings s = settingsBuilder(settings).c(Standards::C17).build(); + check(code, s, false); // C17 file => nullptr does not mean NULL ASSERT_EQUALS("", errout_str()); check(code, dinit(CheckOptions, $.cpp = false)); @@ -1342,7 +1360,7 @@ class TestNullPointer : public TestFixture { " char *p = 0;\n" " if (x) p = \"abcd\";\n" " return p ? f(*p) : f(0);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1351,7 +1369,7 @@ class TestNullPointer : public TestFixture { " int *p = 0;\n" " bar(&p);\n" " *p = 0;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } @@ -1360,14 +1378,14 @@ class TestNullPointer : public TestFixture { " int *p = 0;\n" " if (x) { return 0; }\n" " return !p || *p;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("int foo() {\n" " int *p = 0;\n" " if (x) { return 0; }\n" " return p && *p;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } @@ -1380,14 +1398,14 @@ class TestNullPointer : public TestFixture { " {\n" " i++;\n" " };\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:10]: (error) Null pointer dereference: str [nullPointer]\n", errout_str()); } void nullpointer19() { // #3811 check("int foo() {\n" " perror(0);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } @@ -1396,15 +1414,17 @@ class TestNullPointer : public TestFixture { " struct xy *p = 0;\n" " if (x) p = q;\n" " if (p ? p->x || p->y : 0) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" // false negative " struct xy *p = 0;\n" " if (x) p = q;\n" " if (y ? p->x : p->y) { }\n" - "}"); - TODO_ASSERT_EQUALS("[test.cpp:4]: (warning) Possible null pointer dereference: p\n", "", errout_str()); + "}\n"); + ASSERT_EQUALS("[test.cpp:4:13]: (warning) Possible null pointer dereference: p [nullPointer]\n" + "[test.cpp:4:20]: (warning) Possible null pointer dereference: p [nullPointer]\n", + errout_str()); } void nullpointer21() { // #4038 - fp: if (x) p=q; else return; @@ -1413,7 +1433,7 @@ class TestNullPointer : public TestFixture { " if (x) p = q;\n" " else return;\n" " *p = 0;\n" // <- p is not NULL - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1422,7 +1442,7 @@ class TestNullPointer : public TestFixture { " char *c = NULL;\n" " char cBuf[10];\n" " sprintf(cBuf, \"%s\", c ? c : \"0\" );\n" - "}"); + "}\n"); ASSERT_EQUALS("",errout_str()); } @@ -1431,7 +1451,7 @@ class TestNullPointer : public TestFixture { " char *c = NULL;\n" " x = c = new char[10];\n" " *c = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1441,7 +1461,7 @@ class TestNullPointer : public TestFixture { " int *array = NULL;\n" " if (data == 1 && array[i] == 0)\n" " std::cout << \"test\";\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:22]: (error) Null pointer dereference: array [nullPointer]\n", errout_str()); } @@ -1458,7 +1478,7 @@ class TestNullPointer : public TestFixture { " if (t2 && (!t1))\n" " return 0.0;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1472,7 +1492,7 @@ class TestNullPointer : public TestFixture { " pointer_=NULL;\n" " *pointer_=0;\n" " return *this;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:6]: (error) Null pointer dereference: pointer_ [nullPointer]\n", errout_str()); } @@ -1482,7 +1502,7 @@ class TestNullPointer : public TestFixture { " int i = s ? s->value + 1\n" " : s->value - 1; // <-- null ptr dereference\n" " return i;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:3:11] -> [test.cpp:4:15]: (warning) Either the condition 's' is redundant or there is possible null pointer dereference: s. [nullPointerRedundantCheck]\n", errout_str()); @@ -1533,7 +1553,7 @@ class TestNullPointer : public TestFixture { " }\n" "\n" " (void)f->x;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } @@ -1645,7 +1665,7 @@ class TestNullPointer : public TestFixture { "void f(struct A *a) {\n" " if (a->x == NULL) {}\n" " *(a->x);\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:3:14] -> [test.cpp:4:8]: (warning) Either the condition 'a->x==NULL' is redundant or there is possible null pointer dereference: a->x. [nullPointerRedundantCheck]\n", errout_str()); @@ -1656,7 +1676,7 @@ class TestNullPointer : public TestFixture { "void f(struct A *a) {\n" " if (a->x == nullptr) {}\n" " *(a->x);\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:3:14] -> [test.cpp:4:8]: (warning) Either the condition 'a->x==nullptr' is redundant or there is possible null pointer dereference: a->x. [nullPointerRedundantCheck]\n", errout_str()); @@ -1667,7 +1687,7 @@ class TestNullPointer : public TestFixture { "void f(struct A *a) {\n" " if (a->g() == nullptr) {}\n" " *(a->g());\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:3:16] -> [test.cpp:4:11]: (warning) Either the condition 'a->g()==nullptr' is redundant or there is possible null pointer dereference: a->g(). [nullPointerRedundantCheck]\n", errout_str()); @@ -1676,7 +1696,7 @@ class TestNullPointer : public TestFixture { "void f(struct A *a) {\n" " if (a->g() == nullptr) {}\n" " *(a->g());\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1685,7 +1705,7 @@ class TestNullPointer : public TestFixture { "void f(struct A *a) {\n" " if (a->g() == nullptr) {}\n" " *(a->g());\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:3:16] -> [test.cpp:4:11]: (warning) Either the condition 'a->g()==nullptr' is redundant or there is possible null pointer dereference: a->g(). [nullPointerRedundantCheck]\n", errout_str()); @@ -1698,7 +1718,7 @@ class TestNullPointer : public TestFixture { " if (x) {\n" " (void)*a->x;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1710,7 +1730,7 @@ class TestNullPointer : public TestFixture { " if ( w == 0.0 )\n" " return 0;\n" " return b->get();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9423 check("extern F* GetF();\n" @@ -1727,7 +1747,7 @@ class TestNullPointer : public TestFixture { " if (!lPtrOk)\n" " return;\n" " lPtr->Clear();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1744,7 +1764,7 @@ class TestNullPointer : public TestFixture { " g();\n" " a d = *c->b();\n" " return d;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct a {\n" @@ -1760,7 +1780,7 @@ class TestNullPointer : public TestFixture { " e();\n" " a d = *c->b();\n" " return d;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1768,7 +1788,7 @@ class TestNullPointer : public TestFixture { check("void f() {\n" " char* p = new(std::nothrow) char[1];\n" " if( p ) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1777,7 +1797,7 @@ class TestNullPointer : public TestFixture { " if(!p[0]) {}\n" " const int *const a = p;\n" " if(!a){}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:7] -> [test.cpp:2:8]: (warning) Either the condition '!a' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); } @@ -1786,7 +1806,7 @@ class TestNullPointer : public TestFixture { "auto f(T& x) -> decltype(x);\n" "int& g(int* x) {\n" " return f(*x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1796,7 +1816,7 @@ class TestNullPointer : public TestFixture { " if(n > 10) q = p;\n" " *p +=2;\n" " if(n < 120) *q+=12;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:18]: (warning) Possible null pointer dereference: q [nullPointer]\n", errout_str()); check("void f(int *p, int n) {\n" @@ -1804,7 +1824,7 @@ class TestNullPointer : public TestFixture { " if(n > 10) q = p;\n" " *p +=2;\n" " if(n > 10) *q+=12;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1818,7 +1838,7 @@ class TestNullPointer : public TestFixture { " }\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:8] -> [test.cpp:6:18]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); @@ -1834,7 +1854,7 @@ class TestNullPointer : public TestFixture { " if (c(e, \"\"))\n" " return nullptr;\n" " return e->b();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1844,7 +1864,7 @@ class TestNullPointer : public TestFixture { " if(b) c = b;\n" " if (!c) c = &a;\n" " return *c;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f(int a, int* b) {\n" @@ -1853,7 +1873,7 @@ class TestNullPointer : public TestFixture { " bool d = !c;\n" " if (d) c = &a;\n" " return *c;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A { int* x; };\n" @@ -1863,7 +1883,7 @@ class TestNullPointer : public TestFixture { " if(b) c.x = b;\n" " if (!c.x) c.x = &a;\n" " return *c.x;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A { int* x; };\n" @@ -1874,7 +1894,7 @@ class TestNullPointer : public TestFixture { " bool d = !c.x;\n" " if (d) c.x = &a;\n" " return *c.x;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A { int* x; };\n" @@ -1897,7 +1917,7 @@ class TestNullPointer : public TestFixture { "}\n" "void bar() {\n" " f(0, 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (warning) Possible null pointer dereference: params [nullPointer]\n", errout_str()); } @@ -1913,7 +1933,7 @@ class TestNullPointer : public TestFixture { "int bar() {\n" " int **array = NULL;\n" " foo (array, 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1923,7 +1943,7 @@ class TestNullPointer : public TestFixture { " while (tok3->astParent() && tok3->str() == \",\")\n" " tok3 = tok3->astParent();\n" " if (tok3 && tok3->str() == \"(\") {}\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:5:9] -> [test.cpp:3:12]: (warning) Either the condition 'tok3' is redundant or there is possible null pointer dereference: tok3. [nullPointerRedundantCheck]\n", errout_str()); @@ -1936,7 +1956,7 @@ class TestNullPointer : public TestFixture { " }\n" " if (!t1 || !t2)\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("bool f(int* i);\n" @@ -1944,7 +1964,7 @@ class TestNullPointer : public TestFixture { " while(f(i) && *i == 0)\n" " i++;\n" " if (!i) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1956,7 +1976,7 @@ class TestNullPointer : public TestFixture { " ListEntry *prev = NULL;\n" " for (ListEntry *cursor = listHead; cursor != NULL; prev = cursor, cursor = cursor->next) {}\n" " if (prev) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -2433,6 +2453,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" @@ -2448,6 +2471,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" @@ -2456,6 +2481,14 @@ class TestNullPointer : public TestFixture { " if (h(i) && *i == 1) {}\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("void f(int i) {\n" // #13797 + " int* p = nullptr;\n" + " if (!i) {\n" + " *p = 0;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:10]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); } void nullpointer78() // #7802 @@ -2466,7 +2499,7 @@ class TestNullPointer : public TestFixture { " int *p = 0;\n" " pp = &p;\n" " **pp = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:6]: (error) Null pointer dereference: *pp [nullPointer]\n", errout_str()); } @@ -2702,7 +2735,7 @@ class TestNullPointer : public TestFixture { " }\n" " }\n" " return \"unknown\";\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:7:12] -> [test.cpp:3:7]: (warning) Either the condition 'ctx' is redundant or there is possible null pointer dereference: ctx. [nullPointerRedundantCheck]\n", errout_str()); @@ -2744,7 +2777,7 @@ class TestNullPointer : public TestFixture { " int* myNull = GetThing();\n" " *myNull=42;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:10]: (error) Null pointer dereference: myNull [nullPointer]\n", errout_str()); check("struct foo {\n" @@ -2755,7 +2788,7 @@ class TestNullPointer : public TestFixture { " int* myNull = myFoo.GetThing();\n" " *myNull=42;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:10]: (error) Null pointer dereference: myNull [nullPointer]\n", errout_str()); check("struct T { bool g() const; };\n" @@ -2852,7 +2885,7 @@ class TestNullPointer : public TestFixture { " int * buf = foo(true);\n" " buf[2] = 0;" // << " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:14:9]: (error) Null pointer dereference: buf [nullPointer]\n", errout_str()); } @@ -2943,17 +2976,188 @@ 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" + "}\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 nullpointer110() + { // #14937 - noreturn member function called on operator() result + check("struct A {\n" + " [[noreturn]] void g(int);\n" + "};\n" + "template\n" + "struct Thunk {\n" + " T& operator()() const;\n" + "};\n" + "void f(Thunk thunk, int* p) {\n" + " if (!p)\n" + " thunk().g(0);\n" + " *p = 1;\n" + "}\n", + dinit(CheckOptions, $.inconclusive = true)); + ASSERT_EQUALS("", errout_str()); + } + void nullpointer_addressOf() { // address of check("void f() {\n" " struct X *x = 0;\n" " if (addr == &x->y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " struct X *x = 0;\n" " if (addr == &x->y.z[0]) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkP("typedef int Count;\n" // #10018 @@ -2979,7 +3183,7 @@ class TestNullPointer : public TestFixture { " break;\n" " }\n" " return p;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:7:10]: (warning) Possible null pointer dereference: p [nullPointer]\n", errout_str()); } @@ -2989,7 +3193,7 @@ class TestNullPointer : public TestFixture { " while (*p && nasm_isspace(*p))\n" " p++;\n" " return p;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(char* origin) {\n" // #11449 @@ -3004,7 +3208,7 @@ class TestNullPointer : public TestFixture { check("void f () {\n" " int *buf; buf = NULL;\n" " buf;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } @@ -3026,27 +3230,27 @@ class TestNullPointer : public TestFixture { " if (!p) {\n" " }\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:4:6]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(char *p) {\n" " if (p && *p == 0) {\n" " }\n" " printf(\"%c\", *p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:4:19]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(char *p) {\n" " if (p && *p == 0) {\n" " } else { *p = 0; }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:15]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(char *p) {\n" " if (p) {\n" " }\n" " strcpy(p, \"abc\");\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:4:12]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(char *p) {\n" @@ -3054,7 +3258,7 @@ class TestNullPointer : public TestFixture { " }\n" " bar();\n" " strcpy(p, \"abc\");\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:5:12]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(abc *p) {\n" @@ -3062,7 +3266,7 @@ class TestNullPointer : public TestFixture { " }\n" " else { if (!p->x) {\n" " } }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); { @@ -3072,7 +3276,7 @@ class TestNullPointer : public TestFixture { " abort();\n" " }\n" " *p = 0;\n" - "}"; + "}\n"; check(code); ASSERT_EQUALS("", errout_str()); @@ -3085,7 +3289,7 @@ class TestNullPointer : public TestFixture { " (*bail)();\n" " }\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(char *p) {\n" @@ -3093,7 +3297,7 @@ class TestNullPointer : public TestFixture { " throw x;\n" " }\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(char *p) {\n" @@ -3101,21 +3305,21 @@ class TestNullPointer : public TestFixture { " ab.abort();\n" " }\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(char *p) {\n" " if (!p) {\n" " switch (x) { }\n" " }\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void foo(char *p) {\n" " if (!p) {\n" " }\n" " return *x;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("int foo(int *p) {\n" @@ -3123,7 +3327,7 @@ class TestNullPointer : public TestFixture { " x = *p;\n" " return 5+*p;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:14]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n" "[test.cpp:2:9] -> [test.cpp:4:19]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); @@ -3133,7 +3337,7 @@ class TestNullPointer : public TestFixture { " if (!a) {\n" " a.x();\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // This is why this check can't be used on the simplified token list @@ -3141,7 +3345,7 @@ class TestNullPointer : public TestFixture { " if (!dynamic_cast(foo)) {\n" " *foo = 0;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // ticket: #2300 - calling unknown function that may initialize the pointer @@ -3151,7 +3355,7 @@ class TestNullPointer : public TestFixture { " initfred();\n" " fred->x = 0;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // ticket #1219 @@ -3160,7 +3364,7 @@ class TestNullPointer : public TestFixture { " return;\n" " }\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:5:6]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); // #2467 - unknown macro may terminate the application @@ -3169,7 +3373,7 @@ class TestNullPointer : public TestFixture { " MACRO;\n" " }\n" " fred->a();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #2493 - switch @@ -3182,7 +3386,7 @@ class TestNullPointer : public TestFixture { " fred->a();\n" " break;\n" " };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #4118 - second if @@ -3190,7 +3394,7 @@ class TestNullPointer : public TestFixture { " int x = 1;\n" " if (!p) x = 0;\n" " if (x) *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #2674 - different functions @@ -3207,7 +3411,7 @@ class TestNullPointer : public TestFixture { "\n" "void Fred::b() {\n" " wilma->Reload();\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void test(int *i) {\n" @@ -3215,7 +3419,7 @@ class TestNullPointer : public TestFixture { " else {\n" " int b = *i;\n" " }\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // #2696 - false positives nr 1 @@ -3228,7 +3432,7 @@ class TestNullPointer : public TestFixture { "\n" " if (pFoo)\n" " bar();\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // #2696 - false positives nr 2 @@ -3241,7 +3445,7 @@ class TestNullPointer : public TestFixture { " pFoo = pFoo->next;\n" "\n" " len = sizeof(pFoo->data);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // #2696 - false positives nr 3 @@ -3254,13 +3458,13 @@ class TestNullPointer : public TestFixture { " pFoo = pFoo->next;\n" "\n" " len = decltype(*pFoo);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("int foo(struct Fred *fred) {\n" " if (fred) { }\n" " return fred->a;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:12]: (warning) Either the condition 'fred' is redundant or there is possible null pointer dereference: fred. [nullPointerRedundantCheck]\n", errout_str()); // #2789 - assign and check pointer @@ -3268,7 +3472,7 @@ class TestNullPointer : public TestFixture { " char *p; p = x();\n" " if (!p) { }\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9] -> [test.cpp:4:6]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); // check, assign and use @@ -3277,7 +3481,7 @@ class TestNullPointer : public TestFixture { " if (p == 0 && (p = malloc(10)) != 0) {\n" " *p = 0;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // check, assign and use @@ -3286,7 +3490,7 @@ class TestNullPointer : public TestFixture { " if (p == 0 && (p = malloc(10)) != a && (*p = a)) {\n" " *p = 0;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // check, and use @@ -3295,7 +3499,7 @@ class TestNullPointer : public TestFixture { " if (p == 0 && (*p = 0)) {\n" " return;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:3:21]: (warning) Either the condition 'p==0' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); // check, and use @@ -3304,7 +3508,7 @@ class TestNullPointer : public TestFixture { " if (p == 0 && p->x == 10) {\n" " return;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:3:19]: (warning) Either the condition 'p==0' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); // check, and use @@ -3313,7 +3517,7 @@ class TestNullPointer : public TestFixture { " if (p == 0 || p->x == 10) {\n" " return;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // check, and use @@ -3322,7 +3526,7 @@ class TestNullPointer : public TestFixture { " if (p == NULL && (*p = a)) {\n" " return;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:3:24]: (warning) Either the condition 'p==NULL' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); // check, and use @@ -3330,14 +3534,14 @@ class TestNullPointer : public TestFixture { " if (!p && x==1 || p && p->x==0) {\n" " return;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); { const char code[] = "void f(Fred *fred) {\n" " if (fred == NULL) { }\n" " fred->x();\n" - "}"; + "}\n"; check(code); // inconclusive ASSERT_EQUALS("[test.cpp:2:14] -> [test.cpp:3:5]: (warning) Either the condition 'fred==NULL' is redundant or there is possible null pointer dereference: fred. [nullPointerRedundantCheck]\n", errout_str()); @@ -3346,53 +3550,67 @@ class TestNullPointer : public TestFixture { check("void f(char *s) {\n" // #3358 " if (s==0);\n" " strcpy(a, s?b:c);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // sizeof check("void f(struct fred_t *fred) {\n" " if (!fred)\n" " int sz = sizeof(fred->x);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // check in macro check("void f(int *x) {\n" " $if (!x) {}\n" " *x = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // return ?: check("int f(ABC *p) {\n" // FP : return ?: " if (!p) {}\n" " return p ? p->x : 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f(ABC *p) {\n" // no fn " if (!p) {}\n" " return q ? p->x : 0;\n" - "}"); - TODO_ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p.\n", "", errout_str()); + "}\n"); + ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:16]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("int f(ABC *p) {\n" // FP : return && " if (!p) {}\n" " return p && p->x;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x, int *p) {\n" " if (x || !p) {}\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:14] -> [test.cpp:3:6]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); // sizeof check("void f() {\n" " int *pointer = NULL;\n" " pointer = func(sizeof pointer[0]);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); + + check("struct T {\n" // #14164 + " T* next;\n" + " char op;\n" + "};\n" + "void h(int, char);\n" + "void g(const T* tok, bool b) {\n" + " if (tok->op == '<') {\n" + " while ((tok = tok->next) && tok->op != '>') {}\n" + " }\n" + " h(b ? 1 : 0, tok->op);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:8:21] -> [test.cpp:10:18]: (warning) Either the condition 'tok=tok->next' is redundant or there is possible null pointer dereference: tok. [nullPointerRedundantCheck]\n", + errout_str()); } // Test CheckNullPointer::nullConstantDereference @@ -3400,12 +3618,12 @@ class TestNullPointer : public TestFixture { check("int f() {\n" " int* p = 0;\n" " return p[4];\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:12]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); check("void f() {\n" " typeof(*NULL) y;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("int * f() {\n" @@ -3413,7 +3631,7 @@ class TestNullPointer : public TestFixture { "}\n" "int main() {\n" " return *f();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:12]: (error) Null pointer dereference: f() [nullPointer]\n", errout_str()); } @@ -3421,7 +3639,7 @@ class TestNullPointer : public TestFixture { // Ticket #2621 check("void f(struct ABC *abc) {\n" " ({ if (abc) dbg(); })\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -3429,7 +3647,7 @@ class TestNullPointer : public TestFixture { // Ticket #2840 check("void f() {\n" " int bytes = snprintf(0, 0, \"%u\", 1);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } @@ -3437,150 +3655,143 @@ class TestNullPointer : public TestFixture { // Ticket #2840 check("void f() {\n" " int bytes = snprintf(0, 10, \"%u\", 1);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:26]: (error) Null pointer dereference [nullPointer]\n", errout_str()); } void printf_with_invalid_va_argument() { check("void f() {\n" " printf(\"%s\", 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:18]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("void f(char* s) {\n" " printf(\"%s\", s);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " char* s = 0;\n" " printf(\"%s\", s);\n" - "}"); + "}\n"); ASSERT_EQUALS( - "[test.cpp:3:18]: (error) Null pointer dereference: s [nullPointer]\n" - "[test.cpp:3:18]: (error) Null pointer dereference [nullPointer]\n", + "[test.cpp:3:18]: (error) Null pointer dereference: s [nullPointer]\n", errout_str()); check("void f() {\n" " char *s = 0;\n" " printf(\"%s\", s == 0 ? a : s);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " printf(\"%u%s\", 0, 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:23]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("void f(char* s) {\n" " printf(\"%u%s\", 0, s);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " char* s = 0;\n" " printf(\"%u%s\", 123, s);\n" - "}"); + "}\n"); ASSERT_EQUALS( - "[test.cpp:3:25]: (error) Null pointer dereference: s [nullPointer]\n" - "[test.cpp:3:25]: (error) Null pointer dereference [nullPointer]\n", + "[test.cpp:3:25]: (error) Null pointer dereference: s [nullPointer]\n", errout_str()); check("void f() {\n" " printf(\"%%%s%%\", 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:22]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("void f(char* s) {\n" " printf(\"text: %s, %s\", s, 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:31]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("void f() {\n" " char* s = \"blabla\";\n" " printf(\"%s\", s);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(char* s) {\n" " printf(\"text: %m%s, %s\", s, 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:33]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("void f(char* s) {\n" " printf(\"text: %*s, %s\", s, 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:32]: (error) Null pointer dereference [nullPointer]\n", errout_str()); // Ticket #3364 check("void f() {\n" " printf(\"%-*.*s\", s, 0);\n" " sprintf(\"%*\", s);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void scanf_with_invalid_va_argument() { check("void f(char* s) {\n" " sscanf(s, \"%s\", 0);\n" - "}"); + "}\n"); ASSERT_EQUALS( - "[test.cpp:2:21]: (error) Null pointer dereference [nullPointer]\n" - "[test.cpp:2:21]: (error) Null pointer dereference [nullPointer]\n", // duplicate + "[test.cpp:2:21]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("void f() {\n" " scanf(\"%d\", 0);\n" - "}"); + "}\n"); ASSERT_EQUALS( - "[test.cpp:2:17]: (error) Null pointer dereference [nullPointer]\n" - "[test.cpp:2:17]: (error) Null pointer dereference [nullPointer]\n", // duplicate + "[test.cpp:2:17]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("void f(char* foo) {\n" " char location[200];\n" " int width, height;\n" " sscanf(imgInfo, \"%s %d %d\", location, &width, &height);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // ticket #3207 check("void f(char *dummy) {\n" " int iVal;\n" " sscanf(dummy, \"%d%c\", &iVal);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // ticket #3211 check("void f(char *dummy) {\n" " int* iVal = 0;\n" " sscanf(dummy, \"%d\", iVal);\n" - "}"); + "}\n"); ASSERT_EQUALS( - "[test.cpp:3:25]: (error) Null pointer dereference: iVal [nullPointer]\n" - "[test.cpp:3:25]: (error) Null pointer dereference [nullPointer]\n" - "[test.cpp:3:25]: (error) Null pointer dereference [nullPointer]\n", // duplicate + "[test.cpp:3:25]: (error) Null pointer dereference: iVal [nullPointer]\n", errout_str()); check("void f(char *dummy) {\n" " int* iVal;\n" " sscanf(dummy, \"%d\", foo(iVal));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(char *dummy) {\n" " int* iVal = 0;\n" " sscanf(dummy, \"%d%d\", foo(iVal), iVal);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(char* dummy) {\n" " sscanf(dummy, \"%*d%u\", 0);\n" - "}"); + "}\n"); ASSERT_EQUALS( - "[test.cpp:2:28]: (error) Null pointer dereference [nullPointer]\n" - "[test.cpp:2:28]: (error) Null pointer dereference [nullPointer]\n", // duplicate + "[test.cpp:2:28]: (error) Null pointer dereference [nullPointer]\n", errout_str()); } @@ -3590,12 +3801,12 @@ class TestNullPointer : public TestFixture { " int* iVal = 0;\n" " if(maybe()) iVal = g();\n" " return iVal[0];\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:12]: (warning) Possible null pointer dereference: iVal [nullPointer]\n", errout_str()); check("int foo(int* iVal) {\n" " return iVal[0];\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } @@ -3605,20 +3816,20 @@ class TestNullPointer : public TestFixture { "bool foo() {\n" " PolymorphicA* a = 0;\n" " return typeid(*a) == typeid(*a);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("struct NonPolymorphicA { ~A() {} };\n" "bool foo() {\n" " NonPolymorphicA* a = 0;\n" " return typeid(*a) == typeid(*a);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("bool foo() {\n" " char* c = 0;\n" " return typeid(*c) == typeid(*c);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } @@ -3627,40 +3838,40 @@ class TestNullPointer : public TestFixture { check("size_t foo() {\n" " char* c = 0;\n" " return alignof(*c);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("size_t foo() {\n" " return alignof(*0);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void foo(int *p) {\n" " f(alignof(*p));\n" " if (p) {}\n" " return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("size_t foo() {\n" " char* c = 0;\n" " return _Alignof(*c);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("size_t foo() {\n" " return _alignof(*0);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("size_t foo() {\n" " return __alignof(*0);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("size_t foo() {\n" " return __alignof__(*0);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } @@ -3671,7 +3882,7 @@ class TestNullPointer : public TestFixture { " cnt = 0;\n" " for (int i = 0; i < cnt; ++i)\n" " *ptr++ = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #11635 @@ -3685,6 +3896,26 @@ class TestNullPointer : public TestFixture { " i++;\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("void f(const int* p) {\n" // #6710 + " for (int i = *p; i < 5; ++i) {}\n" + " if (p) {}\n" + "}\n" + "struct S { int a; };\n" + "void g(const S* s) {\n" + " for (int i = s->a; i < 5; ++i) {}\n" + " if (s) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:9] -> [test.cpp:2:19]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n" + "[test.cpp:8:9] -> [test.cpp:7:18]: (warning) Either the condition 's' is redundant or there is possible null pointer dereference: s. [nullPointerRedundantCheck]\n", + errout_str()); + + check("struct S { int a; };\n" // #6492 + "void h(const S* s) {\n" + " for (int i = s->a; s; ++i) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:24] -> [test.cpp:3:18]: (warning) Either the condition 's' is redundant or there is possible null pointer dereference: s. [nullPointerRedundantCheck]\n", + errout_str()); } void nullpointerDeadCode() { @@ -3726,6 +3957,15 @@ class TestNullPointer : public TestFixture { " return 1 ? 1 : *(int*)0 = 1;\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check ("struct S {\n" // #13220 + " explicit S(int* p) : i(*p) {\n" + " if (p) {}\n" + " }\n" + " int i;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:3:13] -> [test.cpp:2:29]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", + errout_str()); } void nullpointerDelete() { @@ -3752,7 +3992,22 @@ class TestNullPointer : public TestFixture { "void f(int* x) {\n" " if (x)\n" " g(x);\n" - "}"); + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct T {\n" // #14308 + " bool b{};\n" + " T* next{};\n" + "};\n" + "bool g(const T*& r) {\n" + " const T* t = r;\n" + " r = t->next;\n" + " return t->b;\n" + "}\n" + "void f(const T* tok) {\n" + " if (g(tok)) {}\n" + " if (tok) {}\n" + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -3779,7 +4034,7 @@ class TestNullPointer : public TestFixture { " std::string s4 = p;\n" " std::string s5(p);\n" " foo(std::string(p));\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:9:10]: (error) Null pointer dereference: p [nullPointer]\n" "[test.cpp:10:22]: (error) Null pointer dereference: p [nullPointer]\n" "[test.cpp:11:20]: (error) Null pointer dereference: p [nullPointer]\n" @@ -3795,7 +4050,7 @@ class TestNullPointer : public TestFixture { " std::string s2 = nullptr;\n" " std::string s3(nullptr);\n" " foo(std::string(nullptr));\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2:10]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:3:22]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:4:17]: (error) Null pointer dereference [nullPointer]\n" @@ -3807,7 +4062,7 @@ class TestNullPointer : public TestFixture { " std::string s2 = NULL;\n" " std::string s3(NULL);\n" " foo(std::string(NULL));\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2:10]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:3:22]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:4:17]: (error) Null pointer dereference [nullPointer]\n" @@ -3823,7 +4078,7 @@ class TestNullPointer : public TestFixture { " foo(p == s1);\n" " foo(p == s2);\n" " foo(p == s3);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:4:15]: (error) Null pointer dereference: p [nullPointer]\n" "[test.cpp:5:15]: (error) Null pointer dereference: p [nullPointer]\n" "[test.cpp:7:9]: (error) Null pointer dereference: p [nullPointer]\n" @@ -3838,7 +4093,7 @@ class TestNullPointer : public TestFixture { " foo(s1.size() == 0);\n" " foo(s2.size() == 0);\n" " foo(s3->size() == 0);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f(std::string s1, const std::string& s2) {\n" @@ -3847,7 +4102,7 @@ class TestNullPointer : public TestFixture { " foo(0 == s2[0]);\n" " foo(s1[0] == 0);\n" " foo(s2[0] == 0);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f(std::string s1, const std::string& s2) {\n" @@ -3856,7 +4111,7 @@ class TestNullPointer : public TestFixture { " foo(s2 == '\\0');\n" " foo('\\0' == s1);\n" " foo('\\0' == s2);\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("class Bar {\n" @@ -3867,19 +4122,19 @@ class TestNullPointer : public TestFixture { " std::string s;\n" " Foo();\n" "};\n" - "Foo::Foo() : s(0) {}"); + "Foo::Foo() : s(0) {}\n"); ASSERT_EQUALS("[test.cpp:3:13]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:9:14]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("void f() {\n" " std::string s = 0 == x ? \"a\" : \"b\";\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " const std::string s = g();\n" " ASSERT_MESSAGE(\"Error on s\", 0 == s.compare(\"Some text\"));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int i, std::string s);\n" @@ -3890,7 +4145,7 @@ class TestNullPointer : public TestFixture { " foo(var, NULL);\n" " foo(var, nullptr);\n" " foo(0, var);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:10]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:5:12]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:6:12]: (error) Null pointer dereference [nullPointer]\n" @@ -3904,7 +4159,8 @@ class TestNullPointer : public TestFixture { " std::string s(p);\n" " return s;\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); - ASSERT_EQUALS("", errout_str()); + ASSERT_EQUALS("[test.cpp:6:17]: (warning, inconclusive) Possible null pointer dereference: p [nullPointer]\n", + errout_str()); check("void f() {\n" // #11078 " const char* p = nullptr;\n" @@ -3919,13 +4175,22 @@ class TestNullPointer : public TestFixture { "void f() { std::string s = g(0L); }\n"); ASSERT_EQUALS("[test.cpp:2:29]: (error) Null pointer dereference: g(0L) [nullPointer]\n", errout_str()); + + check("const char* g() { return nullptr; }\n" // #14098 + "std::string f() {\n" + " std::string s{ g() };\n" + " return s + std::string(g());\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:21]: (error) Null pointer dereference: g() [nullPointer]\n" + "[test.cpp:4:29]: (error) Null pointer dereference: g() [nullPointer]\n", + errout_str()); } void nullpointerStdStream() { check("void f(std::ifstream& is) {\n" " char* p = 0;\n" " is >> p;\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:3]: (error) Possible null pointer dereference: p\n", "", errout_str()); check("void f(const std::ostringstream& oss, char* q) {\n" @@ -3934,7 +4199,7 @@ class TestNullPointer : public TestFixture { " oss << foo << p;\n" " if(q == 0)\n" " oss << foo << q;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:12]: (error) Null pointer dereference: p [nullPointer]\n" "[test.cpp:4:19]: (error) Null pointer dereference: p [nullPointer]\n" "[test.cpp:5:10] -> [test.cpp:6:23]: (warning) Either the condition 'q==0' is redundant or there is possible null pointer dereference: q. [nullPointerRedundantCheck]\n", errout_str()); @@ -3946,7 +4211,7 @@ class TestNullPointer : public TestFixture { " std::cin >> p;\n" " std::cout << abc << p;\n" " }\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:2:10] -> [test.cpp:3:22]: (warning) Either the condition 'p==0' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n" "[test.cpp:2:10] -> [test.cpp:4:22]: (warning) Either the condition 'p==0' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n" "[test.cpp:2:10] -> [test.cpp:5]: (warning) Either the condition 'p==0' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n" @@ -3961,7 +4226,7 @@ class TestNullPointer : public TestFixture { " char* p2 = 0;\n" " std::cin >> (int)p;\n" // result casted " std::cout << (int)p;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f(const std::string& str) {\n" @@ -3969,13 +4234,13 @@ class TestNullPointer : public TestFixture { " std::istringstream istr(str);\n" " istr >> std::hex >> ret;\n" // Read integer " return ret;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f(int* i) {\n" " if(i) return;\n" " std::cout << i;\n" // Its no char* (#4240) - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // #5811 false positive: (error) Null pointer dereference @@ -3984,7 +4249,7 @@ class TestNullPointer : public TestFixture { " stringstream out;\n" " out << ((ip >> 0) & 0xFF);\n" " return out.str();\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // avoid regression from first fix attempt for #5811... check("void deserialize(const std::string &data) {\n" @@ -4004,42 +4269,42 @@ class TestNullPointer : public TestFixture { "void f(std::shared_ptr p) {\n" " if (p) {}\n" " dostuff(p->x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:7] -> [test.cpp:4:11]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("struct Fred { int x; };\n" "void f(std::shared_ptr p) {\n" " p = nullptr;\n" " dostuff(p->x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:11]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); check("struct Fred { int x; };\n" "void f(std::unique_ptr p) {\n" " if (p) {}\n" " dostuff(p->x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:7] -> [test.cpp:4:11]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("struct Fred { int x; };\n" "void f(std::unique_ptr p) {\n" " p = nullptr;\n" " dostuff(p->x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:11]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); check("struct Fred { int x; };\n" "void f() {\n" " std::shared_ptr p;\n" " dostuff(p->x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:11]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); check("struct Fred { int x; };\n" "void f(std::shared_ptr p) {\n" " p.reset();\n" " dostuff(p->x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:11]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); check("struct Fred { int x; };\n" @@ -4047,7 +4312,7 @@ class TestNullPointer : public TestFixture { " Fred * pp = nullptr;\n" " p.reset(pp);\n" " dostuff(p->x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:11]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); check("struct Fred { int x; };\n" @@ -4055,28 +4320,28 @@ class TestNullPointer : public TestFixture { " std::shared_ptr p;\n" " p.reset(&f);\n" " dostuff(p->x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct Fred { int x; };\n" "void f(std::shared_ptr p) {\n" " p.reset();\n" " dostuff(p->x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:11]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); check("struct Fred { int x; };\n" "void f() {\n" " std::shared_ptr p(nullptr);\n" " dostuff(p->x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:11]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); check("struct A {};\n" "void f(int n) {\n" " std::unique_ptr p;\n" " p.reset(new const A*[n]);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9216 @@ -4087,7 +4352,7 @@ class TestNullPointer : public TestFixture { "void g(std::unique_ptr var) {\n" " var->reset();\n" " var->f();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9439 @@ -4115,21 +4380,21 @@ class TestNullPointer : public TestFixture { " int *p = malloc(10);\n" " *p = 0;\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:6]: (warning) If memory allocation fails, then there is a possible null pointer dereference: p [nullPointerOutOfMemory]\n", errout_str()); check("void f() {\n" " int *p = malloc(10);\n" " *(p+2) = 0;\n" " free(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8]: (error) If memory allocation fails: pointer addition with NULL pointer. [nullPointerArithmeticOutOfMemory]\n", errout_str()); check("void f() {\n" // #13676 " int* q = static_cast(std::malloc(4));\n" " *q = 0;\n" " std::free(q);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:6]: (warning) If memory allocation fails, then there is a possible null pointer dereference: q [nullPointerOutOfMemory]\n", errout_str()); } @@ -4141,7 +4406,7 @@ class TestNullPointer : public TestFixture { " *p = 0;\n" " foo(p);\n" " if (p) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // function seen (taking pointer parameter) @@ -4151,7 +4416,7 @@ class TestNullPointer : public TestFixture { " *p = 0;\n" " foo(p);\n" " if (p) { }\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:6:9] -> [test.cpp:4:6]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); @@ -4163,7 +4428,7 @@ class TestNullPointer : public TestFixture { " *p = 0;\n" " foo(p);\n" " if (p) { }\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // function implementation not seen @@ -4173,7 +4438,7 @@ class TestNullPointer : public TestFixture { " *p = 0;\n" " foo(p);\n" " if (p) { }\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:6:9] -> [test.cpp:4:6]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); @@ -4183,7 +4448,7 @@ class TestNullPointer : public TestFixture { " *p = 0;\n" " foo(p);\n" " if (p) { }\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS( "[test.cpp:4:9] -> [test.cpp:2:6]: (warning, inconclusive) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); @@ -4196,7 +4461,7 @@ class TestNullPointer : public TestFixture { " abc->a = 0;\n" " foo(abc);\n" " if (abc) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // function seen (taking pointer parameter) @@ -4206,7 +4471,7 @@ class TestNullPointer : public TestFixture { " abc->a = 0;\n" " foo(abc);\n" " if (abc) { }\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:6:9] -> [test.cpp:4:5]: (warning) Either the condition 'abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n", errout_str()); @@ -4218,7 +4483,7 @@ class TestNullPointer : public TestFixture { " abc->a = 0;\n" " foo(abc);\n" " if (abc) { }\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:6:9] -> [test.cpp:4:5]: (warning) Either the condition 'abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n", errout_str()); @@ -4228,16 +4493,81 @@ class TestNullPointer : public TestFixture { " abc->a = 0;\n" " foo(abc);\n" " if (abc) { }\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS( "[test.cpp:4:9] -> [test.cpp:2:5]: (warning, inconclusive) Either the condition 'abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n", errout_str()); } } + void nullpointerOutOfResources() { + check("void f() {\n" + " FILE* fid = fopen(\"x.txt\", \"w\");\n" + " fprintf(fid, \"abcdef\");\n" + " fclose(fid);\n" + "}\n"); + ASSERT_EQUALS( + "[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() { SimpleTokenizer tokenizer(settingsDefault,*this,false); - const char code[] = "void f() { int a,b,c; x(a,b,c); }"; + const char code[] = "void f() { int a,b,c; x(a,b,c); }\n"; ASSERT_EQUALS(true, tokenizer.tokenize(code)); const Token *xtok = Token::findsimplematch(tokenizer.tokens(), "x"); @@ -4255,8 +4585,7 @@ class TestNullPointer : public TestFixture { Library library; ASSERT(LibraryHelper::loadxmldata(library, xmldata, sizeof(xmldata))); - std::list null; - CheckNullPointer::parseFunctionCall(*xtok, null, library); + const std::list null = CheckNullPointerImpl::parseFunctionCall(*xtok, library); ASSERT_EQUALS(0U, null.size()); } @@ -4274,8 +4603,7 @@ class TestNullPointer : public TestFixture { Library library; ASSERT(LibraryHelper::loadxmldata(library, xmldata, sizeof(xmldata))); - std::list null; - CheckNullPointer::parseFunctionCall(*xtok, null, library); + const std::list null = CheckNullPointerImpl::parseFunctionCall(*xtok, library); ASSERT_EQUALS(1U, null.size()); ASSERT_EQUALS("a", null.front()->str()); } @@ -4285,51 +4613,51 @@ class TestNullPointer : public TestFixture { check("void f(int *p = 0) {\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:6]: (warning) Possible null pointer dereference if the default parameter value is used: p [nullPointerDefaultArg]\n", errout_str()); check("void f(int *p = 0) {\n" " if (!p)\n" " return;\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(char a, int *p = 0) {\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:6]: (warning) Possible null pointer dereference if the default parameter value is used: p [nullPointerDefaultArg]\n", errout_str()); check("void f(int *p = 0) {\n" " printf(\"p = %d\", *p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:23]: (warning) Possible null pointer dereference if the default parameter value is used: p [nullPointerDefaultArg]\n", errout_str()); check("void f(int *p = 0) {\n" " printf(\"p[1] = %d\", p[1]);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:25]: (warning) Possible null pointer dereference if the default parameter value is used: p [nullPointerDefaultArg]\n", errout_str()); check("void f(int *p = 0) {\n" " buf[p] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int *p = 0) {\n" " if (p != 0 && bar())\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int *p) {\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int *p = 0) {\n" " if (p != 0)\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int *p = 0) {\n" @@ -4337,13 +4665,13 @@ class TestNullPointer : public TestFixture { " if (p == 0)\n" " p = &y;\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int a, int *p = 0) {\n" " if (a != 0)\n" " *p = 0;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS( "[test.cpp:3:8]: (warning) Possible null pointer dereference if the default parameter value is used: p [nullPointerDefaultArg]\n", errout_str()); @@ -4351,13 +4679,13 @@ class TestNullPointer : public TestFixture { check("void f(int *p = 0) {\n" " p = a;\n" " *p = 0;\n" // <- don't simplify and verify - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int *p = 0) {\n" " p += a;\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f(int *p = 0) {\n" @@ -4365,17 +4693,17 @@ class TestNullPointer : public TestFixture { " return 0;\n" " }\n" " return *p;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int *p = 0) {\n" " std::cout << p ? *p : 0;\n" // Due to operator precedence, this is equivalent to: (std::cout << p) ? *p : 0; - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:23]: (warning) Possible null pointer dereference if the default parameter value is used: p [nullPointerDefaultArg]\n", errout_str()); // Check the first branch of ternary check("void f(char *p = 0) {\n" " std::cout << p ? *p : 0;\n" // Due to operator precedence, this is equivalent to: (std::cout << p) ? *p : 0; - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:18]: (warning) Possible null pointer dereference if the default parameter value is used: p [nullPointerDefaultArg]\n" "[test.cpp:2:23]: (warning) Possible null pointer dereference if the default parameter value is used: p [nullPointerDefaultArg]\n", // duplicate @@ -4383,27 +4711,27 @@ class TestNullPointer : public TestFixture { check("void f(int *p = 0) {\n" " std::cout << (p ? *p : 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int *p = 0) {\n" " std::cout << p;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int *p = 0) {\n" " std::cout << (p && p[0] ? *p : 42);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void isEmpty(int *p = 0) {\n" " return p && *p;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void g(int *p = 0) {\n" " return !p || *p;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); @@ -4412,13 +4740,13 @@ class TestNullPointer : public TestFixture { check("void f(int *p = 0) {\n" " bar(p);\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int *p = 0) {\n" " printf(\"%p\", p);\n" " *p = 0;\n" - "}", dinit(CheckOptions, $.inconclusive = true)); + "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:3:6]: (warning) Possible null pointer dereference if the default parameter value is used: p [nullPointerDefaultArg]\n", errout_str()); // The init() function may or may not initialize p, but since the address @@ -4427,14 +4755,14 @@ class TestNullPointer : public TestFixture { check("void f(int *p = 0) {\n" " init(&p);\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void init(int* &g);\n" "void f(int *p = 0) {\n" " init(p);\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int *p = 0) {\n" @@ -4442,7 +4770,7 @@ class TestNullPointer : public TestFixture { " init(&p);\n" " }\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int *p = 0) {\n" @@ -4450,12 +4778,12 @@ class TestNullPointer : public TestFixture { " throw SomeException;\n" " }\n" " *p = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int x, int *p = 0) {\n" " int var1 = x ? *p : 5;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:21]: (warning) Possible null pointer dereference if the default parameter value is used: p [nullPointerDefaultArg]\n", errout_str()); check("void f(int* i = nullptr) { *i = 0; }\n" // #11567 @@ -4470,7 +4798,7 @@ class TestNullPointer : public TestFixture { " unsigned int j;\n" " for (j = 0; j < b[0].a->size; ++j) {\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -4494,33 +4822,33 @@ class TestNullPointer : public TestFixture { check("void foo(char *s) {\n" " char *p = s - 20;\n" "}\n" - "void bar() { foo(0); }"); + "void bar() { foo(0); }\n"); ASSERT_EQUALS("[test.cpp:2:15]: (error) Overflow in pointer arithmetic, NULL pointer is subtracted. [nullPointerArithmetic]\n", errout_str()); check("void foo(char *s) {\n" " if (!s) {}\n" " char *p = s - 20;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:7] -> [test.cpp:3:15]: (warning) Either the condition '!s' is redundant or there is overflow in pointer subtraction. [nullPointerArithmeticRedundantCheck]\n", errout_str()); check("void foo(char *s) {\n" " s -= 20;\n" "}\n" - "void bar() { foo(0); }"); + "void bar() { foo(0); }\n"); ASSERT_EQUALS("[test.cpp:2:5]: (error) Overflow in pointer arithmetic, NULL pointer is subtracted. [nullPointerArithmetic]\n", errout_str()); check("void foo(char *s) {\n" " if (!s) {}\n" " s -= 20;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:7] -> [test.cpp:3:5]: (warning) Either the condition '!s' is redundant or there is overflow in pointer subtraction. [nullPointerArithmeticRedundantCheck]\n", errout_str()); - check("int* f8() { int *x = NULL; return --x; }"); + check("int* f8() { int *x = NULL; return --x; }\n"); ASSERT_EQUALS("[test.cpp:1:35]: (error) Overflow in pointer arithmetic, NULL pointer is subtracted. [nullPointerArithmetic]\n", errout_str()); - check("int* f9() { int *x = NULL; return x--; }"); + check("int* f9() { int *x = NULL; return x--; }\n"); ASSERT_EQUALS("[test.cpp:1:36]: (error) Overflow in pointer arithmetic, NULL pointer is subtracted. [nullPointerArithmetic]\n", errout_str()); } @@ -4528,48 +4856,48 @@ class TestNullPointer : public TestFixture { check("void foo(char *s) {\n" " char * p = s + 20;\n" "}\n" - "void bar() { foo(0); }"); + "void bar() { foo(0); }\n"); ASSERT_EQUALS("[test.cpp:2:16]: (error) Pointer addition with NULL pointer. [nullPointerArithmetic]\n", errout_str()); check("void foo(char *s) {\n" " if (!s) {}\n" " char * p = s + 20;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:7] -> [test.cpp:3:16]: (warning) Either the condition '!s' is redundant or there is pointer arithmetic with NULL pointer. [nullPointerArithmeticRedundantCheck]\n", errout_str()); check("void foo(char *s) {\n" " char * p = 20 + s;\n" "}\n" - "void bar() { foo(0); }"); + "void bar() { foo(0); }\n"); ASSERT_EQUALS("[test.cpp:2:17]: (error) Pointer addition with NULL pointer. [nullPointerArithmetic]\n", errout_str()); check("void foo(char *s) {\n" " if (!s) {}\n" " char * p = 20 + s;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:7] -> [test.cpp:3:17]: (warning) Either the condition '!s' is redundant or there is pointer arithmetic with NULL pointer. [nullPointerArithmeticRedundantCheck]\n", errout_str()); check("void foo(char *s) {\n" " s += 20;\n" "}\n" - "void bar() { foo(0); }"); + "void bar() { foo(0); }\n"); ASSERT_EQUALS("[test.cpp:2:5]: (error) Pointer addition with NULL pointer. [nullPointerArithmetic]\n", errout_str()); check("void foo(char *s) {\n" " if (!s) {}\n" " s += 20;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:7] -> [test.cpp:3:5]: (warning) Either the condition '!s' is redundant or there is pointer arithmetic with NULL pointer. [nullPointerArithmeticRedundantCheck]\n", errout_str()); - check("int* f7() { int *x = NULL; return ++x; }"); + check("int* f7() { int *x = NULL; return ++x; }\n"); ASSERT_EQUALS("[test.cpp:1:35]: (error) Pointer addition with NULL pointer. [nullPointerArithmetic]\n", errout_str()); - check("int* f10() { int *x = NULL; return x++; }"); + check("int* f10() { int *x = NULL; return x++; }\n"); ASSERT_EQUALS("[test.cpp:1:37]: (error) Pointer addition with NULL pointer. [nullPointerArithmetic]\n", errout_str()); check("class foo {};\n" "const char* get() const { return 0; }\n" - "void f(foo x) { if (get()) x += get(); }"); + "void f(foo x) { if (get()) x += get(); }\n"); ASSERT_EQUALS("", errout_str()); check("typedef struct { uint8_t* buf, *buf_end; } S;\n" // #11117 @@ -4585,22 +4913,22 @@ class TestNullPointer : public TestFixture { } void isPointerDeRefFunctionDecl() { - check("const char** get() { return 0; }"); + check("const char** get() { return 0; }\n"); ASSERT_EQUALS("", errout_str()); } -#define ctu(code) ctu_(code, __FILE__, __LINE__) +#define ctu(...) ctu_(__FILE__, __LINE__, __VA_ARGS__) template - void ctu_(const char (&code)[size], const char* file, int line) { + void ctu_(const char* file, int line, const char (&code)[size]) { // Tokenize.. 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()) { @@ -4619,7 +4947,7 @@ class TestNullPointer : public TestFixture { "int main() {\n" " int *p = 0;\n" " f(p);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:10]: error: Null pointer dereference: fp [ctunullpointer]\n" "[test.cpp:5:12]: note: Assignment 'p=0', assigned value is 0\n" "[test.cpp:6:4]: note: Calling function f, 1st argument is null\n" @@ -4629,7 +4957,7 @@ class TestNullPointer : public TestFixture { "void call(int x, int *p) { x++; use(p); }\n" "int main() {\n" " call(4,0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:25]: error: Null pointer dereference: p [ctunullpointer]\n" "[test.cpp:4:7]: note: Calling function call, 2nd argument is null\n" "[test.cpp:2:33]: note: Calling function use, 1st argument is null\n" @@ -4643,7 +4971,7 @@ class TestNullPointer : public TestFixture { "\n" "void f() {\n" " dostuff(a, 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); ctu("void dostuff(int *x, int *y) {\n" @@ -4654,7 +4982,7 @@ class TestNullPointer : public TestFixture { "\n" "void f() {\n" " dostuff(a, 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // else @@ -4665,7 +4993,7 @@ class TestNullPointer : public TestFixture { "\n" "void f() {\n" " dostuff(0, 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // ?, &&, || @@ -4675,14 +5003,14 @@ class TestNullPointer : public TestFixture { "\n" "void f() {\n" " dostuff(0, 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); ctu("void g(int* x) { *x; }\n" "void f(int* x) {\n" " if (x)\n" " g(x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); ctu("size_t f(int* p) {\n" @@ -4730,6 +5058,15 @@ class TestNullPointer : public TestFixture { "[test.cpp:5:20]: note: Assignment 'f=fopen(notexist,t)', assigned value is 0\n" "[test.cpp:6:8]: note: Calling function foo, 1st argument is null\n" "[test.cpp:2:13]: note: Dereferencing argument f that is null\n", errout_str()); + + ctu("void g(std::optional& o) {\n" // #14728 + " *o = 1;\n" + "}\n" + "void f() {\n" + " std::optional x = 0;\n" + " g(x);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } }; diff --git a/test/testoptions.cpp b/test/testoptions.cpp index 7c72b2de336..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 @@ -35,9 +35,8 @@ class TestOptions : public TestFixture { TEST_CASE(which_test); TEST_CASE(which_test_method); TEST_CASE(no_test_method); - TEST_CASE(not_quiet); + TEST_CASE(defaults); TEST_CASE(quiet); - TEST_CASE(not_help); TEST_CASE(help); TEST_CASE(help_long); TEST_CASE(multiple_testcases); @@ -45,54 +44,65 @@ class TestOptions : public TestFixture { TEST_CASE(invalid_switches); TEST_CASE(summary); TEST_CASE(dry_run); + TEST_CASE(exclude_tests); + TEST_CASE(timer_results); } void which_test() const { const char* argv[] = {"./test_runner", "TestClass"}; options args(getArrayLength(argv), argv); - ASSERT(std::set {"TestClass"} == args.which_test()); + const std::map> expected{ + { "TestClass", {} } + }; + ASSERT(expected == args.which_tests()); + ASSERT(args.errors().empty()); } void which_test_method() const { const char* argv[] = {"./test_runner", "TestClass::TestMethod"}; options args(getArrayLength(argv), argv); - ASSERT(std::set {"TestClass::TestMethod"} == args.which_test()); + const std::map> expected{ + { "TestClass", {"TestMethod"} } + }; + ASSERT(expected == args.which_tests()); + ASSERT(args.errors().empty()); } void no_test_method() const { const char* argv[] = {"./test_runner"}; options args(getArrayLength(argv), argv); - ASSERT(std::set {""} == args.which_test()); + const std::map> expected{}; + ASSERT(expected == args.which_tests()); + ASSERT(args.errors().empty()); } - void not_quiet() const { - const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-v"}; + void defaults() const { + const char* argv[] = {"./test_runner", "TestClass::TestMethod"}; options args(getArrayLength(argv), argv); ASSERT_EQUALS(false, args.quiet()); + ASSERT_EQUALS(false, args.help()); + ASSERT_EQUALS(true, args.summary()); + ASSERT_EQUALS(false, args.dry_run()); + ASSERT_EQUALS(false, args.exclude_tests()); + ASSERT(args.errors().empty()); } - void quiet() const { const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-q"}; options args(getArrayLength(argv), argv); ASSERT_EQUALS(true, args.quiet()); + ASSERT(args.errors().empty()); } - void not_help() const { - const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-v"}; - options args(getArrayLength(argv), argv); - ASSERT_EQUALS(false, args.help()); - } - - void help() const { const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-h"}; options args(getArrayLength(argv), argv); ASSERT_EQUALS(true, args.help()); + ASSERT(args.errors().empty()); } @@ -100,40 +110,69 @@ class TestOptions : public TestFixture { const char* argv[] = {"./test_runner", "TestClass::TestMethod", "--help"}; options args(getArrayLength(argv), argv); ASSERT_EQUALS(true, args.help()); + ASSERT(args.errors().empty()); } void multiple_testcases() const { const char* argv[] = {"./test_runner", "TestClass::TestMethod", "TestClass::AnotherTestMethod"}; options args(getArrayLength(argv), argv); - std::set expected {"TestClass::TestMethod", "TestClass::AnotherTestMethod"}; - ASSERT(expected == args.which_test()); + const std::map> expected{ + { "TestClass", { "TestMethod", "AnotherTestMethod" } } + }; + ASSERT(expected == args.which_tests()); + ASSERT(args.errors().empty()); } void multiple_testcases_ignore_duplicates() const { const char* argv[] = {"./test_runner", "TestClass::TestMethod", "TestClass"}; options args(getArrayLength(argv), argv); - std::set expected {"TestClass"}; - ASSERT(expected == args.which_test()); + const std::map> expected{ + { "TestClass", {} } + }; + ASSERT(expected == args.which_tests()); + ASSERT(args.errors().empty()); } void invalid_switches() const { const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-a", "-v", "-q"}; options args(getArrayLength(argv), argv); - std::set expected {"TestClass::TestMethod"}; - ASSERT(expected == args.which_test()); + const std::map> expected { + { "TestClass", { "TestMethod" } } + }; + ASSERT(expected == args.which_tests()); ASSERT_EQUALS(true, args.quiet()); + ASSERT_EQUALS(2, args.errors().size()); + auto it = args.errors().cbegin(); + ASSERT_EQUALS("unknown option '-a'", *it); + ++it; + ASSERT_EQUALS("unknown option '-v'", *it); } void summary() const { const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-n"}; options args(getArrayLength(argv), argv); ASSERT_EQUALS(false, args.summary()); + ASSERT(args.errors().empty()); } void dry_run() const { const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-d"}; options args(getArrayLength(argv), argv); ASSERT_EQUALS(true, args.dry_run()); + ASSERT(args.errors().empty()); + } + + void exclude_tests() const { + const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-x"}; + options args(getArrayLength(argv), argv); + ASSERT_EQUALS(true, args.exclude_tests()); + ASSERT(args.errors().empty()); + } + + void timer_results() const { + const char* argv[] = {"./test_runner", "TestClass::TestMethod", "-t"}; + options args(getArrayLength(argv), argv); + ASSERT(!!args.timer_results()); } }; diff --git a/test/testother.cpp b/test/testother.cpp index 64e8ddf5960..3c301a3fc3c 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,14 +25,28 @@ #include "standards.h" #include +#include #include +static std::string unionZeroInitMessage(int lno, int cno, const std::string &varName, const std::string &largestMemberName) +{ + std::stringstream ss; + ss << "[test.cpp:" << lno << ":" << cno << "]: (portability) "; + ss << "Zero initializing union '" << varName << "' "; + ss << "does not guarantee its complete storage to be zero initialized as its largest member is not declared as the first member. "; + ss << "Consider making " << largestMemberName << " the first member or favor memset(). [UnionZeroInit]"; + ss << std::endl; + return ss.str(); +} + class TestOther : public TestFixture { public: TestOther() : TestFixture("TestOther") {} private: - /*const*/ Settings _settings = settingsBuilder().library("std.cfg").build(); + const Settings settings0 = settingsBuilder().library("std.cfg").build(); + /*const*/ Settings settings1 = settingsBuilder().library("std.cfg").severity(Severity::style).severity(Severity::warning).severity(Severity::portability).severity(Severity::performance).build(); + const Settings settings2 = settingsBuilder(settings1).certainty(Certainty::inconclusive).build(); void run() override { mNewTemplate = true; @@ -107,6 +121,9 @@ class TestOther : public TestFixture { TEST_CASE(varScope41); // #11845 TEST_CASE(varScope42); TEST_CASE(varScope43); + TEST_CASE(varScope44); + TEST_CASE(varScope45); + TEST_CASE(varScope46); TEST_CASE(oldStylePointerCast); TEST_CASE(intToPointerCast); @@ -181,8 +198,13 @@ class TestOther : public TestFixture { TEST_CASE(duplicateExpression16); // #10569 TEST_CASE(duplicateExpression17); // #12036 TEST_CASE(duplicateExpression18); + TEST_CASE(duplicateExpression19); + TEST_CASE(duplicateExpression20); + TEST_CASE(duplicateExpression21); + TEST_CASE(duplicateExpression22); TEST_CASE(duplicateExpressionLoop); TEST_CASE(duplicateValueTernary); + TEST_CASE(duplicateValueTernarySizeof); // #13773 TEST_CASE(duplicateExpressionTernary); // #6391 TEST_CASE(duplicateExpressionTemplate); // #6930 TEST_CASE(duplicateExpressionCompareWithZero); @@ -242,6 +264,9 @@ class TestOther : public TestFixture { TEST_CASE(raceAfterInterlockedDecrement); TEST_CASE(testUnusedLabel); + TEST_CASE(testUnusedLabelConfiguration); + TEST_CASE(testUnusedLabelSwitchConfiguration); + TEST_CASE(testUnusedLabelPremiumMisra); TEST_CASE(testEvaluationOrder); TEST_CASE(testEvaluationOrderSelfAssignment); @@ -281,6 +306,8 @@ class TestOther : public TestFixture { TEST_CASE(moveForRange); TEST_CASE(moveTernary); TEST_CASE(movePointerAlias); + TEST_CASE(moveOutparam); + TEST_CASE(moveTryEmplace); TEST_CASE(funcArgNamesDifferent); TEST_CASE(funcArgOrderDifferent); @@ -307,75 +334,71 @@ class TestOther : public TestFixture { TEST_CASE(knownConditionFloating); TEST_CASE(knownConditionPrefixed); + + TEST_CASE(unionZeroInitBasic); + TEST_CASE(unionZeroInitArrayMember); + TEST_CASE(unionZeroInitStructMember); + TEST_CASE(unionZeroInitUnknownType); + TEST_CASE(unionZeroInitBitfields); } + struct CheckOptions + { + bool cpp = true; + bool inconclusive = true; + bool verbose = false; + Settings* settings = nullptr; // TODO: split from this + }; + #define check(...) check_(__FILE__, __LINE__, __VA_ARGS__) template - void check_(const char* file, int line, const char (&code)[size], bool cpp = true, bool inconclusive = true, bool runSimpleChecks=true, bool verbose=false, Settings* settings = nullptr) { - if (!settings) { - settings = &_settings; + void check_(const char* file, int line, const char (&code)[size], const CheckOptions& opt = make_default_obj{}) { + // TODO: do not modify object passed into + Settings* settings; + if (!opt.settings) { + settings = &settings1; } - settings->severity.enable(Severity::style); - settings->severity.enable(Severity::warning); - settings->severity.enable(Severity::portability); - settings->severity.enable(Severity::performance); - settings->standards.c = Standards::CLatest; - settings->standards.cpp = Standards::CPPLatest; - settings->certainty.setEnabled(Certainty::inconclusive, inconclusive); - settings->verbose = verbose; + else { + settings = opt.settings; + } + settings->certainty.setEnabled(Certainty::inconclusive, opt.inconclusive); + settings->verbose = opt.verbose; // Tokenize.. - SimpleTokenizer tokenizer(*settings, *this, cpp); + SimpleTokenizer tokenizer(*settings, *this, opt.cpp); ASSERT_LOC(tokenizer.tokenize(code), file, line); - // Check.. - runChecks(tokenizer, this); - - (void)runSimpleChecks; // TODO Remove this - } - - template - void check_(const char* file, int line, const char (&code)[size], Settings *s) { - check_(file, line, code, true, true, true, false, s); + CheckOther check; + runChecks(check, tokenizer, *this); } struct CheckPOptions { - CheckPOptions() = default; bool cpp = true; }; #define checkP(...) checkP_(__FILE__, __LINE__, __VA_ARGS__) template void checkP_(const char* file, int line, const char (&code)[size], const CheckPOptions& options = make_default_obj()) { - Settings* settings = &_settings; - settings->severity.enable(Severity::style); - settings->severity.enable(Severity::warning); - settings->severity.enable(Severity::portability); - settings->severity.enable(Severity::performance); - settings->standards.c = Standards::CLatest; - settings->standards.cpp = Standards::CPPLatest; - settings->certainty.enable(Certainty::inconclusive); - - SimpleTokenizer2 tokenizer(*settings, *this, code, options.cpp ? "test.cpp" : "test.c"); + SimpleTokenizer2 tokenizer(settings2, *this, code, options.cpp ? "test.cpp" : "test.c"); // Tokenizer.. ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); - // Check.. - runChecks(tokenizer, this); + CheckOther check; + runChecks(check, tokenizer, *this); } template void checkInterlockedDecrement(const char (&code)[size]) { /*const*/ Settings settings = settingsBuilder().platform(Platform::Type::Win32A).build(); - check(code, true, false, true, false, &settings); + check(code, dinit(CheckOptions, $.inconclusive = false, $.settings = &settings)); } void emptyBrackets() { check("{\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -383,22 +406,22 @@ class TestOther : public TestFixture { void zeroDiv1() { // floating point division by zero => no error check("void foo() {\n" " cout << 1. / 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " cout << 42 / (double)0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " cout << 42 / (float)0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " cout << 42 / (int)0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:16]: (error) Division by zero. [zerodiv]\n", errout_str()); } @@ -411,34 +434,34 @@ class TestOther : public TestFixture { " sum += i;\n" " }\n" " cout<(fStepMain / fStepHelp);\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -569,7 +592,7 @@ class TestOther : public TestFixture { " << boost::format(\" %d :: %s <> %s\") % 0 % \"a\" % \"b\"\n" " << std::endl;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -577,13 +600,13 @@ class TestOther : public TestFixture { check("void f(int a) {\n" " int res = (a+2)/0;\n" " int res = (a*2)/0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:18]: (error) Division by zero. [zerodiv]\n" "[test.cpp:3:18]: (error) Division by zero. [zerodiv]\n", errout_str()); check("void f() {\n" " int res = (a+2)/0;\n" " int res = (a*2)/0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -591,7 +614,7 @@ class TestOther : public TestFixture { // #8141 check("intmax_t f() {\n" " return 1 / imaxabs(0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:12]: (error) Division by zero. [zerodiv]\n", errout_str()); } void zeroDiv13() { @@ -686,7 +709,7 @@ class TestOther : public TestFixture { "{\n" " uint16_t x = 0xFFFFU;\n" // UINT16_MAX=0xFFFF " return 42/(++x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:14]: (error) Division by zero. [zerodiv]\n", errout_str()); } @@ -713,25 +736,25 @@ class TestOther : public TestFixture { check("void f(unsigned int x) {\n" " int y = 17 / x;\n" " if (x > 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9] -> [test.cpp:2:14]: (warning) Either the condition 'x>0' is redundant or there is division by zero at line 2. [zerodivcond]\n", errout_str()); check("void f(unsigned int x) {\n" " int y = 17 / x;\n" " if (x >= 1) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9] -> [test.cpp:2:14]: (warning) Either the condition 'x>=1' is redundant or there is division by zero at line 2. [zerodivcond]\n", errout_str()); check("void f(int x) {\n" " int y = 17 / x;\n" " if (x == 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9] -> [test.cpp:2:14]: (warning) Either the condition 'x==0' is redundant or there is division by zero at line 2. [zerodivcond]\n", errout_str()); check("void f(unsigned int x) {\n" " int y = 17 / x;\n" " if (x != 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9] -> [test.cpp:2:14]: (warning) Either the condition 'x!=0' is redundant or there is division by zero at line 2. [zerodivcond]\n", errout_str()); // function call @@ -739,7 +762,7 @@ class TestOther : public TestFixture { "void f2(unsigned int y) {\n" " f1(123,y);\n" " if (y>0){}\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:4:10] -> [test.cpp:1:28]: (warning) Either the condition 'y>0' is redundant or there is division by zero at line 1. [zerodivcond]\n", errout_str()); @@ -750,7 +773,7 @@ class TestOther : public TestFixture { " int y = 17 / x;\n" " x = some+calculation;\n" " if (x != 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); { @@ -761,7 +784,7 @@ class TestOther : public TestFixture { " int y = 17 / x;\n" " do_something();\n" " if (x != 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // function is called. but don't care, variable is local @@ -771,7 +794,7 @@ class TestOther : public TestFixture { " int y = 17 / x;\n" " do_something();\n" " if (x != 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:9] -> [test.cpp:4:14]: (warning) Either the condition 'x!=0' is redundant or there is division by zero at line 4. [zerodivcond]\n", errout_str()); } @@ -779,14 +802,14 @@ class TestOther : public TestFixture { "void f(int x) {\n" " int y = 17 / x;\n" " do_something(x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int x;\n" "void f() {\n" " int y = 17 / x;\n" " while (y || x == 0) { x--; }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // ticket 5033 segmentation fault (valid code) in CheckOther::checkZeroDivisionOrUselessCondition @@ -795,33 +818,33 @@ class TestOther : public TestFixture { "double* p2= new double[1];\n" "double* p3= new double[1];\n" "double* pp[3] = {p1,p2,p3};\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #5105 - FP check("int f(int a, int b) {\n" " int r = a / b;\n" " if (func(b)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Unknown types for b and c --> do not warn check("int f(int d) {\n" " int r = (a?b:c) / d;\n" " if (d == 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f(int a) {\n" " int r = a ? 1 / a : 0;\n" " if (a == 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f(int a) {\n" " int r = (a == 0) ? 0 : 1 / a;\n" " if (a == 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int g();\n" @@ -831,7 +854,7 @@ class TestOther : public TestFixture { " else if (x > 0) {}\n" " else\n" " a = b / -x;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A {\n" @@ -878,35 +901,35 @@ class TestOther : public TestFixture { "{\n" " double x = 3.0 / 0.0 + 1.0;\n" " printf(\"%f\", x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:19]: (style) Using NaN/Inf in a computation. [nanInArithmeticExpression]\n", errout_str()); check("void f()\n" "{\n" " double x = 3.0 / 0.0 - 1.0;\n" " printf(\"%f\", x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:19]: (style) Using NaN/Inf in a computation. [nanInArithmeticExpression]\n", errout_str()); check("void f()\n" "{\n" " double x = 1.0 + 3.0 / 0.0;\n" " printf(\"%f\", x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:25]: (style) Using NaN/Inf in a computation. [nanInArithmeticExpression]\n", errout_str()); check("void f()\n" "{\n" " double x = 1.0 - 3.0 / 0.0;\n" " printf(\"%f\", x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:25]: (style) Using NaN/Inf in a computation. [nanInArithmeticExpression]\n", errout_str()); check("void f()\n" "{\n" " double x = 3.0 / 0.0;\n" " printf(\"%f\", x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -937,7 +960,7 @@ class TestOther : public TestFixture { " }\n" "\n" " return 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -947,7 +970,7 @@ class TestOther : public TestFixture { " Error e;\n" " e.SetValue(12);\n" " throw e;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -961,7 +984,7 @@ class TestOther : public TestFixture { " p = &i;\n" " }\n" " *p = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -969,7 +992,7 @@ class TestOther : public TestFixture { check("void foo()\n" "{\n" " int i;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -980,7 +1003,7 @@ class TestOther : public TestFixture { " if (x) {\n" " for ( ; i < 10; ++i) ;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9]: (style) The scope of the variable 'i' can be reduced. [variableScope]\n", errout_str()); check("void f(int x) {\n" @@ -988,7 +1011,7 @@ class TestOther : public TestFixture { " if (x) {\n" " for ( ; i < 10; ++i) ;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x)\n" @@ -998,7 +1021,7 @@ class TestOther : public TestFixture { " else {\n" " for ( ; i < 10; ++i) ;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9]: (style) The scope of the variable 'i' can be reduced. [variableScope]\n", errout_str()); } @@ -1012,7 +1035,7 @@ class TestOther : public TestFixture { " if (b) {\n" " c(i);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" // #5398 @@ -1021,14 +1044,14 @@ class TestOther : public TestFixture { " if (success) {\n" " foo(notReducable);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(Test &test) {\n" " int& x = test.getData();\n" " if (test.process())\n" " x = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f()\n" @@ -1043,7 +1066,7 @@ class TestOther : public TestFixture { " return 0;\n" " }\n" "}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int &x)\n" @@ -1054,7 +1077,7 @@ class TestOther : public TestFixture { " ++n;\n" " ++x;\n" " } while (x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1066,7 +1089,7 @@ class TestOther : public TestFixture { " if (x) {\n" " y++;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1077,7 +1100,7 @@ class TestOther : public TestFixture { " BOOST_FOREACH(int edge, edges) {\n" " edgeResistance = (edge+1) / 2.0;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) The scope of the variable 'edgeResistance' can be reduced. [variableScope]\n", errout_str()); } @@ -1085,6 +1108,7 @@ class TestOther : public TestFixture { // classes may have extra side effects check("class fred {\n" "public:\n" + " fred();\n" " void x();\n" "};\n" "void test(int a) {\n" @@ -1092,8 +1116,30 @@ class TestOther : public TestFixture { " if (a == 2) {\n" " f.x();\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); + + check("class fred {\n" // #2062 + "public:\n" + " void x();\n" + "};\n" + "void test(int a) {\n" + " fred f;\n" + " if (a == 2) {\n" + " f.x();\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6:10]: (style) The scope of the variable 'f' can be reduced. [variableScope]\n", errout_str()); + + check("struct S { int a, b; };\n" + "bool f() {\n" + " S s{};\n" + " {\n" + " bool b = s.a && a.b;\n" + " return b;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:7]: (style) The scope of the variable 's' can be reduced. [variableScope]\n", errout_str()); } void varScope10() { @@ -1103,7 +1149,7 @@ class TestOther : public TestFixture { " FOR {\n" " foo(x++);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1111,21 +1157,21 @@ class TestOther : public TestFixture { check("int f() {\n" " int x = 0;\n" " AB ab = { x, 0 };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f() {\n" " int x = 0;\n" " if (a == 0) { ++x; }\n" " AB ab = { x, 0 };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f() {\n" " int x = 0;\n" " if (a == 0) { ++x; }\n" " if (a == 1) { AB ab = { x, 0 }; }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1136,7 +1182,7 @@ class TestOther : public TestFixture { " if (x)\n" " foo(i);\n" " foo(j);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) The scope of the variable 'i' can be reduced. [variableScope]\n", errout_str()); check("void f(int x) {\n" @@ -1145,7 +1191,7 @@ class TestOther : public TestFixture { " if (x)\n" " j = i;\n" " foo(j);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" @@ -1153,7 +1199,7 @@ class TestOther : public TestFixture { " x++;\n" " if (x == 5)\n" " foo(b);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" @@ -1161,7 +1207,7 @@ class TestOther : public TestFixture { " x++;\n" " if (x == 5)\n" " foo(b);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1172,7 +1218,7 @@ class TestOther : public TestFixture { " forever {\n" " if (i++ == 42) { break; }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1183,7 +1229,7 @@ class TestOther : public TestFixture { " if(a) {\n" " for ( ; i < 10; ++i) ;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1195,7 +1241,7 @@ class TestOther : public TestFixture { " else if(b);\n" " else if(c);\n" " else;\n" - "}", true, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); } @@ -1205,7 +1251,7 @@ class TestOther : public TestFixture { " while((++a) < 56) {\n" " foo();\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -1213,7 +1259,7 @@ class TestOther : public TestFixture { " do {\n" " foo();\n" " } while((++a) < 56);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -1222,7 +1268,7 @@ class TestOther : public TestFixture { " a = 64;\n" " foo(a);\n" " } while((++a) < 56);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -1231,7 +1277,7 @@ class TestOther : public TestFixture { " a = 64;\n" " foo(a);\n" " } while(z());\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) The scope of the variable 'a' can be reduced. [variableScope]\n", errout_str()); } @@ -1242,7 +1288,7 @@ class TestOther : public TestFixture { " x = stuff(x);\n" " morestuff(x);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) The scope of the variable 'x' can be reduced. [variableScope]\n", errout_str()); check("void f() {\n" @@ -1252,7 +1298,7 @@ class TestOther : public TestFixture { " morestuff(x);\n" " }\n" " if (b) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) The scope of the variable 'x' can be reduced. [variableScope]\n", errout_str()); } @@ -1272,7 +1318,7 @@ class TestOther : public TestFixture { " x = foo();\n" " do_something(x);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) The scope of the variable 'x' can be reduced. [variableScope]\n", errout_str()); check("void f() {\n" @@ -1291,7 +1337,7 @@ class TestOther : public TestFixture { " x = foo();\n" " do_something(x);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -1306,7 +1352,7 @@ class TestOther : public TestFixture { " default:\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) The scope of the variable 'x' can be reduced. [variableScope]\n", errout_str()); check("void f() {\n" @@ -1323,7 +1369,7 @@ class TestOther : public TestFixture { " do_something(x);\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1333,7 +1379,7 @@ class TestOther : public TestFixture { " int b = a;\n" " if (b > 32) b = x;\n" " return b;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1342,7 +1388,7 @@ class TestOther : public TestFixture { " int test_value = 3;\n" " int test_array[1][1] = { { test_value } };\n" " return sizeof(test_array);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1355,7 +1401,7 @@ class TestOther : public TestFixture { " ++p;\n" " ++i;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // try to avoid an obvious false negative after applying the fix for the example above: check("void foo() {\n" @@ -1368,7 +1414,7 @@ class TestOther : public TestFixture { " ++p;\n" " ++i;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) The scope of the variable 'p' can be reduced. [variableScope]\n", errout_str()); } @@ -1378,7 +1424,7 @@ class TestOther : public TestFixture { " Test myTest([&](size_t aX){\n" " std::cout << myCounter += aX << std::endl;\n" " });\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1388,7 +1434,7 @@ class TestOther : public TestFixture { " if (cond) {\n" " r.dostuff();\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) The scope of the variable 'r' can be reduced. [variableScope]\n", errout_str()); check("void f(Foo x) {\n" @@ -1396,7 +1442,7 @@ class TestOther : public TestFixture { " if (cond) {\n" " foo.dostuff();\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1407,7 +1453,7 @@ class TestOther : public TestFixture { " currtime = time(&dummy);\n" " if (currtime > t) {}\n" " }\n" - "}", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("[test.c:2:12]: (style) The scope of the variable 'currtime' can be reduced. [variableScope]\n", errout_str()); } @@ -1419,7 +1465,7 @@ class TestOther : public TestFixture { " if (cond2) { dostuff(key); }\n" " }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1429,7 +1475,7 @@ class TestOther : public TestFixture { "#ifdef X\n" "#endif\n" " if (id == ABC) { return x; }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkP("void f() {\n" @@ -1437,7 +1483,7 @@ class TestOther : public TestFixture { "#endif\n" " int x = 0;\n" " if (id == ABC) { return x; }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:7]: (style) The scope of the variable 'x' can be reduced. [variableScope]\n", errout_str()); } @@ -1460,7 +1506,7 @@ class TestOther : public TestFixture { " s.i = 0;\n" " g(e, s);\n" " }\n" - "}\n", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("[test.c:4:12]: (style) The scope of the variable 'e' can be reduced. [variableScope]\n" "[test.c:5:14]: (style) The scope of the variable 's' can be reduced. [variableScope]\n", errout_str()); @@ -1471,7 +1517,7 @@ class TestOther : public TestFixture { " s = \"abc\";\n" " g(s);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:17]: (style) The scope of the variable 's' can be reduced. [variableScope]\n", errout_str()); check("auto foo(std::vector& vec, bool flag) {\n" @@ -1484,7 +1530,7 @@ class TestOther : public TestFixture { " iter = dummy.begin();\n" " }\n" " return *iter;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:28]: (style) Parameter 'vec' can be declared as reference to const [constParameterReference]\n", errout_str()); check("auto& foo(std::vector& vec, bool flag) {\n" @@ -1497,7 +1543,7 @@ class TestOther : public TestFixture { " iter = dummy.begin();\n" " }\n" " return *iter;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -1719,7 +1765,7 @@ class TestOther : public TestFixture { " else{\n" " for( i = 0U; i < 5U; i++ ) {}\n" " }\n" - "}\n", true, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:2:14]: (style) The scope of the variable 'i' can be reduced. [variableScope]\n", errout_str()); } @@ -1734,7 +1780,7 @@ class TestOther : public TestFixture { " for( i = 0U; i < 5U; i++ ) {}\n" " }\n" " }\n" - "}\n", true, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:2:14]: (style) The scope of the variable 'i' can be reduced. [variableScope]\n", errout_str()); } @@ -1750,7 +1796,7 @@ class TestOther : public TestFixture { void varScope39() { check("struct S {\n" // #12405 - " void f(const std::string&) const;\n" + " void f(const std::string& s) const;\n" " const int* g(std::string&) const;\n" "};\n" "void h(int);\n" @@ -1906,6 +1952,100 @@ class TestOther : public TestFixture { ASSERT_EQUALS("[test.cpp:3:12]: (style) The scope of the variable 'x' can be reduced. [variableScope]\n", errout_str()); } + void varScope44() { // #14496 + check("char* f() {\n" + " char* p = nullptr;\n" + " {\n" + " p = strdup(\"abc\");\n" + " if (p) {\n" + " return p;\n" + " }\n" + " }\n" + " return nullptr;\n" + "}\n" + "char* g() {\n" + " char* q = NULL;\n" + " {\n" + " q = strdup(\"abc\");\n" + " if (q) {\n" + " return q;\n" + " }\n" + " }\n" + " return nullptr;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:11]: (style) The scope of the variable 'p' can be reduced. [variableScope]\n" + "[test.cpp:12:11]: (style) The scope of the variable 'q' can be reduced. [variableScope]\n", + errout_str()); + } + + void varScope45() { + check("void g(int x, int y) {\n" // #14497 + " int a = x, b = y;\n" + " if (a) {}\n" + " else {\n" + " if (b) {}\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:16]: (style) The scope of the variable 'b' can be reduced. [variableScope]\n", errout_str()); + } + + void varScope46() { + check("void f() {\n" // #7091 + " int y1;\n" + " for (int i = 0; i < 3; ++i) {\n" + " for(int j = 0; j < 3; ++j) {\n" + " y1 = 2 * 1;\n" + " y1 += 1;\n" + " }\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:9]: (style) The scope of the variable 'y1' can be reduced. [variableScope]\n", + errout_str()); + + check("bool f() {\n" + "bool b = false;\n" + "do {\n" + " switch (g()) {\n" + " case 0:\n" + " b = true;\n" + " break;\n" + " case 1:\n" + " return b;\n" + " break;\n" + " default:\n" + " break;\n" + " }\n" + "}\n" + "while (true);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" + " int y1 = 0;\n" + " for (int i = 0; i < 3; ++i) {\n" + " for(int j = 0; j < 3; ++j) {\n" + " y1 = y1 + 1;\n" + " dostuff(y1);\n" + " }\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f(int& r) {\n" // #14566 + " int i = 0;\n" + " while (g()) {\n" + " {\n" + " if (g()) {\n" + " i = 0;" + " std::swap(i, r);\n" + " }\n" + " }\n" + " }\n" + " use(i);" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + #define checkOldStylePointerCast(...) checkOldStylePointerCast_(__FILE__, __LINE__, __VA_ARGS__) template void checkOldStylePointerCast_(const char* file, int line, const char (&code)[size], Standards::cppstd_t std = Standards::CPPLatest) { @@ -1916,7 +2056,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(); } @@ -1927,7 +2067,7 @@ class TestOther : public TestFixture { "void foo(Base* base)\n" "{\n" " Derived * d = (Derived *) base;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:19]: (warning) Potentially invalid type conversion in old-style C cast, clarify/fix with C++ cast [dangerousTypeCast]\n", errout_str()); checkOldStylePointerCast("class Base{};\n" @@ -1935,13 +2075,13 @@ class TestOther : public TestFixture { "void foo(Derived* derived)\n" "{\n" " Base * b = (Base *) derived;\n" // <- cast from derived to base is safe => cstyleCast - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:16]: (style) C-style pointer casting [cstyleCast]\n", errout_str()); checkOldStylePointerCast("void foo(Base* base)\n" "{\n" " Derived * d = (Derived *) base;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:19]: (warning) Potentially invalid type conversion in old-style C cast, clarify/fix with C++ cast [dangerousTypeCast]\n", errout_str()); checkOldStylePointerCast("class Base{};\n" @@ -1949,7 +2089,7 @@ class TestOther : public TestFixture { "void foo(Base* base)\n" "{\n" " Derived * d = (const Derived *) base;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:19]: (warning) Potentially invalid type conversion in old-style C cast, clarify/fix with C++ cast [dangerousTypeCast]\n", errout_str()); checkOldStylePointerCast("class Base{};\n" @@ -1957,7 +2097,7 @@ class TestOther : public TestFixture { "void foo()\n" "{\n" " Derived * d = (const Derived *) ( new Base() );\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:19]: (warning) Potentially invalid type conversion in old-style C cast, clarify/fix with C++ cast [dangerousTypeCast]\n", errout_str()); checkOldStylePointerCast("class Base{};\n" @@ -1965,102 +2105,102 @@ class TestOther : public TestFixture { "void foo()\n" "{\n" " Derived * d = (const Derived *) new Base();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:19]: (warning) Potentially invalid type conversion in old-style C cast, clarify/fix with C++ cast [dangerousTypeCast]\n", errout_str()); checkOldStylePointerCast("class Base{};\n" "void foo()\n" "{\n" " Base * b = (Base *) new short[10];\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:16]: (warning) Potentially invalid type conversion in old-style C cast, clarify/fix with C++ cast [dangerousTypeCast]\n", errout_str()); checkOldStylePointerCast("class Base;\n" "void foo()\n" "{\n" " Base * b = (volatile Base *) derived;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:16]: (style) C-style pointer casting [cstyleCast]\n", errout_str()); checkOldStylePointerCast("class Base;\n" "void foo()\n" "{\n" " Base * b = (volatile Base * const) derived;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:16]: (style) C-style pointer casting [cstyleCast]\n", errout_str()); checkOldStylePointerCast("class Base;\n" "void foo()\n" "{\n" " Base * b = (const volatile Base *) derived;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:16]: (style) C-style pointer casting [cstyleCast]\n", errout_str()); checkOldStylePointerCast("class Base;\n" "void foo()\n" "{\n" " Base * b = (const volatile Base * const) derived;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:16]: (style) C-style pointer casting [cstyleCast]\n", errout_str()); checkOldStylePointerCast("class Base;\n" "void foo()\n" "{\n" " Base * b = (const Base *) ( new Derived() );\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:16]: (style) C-style pointer casting [cstyleCast]\n", errout_str()); checkOldStylePointerCast("class Base;\n" "void foo()\n" "{\n" " Base * b = (const Base *) new Derived();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:16]: (style) C-style pointer casting [cstyleCast]\n", errout_str()); checkOldStylePointerCast("class Base;\n" "void foo()\n" "{\n" " Base * b = (const Base *) new short[10];\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:16]: (warning) Potentially invalid type conversion in old-style C cast, clarify/fix with C++ cast [dangerousTypeCast]\n", errout_str()); checkOldStylePointerCast("class B;\n" "class A\n" "{\n" " virtual void abc(B *) const = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkOldStylePointerCast("class B;\n" "class A\n" "{\n" " virtual void abc(const B *) const = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #3630 checkOldStylePointerCast("class SomeType{};\n" "class X : public Base {\n" " X() : Base((SomeType*)7) {}\n" // <- intToPointerCast - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOldStylePointerCast("class SomeType{};\n" "class X : public Base {\n" " X() : Base((SomeType*)0x7000) {}\n" // <- it's common in embedded code to cast address - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); checkOldStylePointerCast("class SomeType;\n" "class X : public Base {\n" " X() : Base((SomeType*)var) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:3:16]: (style) C-style pointer casting [cstyleCast]\n", errout_str()); checkOldStylePointerCast("class SomeType;\n" "class X : public Base {\n" " X() : Base((SomeType*)0) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); // #5560 @@ -2070,7 +2210,7 @@ class TestOther : public TestFixture { "{ virtual G* createGui(S*, C*) const = 0; };\n" "\n" "class MS : public M\n" - "{ virtual void addController(C*) override {} };", Standards::CPP03); + "{ virtual void addController(C*) override {} };\n", Standards::CPP03); ASSERT_EQUALS("", errout_str()); // #6164 @@ -2079,7 +2219,7 @@ class TestOther : public TestFixture { "void testCC() {\n" " std::vector v;\n" " v.push_back((Base*)new Derived);\n" - "}"); + "}\n"); // FIXME write a dangerousTypeCast warning instead ASSERT_EQUALS("[test.cpp:5:15]: (style) C-style pointer casting [cstyleCast]\n", errout_str()); @@ -2202,40 +2342,49 @@ 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(); } void intToPointerCast() { // #3630 - checkIntToPointerCast("uint8_t* ptr = (uint8_t*)7;"); + checkIntToPointerCast("uint8_t* ptr = (uint8_t*)7;\n"); ASSERT_EQUALS("[test.cpp:1:16]: (portability) Casting non-zero decimal integer literal to pointer. [intToPointerCast]\n", errout_str()); - checkIntToPointerCast("void* ptr = (void*)7;"); + checkIntToPointerCast("void* ptr = (void*)7;\n"); ASSERT_EQUALS("[test.cpp:1:13]: (portability) Casting non-zero decimal integer literal to pointer. [intToPointerCast]\n", errout_str()); - checkIntToPointerCast("uint8_t* ptr = (uint8_t*)0;"); + checkIntToPointerCast("uint8_t* ptr = (uint8_t*)0;\n"); ASSERT_EQUALS("", errout_str()); - checkIntToPointerCast("uint8_t* ptr = (uint8_t*)0x7000;"); // <- it's common in embedded code to cast address + checkIntToPointerCast("uint8_t* ptr = (uint8_t*)0x7000;\n"); // <- it's common in embedded code to cast address ASSERT_EQUALS("", errout_str()); checkIntToPointerCast("struct S { int i; };\n" // #13886, don't crash - "int f() { return sizeof(((struct S*)0)->i); }"); + "int f() { return sizeof(((struct S*)0)->i); }\n"); ASSERT_EQUALS("", errout_str()); + + checkIntToPointerCast("auto p = (int*)0b10;\n"); // #14180 + ASSERT_EQUALS("[test.cpp:1:10]: (portability) Casting non-zero binary integer literal to pointer. [intToPointerCast]\n", errout_str()); } + struct CheckInvalidPointerCastOptions + { + bool portability = true; + bool inconclusive = false; + }; + #define checkInvalidPointerCast(...) checkInvalidPointerCast_(__FILE__, __LINE__, __VA_ARGS__) template - void checkInvalidPointerCast_(const char* file, int line, const char (&code)[size], bool portability = true, bool inconclusive = false) { - /*const*/ Settings settings = settingsBuilder().severity(Severity::warning).severity(Severity::portability, portability).certainty(Certainty::inconclusive, inconclusive).build(); + void checkInvalidPointerCast_(const char* file, int line, const char (&code)[size], const CheckInvalidPointerCastOptions& opt = make_default_obj{}) { + /*const*/ Settings settings = settingsBuilder().severity(Severity::warning).severity(Severity::portability, opt.portability).certainty(Certainty::inconclusive, opt.inconclusive).build(); settings.platform.defaultSign = 's'; // Tokenize.. SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); - CheckOther checkOtherCpp(&tokenizer, &settings, this); + CheckOtherImpl checkOtherCpp(&tokenizer, settings, *this); checkOtherCpp.invalidPointerCast(); } @@ -2245,19 +2394,19 @@ class TestOther : public TestFixture { " float *f = new float[10];\n" " delete [] (double*)f;\n" " delete [] (long double const*)(new float[10]);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:15]: (portability) Casting between float * and double * which have an incompatible binary data representation. [invalidPointerCast]\n" "[test.cpp:4:15]: (portability) Casting between float * and const long double * which have an incompatible binary data representation. [invalidPointerCast]\n", errout_str()); checkInvalidPointerCast("void test(const float* f) {\n" " double *d = (double*)f;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:17]: (portability) Casting between const float * and double * which have an incompatible binary data representation. [invalidPointerCast]\n", errout_str()); checkInvalidPointerCast("void test(double* d1) {\n" " long double *ld = (long double*)d1;\n" " double *d2 = (double*)ld;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:23]: (portability) Casting between double * and long double * which have an incompatible binary data representation. [invalidPointerCast]\n" "[test.cpp:3:18]: (portability) Casting between long double * and double * which have an incompatible binary data representation. [invalidPointerCast]\n", errout_str()); @@ -2265,148 +2414,148 @@ class TestOther : public TestFixture { " long double *d = (long double*)(i);\n" " double *d = (double*)(i);\n" " float *f = reinterpret_cast(i);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:22]: (portability) Casting between signed int * and long double * which have an incompatible binary data representation. [invalidPointerCast]\n" "[test.cpp:3:17]: (portability) Casting between signed int * and double * which have an incompatible binary data representation. [invalidPointerCast]\n" "[test.cpp:4:16]: (portability) Casting between signed int * and float * which have an incompatible binary data representation. [invalidPointerCast]\n", errout_str()); checkInvalidPointerCast("float* test(unsigned int* i) {\n" " return (float*)i;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:12]: (portability) Casting between unsigned int * and float * which have an incompatible binary data representation. [invalidPointerCast]\n", errout_str()); checkInvalidPointerCast("float* test(unsigned int* i) {\n" " return (float*)i[0];\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkInvalidPointerCast("float* test(double& d) {\n" " return (float*)&d;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:12]: (portability) Casting between double * and float * which have an incompatible binary data representation. [invalidPointerCast]\n", errout_str()); checkInvalidPointerCast("void test(float* data) {\n" " f.write((char*)data,sizeof(float));\n" - "}", true, false); + "}\n"); ASSERT_EQUALS("", errout_str()); checkInvalidPointerCast("void test(float* data) {\n" " f.write((char*)data,sizeof(float));\n" - "}", true, true); // #3639 - ASSERT_EQUALS("[test.cpp:2:13]: (portability, inconclusive) Casting from float * to signed char * is not portable due to different binary data representations on different platforms. [invalidPointerCast]\n", errout_str()); + "}\n", dinit(CheckInvalidPointerCastOptions, $.inconclusive = true)); // #3639 + ASSERT_EQUALS("[test.cpp:2:13]: (portability, inconclusive) Casting from float * to char * is not portable due to different binary data representations on different platforms. [invalidPointerCast]\n", errout_str()); checkInvalidPointerCast("long long* test(float* f) {\n" " return (long long*)f;\n" - "}", false); + "}\n", dinit(CheckInvalidPointerCastOptions, $.portability = false)); ASSERT_EQUALS("", errout_str()); checkInvalidPointerCast("long long* test(float* f, char* c) {\n" " foo((long long*)f);\n" " return reinterpret_cast(c);\n" - "}", true); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (portability) Casting from float * to signed long long * is not portable due to different binary data representations on different platforms. [invalidPointerCast]\n", errout_str()); - checkInvalidPointerCast("Q_DECLARE_METATYPE(int*)"); // #4135 - don't crash + checkInvalidPointerCast("Q_DECLARE_METATYPE(int*)\n"); // #4135 - don't crash } void passedByValue() { - check("void f(const std::string str) {}"); + check("void f(const std::string str) {}\n"); ASSERT_EQUALS("[test.cpp:1:26]: (performance) Function parameter 'str' should be passed by const reference. [passedByValue]\n", errout_str()); - check("void f(std::unique_ptr ptr) {}"); + check("void f(std::unique_ptr ptr) {}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(const std::shared_ptr ptr) {}"); + check("void f(const std::shared_ptr ptr) {}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(const std::function ptr) {}"); + check("void f(const std::function ptr) {}\n"); ASSERT_EQUALS("", errout_str()); { - check("void f(const std::pair x) {}"); + check("void f(const std::pair x) {}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(const std::pair x) {}"); + check("void f(const std::pair x) {}\n"); TODO_ASSERT_EQUALS("error", "", errout_str()); } - check("void f(const std::string::size_type x) {}"); + check("void f(const std::string::size_type x) {}\n"); ASSERT_EQUALS("", errout_str()); - check("class Foo;\nvoid f(const Foo foo) {}"); // Unknown class + check("class Foo;\nvoid f(const Foo foo) {}\n"); // Unknown class ASSERT_EQUALS("[test.cpp:2:18]: (performance, inconclusive) Function parameter 'foo' should be passed by const reference. [passedByValue]\n", errout_str()); - check("class Foo { std::vector v; };\nvoid f(const Foo foo) {}"); // Large class (STL member) + check("class Foo { std::vector v; };\nvoid f(const Foo foo) {}\n"); // Large class (STL member) ASSERT_EQUALS("[test.cpp:2:18]: (performance) Function parameter 'foo' should be passed by const reference. [passedByValue]\n", errout_str()); - check("class Foo { int i; };\nvoid f(const Foo foo) {}"); // Small class + check("class Foo { int i; };\nvoid f(const Foo foo) {}\n"); // Small class ASSERT_EQUALS("", errout_str()); - check("class Foo { int i[6]; };\nvoid f(const Foo foo) {}"); // Large class (array) + check("class Foo { int i[6]; };\nvoid f(const Foo foo) {}\n"); // Large class (array) ASSERT_EQUALS("[test.cpp:2:18]: (performance) Function parameter 'foo' should be passed by const reference. [passedByValue]\n", errout_str()); - check("class Foo { std::string* s; };\nvoid f(const Foo foo) {}"); // Small class (pointer) + check("class Foo { std::string* s; };\nvoid f(const Foo foo) {}\n"); // Small class (pointer) ASSERT_EQUALS("", errout_str()); - check("class Foo { static std::string s; };\nvoid f(const Foo foo) {}"); // Small class (static member) + check("class Foo { static std::string s; };\nvoid f(const Foo foo) {}\n"); // Small class (static member) ASSERT_EQUALS("", errout_str()); - check("class X { std::string s; }; class Foo : X { };\nvoid f(const Foo foo) {}"); // Large class (inherited) + check("class X { std::string s; }; class Foo : X { };\nvoid f(const Foo foo) {}\n"); // Large class (inherited) ASSERT_EQUALS("[test.cpp:2:18]: (performance) Function parameter 'foo' should be passed by const reference. [passedByValue]\n", errout_str()); - check("class X { std::string s; }; class Foo { X x; };\nvoid f(const Foo foo) {}"); // Large class (inherited) + check("class X { std::string s; }; class Foo { X x; };\nvoid f(const Foo foo) {}\n"); // Large class (inherited) ASSERT_EQUALS("[test.cpp:2:18]: (performance) Function parameter 'foo' should be passed by const reference. [passedByValue]\n", errout_str()); - check("void f(const std::string &str) {}"); + check("void f(const std::string &str) {}\n"); ASSERT_EQUALS("", errout_str()); // The idiomatic way of passing a std::string_view is by value - check("void f(const std::string_view str) {}"); + check("void f(const std::string_view str) {}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(std::string_view str) {}"); + check("void f(std::string_view str) {}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(const std::string_view &str) {}"); + check("void f(const std::string_view &str) {}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(const std::vector v) {}"); + check("void f(const std::vector v) {}\n"); ASSERT_EQUALS("[test.cpp:1:31]: (performance) Function parameter 'v' should be passed by const reference. [passedByValue]\n", errout_str()); - check("void f(const std::vector v) {}"); + check("void f(const std::vector v) {}\n"); ASSERT_EQUALS("[test.cpp:1:39]: (performance) Function parameter 'v' should be passed by const reference. [passedByValue]\n", errout_str()); - check("void f(const std::vector::size_type s) {}"); + check("void f(const std::vector::size_type s) {}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(const std::vector &v) {}"); + check("void f(const std::vector &v) {}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(const std::map &v) {}"); + check("void f(const std::map &v) {}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(const std::map v) {}"); + check("void f(const std::map v) {}\n"); ASSERT_EQUALS("[test.cpp:1:32]: (performance) Function parameter 'v' should be passed by const reference. [passedByValue]\n", errout_str()); - check("void f(const std::map v) {}"); + check("void f(const std::map v) {}\n"); ASSERT_EQUALS("[test.cpp:1:48]: (performance) Function parameter 'v' should be passed by const reference. [passedByValue]\n", errout_str()); - check("void f(const std::map v) {}"); + check("void f(const std::map v) {}\n"); ASSERT_EQUALS("[test.cpp:1:40]: (performance) Function parameter 'v' should be passed by const reference. [passedByValue]\n", errout_str()); - check("void f(const std::map v) {}"); + check("void f(const std::map v) {}\n"); ASSERT_EQUALS("[test.cpp:1:40]: (performance) Function parameter 'v' should be passed by const reference. [passedByValue]\n", errout_str()); - check("void f(const std::streamoff pos) {}"); + check("void f(const std::streamoff pos) {}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(std::initializer_list i) {}"); + check("void f(std::initializer_list i) {}\n"); ASSERT_EQUALS("", errout_str()); // #5824 - check("void log(const std::string& file, int line, const std::string& function, const std::string str, ...) {}"); + check("void log(const std::string& file, int line, const std::string& function, const std::string str, ...) {}\n"); ASSERT_EQUALS("", errout_str()); // #5534 @@ -2415,12 +2564,12 @@ class TestOther : public TestFixture { "class Plane {\n" " vec Refract(vec &vec) const;\n" " bool IntersectLinePlane(const vec &planeNormal);\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class X {\n" " virtual void func(const std::string str) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:2:41]: (performance) Function parameter 'str' should be passed by const reference. [passedByValue]\n", errout_str()); check("enum X;\n" @@ -2437,7 +2586,7 @@ class TestOther : public TestFixture { ASSERT_EQUALS("", errout_str()); check("enum X;\n" - "enum X { a, b, c };" + "enum X { a, b, c };\n" "void foo(X x4){}\n"); ASSERT_EQUALS("", errout_str()); @@ -2524,7 +2673,7 @@ class TestOther : public TestFixture { "}\n"); ASSERT_EQUALS("[test.cpp:1:42]: (performance) Function parameter 't' should be passed by const reference. [passedByValue]\n", errout_str()); - /*const*/ Settings settings0 = settingsBuilder(_settings).platform(Platform::Type::Unix64).build(); + /*const*/ Settings settingsUnix64 = settingsBuilder(settings0).platform(Platform::Type::Unix64).build(); check("struct S {\n" // #12138 " union {\n" " int a = 0;\n" @@ -2541,7 +2690,7 @@ class TestOther : public TestFixture { "};\n" "void f(S s) {\n" " if (s.x > s.y) {}\n" - "}\n", /*cpp*/ true, /*inconclusive*/ true, /*runSimpleChecks*/ true, /*verbose*/ false, &settings0); + "}\n", dinit(CheckOptions, $.settings = &settingsUnix64)); ASSERT_EQUALS("", errout_str()); check("struct S { std::list l; };\n" // #12147 @@ -2581,93 +2730,103 @@ class TestOther : public TestFixture { check("void f(const std::array a[]) {}\n"); // #13524 ASSERT_EQUALS("", errout_str()); - /*const*/ Settings settings1 = settingsBuilder().platform(Platform::Type::Win64).build(); + check("struct S {\n" // #10733 + " std::vector v;\n" + " using F = void (*)();\n" + " void func(F f);\n" + "};\n" + "void S::func(S::F f) {}\n"); + ASSERT_EQUALS("", errout_str()); + + /*const*/ Settings settingsWin64 = settingsBuilder().platform(Platform::Type::Win64).build(); check("using ui64 = unsigned __int64;\n" "ui64 Test(ui64 one, ui64 two) { return one + two; }\n", - /*cpp*/ true, /*inconclusive*/ true, /*runSimpleChecks*/ true, /*verbose*/ false, &settings1); + dinit(CheckOptions, $.settings = &settingsWin64)); ASSERT_EQUALS("", errout_str()); } void passedByValue_nonConst() { - check("void f(std::string str) {}"); + check("void f(std::string str) {}\n"); ASSERT_EQUALS("[test.cpp:1:20]: (performance) Function parameter 'str' should be passed by const reference. [passedByValue]\n", errout_str()); check("void f(std::string str) {\n" " return str + x;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:20]: (performance) Function parameter 'str' should be passed by const reference. [passedByValue]\n", errout_str()); check("void f(std::string str) {\n" " std::cout << str;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:20]: (performance) Function parameter 'str' should be passed by const reference. [passedByValue]\n", errout_str()); check("void f(std::string str) {\n" " std::cin >> str;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(std::string str) {\n" " std::string s2 = str;\n" - "}"); - ASSERT_EQUALS("[test.cpp:1:20]: (performance) Function parameter 'str' should be passed by const reference. [passedByValue]\n", errout_str()); + "}\n"); + ASSERT_EQUALS("[test.cpp:2:17]: (performance, inconclusive) Use const reference for 's2' to avoid unnecessary data copying. [redundantCopyLocalConst]\n" + "[test.cpp:1:20]: (performance) Function parameter 'str' should be passed by const reference. [passedByValue]\n", + errout_str()); check("void f(std::string str) {\n" " std::string& s2 = str;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:20]: (performance) Function parameter 'str' should be passed by const reference. [passedByValue]\n" "[test.cpp:2:18]: (style) Variable 's2' can be declared as reference to const [constVariableReference]\n", errout_str()); check("void f(std::string str) {\n" " const std::string& s2 = str;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:20]: (performance) Function parameter 'str' should be passed by const reference. [passedByValue]\n", errout_str()); check("void f(std::string str) {\n" " str = \"\";\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(std::string str) {\n" " foo(str);\n" // It could be that foo takes str as non-const-reference - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(const std::string& str);\n" "void f(std::string str) {\n" " foo(str);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:20]: (performance) Function parameter 'str' should be passed by const reference. [passedByValue]\n", errout_str()); check("void foo(std::string str);\n" "void f(std::string str) {\n" " foo(str);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:20]: (performance) Function parameter 'str' should be passed by const reference. [passedByValue]\n", errout_str()); check("void foo(std::string& str);\n" "void f(std::string str) {\n" " foo(str);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(std::string* str);\n" "void f(std::string str) {\n" " foo(&str);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int& i1, const std::string& str, int& i2);\n" "void f(std::string str) {\n" " foo((a+b)*c, str, x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:20]: (performance) Function parameter 'str' should be passed by const reference. [passedByValue]\n", errout_str()); check("std::string f(std::string str) {\n" " str += x;\n" " return str;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class X {\n" @@ -2676,7 +2835,7 @@ class TestOther : public TestFixture { "};\n" "Y f(X x) {\n" " x.func();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:7]: (performance) Function parameter 'x' should be passed by const reference. [passedByValue]\n", errout_str()); check("class X {\n" @@ -2684,17 +2843,17 @@ class TestOther : public TestFixture { "};\n" "Y f(X x) {\n" " x.func();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class X {\n" " void func(std::string str) {}\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:2:27]: (performance) Function parameter 'str' should be passed by const reference. [passedByValue]\n", errout_str()); check("class X {\n" " virtual void func(std::string str) {}\n" // Do not warn about virtual functions, if 'str' is not declared as const - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("class X {\n" @@ -2704,7 +2863,7 @@ class TestOther : public TestFixture { " char b;\n" "};\n" "void f(Y y) {\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:10]: (performance) Function parameter 'y' should be passed by const reference. [passedByValue]\n", errout_str()); check("class X {\n" @@ -2717,7 +2876,7 @@ class TestOther : public TestFixture { " char c;\n" "};\n" "void f(X x, Y y) {\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:10:15]: (performance) Function parameter 'y' should be passed by const reference. [passedByValue]\n", errout_str()); { @@ -2726,14 +2885,14 @@ class TestOther : public TestFixture { " uint64_t a;\n" " uint64_t b;\n" "};\n" - "void f(X x) {}"; + "void f(X x) {}\n"; - /*const*/ Settings s32 = settingsBuilder(_settings).platform(Platform::Type::Unix32).build(); - check(code, &s32); + /*const*/ Settings s32 = settingsBuilder(settings1).platform(Platform::Type::Unix32).build(); + check(code, dinit(CheckOptions, $.settings = &s32)); ASSERT_EQUALS("[test.cpp:5:10]: (performance) Function parameter 'x' should be passed by const reference. [passedByValue]\n", errout_str()); - /*const*/ Settings s64 = settingsBuilder(_settings).platform(Platform::Type::Unix64).build(); - check(code, &s64); + /*const*/ Settings s64 = settingsBuilder(settings1).platform(Platform::Type::Unix64).build(); + check(code, dinit(CheckOptions, $.settings = &s64)); ASSERT_EQUALS("", errout_str()); } @@ -2741,27 +2900,30 @@ class TestOther : public TestFixture { "\n" "void foo(Buffer& buffer) {\n" " getWriter()->operator<<(buffer);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void passedByValue_externC() { - check("struct X { int a[5]; }; void f(X v) { }"); + check("struct X { int a[5]; }; void f(X v) { }\n"); ASSERT_EQUALS("[test.cpp:1:34]: (performance) Function parameter 'v' should be passed by const reference. [passedByValue]\n", errout_str()); - check("extern \"C\" { struct X { int a[5]; }; void f(X v) { } }"); + check("extern \"C\" { struct X { int a[5]; }; void f(X v) { } }\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct X { int a[5]; }; extern \"C\" void f(X v) { }\n"); ASSERT_EQUALS("", errout_str()); - check("struct X { int a[5]; }; extern \"C\" void f(X v) { }"); + check("struct X { int a[5]; }; void f(const X v);\n"); ASSERT_EQUALS("", errout_str()); - check("struct X { int a[5]; }; void f(const X v);"); + check("struct X { int a[5]; }; void f(const X v) { (void) v; }\n"); ASSERT_EQUALS("[test.cpp:1:40]: (performance) Function parameter 'v' should be passed by const reference. [passedByValue]\n", errout_str()); - check("extern \"C\" { struct X { int a[5]; }; void f(const X v); }"); + check("extern \"C\" { struct X { int a[5]; }; void f(const X v); }\n"); ASSERT_EQUALS("", errout_str()); - check("struct X { int a[5]; }; extern \"C\" void f(const X v) { }"); + check("struct X { int a[5]; }; extern \"C\" void f(const X v) { }\n"); ASSERT_EQUALS("", errout_str()); } @@ -2769,140 +2931,140 @@ class TestOther : public TestFixture { check("int f(std::vector x) {\n" " int& i = x[0];\n" " return i;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:24]: (performance) Function parameter 'x' should be passed by const reference. [passedByValue]\n" "[test.cpp:2:10]: (style) Variable 'i' can be declared as reference to const [constVariableReference]\n", errout_str()); check("int f(std::vector& x) {\n" " return x[0];\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:25]: (style) Parameter 'x' can be declared as reference to const [constParameterReference]\n", errout_str()); check("int f(std::vector x) {\n" " const int& i = x[0];\n" " return i;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:24]: (performance) Function parameter 'x' should be passed by const reference. [passedByValue]\n", errout_str()); check("int f(std::vector x) {\n" " static int& i = x[0];\n" " return i;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:24]: (performance) Function parameter 'x' should be passed by const reference. [passedByValue]\n", errout_str()); check("int f(std::vector x) {\n" " int& i = x[0];\n" " i++;\n" " return i;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int& f(std::vector& x) {\n" " x.push_back(1);\n" " int& i = x[0];\n" " return i;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f(const std::vector& x) {\n" " return x[0];\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int& f(std::vector& x) {\n" " return x[0];\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("const int& f(std::vector& x) {\n" " return x[0];\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:32]: (style) Parameter 'x' can be declared as reference to const [constParameterReference]\n", errout_str()); check("int f(std::vector& x) {\n" " x[0]++;\n" " return x[0];\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A { int a; };\n" "A f(std::vector& x) {\n" " x[0].a = 1;\n" " return x[0];\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A { int a(); };\n" "A f(std::vector& x) {\n" " x[0].a();\n" " return x[0];\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int g(int& x);\n" "int f(std::vector& x) {\n" " g(x[0]);\n" " return x[0];\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("template\n" "T f(T& x) {\n" " return x[0];\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("template\n" "T f(T&& x) {\n" " return x[0];\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("template\n" "T f(T& x) {\n" " return x[0];\n" "}\n" - "void h() { std::vector v; h(v); }"); + "void h() { std::vector v; h(v); }\n"); ASSERT_EQUALS("", errout_str()); check("int f(int& x) {\n" " return std::move(x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(std::ostream& os) {\n" " os << \"Hello\";\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void g(int*);\n" "void f(int& x) {\n" " g(&x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A { A(int*); };\n" "A f(int& x) {\n" " return A(&x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A { A(int*); };\n" "A f(int& x) {\n" " return A{&x};\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int& x, int& y) {\n" " y++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:13]: (style) Parameter 'x' can be declared as reference to const [constParameterReference]\n", errout_str()); check("struct A {\n" " explicit A(int& y) : x(&y) {}\n" " int * x = nullptr;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct A {\n" @@ -2910,7 +3072,7 @@ class TestOther : public TestFixture { " void swap(A& a) {\n" " v.swap(a.v);\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct A {\n" @@ -2921,24 +3083,24 @@ class TestOther : public TestFixture { "};\n" "void g(A& a) {\n" " a.f();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(std::vector& v) {\n" " for(auto&& x:v)\n" " x = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(std::vector& v) {\n" " for(auto x:v)\n" " x = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:26]: (style) Parameter 'v' can be declared as reference to const [constParameterReference]\n", errout_str()); check("void f(std::vector& v) {\n" " for(auto& x:v) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (style) Variable 'x' can be declared as reference to const [constVariableReference]\n", errout_str()); @@ -2959,32 +3121,32 @@ class TestOther : public TestFixture { check("void f(std::vector& v) {\n" " for(const auto& x:v) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:26]: (style) Parameter 'v' can be declared as reference to const [constParameterReference]\n", errout_str()); check("void f(int& i) {\n" " int& j = i;\n" " j++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(std::vector& v) {\n" " int& i = v[0];\n" " i++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(std::map >& m, unsigned int i) {\n" " std::map& members = m[i];\n" " members.clear();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A {\n" " int& x;\n" " A(int& y) : x(y)\n" " {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct A {\n" @@ -2993,14 +3155,14 @@ class TestOther : public TestFixture { "struct B : A {\n" " B(int& x) : A(x)\n" " {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("void f(bool b, int& x, int& y) {\n" " auto& z = x;\n" " auto& w = b ? y : z;\n" " w = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct S {\n" @@ -3008,7 +3170,7 @@ class TestOther : public TestFixture { "};\n" "int& f(S& s) {\n" " return s.i;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int* f(std::list& x, unsigned int y) {\n" @@ -3017,7 +3179,7 @@ class TestOther : public TestFixture { " return &m;\n" " }\n" " return nullptr;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int& f(std::list& x, int& y) {\n" @@ -3026,7 +3188,7 @@ class TestOther : public TestFixture { " return m;\n" " }\n" " return y;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("bool from_string(int& t, const std::string& s) {\n" @@ -3070,7 +3232,7 @@ class TestOther : public TestFixture { check("struct T { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Parameter 'x' can be declared as reference to const [constParameterReference]\n", errout_str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" @@ -3078,86 +3240,86 @@ class TestOther : public TestFixture { " const T& z = x;\n" // Make sure we find all assignments " T& y = x;\n" " y.mutate();\n" // to avoid warnings that y can be const - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " const U& y = x\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Parameter 'x' can be declared as reference to const [constParameterReference]\n", errout_str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " U& y = x;\n" " y.mutate();\n" // to avoid warnings that y can be const - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " my::type& y = x;\n" // we don't know if y is const or not " y.mutate();\n" // to avoid warnings that y can be const - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " const U& y = static_cast(x);\n" " y.mutate();\n" // to avoid warnings that y can be const - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Parameter 'x' can be declared as reference to const [constParameterReference]\n", errout_str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " U& y = static_cast(x);\n" " y.mutate();\n" // to avoid warnings that y can be const - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " const U& y = dynamic_cast(x)\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Parameter 'x' can be declared as reference to const [constParameterReference]\n", errout_str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " const U& y = dynamic_cast(x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Parameter 'x' can be declared as reference to const [constParameterReference]\n", errout_str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " const U& y = dynamic_cast(x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Parameter 'x' can be declared as reference to const [constParameterReference]\n", errout_str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " U& y = dynamic_cast(x);\n" " y.mutate();\n" // to avoid warnings that y can be const - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " const U& y = dynamic_cast(x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Parameter 'x' can be declared as reference to const [constParameterReference]\n", errout_str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " U& y = dynamic_cast(x);\n" " y.mutate();\n" // to avoid warnings that y can be const - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " U* y = dynamic_cast(&x);\n" " y->mutate();\n" // to avoid warnings that y can be const - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct T : public U { void dostuff() const {}};\n" @@ -3165,49 +3327,49 @@ class TestOther : public TestFixture { " x.dostuff();\n" " const U * y = dynamic_cast(&x);\n" " y->mutate();\n" // to avoid warnings that y can be const - "}"); + "}\n"); TODO_ASSERT_EQUALS("can be const", errout_str(), ""); //Currently taking the address is treated as a non-const operation when it should depend on what we do with it check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " U const * y = dynamic_cast(&x);\n" " y->mutate();\n" // to avoid warnings that y can be const - "}"); + "}\n"); TODO_ASSERT_EQUALS("can be const", errout_str(), ""); //Currently taking the address is treated as a non-const operation when it should depend on what we do with it check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " const U const * const * const * const y = dynamic_cast(&x);\n" " y->mutate();\n" // to avoid warnings that y can be const - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " const U const * const * const * const y = dynamic_cast(&x);\n" " y->mutate();\n" // to avoid warnings that y can be const - "}"); + "}\n"); TODO_ASSERT_EQUALS("can be const", errout_str(), ""); //Currently taking the address is treated as a non-const operation when it should depend on what we do with it check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " const U const * const * * const y = dynamic_cast(&x);\n" " y->mutate();\n" // to avoid warnings that y can be const - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " my::fancy const * const * const y = dynamic_cast const * const * const>(&x);\n" " y->mutate();\n" // to avoid warnings that y can be const - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " const U& y = (const U&)(x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:18]: (warning) Potentially invalid type conversion in old-style C cast, clarify/fix with C++ cast [dangerousTypeCast]\n" "[test.cpp:2:11]: (style) Parameter 'x' can be declared as reference to const [constParameterReference]\n", errout_str()); @@ -3216,13 +3378,13 @@ class TestOther : public TestFixture { " x.dostuff();\n" " U& y = (U&)(x);\n" " y.mutate();\n" // to avoid warnings that y can be const - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:12]: (warning) Potentially invalid type conversion in old-style C cast, clarify/fix with C++ cast [dangerousTypeCast]\n", errout_str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " const U& y = (typename const U&)(x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:18]: (warning) Potentially invalid type conversion in old-style C cast, clarify/fix with C++ cast [dangerousTypeCast]\n" "[test.cpp:2:11]: (style) Parameter 'x' can be declared as reference to const [constParameterReference]\n", errout_str()); @@ -3231,14 +3393,14 @@ class TestOther : public TestFixture { " x.dostuff();\n" " U& y = (typename U&)(x);\n" " y.mutate();\n" // to avoid warnings that y can be const - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:12]: (warning) Potentially invalid type conversion in old-style C cast, clarify/fix with C++ cast [dangerousTypeCast]\n", errout_str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " U* y = (U*)(&x);\n" " y->mutate();\n" // to avoid warnings that y can be const - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:12]: (warning) Potentially invalid type conversion in old-style C cast, clarify/fix with C++ cast [dangerousTypeCast]\n", errout_str()); check("struct C { void f() const; };\n" // #9875 - crash @@ -3246,7 +3408,7 @@ class TestOther : public TestFixture { "void foo(C& x) {\n" " x.f();\n" " foo( static_cast(0) );\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:13]: (style) Parameter 'x' can be declared as reference to const [constParameterReference]\n", errout_str()); check("class a {\n" @@ -3300,6 +3462,10 @@ class TestOther : public TestFixture { "};\n"); ASSERT_EQUALS("", errout_str()); + // #14136 + check("void f(int& x) { (void)x; }\n"); + ASSERT_EQUALS("", errout_str()); + check("void e();\n" "void g(void);\n" "void h(void);\n" @@ -3450,7 +3616,7 @@ class TestOther : public TestFixture { "void bh(const std::list &ak, const std::list &al);\n" "void ah();\n" "void an();\n" - "void h();"); + "void h();\n"); ASSERT_EQUALS("[test.cpp:131:12]: (style) Variable 'tm' can be declared as pointer to const [constVariablePointer]\n" "[test.cpp:136:19]: (style) Variable 'af' can be declared as pointer to const [constVariablePointer]\n" "[test.cpp:137:12]: (style) Variable 'ag' can be declared as pointer to const [constVariablePointer]\n", @@ -3465,7 +3631,7 @@ class TestOther : public TestFixture { "class D\n" "{\n" "public:\n" - " explicit D(int&);\n" + " explicit D(int& i);\n" "\n" "private:\n" " C c;\n" @@ -3474,7 +3640,7 @@ class TestOther : public TestFixture { "D::D(int& i)\n" " : c(i)\n" "{\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class C\n" @@ -3486,7 +3652,7 @@ class TestOther : public TestFixture { "class D\n" "{\n" "public:\n" - " explicit D(int&) noexcept;\n" + " explicit D(int& i) noexcept;\n" "\n" "private:\n" " C c;\n" @@ -3494,7 +3660,7 @@ class TestOther : public TestFixture { "\n" "D::D(int& i) noexcept\n" " : c(i)\n" - "{}"); + "{}\n"); ASSERT_EQUALS("", errout_str()); check("class C\n" @@ -3506,7 +3672,7 @@ class TestOther : public TestFixture { "class D\n" "{\n" "public:\n" - " explicit D(int&);\n" + " explicit D(int& i);\n" "\n" "private:\n" " C c;\n" @@ -3515,7 +3681,7 @@ class TestOther : public TestFixture { "D::D(int& i)\n" " : c(i)\n" "{\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:16]: (style) Parameter 'i' can be declared as reference to const\n", "", errout_str()); check("class C\n" @@ -3527,7 +3693,7 @@ class TestOther : public TestFixture { "class D\n" "{\n" "public:\n" - " explicit D(int&);\n" + " explicit D(int& i);\n" "\n" "private:\n" " C c;\n" @@ -3536,7 +3702,7 @@ class TestOther : public TestFixture { "D::D(int& i)\n" " : c(i)\n" "{\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:16]: (style) Parameter 'i' can be declared as reference to const\n", "", errout_str()); check("class C\n" @@ -3548,7 +3714,7 @@ class TestOther : public TestFixture { "class D\n" "{\n" "public:\n" - " explicit D(int&);\n" + " explicit D(int& i);\n" "\n" "private:\n" " C c;\n" @@ -3557,13 +3723,13 @@ class TestOther : public TestFixture { "D::D(int& i)\n" " : c(0, i)\n" "{\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:16]: (style) Parameter 'i' can be declared as reference to const\n", "", errout_str()); check("void f(std::map> &map) {\n" // #10266 " for (auto &[slave, panels] : map)\n" " panels.erase(it);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct S { void f(); int i; };\n" @@ -3749,7 +3915,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" @@ -3912,13 +4080,97 @@ class TestOther : public TestFixture { "[test.cpp:10:25]: (style) Parameter 'v' can be declared as reference to const [constParameterReference]\n", errout_str()); - check("void push(V& v) { v.push_back({ .x = 1 }); }"); // #14010 + check("void push(V& v) { v.push_back({ .x = 1 }); }\n"); // #14010 + ASSERT_EQUALS("", errout_str()); + + check("size_t* f(std::array& a) { return reinterpret_cast(a.data()); }\n"); // #14074 + ASSERT_EQUALS("", errout_str()); + + check("struct S { int i; };\n" // #14231 + "void* f(S& s, int& v) {\n" + " v = s.i;\n" + " return (void*)&s;\n" + "}\n"); // don't crash + ASSERT_EQUALS("", errout_str()); + + check("struct S { int i; };\n" // #14251 + "struct T { std::optional s; };\n" + "void f(T& t) {\n" + " t.s->i = 0;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct B {};\n" // #13877 + "struct D : B { int i; };\n" + "void f(B& b) {\n" + " static_cast(b).i = 0;\n" + "}\n" + "void g(B& b) {\n" + " std::cin >> static_cast(b).i;\n" + "}\n" + "int h(B& b) {\n" + " return static_cast(b).i;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:9:10]: (style) Parameter 'b' can be declared as reference to const [constParameterReference]\n", errout_str()); + + check("void f(int *p) {\n" // #14409 + " int*& pp{ p };\n" + " if (*pp) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("class C {\n" + "public:\n" + " explicit C(const std::string s);\n" + "private:\n" + " std::string _s;\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f(int& r) {\n" // #9761 + " o1 = r;\n" + "}\n" + "boost::optional o2;\n" + "void g(int& r) {\n" + " o2 = r;\n" + "}\n" + "struct T {\n" + " int* p;\n" + " T& operator=(int& rhs) { p = &rhs; return *this; }\n" + "};\n" + "void h(T& t, int& r) {\n" + " t = r;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f(std::optional& o) {\n" + " *o = 1;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("int f() {\n" + " int x = 0;\n" + " int& r(x);\n" + " r = x;\n" + " return r;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct Item { int state; };\n" + "void foo(std::vector &items) {\n" + " for (auto &item : items) {\n" + " switch (auto &s = item.state) {\n" + " case 0: s = 1; break;\n" + " default: break;\n" + " }\n" + " }\n" + "}\n"); ASSERT_EQUALS("", errout_str()); } void constParameterCallback() { check("int callback(std::vector& x) { return x[0]; }\n" - "void f() { dostuff(callback); }"); + "void f() { dostuff(callback); }\n"); ASSERT_EQUALS("[test.cpp:2:20] -> [test.cpp:1:32]: (style) Parameter 'x' can be declared as reference to const. However it seems that 'callback' is a callback function, if 'x' is declared with const you might also need to cast function pointer(s). [constParameterCallback]\n", errout_str()); // #9906 @@ -3936,13 +4188,13 @@ class TestOther : public TestFixture { "\n" "void EventEngine::signalEvent(ev::sig& signal, int revents) {\n" " switch (signal.signum) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:10:48] -> [test.cpp:13:40]: (style) Parameter 'signal' can be declared as reference to const. However it seems that 'signalEvent' is a callback function, if 'signal' is declared with const you might also need to cast function pointer(s). [constParameterCallback]\n", errout_str()); check("void f(int* p) {}\n" // 12843 "void g(std::map&m) {\n" " m[&f] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:1:13]: (style) Parameter 'p' can be declared as pointer to const. " "However it seems that 'f' is a callback function, if 'p' is declared with const you might also need to cast function pointer(s). [constParameterCallback]\n", errout_str()); @@ -3955,52 +4207,62 @@ class TestOther : public TestFixture { " S s2{ cb };\n" "}\n"); ASSERT_EQUALS("[test.cpp:6:11] -> [test.cpp:2:21]: (performance) Function parameter 's' should be passed by const reference. However it seems that 'cb' is a callback function. [passedByValueCallback]\n", errout_str()); + + check("struct S {\n" // #14696 + " explicit S(std::string s = {}) {}\n" + "};\n" + "struct T {\n" + " explicit T(std::string* s = {}) {}\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:28]: (performance) Function parameter 's' should be passed by const reference. [passedByValue]\n" + "[test.cpp:5:29]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n", + errout_str()); } void constPointer() { - check("void foo(int *p) { return *p; }"); + check("void foo(int *p) { return *p; }\n"); ASSERT_EQUALS("[test.cpp:1:15]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); - check("void foo(int *p) { x = *p; }"); + check("void foo(int *p) { x = *p; }\n"); ASSERT_EQUALS("[test.cpp:1:15]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); - check("void foo(int *p) { int &ref = *p; ref = 12; }"); + check("void foo(int *p) { int &ref = *p; ref = 12; }\n"); ASSERT_EQUALS("", errout_str()); - check("void foo(int *p) { x = *p + 10; }"); + check("void foo(int *p) { x = *p + 10; }\n"); ASSERT_EQUALS("[test.cpp:1:15]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); - check("void foo(int *p) { return p[10]; }"); + check("void foo(int *p) { return p[10]; }\n"); ASSERT_EQUALS("[test.cpp:1:15]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); - check("void foo(int *p) { int &ref = p[0]; ref = 12; }"); + check("void foo(int *p) { int &ref = p[0]; ref = 12; }\n"); ASSERT_EQUALS("", errout_str()); - check("void foo(int *p) { x[*p] = 12; }"); + check("void foo(int *p) { x[*p] = 12; }\n"); ASSERT_EQUALS("[test.cpp:1:15]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); - check("void foo(int *p) { if (p) {} }"); + check("void foo(int *p) { if (p) {} }\n"); ASSERT_EQUALS("[test.cpp:1:15]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); - check("void foo(int *p) { if (p || x) {} }"); + check("void foo(int *p) { if (p || x) {} }\n"); ASSERT_EQUALS("[test.cpp:1:15]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); - check("void foo(int *p) { if (p == 0) {} }"); + check("void foo(int *p) { if (p == 0) {} }\n"); ASSERT_EQUALS("[test.cpp:1:15]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); - check("void foo(int *p) { if (!p) {} }"); + check("void foo(int *p) { if (!p) {} }\n"); ASSERT_EQUALS("[test.cpp:1:15]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); - check("void foo(int *p) { if (*p > 123) {} }"); + check("void foo(int *p) { if (*p > 123) {} }\n"); ASSERT_EQUALS("[test.cpp:1:15]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); - check("void foo(int *p) { return *p + 1; }"); + check("void foo(int *p) { return *p + 1; }\n"); ASSERT_EQUALS("[test.cpp:1:15]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); - check("void foo(int *p) { return *p > 1; }"); + check("void foo(int *p) { return *p > 1; }\n"); ASSERT_EQUALS("[test.cpp:1:15]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); - check("void foo(const int* c) { if (c == 0) {}; }"); + check("void foo(const int* c) { if (c == 0) {}; }\n"); ASSERT_EQUALS("", errout_str()); check("struct a { void b(); };\n" @@ -4033,59 +4295,59 @@ class TestOther : public TestFixture { " int& i = (*x)[0];\n" " i++;\n" " return i;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A { int a; };\n" "A f(std::vector* x) {\n" " x->front().a = 1;\n" " return x->front();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(std::vector* v) {\n" " for(auto&& x:*v)\n" " x = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A {\n" " int* x;\n" " A(int* y) : x(y)\n" " {}\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("void f(bool b, int* x, int* y) {\n" " int* z = x;\n" " int* w = b ? y : z;\n" " *w = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(bool b, int* x, int* y) {\n" " int& z = *x;\n" " int& w = b ? *y : z;\n" " w = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class Base { virtual void dostuff(int *p) = 0; };\n" // #10397 - "class Derived: public Base { int x; void dostuff(int *p) override { x = *p; } };"); + "class Derived: public Base { int x; void dostuff(int *p) override { x = *p; } };\n"); ASSERT_EQUALS("", errout_str()); check("struct Data { char buf[128]; };\n" // #10483 "void encrypt(Data& data) {\n" " const char a[] = \"asfasd\";\n" " memcpy(data.buf, &a, sizeof(a));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #10547 check("void foo(std::istream &istr) {\n" " unsigned char x[2];\n" " istr >> x[0];\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #10744 @@ -4497,6 +4759,195 @@ class TestOther : public TestFixture { ASSERT_EQUALS("[test.cpp:2:18]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:5:18]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("struct T;\n" + "void use(const T*);\n" + "void f(T* tok0) {\n" + " T *tok1 = tok0;\n" + " const T *tok2 = tok1;\n" + " use(tok2);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:8]: (style) Variable 'tok1' can be declared as pointer to const [constVariablePointer]\n", + errout_str()); + + check("struct S { S* next; };\n" // #14119 + "void f(S* s) {\n" + " for (S* p = s->next; p != nullptr; p = p->next) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:13]: (style) Variable 'p' can be declared as pointer to const [constVariablePointer]\n", + errout_str()); + + check("void f(int* p) {\n" + " for (int* q = p; q;)\n" + " break;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:15]: (style) Variable 'q' can be declared as pointer to const [constVariablePointer]\n", + errout_str()); + + check("void g(const int*);\n" // #14148 + "void f() {\n" + " int a[] = {1, 2, 3};\n" + " for (int* p = a; *p != 3; p++) {\n" + " g(p);\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:15]: (style) Variable 'p' can be declared as pointer to const [constVariablePointer]\n", + errout_str()); + + check("uintptr_t f(int* p) {\n" + " return (uintptr_t)p;\n" + "}\n" + "uintptr_t g(int* p) {\n" + " return static_cast(p);\n" + "}\n" + "U h(int* p) {\n" + " return (U)p;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:1:18]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n" + "[test.cpp:4:18]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", + errout_str()); + + check("using fp_t = int (*)(int*);\n" // #14510 + "fp_t g_fp;\n" + "struct S { fp_t m_fp; };\n" + "void g(fp_t);\n" + "S f(S* s) {\n" + " g_fp = [](int* p) { return *p; };\n" + " s->m_fp = [](int* p) { return *p; };\n" + " g([](int* p) { return *p; });\n" + " auto x = [](int* p) { return *p; };\n" + " g(x);\n" + " return { [](int* p) { return *p; } };\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" + " int i = 0;\n" + " auto x = [&]() { int* p = &i; if (*p) {} };\n" + " x();\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:27]: (style) Variable 'p' can be declared as pointer to const [constVariablePointer]\n", errout_str()); + + check("int f() {\n" + " int i = 0;\n" + " return [](int* p) { return *p; }(&i);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:20]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("struct S {\n" // #14571 + " char* c;\n" + "};\n" + "struct T {\n" + " S s;\n" + "};\n" + "void f(std::string* p, T& t) {\n" + " S& r = t.s;\n" + " strcpy(r.c, p->c_str());\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:7:21]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("struct S {\n" // #14559 + " int gc() const;\n" + " int gnc();\n" + "};\n" + "int f1(S* s) {\n" + " return h(s ? s->gc() : 1);\n" + "}\n" + "int f2(S* s) {\n" + " return h(s ? s->gnc() : 1);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:11]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("using IntPtr = int *;\n" + "int* foo(IntPtr bar) {\n" + " return bar = 0;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct S { int x; };\n" // #14700 + "int f(S* s) {\n" + " return s->x ? 1 : 0;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:10]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("struct S { int a[1][1]; };\n" // #14714 + "int f(S* s) {\n" + " return s->a[0][0] ? 1 : 0;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:10]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("int f(int *p, int *q) {\n" // #14748 + " return p ? *p : *q;\n" + "}\n" + "void g(int *p, int *q) {\n" + " int& r = p ? *p : *q;\n" + " r = 0;\n" + "}\n" + "void h(int *p, int *q) {\n" + " i(p ? *p : *q);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:1:12]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n" + "[test.cpp:1:20]: (style) Parameter 'q' can be declared as pointer to const [constParameterPointer]\n", + errout_str()); + + 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" + "}\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() { @@ -4568,7 +5019,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:11] -> [test.cpp:9:11]: (style) Variable 'y' is reassigned a value before the old one has been used. 'break;' missing? [redundantAssignInSwitch]\n", errout_str()); check("void foo()\n" @@ -4584,7 +5035,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:11] -> [test.cpp:11:11]: (style) Variable 'y' is reassigned a value before the old one has been used. 'break;' missing? [redundantAssignInSwitch]\n", errout_str()); check("void foo()\n" @@ -4601,7 +5052,7 @@ class TestOther : public TestFixture { " }\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" @@ -4619,7 +5070,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" @@ -4634,7 +5085,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" @@ -4649,7 +5100,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" @@ -4666,7 +5117,7 @@ class TestOther : public TestFixture { " }\n" " bar(y);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" @@ -4683,7 +5134,7 @@ class TestOther : public TestFixture { " }\n" " bar(y);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" @@ -4698,7 +5149,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" @@ -4713,7 +5164,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:11] -> [test.cpp:10:11]: (style) Variable 'y' is reassigned a value before the old one has been used. 'break;' missing? [redundantAssignInSwitch]\n", errout_str()); check("void bar() {}\n" // bar isn't noreturn @@ -4729,7 +5180,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:11] -> [test.cpp:11:11]: (style) Variable 'y' is reassigned a value before the old one has been used. 'break;' missing? [redundantAssignInSwitch]\n", errout_str()); check("void foo(int a) {\n" @@ -4741,7 +5192,7 @@ class TestOther : public TestFixture { " case 3:\n" " strcpy(str, \"b'\");\n" " }\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); TODO_ASSERT_EQUALS("[test.cpp:6] -> [test.cpp:8]: (style) Buffer 'str' is being written before its old content has been used. 'break;' missing?\n", "", errout_str()); @@ -4755,7 +5206,7 @@ class TestOther : public TestFixture { " case 3:\n" " strncpy(str, \"b'\");\n" " }\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:6] -> [test.cpp:8]: (style) Buffer 'str' is being written before its old content has been used. 'break;' missing?\n", "", errout_str()); @@ -4772,7 +5223,7 @@ class TestOther : public TestFixture { " strcpy(str, \"b'\");\n" " z++;\n" " }\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); TODO_ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:10]: (style) Buffer 'str' is being written before its old content has been used. 'break;' missing?\n", "", errout_str()); @@ -4788,7 +5239,7 @@ class TestOther : public TestFixture { " strcpy(str, \"b'\");\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int a) {\n" @@ -4801,7 +5252,7 @@ class TestOther : public TestFixture { " case 3:\n" " strcpy(str, \"b'\");\n" " }\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); // Ticket #5158 "segmentation fault (valid code)" @@ -4815,7 +5266,7 @@ class TestOther : public TestFixture { "} deflate_state;\n" "void f(deflate_state *s) {\n" " s->dyn_ltree[0].fc.freq++;\n" - "}\n", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); // Ticket #6132 "crash: daca: kvirc CheckOther::checkRedundantAssignment()" @@ -4825,7 +5276,7 @@ class TestOther : public TestFixture { "} else {\n" "KviKvsScript :: run ( m_szCompletionCallback , out ? out : ( g_pApp . activeConsole ( ) ) , & vParams ) ;\n" "}\n" - "}\n", true, false, true); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -4834,7 +5285,7 @@ class TestOther : public TestFixture { " case 1: x = 3; goto a;\n" " case 1: x = 6; goto a;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -4850,7 +5301,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:9] -> [test.cpp:9:11]: (style) Variable 'y' is reassigned a value before the old one has been used. 'break;' missing? [redundantAssignInSwitch]\n", errout_str()); check("void foo()\n" "{\n" @@ -4865,7 +5316,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:9] -> [test.cpp:11:11]: (style) Variable 'y' is reassigned a value before the old one has been used. 'break;' missing? [redundantAssignInSwitch]\n", errout_str()); check("void foo()\n" "{\n" @@ -4878,7 +5329,7 @@ class TestOther : public TestFixture { " ++y;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" @@ -4891,7 +5342,7 @@ class TestOther : public TestFixture { " ++y;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" @@ -4904,7 +5355,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:9] -> [test.cpp:9:11]: (style) Variable 'y' is reassigned a value before the old one has been used. 'break;' missing? [redundantAssignInSwitch]\n", errout_str()); check("void foo()\n" "{\n" @@ -4919,7 +5370,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:9] -> [test.cpp:11:11]: (style) Variable 'y' is reassigned a value before the old one has been used. 'break;' missing? [redundantAssignInSwitch]\n", errout_str()); check("void foo()\n" "{\n" @@ -4932,7 +5383,7 @@ class TestOther : public TestFixture { " --y;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" @@ -4945,7 +5396,7 @@ class TestOther : public TestFixture { " --y;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" @@ -4958,7 +5409,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:10] -> [test.cpp:9:11]: (style) Variable 'y' is reassigned a value before the old one has been used. 'break;' missing? [redundantAssignInSwitch]\n", errout_str()); check("void foo()\n" "{\n" @@ -4973,7 +5424,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:10] -> [test.cpp:11:11]: (style) Variable 'y' is reassigned a value before the old one has been used. 'break;' missing? [redundantAssignInSwitch]\n", errout_str()); check("void foo()\n" "{\n" @@ -4986,7 +5437,7 @@ class TestOther : public TestFixture { " y++;\n" " }\n" " bar(y);\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" @@ -4999,7 +5450,7 @@ class TestOther : public TestFixture { " y++;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" @@ -5012,7 +5463,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:10] -> [test.cpp:9:11]: (style) Variable 'y' is reassigned a value before the old one has been used. 'break;' missing? [redundantAssignInSwitch]\n", errout_str()); check("void foo()\n" "{\n" @@ -5027,7 +5478,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:10] -> [test.cpp:11:11]: (style) Variable 'y' is reassigned a value before the old one has been used. 'break;' missing? [redundantAssignInSwitch]\n", errout_str()); check("void foo()\n" "{\n" @@ -5040,7 +5491,7 @@ class TestOther : public TestFixture { " y--;\n" " }\n" " bar(y);\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" @@ -5053,7 +5504,7 @@ class TestOther : public TestFixture { " y--;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" @@ -5069,7 +5520,7 @@ class TestOther : public TestFixture { " }\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" @@ -5086,7 +5537,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" @@ -5100,7 +5551,7 @@ class TestOther : public TestFixture { " y++;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" @@ -5114,7 +5565,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" @@ -5130,7 +5581,7 @@ class TestOther : public TestFixture { " }\n" " bar(y);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" @@ -5146,7 +5597,7 @@ class TestOther : public TestFixture { " }\n" " bar(y);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" @@ -5160,7 +5611,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" @@ -5174,7 +5625,7 @@ class TestOther : public TestFixture { " y = 3;\n" " }\n" " bar(y);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:10] -> [test.cpp:10:11]: (style) Variable 'y' is reassigned a value before the old one has been used. 'break;' missing? [redundantAssignInSwitch]\n", errout_str()); check("bool f() {\n" @@ -5192,7 +5643,7 @@ class TestOther : public TestFixture { " };\n" " ret = true;\n" " return ret;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:13] -> [test.cpp:14:9]: (style) Variable 'ret' is reassigned a value before the old one has been used. [redundantAssignment]\n" "[test.cpp:8:13] -> [test.cpp:14:9]: (style) Variable 'ret' is reassigned a value before the old one has been used. [redundantAssignment]\n" "[test.cpp:11:13] -> [test.cpp:14:9]: (style) Variable 'ret' is reassigned a value before the old one has been used. [redundantAssignment]\n", @@ -5211,7 +5662,7 @@ class TestOther : public TestFixture { " y |= 3;\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:9]: (style) Redundant bitwise operation on 'y' in 'switch' statement. 'break;' missing? [redundantBitwiseOperationInSwitch]\n", errout_str()); check("void foo(int a)\n" @@ -5225,7 +5676,7 @@ class TestOther : public TestFixture { " y = y | 3;\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:9]: (style) Redundant bitwise operation on 'y' in 'switch' statement. 'break;' missing? [redundantBitwiseOperationInSwitch]\n", errout_str()); check("void foo(int a)\n" @@ -5239,7 +5690,7 @@ class TestOther : public TestFixture { " y |= 3;\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:9]: (style) Redundant bitwise operation on 'y' in 'switch' statement. 'break;' missing? [redundantBitwiseOperationInSwitch]\n", errout_str()); check("void foo(int a)\n" @@ -5254,7 +5705,7 @@ class TestOther : public TestFixture { " y |= 3;\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int a)\n" @@ -5269,7 +5720,7 @@ class TestOther : public TestFixture { " y |= z;\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int a)\n" @@ -5284,7 +5735,7 @@ class TestOther : public TestFixture { " y |= 3;\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int a)\n" @@ -5299,7 +5750,7 @@ class TestOther : public TestFixture { " y |= 3;\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:11] -> [test.cpp:8:11]: (style) Variable 'y' is reassigned a value before the old one has been used. [redundantAssignment]\n", errout_str()); check("void foo(int a)\n" @@ -5313,7 +5764,7 @@ class TestOther : public TestFixture { " y &= 3;\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:9]: (style) Redundant bitwise operation on 'y' in 'switch' statement. 'break;' missing? [redundantBitwiseOperationInSwitch]\n", errout_str()); check("void foo(int a)\n" @@ -5328,7 +5779,7 @@ class TestOther : public TestFixture { " y |= 3;\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int a)\n" @@ -5342,7 +5793,7 @@ class TestOther : public TestFixture { " y ^= 3;\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int a)\n" @@ -5356,7 +5807,7 @@ class TestOther : public TestFixture { " y |= 3;\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int a)\n" @@ -5370,7 +5821,7 @@ class TestOther : public TestFixture { " y &= 3;\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int a)\n" @@ -5384,7 +5835,7 @@ class TestOther : public TestFixture { " y &= 2;\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -5396,20 +5847,20 @@ class TestOther : public TestFixture { " continue;\n" " }\n" " }\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:5:13]: (style) Consecutive return, break, continue, goto or throw statements are unnecessary. [duplicateBreak]\n", errout_str()); check("int foo(int a) {\n" " return 0;\n" " return(a-1);\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:3:5]: (style) Consecutive return, break, continue, goto or throw statements are unnecessary. [duplicateBreak]\n", errout_str()); check("int foo(int a) {\n" " A:" " return(0);\n" " goto A;\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:3:5]: (style) Consecutive return, break, continue, goto or throw statements are unnecessary. [duplicateBreak]\n", errout_str()); constexpr char xmldata[] = "\n" @@ -5419,12 +5870,12 @@ class TestOther : public TestFixture { " \n" " \n" ""; - /*const*/ Settings settings = settingsBuilder().libraryxml(xmldata).build(); + /*const*/ Settings settings = settingsBuilder().libraryxml(xmldata).severity(Severity::style).build(); check("void foo() {\n" " exit(0);\n" " break;\n" - "}", true, false, false, false, &settings); + "}\n", dinit(CheckOptions, $.inconclusive = false, $.settings = &settings)); ASSERT_EQUALS("[test.cpp:3:5]: (style) Consecutive return, break, continue, goto or throw statements are unnecessary. [duplicateBreak]\n", errout_str()); check("class NeonSession {\n" @@ -5433,16 +5884,16 @@ class TestOther : public TestFixture { "void NeonSession::exit()\n" "{\n" " SAL_INFO(\"ucb.ucp.webdav\", \"neon commands cannot be aborted\");\n" - "}", true, false, false, false, &settings); + "}\n", dinit(CheckOptions, $.inconclusive = false, $.settings = &settings)); ASSERT_EQUALS("", errout_str()); check("void NeonSession::exit()\n" "{\n" " SAL_INFO(\"ucb.ucp.webdav\", \"neon commands cannot be aborted\");\n" - "}", true, false, false, false, &settings); + "}\n", dinit(CheckOptions, $.inconclusive = false, $.settings = &settings)); ASSERT_EQUALS("", errout_str()); - check("void foo() { xResAccess->exit(); }", true, false, false, false, &settings); + check("void foo() { xResAccess->exit(); }\n", dinit(CheckOptions, $.inconclusive = false, $.settings = &settings)); ASSERT_EQUALS("", errout_str()); check("void foo(int a)\n" @@ -5456,7 +5907,7 @@ class TestOther : public TestFixture { " c++;\n" " break;\n" " }\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:7:13]: (style) Consecutive return, break, continue, goto or throw statements are unnecessary. [duplicateBreak]\n", errout_str()); check("void foo(int a)\n" @@ -5469,7 +5920,7 @@ class TestOther : public TestFixture { " c++;\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int a)\n" @@ -5480,7 +5931,7 @@ class TestOther : public TestFixture { " break;\n" " }\n" " }\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:6:13]: (style) Consecutive return, break, continue, goto or throw statements are unnecessary. [duplicateBreak]\n", errout_str()); check("void foo(int a)\n" @@ -5492,7 +5943,7 @@ class TestOther : public TestFixture { " }\n" " a+=2;\n" " }\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:6:13]: (style) Consecutive return, break, continue, goto or throw statements are unnecessary. [duplicateBreak]\n", errout_str()); check("void foo(int a)\n" @@ -5503,50 +5954,50 @@ class TestOther : public TestFixture { " }\n" " a+=2;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int foo() {\n" " throw 0;\n" " return 1;\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:3:5]: (style) Consecutive return, break, continue, goto or throw statements are unnecessary. [duplicateBreak]\n", errout_str()); check("void foo() {\n" " throw 0;\n" " return;\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:3:5]: (style) Consecutive return, break, continue, goto or throw statements are unnecessary. [duplicateBreak]\n", errout_str()); check("int foo() {\n" " throw = 0;\n" " return 1;\n" - "}", false, false, false); + "}\n", dinit(CheckOptions, $.cpp = false, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); check("int foo() {\n" " return 0;\n" " return 1;\n" - "}", true, false, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:3:5]: (style) Consecutive return, break, continue, goto or throw statements are unnecessary. [duplicateBreak]\n", errout_str()); check("int foo() {\n" " return 0;\n" " foo();\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:3:5]: (style) Statements following 'return' will never be executed. [unreachableCode]\n", errout_str()); check("int foo(int unused) {\n" " return 0;\n" " (void)unused;\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); check("int foo(int unused1, int unused2) {\n" " return 0;\n" " (void)unused1;\n" " (void)unused2;\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); check("int foo(int unused1, int unused2) {\n" @@ -5554,14 +6005,14 @@ class TestOther : public TestFixture { " (void)unused1;\n" " (void)unused2;\n" " foo();\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:5:5]: (style) Statements following 'return' will never be executed. [unreachableCode]\n", errout_str()); check("int foo() {\n" " if(bar)\n" " return 0;\n" " return 124;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int foo() {\n" @@ -5572,7 +6023,7 @@ class TestOther : public TestFixture { " return 0;\n" " }\n" " return 124;\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:4:9]: (style) Consecutive return, break, continue, goto or throw statements are unnecessary. [duplicateBreak]\n", errout_str()); check("void foo() {\n" @@ -5580,7 +6031,7 @@ class TestOther : public TestFixture { " return;\n" " break;\n" " }\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:4:9]: (style) Consecutive return, break, continue, goto or throw statements are unnecessary. [duplicateBreak]\n", errout_str()); // #5707 @@ -5591,20 +6042,20 @@ class TestOther : public TestFixture { " }\n" " return 0;\n" " j=2;\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:7:5]: (style) Statements following 'return' will never be executed. [unreachableCode]\n", errout_str()); check("int foo() {\n" " return 0;\n" " label:\n" " throw 0;\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:3:3]: (style) Label 'label' is not used. [unusedLabel]\n", errout_str()); check("struct A {\n" " virtual void foo (P & Val) throw ();\n" " virtual void foo1 (P & Val) throw ();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int foo() {\n" @@ -5613,7 +6064,7 @@ class TestOther : public TestFixture { " bar();\n" " label:\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #3457 check("int foo() {\n" @@ -5622,7 +6073,7 @@ class TestOther : public TestFixture { " bar();\n" " label:\n" " } while (true);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #3457 check("int foo() {\n" @@ -5631,7 +6082,7 @@ class TestOther : public TestFixture { " bar();\n" " label:\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #3457 // #3383. TODO: Use preprocessor @@ -5640,23 +6091,21 @@ class TestOther : public TestFixture { " return 0;\n" "\n" // #endif " return 1;\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); check("int foo() {\n" "\n" // #ifdef A " return 0;\n" "\n" // #endif " return 1;\n" - "}", true, true, false); + "}\n"); ASSERT_EQUALS("[test.cpp:5:5]: (style, inconclusive) Consecutive return, break, continue, goto or throw statements are unnecessary. [duplicateBreak]\n", errout_str()); // #4711 lambda functions check("int f() {\n" " return g([](int x){(void)x+1; return x;});\n" - "}", - true, - false, - false); + "}\n", + dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); // #4756 @@ -5670,7 +6119,7 @@ class TestOther : public TestFixture { " __asm__ (\"rorw $8, %w0\" : \"=r\" (__v) : \"0\" (__x) : \"cc\");\n" " (void)__v;\n" " }));\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); // #6008 @@ -5679,7 +6128,7 @@ class TestOther : public TestFixture { " int sum = a_ + b_;\n" " return sum;\n" " };\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); // #5789 @@ -5687,20 +6136,20 @@ class TestOther : public TestFixture { " uint64_t enter, exit;\n" " uint64_t events;\n" " per_state_info() : enter(0), exit(0), events(0) {}\n" - "};", true, false, false); + "};\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); // #6664 check("void foo() {\n" " (beat < 100) ? (void)0 : exit(0);\n" " bar();\n" - "}", true, false, false, false, &settings); + "}\n", dinit(CheckOptions, $.inconclusive = false, $.settings = &settings)); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " (beat < 100) ? exit(0) : (void)0;\n" " bar();\n" - "}", true, false, false, false, &settings); + "}\n", dinit(CheckOptions, $.inconclusive = false, $.settings = &settings)); ASSERT_EQUALS("", errout_str()); // #8261 @@ -5708,13 +6157,13 @@ class TestOther : public TestFixture { TODO_ASSERT_THROW(check("void foo() {\n" " (beat < 100) ? (void)0 : throw(0);\n" " bar();\n" - "}", true, false, false, false, &settings), InternalError); + "}\n", dinit(CheckOptions, $.inconclusive = false, $.settings = &settings)), InternalError); //ASSERT_EQUALS("", errout_str()); check("int foo() {\n" " exit(0);\n" " return 1;\n" // <- clarify for tools that function does not continue.. - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -5885,7 +6334,7 @@ class TestOther : public TestFixture { " }\n" " var = 42;\n" " return ret();\n" - "}\n", /*cpp*/ false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" // #13516 @@ -5957,7 +6406,7 @@ class TestOther : public TestFixture { " case A||B:\n" " foo();\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:15]: (warning, inconclusive) Found suspicious case label in switch(). Operator '&&' probably doesn't work as intended. [suspiciousCase]\n" "[test.cpp:5:16]: (warning, inconclusive) Found suspicious case label in switch(). Operator '||' probably doesn't work as intended. [suspiciousCase]\n" "[test.cpp:7:15]: (warning, inconclusive) Found suspicious case label in switch(). Operator '||' probably doesn't work as intended. [suspiciousCase]\n", errout_str()); @@ -5967,7 +6416,7 @@ class TestOther : public TestFixture { " case 1:\n" " a=A&&B;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // TODO Do not throw AST validation exception @@ -5976,19 +6425,19 @@ class TestOther : public TestFixture { " case A&&B?B:A:\n" " foo();\n" " }\n" - "}"), InternalError); + "}\n"), InternalError); //ASSERT_EQUALS("", errout_str()); } void suspiciousEqualityComparison() { check("void foo(int c) {\n" " if (x) c == 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:14]: (warning, inconclusive) Found suspicious equality comparison. Did you intend to assign a value instead? [constStatement]\n", errout_str()); check("void foo(const int* c) {\n" " if (x) *c == 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (warning, inconclusive) Found suspicious equality comparison. Did you intend to assign a value instead? [constStatement]\n", errout_str()); @@ -5996,90 +6445,90 @@ class TestOther : public TestFixture { " if (c == 1) {\n" " c = 0;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int c) {\n" " c == 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:7]: (warning, inconclusive) Found suspicious equality comparison. Did you intend to assign a value instead? [constStatement]\n", errout_str()); check("void foo(int c) {\n" " for (int i = 0; i == 10; i ++) {\n" " a ++;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int c) {\n" " for (i == 0; i < 10; i ++) {\n" " c ++;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:12]: (warning, inconclusive) Found suspicious equality comparison. Did you intend to assign a value instead? [constStatement]\n", errout_str()); check("void foo(int c) {\n" " for (i == 1; i < 10; i ++) {\n" " c ++;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:12]: (warning, inconclusive) Found suspicious equality comparison. Did you intend to assign a value instead? [constStatement]\n", errout_str()); check("void foo(int c) {\n" " for (i == 2; i < 10; i ++) {\n" " c ++;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:12]: (warning, inconclusive) Found suspicious equality comparison. Did you intend to assign a value instead? [constStatement]\n", errout_str()); check("void foo(int c) {\n" " for (int i = 0; i < 10; i == c) {\n" " c ++;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:31]: (warning, inconclusive) Found suspicious equality comparison. Did you intend to assign a value instead? [constStatement]\n", errout_str()); check("void foo(int c) {\n" " for (; running == 1;) {\n" " c ++;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int c) {\n" " printf(\"%i\", ({x==0;}));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int arg) {\n" " printf(\"%i\", ({int x = do_something(); x == 0;}));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int x) {\n" " printf(\"%i\", ({x == 0; x > 0 ? 10 : 20}));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:22]: (warning, inconclusive) Found suspicious equality comparison. Did you intend to assign a value instead? [constStatement]\n", errout_str()); check("void foo(int x) {\n" " for (const Token* end = tok->link(); tok != end; tok = (tok == end) ? end : tok->next()) {\n" " x++;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int x) {\n" " for (int i = (x == 0) ? 0 : 5; i < 10; i ++) {\n" " x++;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int x) {\n" " for (int i = 0; i < 10; i += (x == 5) ? 1 : 2) {\n" " x++;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -6135,26 +6584,26 @@ class TestOther : public TestFixture { " int x = 1;\n" " x = x;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:7]: (style) Redundant assignment of 'x' to itself. [selfAssignment]\n", errout_str()); check("void foo()\n" "{\n" " int x = x;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11]: (style) Redundant assignment of 'x' to itself. [selfAssignment]\n", errout_str()); check("struct A { int b; };\n" "void foo(A* a1, A* a2) {\n" " a1->b = a1->b;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11]: (style) Redundant assignment of 'a1->b' to itself. [selfAssignment]\n", errout_str()); check("int x;\n" "void f()\n" "{\n" " x = x = 3;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:7]: (style) Redundant assignment of 'x' to itself. [selfAssignment]\n", errout_str()); // #4073 (segmentation fault) @@ -6162,59 +6611,59 @@ class TestOther : public TestFixture { "{\n" " if (a == 42)\n" " a = a;\n" - "}"); + "}\n"); check("void foo()\n" "{\n" " int x = 1;\n" " x = x + 1;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" " int *x = getx();\n" " *x = x;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " BAR *x = getx();\n" " x = x;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:7]: (style) Redundant assignment of 'x' to itself. [selfAssignment]\n", errout_str()); // #2502 - non-primitive type -> there might be some side effects check("void foo()\n" "{\n" " Fred fred; fred = fred;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" " x = (x == 0);" " func(x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int x) {\n" " x = (x != 0);" " func(x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // ticket #3001 - false positive check("void foo(int x) {\n" " x = x ? x : 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #3800 - false negative when variable is extern check("extern int i;\n" "void f() {\n" " i = i;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:7]: (style) Redundant assignment of 'i' to itself. [selfAssignment]\n", errout_str()); // #4291 - id for variables accessed through 'this' @@ -6224,16 +6673,16 @@ class TestOther : public TestFixture { "};\n" "void Foo::func() {\n" " this->var = var;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:15]: (style) Redundant assignment of 'this->var' to itself. [selfAssignment]\n", errout_str()); check("class Foo {\n" " int var;\n" - " void func(int var);\n" + " Foo(int var);\n" "};\n" - "void Foo::func(int var) {\n" + "Foo::Foo(int var) {\n" " this->var = var;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #6406 - designated initializer doing bogus self assignment @@ -6243,7 +6692,7 @@ class TestOther : public TestFixture { "void something(void) {}\n" "void f() {\n" " struct callbacks ops = { .s = ops.s };\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:6]: (style) Redundant assignment of 'something' to itself.\n", "", errout_str()); check("class V\n" @@ -6258,12 +6707,12 @@ class TestOther : public TestFixture { " x = x; y = y; z = z;\n" " }\n" " double x, y, z;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:10:11]: (style) Redundant assignment of 'x' to itself. [selfAssignment]\n" "[test.cpp:10:18]: (style) Redundant assignment of 'y' to itself. [selfAssignment]\n" "[test.cpp:10:25]: (style) Redundant assignment of 'z' to itself. [selfAssignment]\n", errout_str()); - check("void f(int i) { i = !!i; }"); + check("void f(int i) { i = !!i; }\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" @@ -6309,6 +6758,10 @@ class TestOther : public TestFixture { " s.i = o;\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("int N;\n" // #14234 + "void f() { ::N = N; }\n"); + ASSERT_EQUALS("[test.cpp:2:16]: (style) Redundant assignment of '::N' to itself. [selfAssignment]\n", errout_str()); } void trac1132() { @@ -6329,7 +6782,7 @@ class TestOther : public TestFixture { " Lock(123);\n" " std::cout << \"hello\" << std::endl;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:15:5]: (style) Instance of 'Lock' object is destroyed immediately. [unusedScopedObject]\n", errout_str()); } @@ -6339,7 +6792,7 @@ class TestOther : public TestFixture { " b = 300\n" " };\n" "};\n" - "const int DFLT_TIMEOUT = A::b % 1000000 ;\n", true, false, false); + "const int DFLT_TIMEOUT = A::b % 1000000 ;\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); } @@ -6348,7 +6801,7 @@ class TestOther : public TestFixture { "{\n" " CouldBeFunction ( 123 ) ;\n" " return 0 ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -6365,7 +6818,7 @@ class TestOther : public TestFixture { " error();\n" " do_something();\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); } @@ -6375,7 +6828,7 @@ class TestOther : public TestFixture { "{\n" " NotAFunction ( 123 );\n" " return 0 ;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:5]: (style) Instance of 'NotAFunction' object is destroyed immediately. [unusedScopedObject]\n", errout_str()); } @@ -6385,7 +6838,7 @@ class TestOther : public TestFixture { "{\n" " NotAClass ( 123 ) ;\n" " return true ;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:5]: (style) Instance of 'NotAClass' object is destroyed immediately. [unusedScopedObject]\n", errout_str()); } @@ -6394,7 +6847,7 @@ class TestOther : public TestFixture { "{\n" " if ( a > b ) return c == a ;\n" " return b == a ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -6404,7 +6857,7 @@ class TestOther : public TestFixture { "public:\n" "~Something ( ) ;\n" "Something ( ) ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -6423,7 +6876,7 @@ class TestOther : public TestFixture { " int a = 1;\n" " IncrementFunctor()(a);\n" " return a;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -6436,7 +6889,7 @@ class TestOther : public TestFixture { " };\n" " Foo();\n" " do_something();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:5]: (style) Instance of 'Foo' object is destroyed immediately. [unusedScopedObject]\n", errout_str()); } @@ -6448,7 +6901,7 @@ class TestOther : public TestFixture { "\n" "void fn() {\n" " Foo().bar();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -6464,10 +6917,10 @@ class TestOther : public TestFixture { " do_something();\n" "}\n"; - check(code, true); + check(code); ASSERT_EQUALS("[test.cpp:7:5]: (style) Instance of 'cb_watch_bool' object is destroyed immediately. [unusedScopedObject]\n", errout_str()); - check(code, false); + check(code, dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("", errout_str()); // Ticket #2639 @@ -6477,14 +6930,14 @@ class TestOther : public TestFixture { "void foo() {\n" " stat(\"file.txt\", &st);\n" " do_something();\n" - "}"); + "}\n"); ASSERT_EQUALS("",errout_str()); check("struct AMethodObject {\n" // #4336 " AMethodObject(double, double, double);\n" "};\n" "struct S {\n" - " static void A(double, double, double);\n" + " static void A(double a1, double a2, double a3);\n" "};\n" "void S::A(double const a1, double const a2, double const a3) {\n" " AMethodObject(a1, a2, a3);\n" @@ -6509,7 +6962,7 @@ class TestOther : public TestFixture { " do_something();\n" "}\n"; - check(code, true); + check(code); ASSERT_EQUALS("", errout_str()); } @@ -6522,7 +6975,7 @@ class TestOther : public TestFixture { " }\n" " Foo(char x, int y) { }\n" "};\n"; - check(code, true); + check(code); ASSERT_EQUALS("[test.cpp:4:5]: (style) Instance of 'Foo' object is destroyed immediately. [unusedScopedObject]\n", errout_str()); } @@ -6537,7 +6990,7 @@ class TestOther : public TestFixture { " int{ i };\n" " int{ g() };\n" // don't warn " g();\n" - "}\n", true); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (style) Instance of 'int' object is destroyed immediately. [unusedScopedObject]\n" "[test.cpp:4:5]: (style) Instance of 'int' object is destroyed immediately. [unusedScopedObject]\n" "[test.cpp:6:5]: (style) Instance of 'int' object is destroyed immediately. [unusedScopedObject]\n" @@ -6547,19 +7000,19 @@ class TestOther : public TestFixture { check("void f(int j) {\n" " for (; bool(j); ) {}\n" - "}\n", true); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void g() {\n" " float (f);\n" " float (*p);\n" - "}\n", true); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f(int i) {\n" " void();\n" " return i;\n" - "}\n", true); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -6572,7 +7025,7 @@ class TestOther : public TestFixture { "int f() {\n" " M::N::S();\n" " return 0;\n" - "}\n", true); + "}\n"); ASSERT_EQUALS("[test.cpp:7:11]: (style) Instance of 'M::N::S' object is destroyed immediately. [unusedScopedObject]\n", errout_str()); check("void f() {\n" // #10057 @@ -6580,8 +7033,9 @@ class TestOther : public TestFixture { " std::string{ \"abc\" };\n" " std::pair(1, 2);\n" " (void)0;\n" - "}\n", true); - ASSERT_EQUALS("[test.cpp:2:10]: (style) Instance of 'std::string' object is destroyed immediately. [unusedScopedObject]\n" + "}\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()); @@ -6597,7 +7051,7 @@ class TestOther : public TestFixture { " std::scoped_lock(m);\n" " }\n" " std::mutex m;\n" - "}\n", true); + "}\n"); ASSERT_EQUALS("[test.cpp:3:14]: (style) Instance of 'std::lock_guard' object is destroyed immediately. [unusedScopedObject]\n" "[test.cpp:6:14]: (style) Instance of 'std::scoped_lock' object is destroyed immediately. [unusedScopedObject]\n" "[test.cpp:9:14]: (style) Instance of 'std::scoped_lock' object is destroyed immediately. [unusedScopedObject]\n", @@ -6606,7 +7060,7 @@ class TestOther : public TestFixture { check("struct S { int i; };\n" "namespace {\n" " S s() { return ::S{42}; }\n" - "}\n", true); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -6619,7 +7073,7 @@ class TestOther : public TestFixture { "void t0() { f() = {}; }\n" "void t1() { g() = {}; }\n" "void t2() { h() = {}; }\n" - "void t3() { *i() = {}; }\n", true); + "void t3() { *i() = {}; }\n"); ASSERT_EQUALS("[test.cpp:6:19]: (style) Instance of 'S' object is destroyed immediately, assignment has no effect. [unusedScopedObject]\n", errout_str()); } @@ -6630,7 +7084,7 @@ class TestOther : public TestFixture { "\n" " { sigaction(SIGHUP, &sa, 0); };\n" " { sigaction(SIGINT, &sa, 0); };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -6641,76 +7095,76 @@ class TestOther : public TestFixture { " };\n" "\n" " const AB ab[3] = { AB(0), AB(1), AB(2) };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void clarifyCalculation() { check("int f(char c) {\n" " return 10 * (c == 0) ? 1 : 2;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:26]: (style) Clarify calculation precedence for '*' and '?'. [clarifyCalculation]\n", errout_str()); check("void f(char c) {\n" " printf(\"%i\", 10 * (c == 0) ? 1 : 2);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:32]: (style) Clarify calculation precedence for '*' and '?'. [clarifyCalculation]\n", errout_str()); check("void f() {\n" " return (2*a)?b:c;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(char c) {\n" " printf(\"%i\", a + b ? 1 : 2);\n" - "}",true,false,false); + "}\n",dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:2:24]: (style) Clarify calculation precedence for '+' and '?'. [clarifyCalculation]\n", errout_str()); check("void f() {\n" " std::cout << x << y ? 2 : 3;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:25]: (style) Clarify calculation precedence for '<<' and '?'. [clarifyCalculation]\n", errout_str()); check("void f() {\n" " int ab = a - b ? 2 : 3;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:20]: (style) Clarify calculation precedence for '-' and '?'. [clarifyCalculation]\n", errout_str()); check("void f() {\n" " int ab = a | b ? 2 : 3;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:20]: (style) Clarify calculation precedence for '|' and '?'. [clarifyCalculation]\n", errout_str()); // ticket #195 check("int f(int x, int y) {\n" " return x >> ! y ? 8 : 2;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:21]: (style) Clarify calculation precedence for '>>' and '?'. [clarifyCalculation]\n", errout_str()); check("int f() {\n" " return shift < sizeof(int64_t)*8 ? 1 : 2;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); - check("void f() { a = *p ? 1 : 2; }"); + check("void f() { a = *p ? 1 : 2; }\n"); ASSERT_EQUALS("", errout_str()); - check("void f(int x) { const char *p = x & 1 ? \"1\" : \"0\"; }"); + check("void f(int x) { const char *p = x & 1 ? \"1\" : \"0\"; }\n"); ASSERT_EQUALS("", errout_str()); - check("void foo() { x = a % b ? \"1\" : \"0\"; }"); + check("void foo() { x = a % b ? \"1\" : \"0\"; }\n"); ASSERT_EQUALS("", errout_str()); - check("void f(int x) { return x & 1 ? '1' : '0'; }"); + check("void f(int x) { return x & 1 ? '1' : '0'; }\n"); ASSERT_EQUALS("", errout_str()); - check("void f(int x) { return x & 16 ? 1 : 0; }"); + check("void f(int x) { return x & 16 ? 1 : 0; }\n"); ASSERT_EQUALS("", errout_str()); - check("void f(int x) { return x % 16 ? 1 : 0; }"); + check("void f(int x) { return x % 16 ? 1 : 0; }\n"); ASSERT_EQUALS("", errout_str()); - check("enum {X,Y}; void f(int x) { return x & Y ? 1 : 0; }"); + check("enum {X,Y}; void f(int x) { return x & Y ? 1 : 0; }\n"); ASSERT_EQUALS("", errout_str()); } @@ -6718,7 +7172,7 @@ class TestOther : public TestFixture { check("char* f(char* c) {\n" " *c++;\n" " return c;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:5]: (warning, inconclusive) Found suspicious operator '*', result is not used. [constStatement]\n" "[test.cpp:2:7]: (warning) In expression like '*A++' the result of '*' is unused. Did you intend to write '(*A)++;'? [clarifyStatement]\n", @@ -6727,7 +7181,7 @@ class TestOther : public TestFixture { check("char* f(char** c) {\n" " *c[5]--;\n" " return *c;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:5]: (warning, inconclusive) Found suspicious operator '*', result is not used. [constStatement]\n" "[test.cpp:2:10]: (warning) In expression like '*A++' the result of '*' is unused. Did you intend to write '(*A)++;'? [clarifyStatement]\n", @@ -6735,7 +7189,7 @@ class TestOther : public TestFixture { check("void f(Foo f) {\n" " *f.a++;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:5]: (warning, inconclusive) Found suspicious operator '*', result is not used. [constStatement]\n" "[test.cpp:2:9]: (warning) In expression like '*A++' the result of '*' is unused. Did you intend to write '(*A)++;'? [clarifyStatement]\n", @@ -6743,7 +7197,7 @@ class TestOther : public TestFixture { check("void f(Foo f) {\n" " *f.a[5].v[3]++;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:5]: (warning, inconclusive) Found suspicious operator '*', result is not used. [constStatement]\n" "[test.cpp:2:17]: (warning) In expression like '*A++' the result of '*' is unused. Did you intend to write '(*A)++;'? [clarifyStatement]\n", @@ -6751,7 +7205,7 @@ class TestOther : public TestFixture { check("void f(Foo f) {\n" " *f.a(1, 5).v[x + y]++;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:5]: (warning, inconclusive) Found suspicious operator '*', result is not used. [constStatement]\n" "[test.cpp:2:24]: (warning) In expression like '*A++' the result of '*' is unused. Did you intend to write '(*A)++;'? [clarifyStatement]\n", @@ -6760,18 +7214,18 @@ class TestOther : public TestFixture { check("char* f(char* c) {\n" " (*c)++;\n" " return c;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(char* c) {\n" " bar(*c++);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("char*** f(char*** c) {\n" " ***c++;\n" " return c;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:5]: (warning, inconclusive) Found suspicious operator '*', result is not used. [constStatement]\n" "[test.cpp:2:9]: (warning) In expression like '*A++' the result of '*' is unused. Did you intend to write '(*A)++;'? [clarifyStatement]\n", @@ -6780,7 +7234,7 @@ class TestOther : public TestFixture { check("char** f(char*** c) {\n" " **c[5]--;\n" " return **c;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:5]: (warning, inconclusive) Found suspicious operator '*', result is not used. [constStatement]\n" "[test.cpp:2:11]: (warning) In expression like '*A++' the result of '*' is unused. Did you intend to write '(*A)++;'? [clarifyStatement]\n", @@ -6789,7 +7243,7 @@ class TestOther : public TestFixture { check("char*** f(char*** c) {\n" " (***c)++;\n" " return c;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(const int*** p) {\n" // #10923 @@ -6799,12 +7253,12 @@ class TestOther : public TestFixture { check("void *f(char** c) {\n" " bar(**c++);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void *f(char* p) {\n" " for (p = path; *p++;) ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -6824,7 +7278,7 @@ class TestOther : public TestFixture { " b = 1;\n" " else\n" " b = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:5] -> [test.cpp:2:5]: (style, inconclusive) Found duplicate branches for 'if' and 'else'. [duplicateBranch]\n", errout_str()); check("void f(int a, int &b) {\n" @@ -6835,7 +7289,7 @@ class TestOther : public TestFixture { " b = 2;\n" " } else\n" " b = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:9] -> [test.cpp:3:9]: (style, inconclusive) Found duplicate branches for 'if' and 'else'. [duplicateBranch]\n", errout_str()); check("void f(int a, int &b) {\n" @@ -6847,7 +7301,7 @@ class TestOther : public TestFixture { " else\n" " b = 2;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:9] -> [test.cpp:5:9]: (style, inconclusive) Found duplicate branches for 'if' and 'else'. [duplicateBranch]\n", errout_str()); check("int f(int signed, unsigned char value) {\n" @@ -6857,7 +7311,7 @@ class TestOther : public TestFixture { " else\n" " ret = (unsigned char)value;\n" " return ret;\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -6865,7 +7319,7 @@ class TestOther : public TestFixture { " __asm__(\"mov ax, bx\");\n" " else\n" " __asm__(\"mov bx, bx\");\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #3407 check("void f() {\n" @@ -6873,7 +7327,7 @@ class TestOther : public TestFixture { " __asm__(\"mov ax, bx\");\n" " else\n" " __asm__(\"mov ax, bx\");\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:5] -> [test.cpp:2:5]: (style, inconclusive) Found duplicate branches for 'if' and 'else'. [duplicateBranch]\n", errout_str()); } @@ -6887,7 +7341,7 @@ class TestOther : public TestFixture { " frac = front/(front-back);\n" " else\n" " frac = front/(front-back);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:3] -> [test.cpp:3:3]: (style, inconclusive) Found duplicate branches for 'if' and 'else'. [duplicateBranch]\n", errout_str()); check("void f()\n" @@ -6896,7 +7350,7 @@ class TestOther : public TestFixture { " { frac = front/(front-back);}\n" " else\n" " frac = front/((front-back));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:3] -> [test.cpp:3:3]: (style, inconclusive) Found duplicate branches for 'if' and 'else'. [duplicateBranch]\n", errout_str()); // No message about empty branches (#5354) @@ -6906,7 +7360,7 @@ class TestOther : public TestFixture { " {}\n" " else\n" " {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -6918,7 +7372,7 @@ class TestOther : public TestFixture { " DOSTUFF1\n" " else\n" " DOSTUFF2\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -6930,7 +7384,7 @@ class TestOther : public TestFixture { " } else {\n" " x = j;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:13] -> [test.cpp:5:7] -> [test.cpp:3:5]: (style, inconclusive) Found duplicate branches for 'if' and 'else'. [duplicateBranch]\n" "[test.cpp:2:9]: (style) The scope of the variable 'j' can be reduced. [variableScope]\n", errout_str()); @@ -6943,7 +7397,7 @@ class TestOther : public TestFixture { " } else {\n" " x = j;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -6954,7 +7408,7 @@ class TestOther : public TestFixture { " } else {\n" " return new A::Z(true);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -6968,7 +7422,7 @@ class TestOther : public TestFixture { " unsigned int i = 0;\n" " j = i;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:7] -> [test.cpp:3:5]: (style, inconclusive) Found duplicate branches for 'if' and 'else'. [duplicateBranch]\n", errout_str()); check("void f(bool b) {\n" @@ -6980,7 +7434,7 @@ class TestOther : public TestFixture { " unsigned int i = 0;\n" " j = 1;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(bool b) {\n" @@ -6990,7 +7444,7 @@ class TestOther : public TestFixture { " } else {\n" " int i = 0;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(bool b) {\n" @@ -7002,7 +7456,16 @@ class TestOther : public TestFixture { " int i = 0;\n" " j = i;\n" " }\n" - "}"); + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f(int i) {\n" + " if (1 == i) {\n" + " ;\n" + " } else {\n" + " ;\n" + " }\n" + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -7012,7 +7475,7 @@ class TestOther : public TestFixture { " } else {\n" " int i = 0;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(bool b) {\n" @@ -7020,14 +7483,14 @@ class TestOther : public TestFixture { " int i = 0;\n" " } else {\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void duplicateExpression1() { check("void foo(int a) {\n" " if (a == a) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Same expression on both sides of '=='. [duplicateExpression]\n", errout_str()); check("void fun(int b) {\n" @@ -7036,7 +7499,7 @@ class TestOther : public TestFixture { " d > d &&\n" " e < e &&\n" " f ;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (style) Same expression on both sides of '&&'. [duplicateExpression]\n" "[test.cpp:3:15]: (style) Same expression on both sides of '=='. [duplicateExpression]\n" "[test.cpp:4:15]: (style) Same expression on both sides of '>'. [duplicateExpression]\n" @@ -7044,82 +7507,82 @@ class TestOther : public TestFixture { check("void foo() {\n" " return a && a;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:14]: (style) Same expression on both sides of '&&'. [duplicateExpression]\n", errout_str()); check("void foo() {\n" " a = b && b;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Same expression on both sides of '&&'. [duplicateExpression]\n", errout_str()); check("void foo(int b) {\n" " f(a,b == b);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Same expression on both sides of '=='. [duplicateExpression]\n", errout_str()); check("void foo(int b) {\n" " f(b == b, a);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) Same expression on both sides of '=='. [duplicateExpression]\n", errout_str()); check("void foo() {\n" " if (x!=2 || x!=2) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:14]: (style) Same expression on both sides of '||'. [duplicateExpression]\n", errout_str()); check("void foo(int a, int b) {\n" " if ((a < b) && (b > a)) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:17]: (style) Same expression on both sides of '&&' because 'aa' represent the same value. [knownConditionTrueFalse]\n", errout_str()); check("void foo(int a, int b) {\n" " if ((a <= b) && (b >= a)) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:18]: (style) Same expression on both sides of '&&' because 'a<=b' and 'b>=a' represent the same value. [knownConditionTrueFalse]\n", errout_str()); check("void foo() {\n" " if (x!=2 || y!=3 || x!=2) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:22]: (style) Same expression 'x!=2' found multiple times in chain of '||' operators. [duplicateExpression]\n", errout_str()); check("void foo() {\n" " if (x!=2 && (x=y) && x!=2) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " if (a && b || a && b) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:16]: (style) Same expression on both sides of '||'. [duplicateExpression]\n", errout_str()); check("void foo() {\n" " if (a && b || b && c) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " if (a && b | b && c) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:16]: (style) Same expression on both sides of '|'. [duplicateExpression]\n", errout_str()); check("void foo() {\n" " if ((a + b) | (a + b)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:17]: (style) Same expression on both sides of '|'. [duplicateExpression]\n", errout_str()); check("void foo() {\n" " if ((a | b) & (a | b)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:17]: (style) Same expression on both sides of '&'. [duplicateExpression]\n", errout_str()); check("void foo(int a, int b) {\n" " if ((a | b) == (a | b)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:17]: (style) Same expression on both sides of '=='. [duplicateExpression]\n", errout_str()); check("void foo() {\n" " if (a1[a2[c & 0xff] & 0xff]) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void d(const char f, int o, int v)\n" @@ -7127,131 +7590,127 @@ class TestOther : public TestFixture { " if (((f=='R') && (o == 1) && ((v < 2) || (v > 99))) ||\n" " ((f=='R') && (o == 2) && ((v < 2) || (v > 99))) ||\n" " ((f=='T') && (o == 2) && ((v < 200) || (v > 9999)))) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); - check("int f(int x) { return x+x; }"); + check("int f(int x) { return x+x; }\n"); ASSERT_EQUALS("", errout_str()); - check("void f(int x) { while (x+=x) ; }"); + check("void f(int x) { while (x+=x) ; }\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " if (a && b && b) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:16]: (style) Same expression on both sides of '&&'. [duplicateExpression]\n", errout_str()); check("void foo() {\n" " if (a || b || b) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:16]: (style) Same expression on both sides of '||'. [duplicateExpression]\n", errout_str()); check("void foo() {\n" " if (a / 1000 / 1000) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int foo(int i) {\n" " return i/i;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:13]: (style) Same expression on both sides of '/'. [duplicateExpression]\n", errout_str()); check("void foo() {\n" " if (a << 1 << 1) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); - check("int f() { return !!y; }"); // No FP + check("int f() { return !!y; }\n"); // No FP ASSERT_EQUALS("", errout_str()); // make sure there are not "same expression" fp when there are different casts - check("void f(long x) { if ((int32_t)x == (int64_t)x) {} }", - true, // filename - false, // inconclusive - false, // runSimpleChecks - false, // verbose - nullptr // settings + check("void f(long x) { if ((int32_t)x == (int64_t)x) {} }\n", + dinit(CheckOptions, $.inconclusive = false) ); ASSERT_EQUALS("", errout_str()); // make sure there are not "same expression" fp when there are different ({}) expressions - check("void f(long x) { if (({ 1+2; }) == ({3+4;})) {} }"); + check("void f(long x) { if (({ 1+2; }) == ({3+4;})) {} }\n"); ASSERT_EQUALS("", errout_str()); // #5535: Reference named like its type - check("void foo() { UMSConfig& UMSConfig = GetUMSConfiguration(); }"); + check("void foo() { UMSConfig& UMSConfig = GetUMSConfiguration(); }\n"); ASSERT_EQUALS("[test.cpp:1:25]: (style) Variable 'UMSConfig' can be declared as reference to const [constVariableReference]\n", errout_str()); // #3868 - false positive (same expression on both sides of |) check("void f(int x) {\n" " a = x ? A | B | C\n" " : A | B;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(const Bar &bar) {\n" " bool a = bar.isSet() && bar->isSet();\n" " bool b = bar.isSet() && bar.isSet();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:26]: (style) Same expression on both sides of '&&'. [duplicateExpression]\n", errout_str()); check("void foo(int a, int b) {\n" " if ((b + a) | (a + b)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:17]: (style) Same expression on both sides of '|' because 'b+a' and 'a+b' represent the same value. [duplicateExpression]\n", errout_str()); check("void foo(const std::string& a, const std::string& b) {\n" " return a.find(b+\"&\") || a.find(\"&\"+b);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int a, int b) {\n" " if ((b > a) | (a > b)) {}\n" // > is not commutative - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(double a, double b) {\n" " if ((b + a) > (a + b)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:17]: (style) The comparison 'b+a > a+b' is always false because 'b+a' and 'a+b' represent the same value. [knownConditionTrueFalse]\n", errout_str()); check("void f(int x) {\n" " if ((x == 1) && (x == 0x00000001))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:18]: (style) Same expression on both sides of '&&' because 'x==1' and 'x==0x00000001' represent the same value. [knownConditionTrueFalse]\n", errout_str()); check("void f() {\n" " enum { Four = 4 };\n" - " if (Four == 4) {}" - "}", true, true, false); + " if (Four == 4) {}\n" + "}\n"); ASSERT_EQUALS("[test.cpp:3:14]: (style) The comparison 'Four == 4' is always true. [knownConditionTrueFalse]\n", errout_str()); check("void f() {\n" " enum { Four = 4 };\n" " static_assert(Four == 4, \"\");\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " enum { Four = 4 };\n" " _Static_assert(Four == 4, \"\");\n" - "}", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " enum { Four = 4 };\n" " static_assert(4 == Four, \"\");\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " enum { FourInEnumOne = 4 };\n" " enum { FourInEnumTwo = 4 };\n" " if (FourInEnumOne == FourInEnumTwo) {}\n" - "}", true, true, false); + "}\n"); ASSERT_EQUALS("[test.cpp:4:23]: (style) The comparison 'FourInEnumOne == FourInEnumTwo' is always true because 'FourInEnumOne' and 'FourInEnumTwo' represent the same value. [knownConditionTrueFalse]\n", errout_str()); @@ -7259,13 +7718,13 @@ class TestOther : public TestFixture { " enum { FourInEnumOne = 4 };\n" " enum { FourInEnumTwo = 4 };\n" " static_assert(FourInEnumOne == FourInEnumTwo, \"\");\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int a, int b) {\n" " if (sizeof(a) == sizeof(a)) { }\n" " if (sizeof(a) == sizeof(b)) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:19]: (style) Same expression on both sides of '=='. [duplicateExpression]\n", errout_str()); check("float bar(int) __attribute__((pure));\n" @@ -7274,7 +7733,7 @@ class TestOther : public TestFixture { " if (bar(a) == bar(a)) { }\n" " if (unknown(a) == unknown(a)) { }\n" " if (foo(a) == foo(a)) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:16]: (style) Same expression on both sides of '=='. [duplicateExpression]\n", errout_str()); } @@ -7284,25 +7743,25 @@ class TestOther : public TestFixture { " if (!(dbl == dbl)) have_nan = 1;\n" " if (flt != flt) have_nan = 1;\n" " return have_nan;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); - check("float f(float x) { return x-x; }"); // ticket #4485 (Inf) + check("float f(float x) { return x-x; }\n"); // ticket #4485 (Inf) ASSERT_EQUALS("", errout_str()); - check("float f(float x) { return (X double)x == (X double)x; }", true, false, false); + check("float f(float x) { return (X double)x == (X double)x; }\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); check("struct X { float f; };\n" - "float f(struct X x) { return x.f == x.f; }"); + "float f(struct X x) { return x.f == x.f; }\n"); ASSERT_EQUALS("", errout_str()); check("struct X { int i; };\n" - "int f(struct X x) { return x.i == x.i; }"); + "int f(struct X x) { return x.i == x.i; }\n"); ASSERT_EQUALS("[test.cpp:2:32]: (style) Same expression on both sides of '=='. [duplicateExpression]\n", errout_str()); // #5284 - when type is unknown, assume it's float - check("int f() { return x==x; }"); + check("int f() { return x==x; }\n"); ASSERT_EQUALS("", errout_str()); } @@ -7315,11 +7774,11 @@ class TestOther : public TestFixture { " \n" " \n" ""; - /*const*/ Settings settings = settingsBuilder().libraryxml(xmldata).build(); + /*const*/ Settings settings = settingsBuilder().libraryxml(xmldata).severity(Severity::style).build(); check("void foo() {\n" " if (x() || x()) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A {\n" @@ -7328,7 +7787,7 @@ class TestOther : public TestFixture { "};\n" "void A::foo() const {\n" " if (bar() && bar()) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:15]: (style) Same expression on both sides of '&&'. [duplicateExpression]\n", errout_str()); check("struct A {\n" @@ -7338,7 +7797,7 @@ class TestOther : public TestFixture { "};\n" "void A::foo() {\n" " if (bar() && bar()) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class B {\n" @@ -7352,74 +7811,74 @@ class TestOther : public TestFixture { " A a;\n" " if (b.bar(1) && b.bar(1)) {}\n" " if (a.bar(1) && a.bar(1)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:11:18]: (style) Same expression on both sides of '&&'. [duplicateExpression]\n", errout_str()); check("class D { void strcmp(); };\n" "void foo() {\n" " D d;\n" " if (d.strcmp() && d.strcmp()) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " if ((mystrcmp(a, b) == 0) || (mystrcmp(a, b) == 0)) {}\n" - "}", true, false, true, false, &settings); + "}\n", dinit(CheckOptions, $.inconclusive = false, $.settings = &settings)); ASSERT_EQUALS("[test.cpp:2:31]: (style) Same expression on both sides of '||'. [duplicateExpression]\n", errout_str()); check("void GetValue() { return rand(); }\n" "void foo() {\n" " if ((GetValue() == 0) || (GetValue() == 0)) { dostuff(); }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void __attribute__((const)) GetValue() { return X; }\n" "void foo() {\n" " if ((GetValue() == 0) || (GetValue() == 0)) { dostuff(); }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:27]: (style) Same expression on both sides of '||'. [duplicateExpression]\n", errout_str()); check("void GetValue() __attribute__((const));\n" "void GetValue() { return X; }\n" "void foo() {\n" " if ((GetValue() == 0) || (GetValue() == 0)) { dostuff(); }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:27]: (style) Same expression on both sides of '||'. [duplicateExpression]\n", errout_str()); check("void foo() {\n" " if (str == \"(\" || str == \"(\") {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:20]: (style) Same expression on both sides of '||'. [duplicateExpression]\n", errout_str()); check("void foo() {\n" " if (bar(a) && !strcmp(a, b) && bar(a) && !strcmp(a, b)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #5334 check("void f(C *src) {\n" " if (x(src) || x(src))\n" " a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(A *src) {\n" " if (dynamic_cast(src) || dynamic_cast(src)) {}\n" - "}\n", true, false, false); // don't run simplifications + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:2:31]: (style) Same expression on both sides of '||'. [duplicateExpression]\n", errout_str()); // #5819 check("Vector func(Vector vec1) {\n" " return fabs(vec1 & vec1 & vec1);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("Vector func(int vec1) {\n" " return fabs(vec1 & vec1 & vec1);\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:22]: (style) Same expression on both sides of '&'. [duplicateExpression]\n" - "[test.cpp:2:29]: (style) Same expression on both sides of '&'. [duplicateExpression]\n", // duplicate + "[test.cpp:2:29]: (style) Same expression on both sides of '&'. [duplicateExpression]\n", errout_str()); } @@ -7427,25 +7886,25 @@ class TestOther : public TestFixture { void duplicateExpression4() { check("void foo() {\n" " if (*a++ != b || *a++ != b) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " if (*a-- != b || *a-- != b) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // assignment check("void f() {\n" " while (*(a+=2)==*(b+=2) && *(a+=2)==*(b+=2)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void duplicateExpression5() { // #3749 - macros with same values check("void f() {\n" " if ($a == $a) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkP("#define X 1\n" @@ -7467,7 +7926,7 @@ class TestOther : public TestFixture { void duplicateExpression6() { // #4639 check("float IsNan(float value) { return !(value == value); }\n" "double IsNan(double value) { return !(value == value); }\n" - "long double IsNan(long double value) { return !(value == value); }"); + "long double IsNan(long double value) { return !(value == value); }\n"); ASSERT_EQUALS("", errout_str()); } @@ -7475,36 +7934,36 @@ class TestOther : public TestFixture { check("void f() {\n" " const int i = sizeof(int);\n" " if ( i != sizeof (int)){}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:25] -> [test.cpp:3:12]: (style) The comparison 'i != sizeof(int)' is always false because 'i' and 'sizeof(int)' represent the same value. [knownConditionTrueFalse]\n", errout_str()); check("void f() {\n" " const int i = sizeof(int);\n" " if ( sizeof (int) != i){}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:25] -> [test.cpp:3:23]: (style) The comparison 'sizeof(int) != i' is always false because 'sizeof(int)' and 'i' represent the same value. [knownConditionTrueFalse]\n", errout_str()); - check("void f(int a = 1) { if ( a != 1){}}"); + check("void f(int a = 1) { if ( a != 1){}}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " int a = 1;\n" " if ( a != 1){}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:13] -> [test.cpp:3:12]: (style) The comparison 'a != 1' is always false. [knownConditionTrueFalse]\n", errout_str()); check("void f() {\n" " int a = 1;\n" " int b = 1;\n" " if ( a != b){}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:13] -> [test.cpp:3:13] -> [test.cpp:4:12]: (style) The comparison 'a != b' is always false because 'a' and 'b' represent the same value. [knownConditionTrueFalse]\n", errout_str()); check("void f() {\n" " int a = 1;\n" " int b = a;\n" " if ( a != b){}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:13] -> [test.cpp:4:12]: (style) The comparison 'a != b' is always false because 'a' and 'b' represent the same value. [knownConditionTrueFalse]\n", errout_str()); check("void use(int);\n" @@ -7513,7 +7972,7 @@ class TestOther : public TestFixture { " int b = 1;\n" " use(b);\n" " if ( a != 1){}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:13] -> [test.cpp:6:12]: (style) The comparison 'a != 1' is always false. [knownConditionTrueFalse]\n", errout_str()); check("void use(int);\n" @@ -7522,7 +7981,7 @@ class TestOther : public TestFixture { " use(a);\n" " a = 2;\n" " if ( a != 1){}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void use(int);\n" @@ -7531,38 +7990,38 @@ class TestOther : public TestFixture { " use(a);\n" " a = 1;\n" " if ( a != 1){}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("const int a = 1;\n" "void f() {\n" " if ( a != 1){}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:15] -> [test.cpp:3:12]: (style) The comparison 'a != 1' is always false. [knownConditionTrueFalse]\n", errout_str()); check("int a = 1;\n" " void f() {\n" " if ( a != 1){}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " static const int a = 1;\n" " if ( a != 1){}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:26] -> [test.cpp:3:12]: (style) The comparison 'a != 1' is always false. [knownConditionTrueFalse]\n", errout_str()); check("void f() {\n" " static int a = 1;\n" " if ( a != 1){}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " int a = 1;\n" " if ( a != 1){\n" " a++;\n" - " }}"); + " }}\n"); ASSERT_EQUALS("[test.cpp:2:13] -> [test.cpp:3:12]: (style) The comparison 'a != 1' is always false. [knownConditionTrueFalse]\n", errout_str()); check("void f(int b) {\n" @@ -7571,13 +8030,13 @@ class TestOther : public TestFixture { " if ( a != 1){}\n" " a++;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("bool f(bool a, bool b) {\n" " const bool c = a;\n" " return a && b && c;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:20] -> [test.cpp:3:19]: (style) Same expression 'a' found multiple times in chain of '&&' operators because 'a' and 'c' represent the same value. [knownConditionTrueFalse]\n", errout_str()); @@ -7585,13 +8044,13 @@ class TestOther : public TestFixture { check("void f(const bool b) {\n" " const bool b1 = !b;\n" " if(!b && b1){}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:20] -> [test.cpp:3:10]: (style) Same expression on both sides of '&&' because '!b' and 'b1' represent the same value. [knownConditionTrueFalse]\n", errout_str()); // 7284 check("void f(void) {\n" " if (a || !!a) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:10]: (style) Same expression on both sides of '||' because 'a' and '!!a' represent the same value. [knownConditionTrueFalse]\n", errout_str()); // 8205 @@ -7602,7 +8061,7 @@ class TestOther : public TestFixture { " if (Diag==0) {}\n" " break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15] -> [test.cpp:5:16]: (style) The comparison 'Diag == 0' is always true. [knownConditionTrueFalse]\n", errout_str()); // #9744 @@ -7630,13 +8089,13 @@ class TestOther : public TestFixture { " int b = a;\n" " a = 2;\n" " if ( b != a){}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(int * a, int i) { int b = a[i]; a[i] = 2; if ( b != a[i]){}}"); + check("void f(int * a, int i) { int b = a[i]; a[i] = 2; if ( b != a[i]){}}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(int * a, int i) { int b = *a; *a = 2; if ( b != *a){}}"); + check("void f(int * a, int i) { int b = *a; *a = 2; if ( b != *a){}}\n"); ASSERT_EQUALS("", errout_str()); check("struct A { int f() const; };\n" @@ -7647,7 +8106,7 @@ class TestOther : public TestFixture { " x = g();\n" " if (x.f() == a) break;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f(int i);\n" @@ -7660,14 +8119,14 @@ class TestOther : public TestFixture { " const bool x = a.f(A::B);\n" " const bool y = a.f(A::C);\n" " if(!x && !y) return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " const bool x = a.f(A::B);\n" " const bool y = a.f(A::C);\n" " if (!x && !y) return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(bool * const b);\n" @@ -7676,17 +8135,17 @@ class TestOther : public TestFixture { " bool y = true;\n" " f(&x);\n" " if (!x && !y) return;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " const int a = {};\n" " if(a == 1) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("volatile const int var = 42;\n" - "void f() { if(var == 42) {} }"); + "void f() { if(var == 42) {} }\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -7695,7 +8154,7 @@ class TestOther : public TestFixture { " c.a = &a;\n" " g(&c);\n" " if (a == 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -7705,7 +8164,7 @@ class TestOther : public TestFixture { " uint16_t x = 1000;\n" " uint8_t y = x;\n" " if (x != y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -7716,7 +8175,7 @@ class TestOther : public TestFixture { " const int b = a-1;\n" " const int c = a+1;\n" " return c;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -7725,7 +8184,7 @@ class TestOther : public TestFixture { "public:\n" " double getScale() const { return m_range * m_zoom; }\n" " void setZoom(double z) { m_zoom = z; }\n" - " void dostuff(int);\n" + " void dostuff(int x);\n" "private:\n" " double m_zoom;\n" " double m_range;\n" @@ -7737,7 +8196,7 @@ class TestOther : public TestFixture { " setZoom(m_zoom + 1);\n" " double scale_ratio = getScale() / old_scale;\n" // <- FP " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -7746,14 +8205,14 @@ class TestOther : public TestFixture { "{\n" " int var = buffer[index - 1];\n" " return buffer[index - 1] - var;\n" // << - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:25] -> [test.cpp:4:34]: (style) Same expression on both sides of '-' because 'buffer[index-1]' and 'var' represent the same value. [duplicateExpression]\n", errout_str()); } void duplicateExpression13() { //#7899 check("void f() {\n" " if (sizeof(long) == sizeof(long long)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -7876,27 +8335,99 @@ class TestOther : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void duplicateExpression19() { + checkP("const int i = 0;\n" + "void f() {\n" + " assert(i == 0);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + + void duplicateExpression20() { + check("enum { N = 1 };\n" // #14202 + "int f() { return N - 1; }\n"); + ASSERT_EQUALS("", errout_str()); + } + + void duplicateExpression21() { + check("struct S { int i; };\n" // #12795 + "struct T {\n" + " std::map m;\n" + " S* get(const std::string& s) { return m[s]; }\n" + " void modify() { for (const auto& e : m) e.second->i = 0; }\n" + "};\n" + "void f(T& t) {\n" + " const S* p = t.get(\"abc\");\n" + " const int o = p->i;\n" + " t.modify();\n" + " if (p->i == o) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct S { int i; };\n" + " struct T {\n" + " std::vector m;\n" + " void modify() { for (auto e : m) e->i = 0; }\n" + "};\n" + "void f(T& t) {\n" + " const S* p = t.m[0];\n" + " const int o = p->i;\n" + " t.modify();\n" + " if (p->i == o) {}\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + + void duplicateExpression22() { + check("int f() {\n" // #14913 + " return 0x1 | (0x2 | 0x4) | 0x1;\n" + "}\n" + "int g() {\n" + " return 0x1 | (0x2 | 0x1);\n" + "}\n" + "int h() {\n" + " return 0x1 | (0x1 | 0x2);\n" + "}\n" + "int i() {\n" + " return 0x2 | (0x4 | 0x1) | 0x1;\n" + "}\n" + "int j() {\n" + " return 0x2 | (0x1 | 0x4) | 0x1;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:30]: (style) Same expression '0x1' found multiple times in chain of '|' operators. [duplicateExpression]\n" + "[test.cpp:5:23]: (style) Same expression '0x1' found multiple times in chain of '|' operators. [duplicateExpression]\n" + "[test.cpp:8:23]: (style) Same expression '0x1' found multiple times in chain of '|' operators. [duplicateExpression]\n" + "[test.cpp:11:23]: (style) Same expression '0x1' found multiple times in chain of '|' operators. [duplicateExpression]\n" + "[test.cpp:14:23]: (style) Same expression '0x1' found multiple times in chain of '|' operators. [duplicateExpression]\n", + errout_str()); + + check("bool f(const int** a, const int** b) {\n" + " return (a[0] != nullptr) != (b[0] != nullptr);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void duplicateExpressionLoop() { check("void f() {\n" " int a = 1;\n" " while ( a != 1){}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:13] -> [test.cpp:3:15]: (style) The comparison 'a != 1' is always false. [knownConditionTrueFalse]\n", errout_str()); - check("void f() { int a = 1; while ( a != 1){ a++; }}"); + check("void f() { int a = 1; while ( a != 1){ a++; }}\n"); ASSERT_EQUALS("", errout_str()); - check("void f() { int a = 1; for ( int i=0; i < 3 && a != 1; i++){ a++; }}"); + check("void f() { int a = 1; for ( int i=0; i < 3 && a != 1; i++){ a++; }}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(int b) { int a = 1; while (b) { if ( a != 1){} b++; } a++; }"); + check("void f(int b) { int a = 1; while (b) { if ( a != 1){} b++; } a++; }\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " for(int i = 0; i < 10;) {\n" " if( i != 0 ) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:17] -> [test.cpp:3:15]: (style) The comparison 'i != 0' is always false. [knownConditionTrueFalse]\n", errout_str()); check("void f() {\n" @@ -7904,7 +8435,7 @@ class TestOther : public TestFixture { " if( i != 0 ) {}\n" " i++;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -7912,14 +8443,14 @@ class TestOther : public TestFixture { " if( i != 0 ) { i++; }\n" " i++;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " for(int i = 0; i < 10;) {\n" " if( i != 0 ) { i++; }\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -7928,7 +8459,7 @@ class TestOther : public TestFixture { " if( i != 0 ) {}\n" " i++;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int b) {\n" @@ -7937,7 +8468,7 @@ class TestOther : public TestFixture { " if ( a != 1){}\n" " b++;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:17] -> [test.cpp:4:16]: (style) The comparison 'a != 1' is always false. [knownConditionTrueFalse]\n", errout_str()); check("struct T {\n" // #11083 @@ -7966,52 +8497,61 @@ class TestOther : public TestFixture { " }\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("void f(const std::vector& v) {\n" // #14193 + " for (const int& r1 : v) {\n" + " for (const int& r2 : v) {\n" + " if (&r1 == &r2) {}\n" + " }\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void duplicateExpressionTernary() { // #6391 check("void f() {\n" " return A ? x : x;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:18]: (style) Same expression in both branches of ternary operator. [duplicateExpressionTernary]\n", errout_str()); check("int f(bool b, int a) {\n" " const int c = a;\n" " return b ? a : c;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:19] -> [test.cpp:3:18]: (style) Same expression in both branches of ternary operator. [duplicateExpressionTernary]\n", errout_str()); check("void f() {\n" " return A ? x : z;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(unsigned char c) {\n" " x = y ? (signed char)c : (unsigned char)c;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("std::string stringMerge(std::string const& x, std::string const& y) {\n" // #7938 " return ((x > y) ? (y + x) : (x + y));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #6426 { const char code[] = "void foo(bool flag) {\n" " bar( (flag) ? ~0u : ~0ul);\n" - "}"; - /*const*/ Settings settings = _settings; + "}\n"; + /*const*/ Settings settings = settings1; settings.platform.sizeof_int = 4; settings.platform.int_bit = 32; settings.platform.sizeof_long = 4; settings.platform.long_bit = 32; - check(code, &settings); + check(code, dinit(CheckOptions, $.settings = &settings)); ASSERT_EQUALS("[test.cpp:2:21]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); settings.platform.sizeof_long = 8; settings.platform.long_bit = 64; - check(code, &settings); + check(code, dinit(CheckOptions, $.settings = &settings)); ASSERT_EQUALS("", errout_str()); } } @@ -8019,32 +8559,32 @@ class TestOther : public TestFixture { void duplicateValueTernary() { check("void f() {\n" " if( a ? (b ? false:false): false ) ;\n" - "}"); - ASSERT_EQUALS("[test.cpp:2:23]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); + "}\n"); + ASSERT_EQUALS("[test.cpp:2:23]: (style) Same expression in both branches of ternary operator. [duplicateExpressionTernary]\n", errout_str()); - check("int f1(int a) {return (a == 1) ? (int)1 : 1; }"); + check("int f1(int a) {return (a == 1) ? (int)1 : 1; }\n"); ASSERT_EQUALS("[test.cpp:1:41]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); - check("int f2(int a) {return (a == 1) ? (int)1 : (int)1; }"); - ASSERT_EQUALS("[test.cpp:1:41]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); + check("int f2(int a) {return (a == 1) ? (int)1 : (int)1; }\n"); + ASSERT_EQUALS("[test.cpp:1:41]: (style) Same expression in both branches of ternary operator. [duplicateExpressionTernary]\n", errout_str()); - check("int f3(int a) {return (a == 1) ? 1 : (int)1; }"); + check("int f3(int a) {return (a == 1) ? 1 : (int)1; }\n"); ASSERT_EQUALS("[test.cpp:1:36]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); - check("int f4(int a) {return (a == 1) ? 1 : 1; }"); - ASSERT_EQUALS("[test.cpp:1:36]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); + check("int f4(int a) {return (a == 1) ? 1 : 1; }\n"); + ASSERT_EQUALS("[test.cpp:1:36]: (style) Same expression in both branches of ternary operator. [duplicateExpressionTernary]\n", errout_str()); - check("int f5(int a) {return (a == (int)1) ? (int)1 : 1; }"); + check("int f5(int a) {return (a == (int)1) ? (int)1 : 1; }\n"); ASSERT_EQUALS("[test.cpp:1:46]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); - check("int f6(int a) {return (a == (int)1) ? (int)1 : (int)1; }"); - ASSERT_EQUALS("[test.cpp:1:46]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); + check("int f6(int a) {return (a == (int)1) ? (int)1 : (int)1; }\n"); + ASSERT_EQUALS("[test.cpp:1:46]: (style) Same expression in both branches of ternary operator. [duplicateExpressionTernary]\n", errout_str()); - check("int f7(int a) {return (a == (int)1) ? 1 : (int)1; }"); + check("int f7(int a) {return (a == (int)1) ? 1 : (int)1; }\n"); ASSERT_EQUALS("[test.cpp:1:41]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); - check("int f8(int a) {return (a == (int)1) ? 1 : 1; }"); - ASSERT_EQUALS("[test.cpp:1:41]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); + check("int f8(int a) {return (a == (int)1) ? 1 : 1; }\n"); + ASSERT_EQUALS("[test.cpp:1:41]: (style) Same expression in both branches of ternary operator. [duplicateExpressionTernary]\n", errout_str()); check("struct Foo {\n" " std::vector bar{1,2,3};\n" @@ -8082,6 +8622,26 @@ class TestOther : public TestFixture { " return (x >= 0.0) ? 0.0 : -0.0;\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("struct A {};\n" // # 14300 + "struct B {};\n" + "void f(bool x) {\n" + " A* a = new A();\n" + " B* b = new B();\n" + " auto p = x ? static_cast(a) : static_cast(b);\n" + " (void)p;\n" + " delete a;\n" + " delete b;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + + void duplicateValueTernarySizeof() { // #13773 + check("int f() { return x ? sizeof(uint32_t) : sizeof(unsigned int); }\n"); + ASSERT_EQUALS("", errout_str()); + + check("int f() { return x ? sizeof(uint32_t) : sizeof(uint32_t); }\n"); + ASSERT_EQUALS("[test.cpp:1:39]: (style) Same expression in both branches of ternary operator. [duplicateExpressionTernary]\n", errout_str()); } void duplicateExpressionTemplate() { @@ -8089,7 +8649,7 @@ class TestOther : public TestFixture { " if (I >= 0 && I < 3) {}\n" "}\n" "\n" - "static auto a = f<0>();"); + "static auto a = f<0>();\n"); ASSERT_EQUALS("", errout_str()); check("template\n" // #7754 @@ -8175,35 +8735,35 @@ class TestOther : public TestFixture { } void oppositeExpression() { - check("void f(bool a) { if(a && !a) {} }"); + check("void f(bool a) { if(a && !a) {} }\n"); ASSERT_EQUALS("[test.cpp:1:23]: (style) Opposite expression on both sides of '&&'. [oppositeExpression]\n", errout_str()); - check("void f(bool a) { if(a != !a) {} }"); + check("void f(bool a) { if(a != !a) {} }\n"); ASSERT_EQUALS("[test.cpp:1:23]: (style) Opposite expression on both sides of '!='. [oppositeExpression]\n", errout_str()); - check("void f(bool a) { if( a == !(a) ) {}}"); + check("void f(bool a) { if( a == !(a) ) {}}\n"); ASSERT_EQUALS("[test.cpp:1:24]: (style) Opposite expression on both sides of '=='. [oppositeExpression]\n", errout_str()); - check("void f(bool a) { if( a != !(a) ) {}}"); + check("void f(bool a) { if( a != !(a) ) {}}\n"); ASSERT_EQUALS("[test.cpp:1:24]: (style) Opposite expression on both sides of '!='. [oppositeExpression]\n", errout_str()); - check("void f(bool a) { if( !(a) == a ) {}}"); + check("void f(bool a) { if( !(a) == a ) {}}\n"); ASSERT_EQUALS("[test.cpp:1:27]: (style) Opposite expression on both sides of '=='. [oppositeExpression]\n", errout_str()); - check("void f(bool a) { if( !(a) != a ) {}}"); + check("void f(bool a) { if( !(a) != a ) {}}\n"); ASSERT_EQUALS("[test.cpp:1:27]: (style) Opposite expression on both sides of '!='. [oppositeExpression]\n", errout_str()); - check("void f(bool a) { if( !(!a) == !(a) ) {}}"); + check("void f(bool a) { if( !(!a) == !(a) ) {}}\n"); ASSERT_EQUALS("[test.cpp:1:28]: (style) Opposite expression on both sides of '=='. [oppositeExpression]\n", errout_str()); - check("void f(bool a) { if( !(!a) != !(a) ) {}}"); + check("void f(bool a) { if( !(!a) != !(a) ) {}}\n"); ASSERT_EQUALS("[test.cpp:1:28]: (style) Opposite expression on both sides of '!='. [oppositeExpression]\n", errout_str()); check("void f1(bool a) {\n" " const bool b = a;\n" " if( a == !(b) ) {}\n" " if( b == !(a) ) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:20] -> [test.cpp:3:11]: (style) Opposite expression on both sides of '=='. [oppositeExpression]\n" "[test.cpp:2:20] -> [test.cpp:4:11]: (style) Opposite expression on both sides of '=='. [oppositeExpression]\n", errout_str()); @@ -8211,26 +8771,26 @@ class TestOther : public TestFixture { " const bool b = *a;\n" " if( *a == !(b) ) {}\n" " if( b == !(*a) ) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:20] -> [test.cpp:3:12]: (style) Opposite expression on both sides of '=='. [oppositeExpression]\n" "[test.cpp:2:20] -> [test.cpp:4:11]: (style) Opposite expression on both sides of '=='. [oppositeExpression]\n", errout_str()); - check("void f(bool a) { a = !a; }"); + check("void f(bool a) { a = !a; }\n"); ASSERT_EQUALS("", errout_str()); - check("void f(int a) { if( a < -a ) {}}"); + check("void f(int a) { if( a < -a ) {}}\n"); ASSERT_EQUALS("[test.cpp:1:23]: (style) Opposite expression on both sides of '<'. [oppositeExpression]\n", errout_str()); - check("void f(int a) { a -= -a; }"); + check("void f(int a) { a -= -a; }\n"); ASSERT_EQUALS("", errout_str()); - check("void f(int a) { a = a / (-a); }"); + check("void f(int a) { a = a / (-a); }\n"); ASSERT_EQUALS("", errout_str()); - check("bool f(int i){ return !((i - 1) & i); }"); + check("bool f(int i){ return !((i - 1) & i); }\n"); ASSERT_EQUALS("", errout_str()); - check("bool f(unsigned i){ return (x > 0) && (x & (x-1)) == 0; }"); + check("bool f(unsigned i){ return (x > 0) && (x & (x-1)) == 0; }\n"); ASSERT_EQUALS("", errout_str()); check("void A::f(bool a, bool c)\n" @@ -8238,27 +8798,27 @@ class TestOther : public TestFixture { " const bool b = a;\n" " if(c) { a = false; }\n" " if(b && !a) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(bool c) {\n" " const bool b = a;\n" " if(c) { a = false; }\n" " if(b && !a) { }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " bool x = a;\n" " dostuff();\n" " if (x && a) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " const bool b = g();\n" " if (!b && g()) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(const bool *a) {\n" @@ -8301,7 +8861,7 @@ class TestOther : public TestFixture { "void test() {\n" " int i = f();\n" " int j = f();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:9] -> [test.cpp:4:9]: (style) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); check("struct Foo { int f() const; int g() const; };\n" @@ -8309,7 +8869,7 @@ class TestOther : public TestFixture { " Foo f = Foo{};\n" " int i = f.f();\n" " int j = f.f();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:9] -> [test.cpp:4:9]: (style) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); check("struct Foo { int f() const; int g() const; };\n" @@ -8318,7 +8878,7 @@ class TestOther : public TestFixture { " Foo f2 = Foo{};\n" " int i = f.f();\n" " int j = f.f();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:9] -> [test.cpp:5:9]: (style) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); check("int f() __attribute__((pure));\n" @@ -8326,7 +8886,7 @@ class TestOther : public TestFixture { "void test() {\n" " int i = 1 + f();\n" " int j = 1 + f();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:9] -> [test.cpp:4:9]: (style) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); check("int f() __attribute__((pure));\n" @@ -8334,7 +8894,7 @@ class TestOther : public TestFixture { "void test() {\n" " int i = f() + 1;\n" " int j = 1 + f();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f() __attribute__((pure));\n" @@ -8343,7 +8903,7 @@ class TestOther : public TestFixture { " int x = f();\n" " int i = x + 1;\n" " int j = f() + 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f() __attribute__((pure));\n" @@ -8351,7 +8911,7 @@ class TestOther : public TestFixture { "void test() {\n" " int i = f() + f();\n" " int j = f() + f();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:9] -> [test.cpp:4:9]: (style) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); check("int f(int) __attribute__((pure));\n" @@ -8359,7 +8919,7 @@ class TestOther : public TestFixture { "void test() {\n" " int i = f(0);\n" " int j = f(0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:9] -> [test.cpp:4:9]: (style) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); check("int f(int) __attribute__((pure));\n" @@ -8368,39 +8928,39 @@ class TestOther : public TestFixture { " const int x = 0;\n" " int i = f(0);\n" " int j = f(x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void test(const int * p, const int * q) {\n" " int i = *p;\n" " int j = *p;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9] -> [test.cpp:2:9]: (style) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); check("struct A { int x; int y; };" "void test(A a) {\n" " int i = a.x;\n" " int j = a.x;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9] -> [test.cpp:2:9]: (style) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); check("void test() {\n" " int i = 0;\n" " int j = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void test() {\n" " int i = -1;\n" " int j = -1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f(int);\n" "void test() {\n" " int i = f(0);\n" " int j = f(1);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int f();\n" @@ -8408,21 +8968,21 @@ class TestOther : public TestFixture { "void test() {\n" " int i = f() || f();\n" " int j = f() && f();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct Foo {};\n" "void test() {\n" " Foo i = Foo();\n" " Foo j = Foo();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct Foo {};\n" "void test() {\n" " Foo i = Foo{};\n" " Foo j = Foo{};\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct Foo { int f() const; float g() const; };\n" @@ -8430,7 +8990,7 @@ class TestOther : public TestFixture { " Foo f = Foo{};\n" " int i = f.f();\n" " int j = f.f();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:9] -> [test.cpp:4:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); check("struct Foo { int f(); int g(); };\n" @@ -8438,43 +8998,43 @@ class TestOther : public TestFixture { " Foo f = Foo{};\n" " int i = f.f();\n" " int j = f.f();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void test() {\n" " int i = f();\n" " int j = f();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void test(int x) {\n" " int i = ++x;\n" " int j = ++x;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void test(int x) {\n" " int i = x++;\n" " int j = x++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void test(int x) {\n" " int i = --x;\n" " int j = --x;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void test(int x) {\n" " int i = x--;\n" " int j = x--;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void test(int x) {\n" " int i = x + 1;\n" " int j = 1 + x;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -8483,7 +9043,7 @@ class TestOther : public TestFixture { "void foo(SW* x) {\n" " int start = x->first;\n" " int end = x->first;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'start' and 'end'. [duplicateAssignExpression]\n" "[test.cpp:2:14]: (style) Parameter 'x' can be declared as pointer to const [constParameterPointer]\n", errout_str()); @@ -8492,7 +9052,7 @@ class TestOther : public TestFixture { "void foo(SW* x, int i, int j) {\n" " int start = x->first;\n" " int end = x->first;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'start' and 'end'. [duplicateAssignExpression]\n" "[test.cpp:2:14]: (style) Parameter 'x' can be declared as pointer to const [constParameterPointer]\n", errout_str()); @@ -8502,13 +9062,13 @@ class TestOther : public TestFixture { " Foo f = Foo{};\n" " int i = f.f();\n" " int j = f.f();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:9] -> [test.cpp:4:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); check("void test(const int * p) {\n" " int i = *p;\n" " int j = *p;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9] -> [test.cpp:2:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); check("struct Foo { int f() const; int g(int) const; };\n" @@ -8516,7 +9076,7 @@ class TestOther : public TestFixture { " Foo f = Foo{};\n" " int i = f.f();\n" " int j = f.f();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:9] -> [test.cpp:4:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); check("struct Foo { int f() const; };\n" @@ -8524,7 +9084,7 @@ class TestOther : public TestFixture { " Foo f = Foo{};\n" " int i = f.f();\n" " int j = f.f();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:9] -> [test.cpp:4:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); } @@ -8536,7 +9096,7 @@ class TestOther : public TestFixture { " int j = a.x;\n" " use(i);\n" " i = j;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); check("struct A { int x; int y; };" @@ -8546,7 +9106,7 @@ class TestOther : public TestFixture { " int j = a.x;\n" " use(j);\n" " j = i;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); check("struct A { int x; int y; };" @@ -8556,10 +9116,9 @@ class TestOther : public TestFixture { " int j = a.x;\n" " use(j);\n" " if (i == j) {}\n" - "}"); + "}\n"); ASSERT_EQUALS( - "[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n" - "[test.cpp:3:14] -> [test.cpp:4:14] -> [test.cpp:6:11]: (style) The comparison 'i == j' is always true because 'i' and 'j' represent the same value. [knownConditionTrueFalse]\n", + "[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); check("struct A { int x; int y; };" @@ -8569,10 +9128,9 @@ class TestOther : public TestFixture { " int j = a.x;\n" " use(j);\n" " if (i == a.x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS( - "[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n" - "[test.cpp:3:14] -> [test.cpp:6:11]: (style) The comparison 'i == a.x' is always true because 'i' and 'a.x' represent the same value. [knownConditionTrueFalse]\n", + "[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); check("struct A { int x; int y; };" @@ -8582,10 +9140,9 @@ class TestOther : public TestFixture { " int j = a.x;\n" " use(i);\n" " if (j == a.x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS( - "[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n" - "[test.cpp:4:14] -> [test.cpp:6:11]: (style) The comparison 'j == a.x' is always true because 'j' and 'a.x' represent the same value. [knownConditionTrueFalse]\n", + "[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n", errout_str()); // Issue #8612 @@ -8614,7 +9171,7 @@ class TestOther : public TestFixture { " }\n" " previous = current;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:16:7] -> [test.cpp:15:7]: (style, inconclusive) Same expression used in consecutive assignments of 'current' and 'previous'. [duplicateAssignExpression]\n", errout_str()); } @@ -8630,21 +9187,21 @@ class TestOther : public TestFixture { " int b = x.f();\n" " (void)a;\n" " (void)b;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:13] -> [test.cpp:7:13]: (style, inconclusive) Same expression used in consecutive assignments of 'a' and 'b'. [duplicateAssignExpression]\n", errout_str()); // Issue #8712 check("void f() {\n" " unsigned char d;\n" " d = d % 5;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("template \n" "T f() {\n" " T x = T();\n" "}\n" - "int &a = f();"); + "int &a = f();\n"); ASSERT_EQUALS("", errout_str()); // Issue #8713 @@ -8656,7 +9213,7 @@ class TestOther : public TestFixture { " uint32_t a = 42;\n" " uint32_t b = uint32_t(A ::B / 1024);\n" " int32_t c = int32_t(a / b);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Issue #8709 @@ -8665,7 +9222,7 @@ class TestOther : public TestFixture { " switch (d) { case b:; }\n" " double e(b);\n" " if(e <= 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #10718 @@ -8686,7 +9243,7 @@ class TestOther : public TestFixture { " int val = 0;\n" " if (val < 0) continue;\n" " if ((val > 0)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:13] -> [test.cpp:3:11]: (style) The comparison 'val < 0' is always false. [knownConditionTrueFalse]\n" "[test.cpp:2:13] -> [test.cpp:4:12]: (style) The comparison 'val > 0' is always false. [knownConditionTrueFalse]\n", errout_str()); @@ -8717,7 +9274,7 @@ class TestOther : public TestFixture { " if (val < 0) {\n" " if ((val > 0)) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:13] -> [test.cpp:3:11]: (style) The comparison 'val < 0' is always false. [knownConditionTrueFalse]\n" "[test.cpp:2:13] -> [test.cpp:4:14]: (style) The comparison 'val > 0' is always false. [knownConditionTrueFalse]\n", errout_str()); @@ -8726,7 +9283,7 @@ class TestOther : public TestFixture { " if (val < 0) {\n" " if ((val < 0)) {}\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:13] -> [test.cpp:3:11]: (style) The comparison 'val < 0' is always false. [knownConditionTrueFalse]\n" "[test.cpp:2:13] -> [test.cpp:4:14]: (style) The comparison 'val < 0' is always false. [knownConditionTrueFalse]\n", errout_str()); @@ -8735,49 +9292,49 @@ class TestOther : public TestFixture { " int foo = 0;\n" " if (activate) {}\n" " else if (foo) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void checkSignOfUnsignedVariable() { check("void foo() {\n" " for(unsigned char i = 10; i >= 0; i--) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:31]: (style) Unsigned expression 'i' can't be negative so it is unnecessary to test it. [unsignedPositive]\n", errout_str()); check("void foo(bool b) {\n" " for(unsigned int i = 10; b || i >= 0; i--) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:35]: (style) Unsigned expression 'i' can't be negative so it is unnecessary to test it. [unsignedPositive]\n", errout_str()); { const char code[] = "void foo(unsigned int x) {\n" " if (x < 0) {}\n" - "}"; - check(code, true, false, true, false); + "}\n"; + check(code, dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:2:9]: (style) Checking if unsigned expression 'x' is less than zero. [unsignedLessThanZero]\n", errout_str()); - check(code, true, false, true, true); + check(code, dinit(CheckOptions, $.inconclusive = false, $.verbose = true)); ASSERT_EQUALS("[test.cpp:2:9]: (style) Checking if unsigned expression 'x' is less than zero. [unsignedLessThanZero]\n", errout_str()); } check("void foo(unsigned int x) {\n" " if (x < 0u) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) Checking if unsigned expression 'x' is less than zero. [unsignedLessThanZero]\n", errout_str()); check("void foo(int x) {\n" " if (x < 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); { const char code[] = "void foo(unsigned x) {\n" " int y = 0;\n" " if (x < y) {}\n" - "}"; - check(code, true, false, true, false); + "}\n"; + check(code, dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:3:9]: (style) Checking if unsigned expression 'x' is less than zero. [unsignedLessThanZero]\n", errout_str()); - check(code, true, false, true, true); + check(code, dinit(CheckOptions, $.inconclusive = false, $.verbose = true)); ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:9]: (style) Checking if unsigned expression 'x' is less than zero. [unsignedLessThanZero]\n", errout_str()); } check("void foo(unsigned x) {\n" @@ -8785,149 +9342,149 @@ class TestOther : public TestFixture { " if (b)\n" " y = 1;\n" " if (x < y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(unsigned int x) {\n" " if (0 > x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) Checking if unsigned expression 'x' is less than zero. [unsignedLessThanZero]\n", errout_str()); check("void foo(unsigned int x) {\n" " if (0UL > x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Checking if unsigned expression 'x' is less than zero. [unsignedLessThanZero]\n", errout_str()); check("void foo(int x) {\n" " if (0 > x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(unsigned int x) {\n" " if (x >= 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) Unsigned expression 'x' can't be negative so it is unnecessary to test it. [unsignedPositive]\n", errout_str()); check("void foo(unsigned int x, unsigned y) {\n" " if (x - y >= 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:13]: (style) Unsigned expression 'x-y' can't be negative so it is unnecessary to test it. [unsignedPositive]\n", errout_str()); check("void foo(unsigned int x) {\n" " if (x >= 0ull) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) Unsigned expression 'x' can't be negative so it is unnecessary to test it. [unsignedPositive]\n", errout_str()); check("void foo(int x) {\n" " if (x >= 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(unsigned int x) {\n" " if (0 <= x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) Unsigned expression 'x' can't be negative so it is unnecessary to test it. [unsignedPositive]\n", errout_str()); check("void foo(unsigned int x) {\n" " if (0ll <= x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (style) Unsigned expression 'x' can't be negative so it is unnecessary to test it. [unsignedPositive]\n", errout_str()); check("void foo(int x) {\n" " if (0 <= x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(unsigned int x, bool y) {\n" " if (x < 0 && y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) Checking if unsigned expression 'x' is less than zero. [unsignedLessThanZero]\n", errout_str()); check("void foo(int x, bool y) {\n" " if (x < 0 && y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(unsigned int x, bool y) {\n" " if (0 > x && y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) Checking if unsigned expression 'x' is less than zero. [unsignedLessThanZero]\n", errout_str()); check("void foo(int x, bool y) {\n" " if (0 > x && y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(unsigned int x, bool y) {\n" " if (x >= 0 && y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) Unsigned expression 'x' can't be negative so it is unnecessary to test it. [unsignedPositive]\n", errout_str()); check("void foo(int x, bool y) {\n" " if (x >= 0 && y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(unsigned int x, bool y) {\n" " if (y && x < 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:14]: (style) Checking if unsigned expression 'x' is less than zero. [unsignedLessThanZero]\n", errout_str()); check("void foo(int x, bool y) {\n" " if (y && x < 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(unsigned int x, bool y) {\n" " if (y && 0 > x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:14]: (style) Checking if unsigned expression 'x' is less than zero. [unsignedLessThanZero]\n", errout_str()); check("void foo(int x, bool y) {\n" " if (y && 0 > x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(unsigned int x, bool y) {\n" " if (y && x >= 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:14]: (style) Unsigned expression 'x' can't be negative so it is unnecessary to test it. [unsignedPositive]\n", errout_str()); check("void foo(int x, bool y) {\n" " if (y && x >= 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(unsigned int x, bool y) {\n" " if (x < 0 || y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) Checking if unsigned expression 'x' is less than zero. [unsignedLessThanZero]\n", errout_str()); check("void foo(int x, bool y) {\n" " if (x < 0 || y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(unsigned int x, bool y) {\n" " if (0 > x || y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) Checking if unsigned expression 'x' is less than zero. [unsignedLessThanZero]\n", errout_str()); check("void foo(int x, bool y) {\n" " if (0 > x || y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(unsigned int x, bool y) {\n" " if (x >= 0 || y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) Unsigned expression 'x' can't be negative so it is unnecessary to test it. [unsignedPositive]\n", errout_str()); check("void foo(int x, bool y) {\n" " if (x >= 0 || y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #3233 - FP when template is used (template parameter is numeric constant) @@ -8935,17 +9492,17 @@ class TestOther : public TestFixture { const char code[] = "template void foo(unsigned int x) {\n" " if (x <= n);\n" "}\n" - "foo<0>();"; - check(code, true, false); + "foo<0>();\n"; + check(code, dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); - check(code, true, true); + check(code); ASSERT_EQUALS("", errout_str()); } { check("template void foo(unsigned int x) {\n" "if (x <= 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:7]: (style) Checking if unsigned expression 'x' is less than zero. [unsignedLessThanZero]\n", errout_str()); } @@ -8956,16 +9513,16 @@ class TestOther : public TestFixture { " {\n" " value = 0u;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:13]: (style) Checking if unsigned expression 'value' is less than zero. [unsignedLessThanZero]\n", errout_str()); // #9040 - /*const*/ Settings settings1 = settingsBuilder().platform(Platform::Type::Win64).build(); + /*const*/ Settings settingsWin64 = settingsBuilder().platform(Platform::Type::Win64).build(); check("using BOOL = unsigned;\n" "int i;\n" "bool f() {\n" " return i >= 0;\n" - "}\n", &settings1); + "}\n", dinit(CheckOptions, $.settings = &settingsWin64)); ASSERT_EQUALS("", errout_str()); // #10612 @@ -8973,7 +9530,7 @@ class TestOther : public TestFixture { " const uint32_t x = 0;\n" " constexpr const auto y = 0xFFFFU;\n" " if (y < x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:10]: (style) Checking if unsigned expression 'y' is less than zero. [unsignedLessThanZero]\n", errout_str()); // #12387 @@ -8985,83 +9542,101 @@ class TestOther : public TestFixture { "}\n" "void g() {\n" " f(0);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #13734 check("void f() {\n" " uint8_t a[N + 1];\n" " for (unsigned p = 0; p < (sizeof(a) / sizeof((a)[0])); ++p) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); + + check("void f(const unsigned char u) {\n" + " if (u > 0) {}\n" + " if (u < 0) {}\n" + " if (u >= 0) {}\n" + " if (u <= 0) {}\n" + " if (0 < u) {}\n" + " if (0 > u) {}\n" + " if (0 <= u) {}\n" + " if (0 >= u) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:11]: (style) Checking if unsigned expression 'u' is less than zero. [unsignedLessThanZero]\n" + "[test.cpp:4:11]: (style) Unsigned expression 'u' can't be negative so it is unnecessary to test it. [unsignedPositive]\n" + "[test.cpp:5:11]: (style) Checking if unsigned expression 'u' is less than zero. [unsignedLessThanZero]\n" + "[test.cpp:7:11]: (style) Checking if unsigned expression 'u' is less than zero. [unsignedLessThanZero]\n" + "[test.cpp:8:11]: (style) Unsigned expression 'u' can't be negative so it is unnecessary to test it. [unsignedPositive]\n" + "[test.cpp:9:11]: (style) Checking if unsigned expression 'u' is less than zero. [unsignedLessThanZero]\n", + errout_str()); } void checkSignOfPointer() { check("void foo(const int* x) {\n" " if (x >= 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) A pointer can not be negative so it is either pointless or an error to check if it is not. [pointerPositive]\n", errout_str()); { const char code[] = "void foo(const int* x) {\n" " int y = 0;\n" " if (x >= y) {}\n" - "}"; - check(code, true, false, true, false); + "}\n"; + check(code, dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:3:9]: (style) A pointer can not be negative so it is either pointless or an error to check if it is not. [pointerPositive]\n", errout_str()); - check(code, true, false, true, true); + check(code, dinit(CheckOptions, $.inconclusive = false, $.verbose = true)); ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:9]: (style) A pointer can not be negative so it is either pointless or an error to check if it is not. [pointerPositive]\n", errout_str()); } check("void foo(const int* x) {\n" " if (*x >= 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(const int* x) {\n" " if (x < 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) A pointer can not be negative so it is either pointless or an error to check if it is. [pointerLessThanZero]\n", errout_str()); { const char code[] = "void foo(const int* x) {\n" " unsigned y = 0u;\n" " if (x < y) {}\n" - "}"; + "}\n"; - check(code, true, false, true, false); + check(code, dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:3:9]: (style) A pointer can not be negative so it is either pointless or an error to check if it is. [pointerLessThanZero]\n", errout_str()); - check(code, true, false, true, true); + check(code, dinit(CheckOptions, $.inconclusive = false, $.verbose = true)); ASSERT_EQUALS("[test.cpp:2:16] -> [test.cpp:3:9]: (style) A pointer can not be negative so it is either pointless or an error to check if it is. [pointerLessThanZero]\n", errout_str()); } check("void foo(const int* x) {\n" " if (*x < 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(const int* x, const int* y) {\n" " if (x - y < 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(const int* x, const int* y) {\n" " if (x - y <= 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(const int* x, const int* y) {\n" " if (x - y > 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(const int* x, const int* y) {\n" " if (x - y >= 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(const Bar* x) {\n" " if (0 <= x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) A pointer can not be negative so it is either pointless or an error to check if it is not. [pointerPositive]\n", errout_str()); check("struct S {\n" @@ -9069,7 +9644,7 @@ class TestOther : public TestFixture { "};\n" "void foo(S* first) {\n" " if (first.ptr >= 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:17]: (style) A pointer can not be negative so it is either pointless or an error to check if it is not. [pointerPositive]\n" "[test.cpp:4:13]: (style) Parameter 'first' can be declared as pointer to const [constParameterPointer]\n", errout_str()); @@ -9079,7 +9654,7 @@ class TestOther : public TestFixture { "};\n" "void foo(S* first, S* second) {\n" " if((first.ptr - second.ptr) >= 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:13]: (style) Parameter 'first' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:4:23]: (style) Parameter 'second' can be declared as pointer to const [constParameterPointer]\n", errout_str()); @@ -9089,7 +9664,7 @@ class TestOther : public TestFixture { "};\n" "void foo(S* first) {\n" " if((first.ptr) >= 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:18]: (style) A pointer can not be negative so it is either pointless or an error to check if it is not. [pointerPositive]\n" "[test.cpp:4:13]: (style) Parameter 'first' can be declared as pointer to const [constParameterPointer]\n", errout_str()); @@ -9099,7 +9674,7 @@ class TestOther : public TestFixture { "};\n" "void foo(S* first, S* second) {\n" " if(0 <= first.ptr - second.ptr) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:13]: (style) Parameter 'first' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:4:23]: (style) Parameter 'second' can be declared as pointer to const [constParameterPointer]\n", errout_str()); @@ -9109,7 +9684,7 @@ class TestOther : public TestFixture { "};\n" "void foo(S* first, S* second) {\n" " if(0 <= (first.ptr - second.ptr)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:13]: (style) Parameter 'first' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:4:23]: (style) Parameter 'second' can be declared as pointer to const [constParameterPointer]\n", errout_str()); @@ -9119,7 +9694,7 @@ class TestOther : public TestFixture { "};\n" "void foo(S* first, S* second) {\n" " if(first.ptr - second.ptr < 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:13]: (style) Parameter 'first' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:4:23]: (style) Parameter 'second' can be declared as pointer to const [constParameterPointer]\n", errout_str()); @@ -9129,7 +9704,7 @@ class TestOther : public TestFixture { "};\n" "void foo(S* first, S* second) {\n" " if((first.ptr - second.ptr) < 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:13]: (style) Parameter 'first' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:4:23]: (style) Parameter 'second' can be declared as pointer to const [constParameterPointer]\n", errout_str()); @@ -9139,7 +9714,7 @@ class TestOther : public TestFixture { "};\n" "void foo(S* first, S* second) {\n" " if(0 > first.ptr - second.ptr) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:13]: (style) Parameter 'first' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:4:23]: (style) Parameter 'second' can be declared as pointer to const [constParameterPointer]\n", errout_str()); @@ -9149,69 +9724,69 @@ class TestOther : public TestFixture { "};\n" "void foo(S* first, S* second) {\n" " if(0 > (first.ptr - second.ptr)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:13]: (style) Parameter 'first' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:4:23]: (style) Parameter 'second' can be declared as pointer to const [constParameterPointer]\n", errout_str()); check("void foo(const int* x) {\n" " if (0 <= x[0]) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(Bar* x) {\n" " if (0 <= x.y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:15]: (style) Parameter 'x' can be declared as pointer to const [constParameterPointer]\n", errout_str()); check("void foo(Bar* x) {\n" " if (0 <= x->y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:15]: (style) Parameter 'x' can be declared as pointer to const [constParameterPointer]\n", errout_str()); check("void foo(Bar* x, Bar* y) {\n" " if (0 <= x->y - y->y ) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:15]: (style) Parameter 'x' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:1:23]: (style) Parameter 'y' can be declared as pointer to const [constParameterPointer]\n", errout_str()); check("void foo(const Bar* x) {\n" " if (0 > x) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) A pointer can not be negative so it is either pointless or an error to check if it is. [pointerLessThanZero]\n", errout_str()); check("void foo(const int* x) {\n" " if (0 > x[0]) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(Bar* x) {\n" " if (0 > x.y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:15]: (style) Parameter 'x' can be declared as pointer to const [constParameterPointer]\n", errout_str()); check("void foo(Bar* x) {\n" " if (0 > x->y) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:15]: (style) Parameter 'x' can be declared as pointer to const [constParameterPointer]\n", errout_str()); check("void foo() {\n" " int (*t)(void *a, void *b);\n" " if (t(a, b) < 0) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " int (*t)(void *a, void *b);\n" " if (0 > t(a, b)) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct object_info { int *typep; };\n" "void packed_object_info(struct object_info *oi) {\n" " if (oi->typep < 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:17]: (style) A pointer can not be negative so it is either pointless or an error to check if it is. [pointerLessThanZero]\n" "[test.cpp:2:45]: (style) Parameter 'oi' can be declared as pointer to const [constParameterPointer]\n", errout_str()); @@ -9219,7 +9794,7 @@ class TestOther : public TestFixture { check("struct object_info { int typep[10]; };\n" "void packed_object_info(struct object_info *oi) {\n" " if (oi->typep < 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:17]: (style) A pointer can not be negative so it is either pointless or an error to check if it is. [pointerLessThanZero]\n" "[test.cpp:2:45]: (style) Parameter 'oi' can be declared as pointer to const [constParameterPointer]\n", errout_str()); @@ -9227,28 +9802,28 @@ class TestOther : public TestFixture { check("struct object_info { int *typep; };\n" "void packed_object_info(struct object_info *oi) {\n" " if (*oi->typep < 0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:45]: (style) Parameter 'oi' can be declared as pointer to const [constParameterPointer]\n", errout_str()); } void checkSuspiciousSemicolon1() { check("void foo() {\n" " for(int i = 0; i < 10; ++i);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Empty block check("void foo() {\n" " for(int i = 0; i < 10; ++i); {\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:3]: (warning) Suspicious use of ; at the end of 'for' statement. [suspiciousSemicolon]\n", errout_str()); check("void foo() {\n" " while (!quit); {\n" " do_something();\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:3]: (warning) Suspicious use of ; at the end of 'while' statement. [suspiciousSemicolon]\n", errout_str()); } @@ -9257,21 +9832,21 @@ class TestOther : public TestFixture { " if (i == 1); {\n" " do_something();\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:3]: (warning) Suspicious use of ; at the end of 'if' statement. [suspiciousSemicolon]\n", errout_str()); // Seen this in the wild check("void foo() {\n" " if (Match());\n" " do_something();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " if (Match());\n" " else\n" " do_something();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" @@ -9280,7 +9855,7 @@ class TestOther : public TestFixture { " {\n" " do_something();\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" @@ -9289,7 +9864,7 @@ class TestOther : public TestFixture { " {\n" " do_something();\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -9298,20 +9873,20 @@ class TestOther : public TestFixture { "void foo() {\n" " if (x == 123);\n" " REQUIRE(y=z);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void checkSuspiciousComparison() { checkP("void f(int a, int b) {\n" " a > b;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (warning, inconclusive) Found suspicious operator '>', result is not used. [constStatement]\n", errout_str()); checkP("void f() {\n" // #10607 " for (auto p : m)\n" " std::vector> k;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -9319,25 +9894,25 @@ class TestOther : public TestFixture { check("void foo(char *p) {\n" " char *a; a = malloc(1024);\n" " free(a + 10);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:3]: (error) Mismatching address is freed. The address you get from malloc() must be freed without offset. [invalidFree]\n", errout_str()); check("void foo(char *p) {\n" " char *a; a = malloc(1024);\n" " free(a - 10);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:3]: (error) Mismatching address is freed. The address you get from malloc() must be freed without offset. [invalidFree]\n", errout_str()); check("void foo(char *p) {\n" " char *a; a = malloc(1024);\n" " free(10 + a);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:3]: (error) Mismatching address is freed. The address you get from malloc() must be freed without offset. [invalidFree]\n", errout_str()); check("void foo(char *p) {\n" " char *a; a = new char[1024];\n" " delete[] (a + 10);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:16]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:3:3]: (error) Mismatching address is deleted. The address you get from new must be deleted without offset. [invalidFree]\n", errout_str()); @@ -9345,7 +9920,7 @@ class TestOther : public TestFixture { check("void foo(char *p) {\n" " char *a; a = new char;\n" " delete a + 10;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:16]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:3:3]: (error) Mismatching address is deleted. The address you get from new must be deleted without offset. [invalidFree]\n", errout_str()); @@ -9354,7 +9929,7 @@ class TestOther : public TestFixture { " char *a; a = new char;\n" " bar(a);\n" " delete a + 10;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(char *p) {\n" @@ -9363,7 +9938,7 @@ class TestOther : public TestFixture { " bar(a);\n" " delete a + 10;\n" " delete b + 10;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:3]: (error) Mismatching address is deleted. The address you get from new must be deleted without offset. [invalidFree]\n", errout_str()); check("void foo(char *p) {\n" @@ -9372,14 +9947,14 @@ class TestOther : public TestFixture { " bar(a, b);\n" " delete a + 10;\n" " delete b + 10;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(char *p) {\n" " char *a; a = new char;\n" " bar()\n" " delete a + 10;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:16]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:4:3]: (error) Mismatching address is deleted. The address you get from new must be deleted without offset. [invalidFree]\n", errout_str()); @@ -9388,7 +9963,7 @@ class TestOther : public TestFixture { " char *ptr; ptr = malloc(42);\n" " ptr += xx;\n" " free(ptr + 1 - xx);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:3]: (error) Mismatching address is freed. The address you get from malloc() must be freed without offset. [invalidFree]\n", errout_str()); check("void foo(size_t xx) {\n" @@ -9396,7 +9971,7 @@ class TestOther : public TestFixture { " std::cout << ptr;\n" " ptr = otherPtr;\n" " free(otherPtr - xx - 1);\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:9]: (style) Variable 'ptr' can be declared as pointer to const [constVariablePointer]\n", errout_str()); @@ -9406,7 +9981,7 @@ class TestOther : public TestFixture { check("const std::string& getA(){static std::string a;return a;}\n" "void foo() {\n" " const std::string a = getA();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:23]: (performance, inconclusive) Use const reference for 'a' to avoid unnecessary data copying. [redundantCopyLocalConst]\n", errout_str()); check("class A { public: A() {} char x[100]; };\n" @@ -9415,7 +9990,7 @@ class TestOther : public TestFixture { "{\n" " const A a = getA();\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:13]: (performance, inconclusive) Use const reference for 'a' to avoid unnecessary data copying. [redundantCopyLocalConst]\n", errout_str()); check("const int& getA(){static int a;return a;}\n" @@ -9423,7 +9998,7 @@ class TestOther : public TestFixture { "{\n" " const int a = getA();\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("const int& getA(){static int a;return a;}\n" @@ -9432,7 +10007,7 @@ class TestOther : public TestFixture { " int getA = 0;\n" " const int a = getA + 3;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:1:12] -> [test.cpp:4:9]: (style) Local variable 'getA' shadows outer function [shadowFunction]\n", errout_str()); check("class A { public: A() {} char x[100]; };\n" @@ -9441,7 +10016,7 @@ class TestOther : public TestFixture { "{\n" " const A a(getA());\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:13]: (performance, inconclusive) Use const reference for 'a' to avoid unnecessary data copying. [redundantCopyLocalConst]\n", errout_str()); check("const int& getA(){static int a;return a;}\n" @@ -9449,7 +10024,7 @@ class TestOther : public TestFixture { "{\n" " const int a(getA());\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class A{\n" @@ -9461,7 +10036,7 @@ class TestOther : public TestFixture { "{\n" " const A a = getA() + 1;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class A{\n" @@ -9473,7 +10048,7 @@ class TestOther : public TestFixture { "{\n" " const A a(getA()+1);\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #5190 - FP when creating object with constructor that takes a reference @@ -9482,7 +10057,7 @@ class TestOther : public TestFixture { "const A &getA();\n" "void f() {\n" " const B b(getA());\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class A {};\n" @@ -9490,7 +10065,7 @@ class TestOther : public TestFixture { "const A& getA();\n" "void f() {\n" " const B b{ getA() };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #5618 @@ -9503,10 +10078,10 @@ class TestOther : public TestFixture { " const std::string temp = tok->str();\n" " tok->str(tok->strAt(2));\n" " }\n" - "}"; - check(code5618, true, true); + "}\n"; + check(code5618); ASSERT_EQUALS("", errout_str()); - check(code5618, true, false); + check(code5618, dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); // #5890 - crash: wesnoth desktop_util.cpp / unicode.hpp @@ -9514,7 +10089,7 @@ class TestOther : public TestFixture { "X f(const X &in) {\n" " const X s = f(in);\n" " return f(s);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #7981 - False positive redundantCopyLocalConst - const ref argument to ctor @@ -9526,7 +10101,7 @@ class TestOther : public TestFixture { " \n" "void foo() {\n" " const CD cd(CD::getOne());\n" - "}", true, true); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct S {\n" // #10545 @@ -9539,7 +10114,7 @@ class TestOther : public TestFixture { " if (i != 0)\n" " return old;\n" " return {};\n" - "}", true, /*inconclusive*/ true); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct X { int x; };\n" // #10191 @@ -9557,7 +10132,7 @@ class TestOther : public TestFixture { " modify();\n" " return x.x;\n" " }\n" - "};\n", true, /*inconclusive*/ true); + "};\n"); ASSERT_EQUALS("", errout_str()); // #10704 @@ -9635,9 +10210,7 @@ class TestOther : public TestFixture { " u.g();\n" " if (c == m->get()) {}\n" "}\n"); - TODO_ASSERT_EQUALS("", - "[test.cpp:16:33] -> [test.cpp:18:11]: (style) The comparison 'c == m->get()' is always true because 'c' and 'm->get()' represent the same value. [knownConditionTrueFalse]\n", - errout_str()); + ASSERT_EQUALS("", errout_str()); check("struct S {\n" // #12925 " const std::string & f() const { return str; }\n" @@ -9664,6 +10237,58 @@ class TestOther : public TestFixture { " if (s.empty()) {}\n" "}\n"); ASSERT_EQUALS("[test.cpp:6:16]: (performance, inconclusive) Use const reference for 's' to avoid unnecessary data copying. [redundantCopyLocalConst]\n", errout_str()); + + check("void f1(const std::string& s) {\n" + " std::string s1 = s;\n" + " (void)s1;\n" + "}\n" + "void f2() {\n" + " const std::string s;\n" + " std::string s1 = s;\n" + " (void)s1;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:17]: (performance, inconclusive) Use const reference for 's1' to avoid unnecessary data copying. [redundantCopyLocalConst]\n" + "[test.cpp:7:17]: (performance, inconclusive) Use const reference for 's1' to avoid unnecessary data copying. [redundantCopyLocalConst]\n", + errout_str()); + + check("struct S {\n" + " std::string m;\n" + " int f(const std::string& s);\n" + "};\n" + "int S::f(const std::string& s) {\n" + " std::string c = s;\n" + " m.clear();\n" + " return c.size();\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct S {\n" + " std::string m;\n" + " int f(std::string s);\n" + "};\n" + "int S::f(std::string s) {\n" + " s += m;\n" + " std::string c = s;\n" + " m.clear();\n" + " return c.size();\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:7:17]: (performance, inconclusive) Use const reference for 'c' to avoid unnecessary data copying. [redundantCopyLocalConst]\n", + errout_str()); + + check("int f(const char* c) {\n" // #14530 + " std::string s = c;\n" + " return s.rfind('.');\n" + "}\n" + "struct M {\n" + " M(const std::array& a);\n" + " double m[3][3];\n" + " double trace() const;\n" + "};\n" + "double g(const std::array& a) {\n" + " M m = a;\n" + " return m.trace();\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void checkNegativeShift() { @@ -9671,62 +10296,62 @@ class TestOther : public TestFixture { "{\n" " int a; a = 123;\n" " (void)(a << -1);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:13]: (error) Shifting by a negative value is undefined behaviour [shiftNegative]\n", errout_str()); check("void foo()\n" "{\n" " int a; a = 123;\n" " (void)(a >> -1);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:13]: (error) Shifting by a negative value is undefined behaviour [shiftNegative]\n", errout_str()); check("void foo()\n" "{\n" " int a; a = 123;\n" " a <<= -1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:6]: (error) Shifting by a negative value is undefined behaviour [shiftNegative]\n", errout_str()); check("void foo()\n" "{\n" " int a; a = 123;\n" " a >>= -1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:6]: (error) Shifting by a negative value is undefined behaviour [shiftNegative]\n", errout_str()); check("void foo()\n" "{\n" " std::cout << -1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" " std::cout << a << -1 ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" " std::cout << 3 << -1 ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " x = (-10+2) << 3;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:16]: (portability) Shifting a negative value is technically undefined behaviour [shiftNegativeLHS]\n", errout_str()); - check("x = y ? z << $-1 : 0;"); + check("x = y ? z << $-1 : 0;\n"); ASSERT_EQUALS("", errout_str()); // Negative LHS - check("const int x = -1 >> 2;"); + check("const int x = -1 >> 2;\n"); ASSERT_EQUALS("[test.cpp:1:18]: (portability) Shifting a negative value is technically undefined behaviour [shiftNegativeLHS]\n", errout_str()); // #6383 - unsigned type - check("const int x = (unsigned int)(-1) >> 2;"); + check("const int x = (unsigned int)(-1) >> 2;\n"); ASSERT_EQUALS("", errout_str()); // #7814 - UB happening in valueflowcode when it tried to compute shifts. check("int shift1() { return 1 >> -1 ;}\n" "int shift2() { return 1 << -1 ;}\n" "int shift3() { return -1 >> 1 ;}\n" - "int shift4() { return -1 << 1 ;}"); + "int shift4() { return -1 << 1 ;}\n"); ASSERT_EQUALS("[test.cpp:1:25]: (error) Shifting by a negative value is undefined behaviour [shiftNegative]\n" "[test.cpp:2:25]: (error) Shifting by a negative value is undefined behaviour [shiftNegative]\n" "[test.cpp:3:26]: (portability) Shifting a negative value is technically undefined behaviour [shiftNegativeLHS]\n" @@ -9775,7 +10400,7 @@ class TestOther : public TestFixture { " memset(a, 123, 5);\n" " memcpy(a, b, 5);\n" " memmove(a, b, 5);\n" - "}"); + "}\n"); ASSERT_EQUALS(// TODO "[test.cpp:4] -> [test.cpp:5]: (performance) Buffer 'a' is being written before its old content has been used.\n" "[test.cpp:3:5]: (warning, inconclusive) Array 'a' is filled incompletely. Did you forget to multiply the size given to 'memset()' with 'sizeof(*a)'? [incompleteArrayFill]\n" "[test.cpp:4:5]: (warning, inconclusive) Array 'a' is filled incompletely. Did you forget to multiply the size given to 'memcpy()' with 'sizeof(*a)'? [incompleteArrayFill]\n" @@ -9786,7 +10411,7 @@ class TestOther : public TestFixture { "void f() {\n" " memset(::a, 123, 5);\n" " memset(Z::b.a, 123, 5);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4:5]: (warning, inconclusive) Array '::a' is filled incompletely. Did you forget to multiply the size given to 'memset()' with 'sizeof(*::a)'? [incompleteArrayFill]\n" "[test.cpp:5]: (warning, inconclusive) Array 'Z::b.a' is filled incompletely. Did you forget to multiply the size given to 'memset()' with 'sizeof(*Z::b.a)'?\n", "[test.cpp:4:5]: (warning, inconclusive) Array '::a' is filled incompletely. Did you forget to multiply the size given to 'memset()' with 'sizeof(*::a)'? [incompleteArrayFill]\n", errout_str()); @@ -9794,45 +10419,45 @@ class TestOther : public TestFixture { check("void f() {\n" " Foo* a[5];\n" " memset(a, 'a', 5);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (warning, inconclusive) Array 'a' is filled incompletely. Did you forget to multiply the size given to 'memset()' with 'sizeof(*a)'? [incompleteArrayFill]\n", errout_str()); check("class Foo {int a; int b;};\n" "void f() {\n" " Foo a[5];\n" " memset(a, 'a', 5);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:5]: (warning, inconclusive) Array 'a' is filled incompletely. Did you forget to multiply the size given to 'memset()' with 'sizeof(*a)'? [incompleteArrayFill]\n", errout_str()); check("void f() {\n" " Foo a[5];\n" // Size of foo is unknown " memset(a, 'a', 5);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " char a[5];\n" " memset(a, 'a', 5);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " int a[5];\n" " memset(a+15, 'a', 5);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " bool a[5];\n" " memset(a, false, 5);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (portability, inconclusive) Array 'a' might be filled incompletely. Did you forget to multiply the size given to 'memset()' with 'sizeof(*a)'? [incompleteArrayFill]\n", errout_str()); check("void f() {\n" " const int n = 5;" " int a[n];\n" " memset(a, 0, n);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (warning, inconclusive) Array 'a' is filled incompletely. Did you forget to multiply the size given to 'memset()' with 'sizeof(*a)'? [incompleteArrayFill]\n", errout_str()); } @@ -9843,7 +10468,7 @@ class TestOther : public TestFixture { check("void f(int i) {\n" " i = 1;\n" " i = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:7]: style: Variable 'i' is reassigned a value before the old one has been used. [redundantAssignment]\n" "[test.cpp:2:7]: note: i is assigned\n" "[test.cpp:3:7]: note: i is overwritten\n", errout_str()); @@ -9853,7 +10478,7 @@ class TestOther : public TestFixture { "void f() {\n" " i = 1;\n" " i = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:7]: style: Variable 'i' is reassigned a value before the old one has been used. [redundantAssignment]\n" "[test.cpp:3:7]: note: i is assigned\n" "[test.cpp:4:7]: note: i is overwritten\n", errout_str()); @@ -9862,7 +10487,7 @@ class TestOther : public TestFixture { " int i;\n" " i = 1;\n" " i = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:7]: style: Variable 'i' is reassigned a value before the old one has been used. [redundantAssignment]\n" "[test.cpp:3:7]: note: i is assigned\n" "[test.cpp:4:7]: note: i is overwritten\n", errout_str()); @@ -9871,14 +10496,14 @@ class TestOther : public TestFixture { " static int i;\n" " i = 1;\n" " i = 1;\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("error", "", errout_str()); check("void f() {\n" " int i[10];\n" " i[2] = 1;\n" " i[2] = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:10]: style: Variable 'i[2]' is reassigned a value before the old one has been used. [redundantAssignment]\n" "[test.cpp:3:10]: note: i[2] is assigned\n" "[test.cpp:4:10]: note: i[2] is overwritten\n", errout_str()); @@ -9888,14 +10513,14 @@ class TestOther : public TestFixture { " i[x] = 1;\n" " x=1;\n" " i[x] = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(const int x) {\n" " int i[10];\n" " i[x] = 1;\n" " i[x] = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:10]: style: Variable 'i[x]' is reassigned a value before the old one has been used. [redundantAssignment]\n" "[test.cpp:3:10]: note: i[x] is assigned\n" "[test.cpp:4:10]: note: i[x] is overwritten\n", errout_str()); @@ -9904,14 +10529,14 @@ class TestOther : public TestFixture { check("void f() {\n" " Foo& bar = foo();\n" " bar = x;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " Foo& bar = foo();\n" " bar = x;\n" " bar = y;\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("error", "", errout_str()); check("void f() {\n" @@ -9919,7 +10544,7 @@ class TestOther : public TestFixture { " bar = y();\n" " foo();\n" " bar = y();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Tests with function call between assignment @@ -9927,7 +10552,7 @@ class TestOther : public TestFixture { " i = 1;\n" " bar();\n" " i = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:7]: style: Variable 'i' is reassigned a value before the old one has been used. [redundantAssignment]\n" "[test.cpp:2:7]: note: i is assigned\n" "[test.cpp:4:7]: note: i is overwritten\n", errout_str()); @@ -9937,7 +10562,7 @@ class TestOther : public TestFixture { " i = 1;\n" " bar();\n" // Global variable might be accessed in bar() " i = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -9945,7 +10570,7 @@ class TestOther : public TestFixture { " i = 1;\n" " bar();\n" // bar() might call f() recursively. This could be a false positive in more complex examples (when value of i is used somewhere. See #4229) " i = 2;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -9953,7 +10578,7 @@ class TestOther : public TestFixture { " i = 1;\n" " bar();\n" " i = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:7]: style: Variable 'i' is reassigned a value before the old one has been used. [redundantAssignment]\n" "[test.cpp:3:7]: note: i is assigned\n" "[test.cpp:5:7]: note: i is overwritten\n", errout_str()); @@ -9963,14 +10588,14 @@ class TestOther : public TestFixture { " i = 1;\n" " bar(i);\n" // Passed as argument " i = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " Foo bar = foo();\n" " bar();\n" // #5568. operator() called " bar = y();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Branch tests @@ -9978,7 +10603,7 @@ class TestOther : public TestFixture { " i = 1;\n" " if(x)\n" " i = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int i) {\n" @@ -9986,7 +10611,7 @@ class TestOther : public TestFixture { " i = 0;\n" " i = 1;\n" " i = 2;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:7]: style: Variable 'i' is reassigned a value before the old one has been used. [redundantAssignment]\n" "[test.cpp:4:7]: note: i is assigned\n" "[test.cpp:5:7]: note: i is overwritten\n", errout_str()); @@ -9999,7 +10624,7 @@ class TestOther : public TestFixture { "void f() {\n" " x = 2;\n" " x = g();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int g() {\n" @@ -10008,7 +10633,7 @@ class TestOther : public TestFixture { "void f(int x) {\n" " x = 2;\n" " x = g();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:7]: style: Variable 'x' is reassigned a value before the old one has been used. [redundantAssignment]\n" "[test.cpp:5:7]: note: x is assigned\n" "[test.cpp:6:7]: note: x is overwritten\n", errout_str()); @@ -10017,7 +10642,7 @@ class TestOther : public TestFixture { " Foo& bar = foo();\n" " bar = x;\n" " bar = y();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class C {\n" @@ -10029,7 +10654,7 @@ class TestOther : public TestFixture { "void C::f() {\n" " x = 2;\n" " x = g();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class C {\n" @@ -10041,7 +10666,7 @@ class TestOther : public TestFixture { "void C::f(Foo z) {\n" " x = 2;\n" " x = z.g();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // ({ }) @@ -10049,7 +10674,7 @@ class TestOther : public TestFixture { " int x;\n" " x = 321;\n" " x = ({ asm(123); })\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // from #3103 (avoid a false negative) @@ -10058,7 +10683,7 @@ class TestOther : public TestFixture { " x = 1;\n" " x = 1;\n" " return x + 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:7]: style: Variable 'x' is reassigned a value before the old one has been used. [redundantAssignment]\n" "[test.cpp:3:7]: note: x is assigned\n" "[test.cpp:4:7]: note: x is overwritten\n", errout_str()); @@ -10070,20 +10695,20 @@ class TestOther : public TestFixture { " if (y)\n" // <-- cppcheck does not know anything about 'y' " x = 2;\n" " return x + 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // initialization, assignment with 0 check("void f() {\n" // Ticket #4356 " int x = 0;\n" // <- ignore initialization with 0 " x = 3;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " state_t *x = NULL;\n" " x = dostuff();\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:12]: style: Variable 'x' can be declared as pointer to const [constVariablePointer]\n", errout_str()); @@ -10092,7 +10717,7 @@ class TestOther : public TestFixture { " state_t *x;\n" " x = NULL;\n" " x = dostuff();\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:12]: style: Variable 'x' can be declared as pointer to const [constVariablePointer]\n", errout_str()); @@ -10102,7 +10727,7 @@ class TestOther : public TestFixture { " bar(++x);\n" " x = 5;\n" " return bar(x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // struct member.. @@ -10113,7 +10738,7 @@ class TestOther : public TestFixture { " ab.a = 1;\n" " ab.a = 2;\n" " return ab.a;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:10]: style: Variable 'ab.a' is reassigned a value before the old one has been used. [redundantAssignment]\n" "[test.cpp:5:10]: note: ab.a is assigned\n" "[test.cpp:6:10]: note: ab.a is overwritten\n", errout_str()); @@ -10125,7 +10750,7 @@ class TestOther : public TestFixture { " ab.a = 1;\n" " ab = do_something();\n" " return ab.a;\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("error", "", errout_str()); check("struct AB { int a; int b; };\n" @@ -10136,7 +10761,7 @@ class TestOther : public TestFixture { " do_something(&ab);\n" " ab.a = 2;\n" " return ab.a;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct AB { int a; int b; };\n" @@ -10147,7 +10772,7 @@ class TestOther : public TestFixture { " do_something(&ab);\n" " ab.a = 2;\n" " return ab.a;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct AB { int a; int b; };\n" @@ -10158,7 +10783,7 @@ class TestOther : public TestFixture { " ab++;\n" " ab->a = 1;\n" " ab->b = 2;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct AB { int a; int b; };\n" @@ -10169,20 +10794,20 @@ class TestOther : public TestFixture { " ab = x;\n" " ab->a = 1;\n" " ab->b = 2;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(struct AB *ab) {\n" // # " ab->data->x = 1;\n" " ab = &ab1;\n" " ab->data->x = 2;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #5964 check("void func(char *buffer, const char *format, int precision, unsigned value) {\n" " (precision < 0) ? sprintf(buffer, format, value) : sprintf(buffer, format, precision, value);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // don't crash @@ -10195,14 +10820,14 @@ class TestOther : public TestFixture { "void func(struct state *s) {\n" " s->foo[s->x++] = 2;\n" " s->d[1].fc.i++;\n" - "}"); + "}\n"); // #6525 - inline assembly check("void f(int i) {\n" " i = 1;\n" " asm(\"foo\");\n" " i = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #6555 @@ -10215,7 +10840,7 @@ class TestOther : public TestFixture { " catch (...) {\n" " barney(p);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" @@ -10227,7 +10852,7 @@ class TestOther : public TestFixture { " catch (...) {\n" " barney(x);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: style: The scope of the variable 'p' can be reduced. [variableScope]\n" "[test.cpp:2:11]: style: Variable 'p' can be declared as pointer to const [constVariablePointer]\n", errout_str()); @@ -10243,17 +10868,17 @@ class TestOther : public TestFixture { " catch (...) {\n" " barney(p);\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Member variable pointers check("void podMemPtrs() {\n" - " int POD::*memptr;\n" + " const int POD::*memptr;\n" " memptr = &POD::a;\n" " memptr = &POD::b;\n" " if (memptr)\n" " memptr = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:12]: style: Variable 'memptr' is reassigned a value before the old one has been used. [redundantAssignment]\n" "[test.cpp:3:12]: note: memptr is assigned\n" "[test.cpp:4:12]: note: memptr is overwritten\n", errout_str()); @@ -10263,7 +10888,7 @@ class TestOther : public TestFixture { "{\n" " var[0] = 0.2f;\n" " var[0] = 0.2f;\n" // <-- is initialized twice - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:10]: style: Variable 'var[0]' is reassigned a value before the old one has been used. [redundantAssignment]\n" "[test.cpp:3:10]: note: var[0] is assigned\n" "[test.cpp:4:10]: note: var[0] is overwritten\n", errout_str()); @@ -10272,7 +10897,7 @@ class TestOther : public TestFixture { "{\n" " *var = 0.2f;\n" " *var = 0.2f;\n" // <-- is initialized twice - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:8]: style: Variable '*var' is reassigned a value before the old one has been used. [redundantAssignment]\n" "[test.cpp:3:8]: note: *var is assigned\n" "[test.cpp:4:8]: note: *var is overwritten\n", errout_str()); @@ -10282,7 +10907,7 @@ class TestOther : public TestFixture { " volatile char *reg = (volatile char *)0x12345;\n" " *reg = 12;\n" " *reg = 34;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(std::map& m, int key, int value) {\n" // #6379 @@ -10299,28 +10924,28 @@ class TestOther : public TestFixture { check("void f() {\n" " int a = 0;\n" " a = 4;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " int a;\n" " a = 0;\n" " a = 4;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " unsigned a;\n" " a = 0u;\n" " a = 2u;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " void* a;\n" " a = (void*)0;\n" " a = p;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:10]: (style) Variable 'a' can be declared as pointer to const [constVariablePointer]\n", errout_str()); @@ -10329,10 +10954,25 @@ class TestOther : public TestFixture { " void* a;\n" " a = (void*)0U;\n" " a = p;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:10]: (style) Variable 'a' can be declared as pointer to const [constVariablePointer]\n", errout_str()); + + check("std::string f() {\n" // #14534 + " std::string s = \"abc\";\n" + " s = \"def\";\n" + " return s;\n" + "}\n" + "const char* g() {\n" + " const char* p = \"abc\";\n" + " p = \"def\";\n" + " return p;\n" + "}\n"); + ASSERT_EQUALS( + "[test.cpp:2:19] -> [test.cpp:3:7]: (style) Redundant initialization for 's'. The initialized value is overwritten before it is read. [redundantInitialization]\n" + "[test.cpp:7:19] -> [test.cpp:8:7]: (style) Redundant initialization for 'p'. The initialized value is overwritten before it is read. [redundantInitialization]\n", + errout_str()); } void redundantVarAssignment_struct() { @@ -10344,7 +10984,7 @@ class TestOther : public TestFixture { " struct foo x;\n" " x.a = _mm_set1_ps(1.0);\n" " x.a = _mm_set1_ps(2.0);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:7] -> [test.cpp:8:7]: (style) Variable 'x.a' is reassigned a value before the old one has been used. [redundantAssignment]\n", errout_str()); check("void f() {\n" @@ -10352,13 +10992,13 @@ class TestOther : public TestFixture { " ab.x = 23;\n" " ab.y = 41;\n" " ab.x = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:8] -> [test.cpp:5:8]: (style) Variable 'ab.x' is reassigned a value before the old one has been used. [redundantAssignment]\n", errout_str()); check("void f() {\n" " struct AB ab = {0};\n" " ab = foo();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -10379,7 +11019,7 @@ class TestOther : public TestFixture { " u.l1 = 1;\n" " lTotal += u.b.b1;\n" " u.l1 = 2;\n" //Should not show RedundantAssignment - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); // Ticket #5115 "redundantAssignment when using a union" @@ -10397,7 +11037,7 @@ class TestOther : public TestFixture { " } u;\n" " u.l1 = 1;\n" " u.l1 = 2;\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:13:10] -> [test.cpp:14:10]: (style) Variable 'u.l1' is reassigned a value before the old one has been used. [redundantAssignment]\n", errout_str()); // Ticket #10093 "redundantAssignment when using a union" @@ -10421,7 +11061,7 @@ class TestOther : public TestFixture { " m.u16.ab = 47;\n" " m.u16.cd = 0;\n" " m.u16.ab = m.u32.abcd / 53;\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); // Ticket #10093 "redundantAssignment when using a union" @@ -10439,7 +11079,7 @@ class TestOther : public TestFixture { " u.as_int = 42;\n" " fn(&u.as_char[0], 4);\n" " u.as_int = 0;\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); // Ticket #5115 "redundantAssignment when using a union" @@ -10450,7 +11090,7 @@ class TestOther : public TestFixture { " } addr;\n" " addr.s8 = ptr;\n" " addr.u64 += 8;\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); check("struct S {\n" // #12895 @@ -10464,6 +11104,48 @@ class TestOther : public TestFixture { " Dst.s->y = Src.s->y;\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + // Ticket #14371 "redundantAssignment when using a union" + check("union U {\n" + " struct {\n" + " unsigned int abcd;\n" + " } u32;\n" + " struct {\n" + " unsigned short ab;\n" + " unsigned short cd;\n" + " } u16;\n" + "};\n" + "void f1() {\n" + " U m;\n" + " m.u32.abcd = 1234;\n" + " m.u32.abcd = 5 * m.u16.ab;\n" + "}\n" + "void f2(unsigned int a, unsigned short b) {\n" + " U m;\n" + " m.u32.abcd = a;\n" + " m.u32.abcd += 0x8000;\n" + " m.u32.abcd = m.u16.ab * b;\n" + "}\n" + "void f3(unsigned int seed) {\n" + " U m, other;\n" + " other.u32.abcd = seed;\n" + " m.u32.abcd = 1234;\n" + " m.u32.abcd = other.u16.ab * 2;\n" + "}\n" + "void f4(unsigned short x) {\n" + " U m;\n" + " m.u16.ab = x;\n" + " m.u16.cd = 0;\n" + " m.u16.ab = m.u32.abcd / 53;\n" + "}\n" + "void f5(unsigned short x, unsigned int y) {\n" + " U m;\n" + " m.u16.ab = x;\n" + " m.u16.cd = 0;\n" + " m.u16.ab = y;\n" + "}\n", dinit(CheckOptions, $.inconclusive = false)); + ASSERT_EQUALS("[test.cpp:24:16] -> [test.cpp:25:16]: (style) Variable 'm.u32.abcd' is reassigned a value before the old one has been used. [redundantAssignment]\n" + "[test.cpp:35:14] -> [test.cpp:37:14]: (style) Variable 'm.u16.ab' is reassigned a value before the old one has been used. [redundantAssignment]\n", errout_str()); } void redundantVarAssignment_7133() { @@ -10485,7 +11167,7 @@ class TestOther : public TestFixture { " }\n" " catch (const uno::Exception&) {\n" " }\n" - "}", true, true); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void ConvertBitmapData(sal_uInt16 nDestBits) {\n" @@ -10494,7 +11176,7 @@ class TestOther : public TestFixture { " BitmapBuffer aDstBuf;\n" " aSrcBuf.mnBitCount = nDestBits;\n" " bConverted = ::ImplFastBitmapConversion( aDstBuf, aSrcBuf, aTwoRects );\n" - "}", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("[test.c:3:24] -> [test.c:5:24]: (style) Variable 'aSrcBuf.mnBitCount' is reassigned a value before the old one has been used. [redundantAssignment]\n", errout_str()); check("void ConvertBitmapData(sal_uInt16 nDestBits) {\n" " BitmapBuffer aSrcBuf;\n" @@ -10502,7 +11184,7 @@ class TestOther : public TestFixture { " BitmapBuffer aDstBuf;\n" " aSrcBuf.mnBitCount = nDestBits;\n" " bConverted = ::ImplFastBitmapConversion( aDstBuf, aSrcBuf, aTwoRects );\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:24] -> [test.cpp:5:24]: (style) Variable 'aSrcBuf.mnBitCount' is reassigned a value before the old one has been used. [redundantAssignment]\n", errout_str()); @@ -10511,7 +11193,7 @@ class TestOther : public TestFixture { " C c;\n" " c = x;\n" " c = x;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:7] -> [test.cpp:5:7]: (style, inconclusive) Variable 'c' is reassigned a value before the old one has been used if variable is no semaphore variable. [redundantAssignment]\n", errout_str()); } @@ -10525,7 +11207,7 @@ class TestOther : public TestFixture { " m->prev->next = m->next;\n" " m->next->prev = m->prev;\n" " return m->next;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -10539,7 +11221,7 @@ class TestOther : public TestFixture { " x = 6;\n" " f();\n" " return y;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #10228 @@ -10559,7 +11241,7 @@ class TestOther : public TestFixture { " for (i = 0; i < 4; i++)\n" " buf[i] = 131;\n" " buf[i] = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void bar() {\n" // #9262 do-while with break @@ -10569,20 +11251,20 @@ class TestOther : public TestFixture { " if (foo()) break;\n" " x = 1;\n" " } while (false);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int num) {\n" // #9420 FP " int a = num;\n" " for (int b = 0; b < num; a = b++)\n" " dostuff(a);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(int num) {\n" // #9420 FN " int a = num;\n" " for (int b = 0; b < num; a = b++);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("error", "", errout_str()); } @@ -10595,7 +11277,7 @@ class TestOther : public TestFixture { " break;\n" " }\n" " ret = 3;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:13] -> [test.cpp:8:9]: (style) Variable 'ret' is reassigned a value before the old one has been used. [redundantAssignment]\n", errout_str()); } @@ -10605,7 +11287,7 @@ class TestOther : public TestFixture { " *x = 23;\n" " foo(ptr);\n" " *x = 32;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #8997 @@ -10615,7 +11297,7 @@ class TestOther : public TestFixture { " *p = 1;\n" " p += 1;\n" " *p = 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -10624,7 +11306,7 @@ class TestOther : public TestFixture { " *p = 1;\n" " if (condition) return;\n" " *p = 2;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -10636,7 +11318,7 @@ class TestOther : public TestFixture { " i += 2;\n" " arr[i] = 3;\n" " dostuff(arr);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -10650,9 +11332,9 @@ class TestOther : public TestFixture { " if (b) break;\n" " ret = 1;\n" " break;\n" - " }" + " }\n" " return ret;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int a, int b) {\n" @@ -10663,8 +11345,8 @@ class TestOther : public TestFixture { " if (b) break;\n" " ret = 1;\n" " break;\n" - " }" - "}"); + " }\n" + "}\n"); ASSERT_EQUALS("[test.cpp:5:13] -> [test.cpp:7:13]: (style) Variable 'ret' is reassigned a value before the old one has been used. [redundantAssignment]\n", errout_str()); } @@ -10674,7 +11356,7 @@ class TestOther : public TestFixture { check("void f() {\n" " int err = -ENOMEM;\n" " err = dostuff();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9]: style: Redundant initialization for 'err'. The initialized value is overwritten before it is read. [redundantInitialization]\n" "[test.cpp:2:13]: note: err is initialized\n" "[test.cpp:3:9]: note: err is overwritten\n", @@ -10683,7 +11365,7 @@ class TestOther : public TestFixture { check("void f() {\n" " struct S s = {1,2,3};\n" " s = dostuff();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:7]: style: Redundant initialization for 's'. The initialized value is overwritten before it is read. [redundantInitialization]\n" "[test.cpp:2:16]: note: s is initialized\n" "[test.cpp:3:7]: note: s is overwritten\n", @@ -10692,7 +11374,7 @@ class TestOther : public TestFixture { check("void f() {\n" " int *p = NULL;\n" " p = dostuff();\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:10]: style: Variable 'p' can be declared as pointer to const [constVariablePointer]\n", errout_str()); @@ -10701,14 +11383,14 @@ class TestOther : public TestFixture { check("void f() {\n" " struct S s = {0};\n" " s = dostuff();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("namespace N { enum E {e0,e1}; }\n" "void f() {\n" " N::E e = N::e0;\n" // #9261 " e = dostuff();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" // #10143 @@ -10729,26 +11411,25 @@ class TestOther : public TestFixture { // cppcheck-suppress unusedPrivateFunction void redundantMemWrite() { // Simple tests - // cppcheck-suppress unreachableCode - remove when code is enabled again check("void f() {\n" " char a[10];\n" " memcpy(a, foo, bar);\n" " memset(a, 0, bar);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (performance) Buffer 'a' is being written before its old content has been used.\n", errout_str()); check("void f() {\n" " char a[10];\n" " strcpy(a, foo);\n" " strncpy(a, 0, bar);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (performance) Buffer 'a' is being written before its old content has been used.\n", errout_str()); check("void f() {\n" " char a[10];\n" " sprintf(a, \"foo\");\n" " memmove(a, 0, bar);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (performance) Buffer 'a' is being written before its old content has been used.\n", errout_str()); check("void f(char *filename) {\n" @@ -10756,14 +11437,14 @@ class TestOther : public TestFixture { " strcpy(p, \"foo\");\n" " dostuff(filename);\n" " strcpy(p, \"foo\");\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Writing to different parts of a buffer check("void f(void* a) {\n" " memcpy(a, foo, bar);\n" " memset(a+5, 0, bar);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Use variable as second argument @@ -10771,7 +11452,7 @@ class TestOther : public TestFixture { " memset(a, 0, 5);\n" " memcpy(b, a, 5);\n" " memset(a, 1, 5);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // strcat is special @@ -10780,7 +11461,7 @@ class TestOther : public TestFixture { " strcpy(a, foo);\n" " strcat(a, bar);\n" // Not redundant " strcpy(a, x);\n" // Redundant - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:5]: (performance) Buffer 'a' is being written before its old content has been used.\n", errout_str()); // Tests with function call between copy @@ -10789,7 +11470,7 @@ class TestOther : public TestFixture { " snprintf(a, foo, bar);\n" " bar();\n" " memset(a, 0, size);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:5]: (performance) Buffer 'a' is being written before its old content has been used.\n", errout_str()); check("void* a;\n" @@ -10797,7 +11478,7 @@ class TestOther : public TestFixture { " memset(a, 0, size);\n" " bar();\n" // Global variable might be accessed in bar() " memset(a, 0, size);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -10805,7 +11486,7 @@ class TestOther : public TestFixture { " memset(a, 0, size);\n" " bar();\n" " memset(a, 0, size);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:5]: (performance) Buffer 'a' is being written before its old content has been used.\n", "", errout_str()); check("void bar(void* a) {}\n" @@ -10813,7 +11494,7 @@ class TestOther : public TestFixture { " memset(a, 0, size);\n" " bar(a);\n" // Passed as argument " memset(a, 0, size);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // Branch tests @@ -10821,7 +11502,7 @@ class TestOther : public TestFixture { " memset(a, 0, size);\n" " if(x)\n" " memset(a, 0, size);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #4455 - initialization of local buffer @@ -10829,14 +11510,14 @@ class TestOther : public TestFixture { " char buf[10];\n" " memset(buf, 0, 10);\n" " strcpy(buf, string);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(void) {\n" " char buf[10] = {0};\n" " memset(buf, 0, 10);\n" " strcpy(buf, string);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (performance) Buffer 'buf' is being written before its old content has been used.\n", errout_str()); // #5689 - use return value of strcpy @@ -10844,7 +11525,7 @@ class TestOther : public TestFixture { " int i = atoi(strcpy(a, foo));\n" " strncpy(a, 0, bar);\n" " return i;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #7175 - read+write @@ -10853,7 +11534,7 @@ class TestOther : public TestFixture { " strcpy(buf, x);\n" " strcpy(buf, dostuff(buf));\n" // <- read + write " strcpy(buf, x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -10861,7 +11542,7 @@ class TestOther : public TestFixture { " strcpy(buf, x);\n" " strcpy(buf, dostuff(buf));\n" " strcpy(buf, x);\n" - "}"); + "}\n"); TODO_ASSERT_EQUALS("error", "", errout_str()); } @@ -10917,15 +11598,31 @@ class TestOther : public TestFixture { " a = x;\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("int f(int a, int b, int c) {\n" // #4491 + " int x = a + b;\n" + " if (c)\n" + " x = a + b;\n" + " return x;\n" + "}\n"); + 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 check("void a(...);\n" - "void b() { a(NULL); }"); + "void b() { a(NULL); }\n"); ASSERT_EQUALS("[test.cpp:2:13]: (portability) Passing NULL after the last typed argument to a variadic function leads to undefined behaviour. [varFuncNullUB]\n", errout_str()); check("void a(char *p, ...);\n" - "void b() { a(NULL, 2); }"); + "void b() { a(NULL, 2); }\n"); + ASSERT_EQUALS("", errout_str()); + + checkP("extern const int sentinel;\n" + "void a(int, ...);\n" + "#define b(x, ...) a((x), __VA_ARGS__, &sentinel)\n" + "void c() { b(1, NULL); }\n"); ASSERT_EQUALS("", errout_str()); } @@ -10939,7 +11636,7 @@ class TestOther : public TestFixture { " bar(c);\n" " c = getchar();\n" " } ;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:10]: (warning) Storing getchar() return value in char variable and then comparing with EOF. [checkCastIntToCharAndBack]\n", errout_str()); check("void f() {\n" @@ -10948,7 +11645,7 @@ class TestOther : public TestFixture { " {\n" " bar(c);\n" " } ;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:17]: (warning) Storing getchar() return value in char variable and then comparing with EOF. [checkCastIntToCharAndBack]\n", errout_str()); check("void f() {\n" @@ -10958,7 +11655,7 @@ class TestOther : public TestFixture { " bar(c);\n" " c = getchar();\n" " } ;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:17]: (warning) Storing getchar() return value in char variable and then comparing with EOF. [checkCastIntToCharAndBack]\n", errout_str()); check("void f() {\n" @@ -10966,7 +11663,7 @@ class TestOther : public TestFixture { " while( EOF != ( c = getchar() ) )\n" " {\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:19]: (warning) Storing getchar() return value in char variable and then comparing with EOF. [checkCastIntToCharAndBack]\n", errout_str()); check("void f() {\n" @@ -10976,7 +11673,7 @@ class TestOther : public TestFixture { " bar(i);\n" " i = getchar();\n" " } ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -10986,7 +11683,7 @@ class TestOther : public TestFixture { " bar(i);\n" " i = getchar();\n" " } ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); @@ -10996,7 +11693,7 @@ class TestOther : public TestFixture { "do {\n" " c = getc (pFile);\n" "} while (c != EOF);" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:10]: (warning) Storing getc() return value in char variable and then comparing with EOF. [checkCastIntToCharAndBack]\n", errout_str()); check("void f (FILE * pFile){\n" @@ -11004,7 +11701,7 @@ class TestOther : public TestFixture { "do {\n" " c = getc (pFile);\n" "} while (EOF != c);" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:17]: (warning) Storing getc() return value in char variable and then comparing with EOF. [checkCastIntToCharAndBack]\n", errout_str()); check("void f (FILE * pFile){\n" @@ -11012,7 +11709,7 @@ class TestOther : public TestFixture { "do {\n" " i = getc (pFile);\n" "} while (i != EOF);" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f (FILE * pFile){\n" @@ -11020,7 +11717,7 @@ class TestOther : public TestFixture { "do {\n" " i = getc (pFile);\n" "} while (EOF != i);" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); @@ -11030,7 +11727,7 @@ class TestOther : public TestFixture { "do {\n" " c = fgetc (pFile);\n" "} while (c != EOF);" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:10]: (warning) Storing fgetc() return value in char variable and then comparing with EOF. [checkCastIntToCharAndBack]\n", errout_str()); check("void f (FILE * pFile){\n" @@ -11038,7 +11735,7 @@ class TestOther : public TestFixture { "do {\n" " c = fgetc (pFile);\n" "} while (EOF != c);" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:17]: (warning) Storing fgetc() return value in char variable and then comparing with EOF. [checkCastIntToCharAndBack]\n", errout_str()); check("void f (FILE * pFile){\n" @@ -11046,7 +11743,7 @@ class TestOther : public TestFixture { "do {\n" " c = fgetc (pFile);\n" "} while (EOF != c);" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f (FILE * pFile){\n" @@ -11054,7 +11751,7 @@ class TestOther : public TestFixture { "do {\n" " i = fgetc (pFile);\n" "} while (i != EOF);" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f (FILE * pFile){\n" @@ -11062,7 +11759,7 @@ class TestOther : public TestFixture { "do {\n" " i = fgetc (pFile);\n" "} while (EOF != i);" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // cin.get() @@ -11072,7 +11769,7 @@ class TestOther : public TestFixture { " std::cout << ch;\n" " ch = std::cin.get();\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:18]: (warning) Storing cin.get() return value in char variable and then comparing with EOF. [checkCastIntToCharAndBack]\n", errout_str()); check("void f(){\n" @@ -11081,7 +11778,7 @@ class TestOther : public TestFixture { " std::cout << ch;\n" " ch = std::cin.get();\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:11]: (warning) Storing cin.get() return value in char variable and then comparing with EOF. [checkCastIntToCharAndBack]\n", errout_str()); check("void f(){\n" @@ -11090,7 +11787,7 @@ class TestOther : public TestFixture { " std::cout << i;\n" " i = std::cin.get();\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(){\n" @@ -11099,7 +11796,7 @@ class TestOther : public TestFixture { " std::cout << i;\n" " i = std::cin.get();\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -11108,32 +11805,32 @@ class TestOther : public TestFixture { " if (a < 0)\n" " return a++,\n" " do_something();\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); TODO_ASSERT_EQUALS("[test.cpp:3]: (style) Comma is used in return statement. The comma can easily be misread as a ';'.\n", "", errout_str()); check("int fun(int a) {\n" " if (a < 0)\n" " return a++, do_something();\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); check("int fun(int a) {\n" " if (a < 0)\n" " return a+5,\n" " do_something();\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); TODO_ASSERT_EQUALS("[test.cpp:3]: (style) Comma is used in return statement. The comma can easily be misread as a ';'.\n", "", errout_str()); check("int fun(int a) {\n" " if (a < 0)\n" " return a+5, do_something();\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); check("int fun(int a) {\n" " if (a < 0)\n" " return c::b;\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); // #4943 take care of C++11 initializer lists @@ -11144,7 +11841,7 @@ class TestOther : public TestFixture { " { \"2\" },\n" " { \"3\" }\n" " };\n" - "}", true, false, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); } @@ -11160,7 +11857,7 @@ class TestOther : public TestFixture { " explicit B(A a) : a(std::move(a)) {}\n" " void Init(A _a) { a = std::move(_a); }\n" " A a;" - "};", true, false, true); + "};\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); check("struct A\n" @@ -11173,7 +11870,7 @@ class TestOther : public TestFixture { " explicit B(A a) : a{std::move(a)} {}\n" " void Init(A _a) { a = std::move(_a); }\n" " A a;" - "};", true, false, true); + "};\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); check("struct A\n" @@ -11187,7 +11884,7 @@ class TestOther : public TestFixture { " void Init(A _a) { a = std::move(_a); }\n" " A a;" " A a2;" - "};", true, false, true); + "};\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); check("struct A\n" @@ -11201,7 +11898,7 @@ class TestOther : public TestFixture { " void Init(A _a) { a = std::move(_a); }\n" " A a;" " A a2;" - "};", true, false, true); + "};\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:8:14]: (performance) Function parameter 'a2' should be passed by const reference. [passedByValue]\n", errout_str()); check("struct A\n" @@ -11215,11 +11912,11 @@ class TestOther : public TestFixture { " void Init(A _a) { a = std::move(_a); }\n" " A a;" " A a2;" - "};", true, false, true); + "};\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:8:14]: (performance) Function parameter 'a2' should be passed by const reference. [passedByValue]\n", errout_str()); check("std::map m;\n" // #10817 - "void f(const decltype(m)::const_iterator i) {}"); + "void f(const decltype(m)::const_iterator i) {}\n"); ASSERT_EQUALS("", errout_str()); check("int (*pf) (std::vector) = nullptr;\n" // #12118 @@ -11252,13 +11949,26 @@ class TestOther : public TestFixture { "void f(S s) {}\n"); ASSERT_EQUALS("", errout_str()); + check("struct T {\n" // #14667 + " U u1, u2;\n" + " union {\n" + " enum { E0, E1 } e;\n" + " U u3;\n" + " T i;\n" + " } x;\n" + "};\n" + "T f(T t) {\n" + " return t;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); // don't crash + Settings settingsUnix32 = settingsBuilder().platform(Platform::Type::Unix32).build(); check("struct S {\n" // #13850 " int i0 : 32;\n" " int i1 : 16;\n" " unsigned short u16;\n" "};\n" - "void f(S s) {}\n", true, true, true, false, &settingsUnix32); + "void f(S s) {}\n", dinit(CheckOptions, $.settings = &settingsUnix32)); ASSERT_EQUALS("", errout_str()); } @@ -11266,33 +11976,33 @@ class TestOther : public TestFixture { // positive test check("bool f(int x){\n" " return isless(x,x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (warning) Comparison of two identical variables with isless(x,x) always evaluates to false. [comparisonFunctionIsAlwaysTrueOrFalse]\n", errout_str()); check("bool f(int x){\n" " return isgreater(x,x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (warning) Comparison of two identical variables with isgreater(x,x) always evaluates to false. [comparisonFunctionIsAlwaysTrueOrFalse]\n", errout_str()); check("bool f(int x){\n" " return islessgreater(x,x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (warning) Comparison of two identical variables with islessgreater(x,x) always evaluates to false. [comparisonFunctionIsAlwaysTrueOrFalse]\n", errout_str()); check("bool f(int x){\n" " return islessequal(x,x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (warning) Comparison of two identical variables with islessequal(x,x) always evaluates to true. [comparisonFunctionIsAlwaysTrueOrFalse]\n", errout_str()); check("bool f(int x){\n" " return isgreaterequal(x,x);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:11]: (warning) Comparison of two identical variables with isgreaterequal(x,x) always evaluates to true. [comparisonFunctionIsAlwaysTrueOrFalse]\n", errout_str()); // no warning should be reported for check("bool f(int x, int y){\n" " return isgreaterequal(x,y) && islessequal(x,y) && islessgreater(x,y) && isgreater(x,y) && isless(x,y);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -11300,19 +12010,19 @@ class TestOther : public TestFixture { // no signed integer overflow should happen check("void f(unsigned long long ull) {\n" " if (ull == 0x89504e470d0a1a0a || ull == 0x8a4d4e470d0a1a0a) ;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void redundantPointerOp() { check("int *f(int *x) {\n" " return &*x;\n" - "}\n", true, true); + "}\n"); ASSERT_EQUALS("[test.cpp:2:12]: (style) Redundant pointer operation on 'x' - it's already a pointer. [redundantPointerOp]\n", errout_str()); check("int *f(int *y) {\n" " return &(*y);\n" - "}\n", true, true); + "}\n"); ASSERT_EQUALS("[test.cpp:2:12]: (style) Redundant pointer operation on 'y' - it's already a pointer. [redundantPointerOp]\n", errout_str()); check("int f() {\n" // #10991 @@ -11320,18 +12030,18 @@ class TestOther : public TestFixture { " int result1 = *(&value);\n" " int result2 = *&value;\n" " return result1 + result2;\n" - "}\n", true, true); + "}\n"); ASSERT_EQUALS("[test.cpp:3:19]: (style) Redundant pointer operation on 'value' - it's already a variable. [redundantPointerOp]\n" "[test.cpp:4:19]: (style) Redundant pointer operation on 'value' - it's already a variable. [redundantPointerOp]\n", errout_str()); check("void f(int& a, int b) {\n" " *(&a) = b;\n" - "}\n", true, true); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (style) Redundant pointer operation on 'a' - it's already a variable. [redundantPointerOp]\n", errout_str()); - check("void f(int**& p) {}\n", true, true); + check("void f(int**& p) {}\n"); ASSERT_EQUALS("", errout_str()); checkP("#define RESTORE(ORIG, COPY) { *ORIG = *COPY; }\n" @@ -11343,38 +12053,38 @@ class TestOther : public TestFixture { // no warning for bitwise AND check("void f(const int *b) {\n" " int x = 0x20 & *b;\n" - "}\n", true, true); + "}\n"); ASSERT_EQUALS("", errout_str()); // No message for double pointers to structs check("void f(struct foo **my_struct) {\n" " char **pass_to_func = &(*my_struct)->buf;\n" - "}\n", true, true); + "}\n"); ASSERT_EQUALS("", errout_str()); // another double pointer to struct - with an array check("void f(struct foo **my_struct) {\n" " char **pass_to_func = &(*my_struct)->buf[10];\n" - "}\n", true, true); + "}\n"); ASSERT_EQUALS("", errout_str()); // double pointer to array check("void f(char **ptr) {\n" " int *x = &(*ptr)[10];\n" - "}\n", true, true); + "}\n"); ASSERT_EQUALS("[test.cpp:2:10]: (style) Variable 'x' can be declared as pointer to const [constVariablePointer]\n", errout_str()); // function calls check("void f(Mutex *mut) {\n" " pthread_mutex_lock(&*mut);\n" - "}\n", true, false); + "}\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:2:24]: (style) Redundant pointer operation on 'mut' - it's already a pointer. [redundantPointerOp]\n", errout_str()); // make sure we got the AST match for "(" right check("void f(char *ptr) {\n" " if (&*ptr == NULL)\n" " return;\n" - "}\n", true, true); + "}\n"); ASSERT_EQUALS("[test.cpp:2:9]: (style) Redundant pointer operation on 'ptr' - it's already a pointer. [redundantPointerOp]\n", errout_str()); // no warning for macros @@ -11395,7 +12105,7 @@ class TestOther : public TestFixture { void test_isSameExpression() { // see #5738 check("bool isInUnoIncludeFile(StringRef name) {" " return name.startswith(SRCDIR \"/com/\") || name.startswith(SRCDIR \"/uno/\");\n" - "};", true, false); + "};\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); } @@ -11404,7 +12114,7 @@ class TestOther : public TestFixture { " int counter = 0;\n" " InterlockedDecrement(&counter);\n" " whatever();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11413,7 +12123,7 @@ class TestOther : public TestFixture { " if (counter)\n" " return;\n" " destroy();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead. [raceAfterInterlockedDecrement]\n", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11421,7 +12131,7 @@ class TestOther : public TestFixture { " InterlockedDecrement(&counter);\n" " if (!counter)\n" " destroy();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead. [raceAfterInterlockedDecrement]\n", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11430,7 +12140,7 @@ class TestOther : public TestFixture { " if (counter > 0)\n" " return;\n" " destroy();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead. [raceAfterInterlockedDecrement]\n", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11439,7 +12149,7 @@ class TestOther : public TestFixture { " if (0 < counter)\n" " return;\n" " destroy();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead. [raceAfterInterlockedDecrement]\n", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11447,7 +12157,7 @@ class TestOther : public TestFixture { " InterlockedDecrement(&counter);\n" " if (counter == 0)\n" " destroy();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead. [raceAfterInterlockedDecrement]\n", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11455,7 +12165,7 @@ class TestOther : public TestFixture { " InterlockedDecrement(&counter);\n" " if (0 == counter)\n" " destroy();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead. [raceAfterInterlockedDecrement]\n", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11464,7 +12174,7 @@ class TestOther : public TestFixture { " if (0 != counter)\n" " return;\n" " destroy()\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead. [raceAfterInterlockedDecrement]\n", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11473,7 +12183,7 @@ class TestOther : public TestFixture { " if (counter != 0)\n" " return;\n" " destroy()\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead. [raceAfterInterlockedDecrement]\n", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11481,7 +12191,7 @@ class TestOther : public TestFixture { " InterlockedDecrement(&counter);\n" " if (counter <= 0)\n" " destroy();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead. [raceAfterInterlockedDecrement]\n", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11489,7 +12199,7 @@ class TestOther : public TestFixture { " InterlockedDecrement(&counter);\n" " if (0 >= counter)\n" " destroy();\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead. [raceAfterInterlockedDecrement]\n", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11498,7 +12208,7 @@ class TestOther : public TestFixture { " if (newCount)\n" " return;\n" " destroy();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11506,7 +12216,7 @@ class TestOther : public TestFixture { " int newCount = InterlockedDecrement(&counter);\n" " if (!newCount)\n" " destroy();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11515,7 +12225,7 @@ class TestOther : public TestFixture { " if (newCount > 0)\n" " return;\n" " destroy();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11524,7 +12234,7 @@ class TestOther : public TestFixture { " if (0 < newCount)\n" " return;\n" " destroy();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11532,7 +12242,7 @@ class TestOther : public TestFixture { " int newCount = InterlockedDecrement(&counter);\n" " if (newCount == 0)\n" " destroy();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11540,7 +12250,7 @@ class TestOther : public TestFixture { " int newCount = InterlockedDecrement(&counter);\n" " if (0 == newCount)\n" " destroy();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11549,7 +12259,7 @@ class TestOther : public TestFixture { " if (0 != newCount)\n" " return;\n" " destroy()\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11558,7 +12268,7 @@ class TestOther : public TestFixture { " if (newCount != 0)\n" " return;\n" " destroy()\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11566,7 +12276,7 @@ class TestOther : public TestFixture { " int newCount = InterlockedDecrement(&counter);\n" " if (newCount <= 0)\n" " destroy();\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkInterlockedDecrement("void f() {\n" @@ -11574,7 +12284,7 @@ class TestOther : public TestFixture { " int newCount = InterlockedDecrement(&counter);\n" " if (0 >= newCount)\n" " destroy;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); checkInterlockedDecrement("int f() {\n" @@ -11585,7 +12295,7 @@ class TestOther : public TestFixture { " } else {\n" " return counter;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:16]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead. [raceAfterInterlockedDecrement]\n", errout_str()); checkInterlockedDecrement("int f() {\n" @@ -11596,7 +12306,7 @@ class TestOther : public TestFixture { " } else {\n" " return counter;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:16]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead. [raceAfterInterlockedDecrement]\n", errout_str()); @@ -11607,7 +12317,7 @@ class TestOther : public TestFixture { " return 0;\n" " }\n" " return counter;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:12]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead. [raceAfterInterlockedDecrement]\n", errout_str()); checkInterlockedDecrement("int f() {\n" @@ -11617,7 +12327,7 @@ class TestOther : public TestFixture { " return 0;\n" " }\n" " return counter;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:12]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead. [raceAfterInterlockedDecrement]\n", errout_str()); checkInterlockedDecrement("int f() {\n" @@ -11628,7 +12338,7 @@ class TestOther : public TestFixture { " } else\n" " return counter;\n" " \n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:16]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead. [raceAfterInterlockedDecrement]\n", errout_str()); checkInterlockedDecrement("int f() {\n" @@ -11639,21 +12349,21 @@ class TestOther : public TestFixture { " } else\n" " return counter;\n" " \n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:16]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead. [raceAfterInterlockedDecrement]\n", errout_str()); } void testUnusedLabel() { check("void f() {\n" " label:\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (style) Label 'label' is not used. [unusedLabel]\n", errout_str()); check("void f() {\n" " label:\n" " foo();\n" " goto label;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" @@ -11663,28 +12373,28 @@ class TestOther : public TestFixture { "}\n" "void g() {\n" " label:\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:5]: (style) Label 'label' is not used. [unusedLabel]\n", errout_str()); check("void f() {\n" " switch(a) {\n" " default:\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " class X {\n" " protected:\n" " };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " class X {\n" " my_protected:\n" " };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int test(char art) {\n" @@ -11696,7 +12406,7 @@ class TestOther : public TestFixture { " case 2:\n" " return 2;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (warning) Label 'caseZERO' is not used. Should this be a 'case' of the enclosing switch()? [unusedLabelSwitch]\n" "[test.cpp:5:5]: (warning) Label 'case1' is not used. Should this be a 'case' of the enclosing switch()? [unusedLabelSwitch]\n", errout_str()); @@ -11706,57 +12416,87 @@ class TestOther : public TestFixture { " return 2;\n" " }\n" " label:\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:5]: (style) Label 'label' is not used. [unusedLabel]\n", errout_str()); } - #define checkCustomSettings(...) checkCustomSettings_(__FILE__, __LINE__, __VA_ARGS__) - // TODO: use options - template - void checkCustomSettings_(const char* file, int line, const char (&code)[size], bool cpp = true, bool inconclusive = true, bool runSimpleChecks=true, bool verbose=false, Settings* settings = nullptr) { - if (!settings) { - settings = &_settings; - } - settings->certainty.setEnabled(Certainty::inconclusive, inconclusive); - settings->verbose = verbose; - // Tokenize.. - SimpleTokenizer tokenizer(*settings, *this, cpp); - ASSERT_LOC(tokenizer.tokenize(code), file, line); + void testUnusedLabelConfiguration() { + checkP("void f() {\n" + "#ifdef X\n" + " goto END;\n" + "#endif\n" + "END:\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5:1]: (style) Label 'END' is not used. There is #if in function body so the label might be used in code that is removed by the preprocessor. [unusedLabelConfiguration]\n", + errout_str()); + } - // Check.. - runChecks(tokenizer, this); + void testUnusedLabelSwitchConfiguration() { + checkP("void f(int i) {\n" + " switch (i) {\n" + " default:\n" + " break;\n" + "#ifdef X\n" + " case 1:\n" + " goto END;\n" + "#endif\n" + " case 2:\n" + " END:\n" + " return;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:10:5]: (warning) Label 'END' is not used. There is #if in function body so the label might be used in code that is removed by the preprocessor. Should this be a 'case' of the enclosing switch()? [unusedLabelSwitchConfiguration]\n", + errout_str()); + } - (void)runSimpleChecks; // TODO Remove this + void testUnusedLabelPremiumMisra() { // #14467 - enable unusedLabel with --premium=misra-c-20xx flag + Settings s; + check("void f() {\n" + " label:\n" + "}\n", dinit(CheckOptions, $.settings = &s)); + ASSERT_EQUALS("", errout_str()); + s.premiumArgs = "--premium=misra-c-2012"; // <- activates unusedLabel checking + check("void f() {\n" + " label:\n" + "}\n", dinit(CheckOptions, $.settings = &s)); + ASSERT_EQUALS("[test.cpp:2:5]: (style) Label 'label' is not used. [unusedLabel]\n", errout_str()); } + // TODO: only used in a single place +#define checkCustomSettings(...) checkCustomSettings_(__FILE__, __LINE__, __VA_ARGS__) template - void checkCustomSettings_(const char* file, int line, const char (&code)[size], Settings *s) { - checkCustomSettings_(file, line, code, true, true, true, false, s); + void checkCustomSettings_(const char* file, int line, const char (&code)[size], const Settings& settings, bool cpp = true) { + // Tokenize.. + SimpleTokenizer tokenizer(settings, *this, cpp); + ASSERT_LOC(tokenizer.tokenize(code), file, line); + + CheckOther check; + runChecks(check, tokenizer, *this); } void testEvaluationOrder() { check("void f() {\n" " int x = dostuff();\n" " return x + x++;\n" - "}", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("[test.c:3:12]: (error) Expression 'x+x++' depends on order of evaluation of side effects [unknownEvaluationOrder]\n", errout_str()); // #7226 check("long int f1(const char *exp) {\n" " return strtol(++exp, (char **)&exp, 10);\n" - "}", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("", errout_str()); check("long int f1(const char *exp) {\n" " return dostuff(++exp, exp, 10);\n" - "}", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("[test.c:2:23]: (error) Expression '++exp,exp' depends on order of evaluation of side effects [unknownEvaluationOrder]\n", errout_str()); check("void f() {\n" " int a;\n" " while (a=x(), a==123) {}\n" - "}", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("", errout_str()); // # 8717 @@ -11764,50 +12504,56 @@ class TestOther : public TestFixture { " char **local_argv = safe_malloc(sizeof (*local_argv));\n" " int local_argc = 0;\n" " local_argv[local_argc++] = argv[0];\n" - "}\n", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " int x = 0;\n" " return 0 + x++;\n" - "}\n", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("", errout_str()); check("void f(int x, int y) {\n" " int a[10];\n" " a[x+y] = a[y+x]++;;\n" - "}\n", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("[test.c:3:10]: (error) Expression 'a[x+y]=a[y+x]++' depends on order of evaluation of side effects [unknownEvaluationOrder]\n", errout_str()); check("void f(int i) {\n" " int n = ++i + i;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:15]: (error) Expression '++i+i' depends on order of evaluation of side effects [unknownEvaluationOrder]\n", errout_str()); check("long int f1(const char *exp) {\n" " return dostuff(++exp, ++exp, 10);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:23]: (portability) Expression '++exp,++exp' depends on order of evaluation of side effects. Behavior is Unspecified according to c++17 [unknownEvaluationOrder]\n" "[test.cpp:2:23]: (portability) Expression '++exp,++exp' depends on order of evaluation of side effects. Behavior is Unspecified according to c++17 [unknownEvaluationOrder]\n", errout_str()); check("void f(int i) {\n" " int n = (~(-(++i)) + i);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:22]: (error) Expression '~(-(++i))+i' depends on order of evaluation of side effects [unknownEvaluationOrder]\n", errout_str()); - /*const*/ Settings settings11 = settingsBuilder(_settings).cpp(Standards::CPP11).build(); + const Settings settings11 = settingsBuilder(settings0).cpp(Standards::CPP11).certainty(Certainty::inconclusive).build(); checkCustomSettings("void f(int i) {\n" " i = i++ + 2;\n" - "}", &settings11); + "}\n", settings11); ASSERT_EQUALS("[test.cpp:2:11]: (error) Expression 'i+++2' depends on order of evaluation of side effects [unknownEvaluationOrder]\n", errout_str()); + + // #14431 + checkCustomSettings("int f(void) {\n" + " struct baz baz = {.bar = {.foo = {.foo = 1}}};\n" + "}\n", settings0, false); + ASSERT_EQUALS("", errout_str()); } void testEvaluationOrderSelfAssignment() { // self assignment check("void f() {\n" " int x = x = y + 1;\n" - "}", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS( "[test.c:2:9]: (style) Redundant assignment of 'x' to itself. [selfAssignment]\n" "[test.c:2:9]: (style) Redundant assignment of 'x' to itself. [selfAssignment]\n", // duplicate @@ -11819,7 +12565,7 @@ class TestOther : public TestFixture { checkP("#define X x\n" "void f(int x) {\n" " return x + X++;\n" - "}", dinit(CheckPOptions, $.cpp = false)); + "}\n", dinit(CheckPOptions, $.cpp = false)); ASSERT_EQUALS("[test.c:3:12]: (error) Expression 'x+x++' depends on order of evaluation of side effects [unknownEvaluationOrder]\n", errout_str()); } @@ -11827,13 +12573,13 @@ class TestOther : public TestFixture { // FP check("void f(int id) {\n" " id = dostuff(id += 42);\n" - "}", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("", errout_str()); // FN check("void f(int id) {\n" " id = id + dostuff(id += 42);\n" - "}", false); + "}\n", dinit(CheckOptions, $.cpp = false)); TODO_ASSERT_EQUALS("error", "", errout_str()); } @@ -11841,19 +12587,19 @@ class TestOther : public TestFixture { check("int f(void) {\n" " int t;\n" " return (unsigned char)(t=1,t^c);\n" - "}", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("", errout_str()); check("void f(void) {\n" " int t;\n" " dostuff(t=1,t^c);\n" - "}", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("[test.c:3:14]: (error) Expression 't=1,t^c' depends on order of evaluation of side effects [unknownEvaluationOrder]\n", errout_str()); check("void f(void) {\n" " int t;\n" " dostuff((t=1,t),2);\n" - "}", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("", errout_str()); // #8230 @@ -11861,28 +12607,28 @@ class TestOther : public TestFixture { " do\n" " ;\n" " while (++fp, (*fp) <= 0177);\n" - "}\n", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("", errout_str()); check("void hprf(const char* fp) {\n" " do\n" " ;\n" " while (i++, ++fp, (*fp) <= 0177);\n" - "}\n", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("", errout_str()); check("void f(const char* fp) {\n" " do\n" " ;\n" " while (f(++fp, (*fp) <= 7));\n" - "}\n", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("[test.c:4:18]: (error) Expression '++fp,(*fp)<=7' depends on order of evaluation of side effects [unknownEvaluationOrder]\n", errout_str()); } void testEvaluationOrderSizeof() { check("void f(char *buf) {\n" " dostuff(buf++, sizeof(*buf));" - "}", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("", errout_str()); } @@ -11901,7 +12647,7 @@ class TestOther : public TestFixture { " if (0 > d.n) {\n" " return;\n" " }\n" - "}", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("[test.c:8:11]: (style) Checking if unsigned expression 'd.n' is less than zero. [unsignedLessThanZero]\n" "[test.c:12:9]: (style) Checking if unsigned expression 'd.n' is less than zero. [unsignedLessThanZero]\n", errout_str()); @@ -11913,7 +12659,7 @@ class TestOther : public TestFixture { " A a;\n" " g(std::move(a));\n" " g(std::move(a));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:17]: (warning) Access of moved variable 'a'. [accessMoved]\n", errout_str()); } @@ -11927,7 +12673,7 @@ class TestOther : public TestFixture { " }\n" " B b1;\n" " B b2;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:6:24]: (warning) Access of moved variable 'b'. [accessMoved]\n", errout_str()); } @@ -11940,7 +12686,7 @@ class TestOther : public TestFixture { " {}\n" " B b1;\n" " B b2;\n" - "};"); + "};\n"); ASSERT_EQUALS("[test.cpp:5:19]: (warning) Access of moved variable 'b'. [accessMoved]\n", errout_str()); } @@ -11971,7 +12717,7 @@ class TestOther : public TestFixture { " A a;\n" " a = g(std::move(a));\n" " a = g(std::move(a));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -11981,7 +12727,7 @@ class TestOther : public TestFixture { " A a;\n" " B b = g(std::move(a));\n" " C c = g(std::move(a));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:23]: (warning) Access of moved variable 'a'. [accessMoved]\n", errout_str()); } @@ -11997,7 +12743,7 @@ class TestOther : public TestFixture { " h(a);\n" " a = b;\n" " h(a);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:7]: (warning) Access of moved variable 'a'. [accessMoved]\n" "[test.cpp:8:7]: (warning) Access of moved variable 'a'. [accessMoved]\n", errout_str()); } @@ -12008,7 +12754,7 @@ class TestOther : public TestFixture { " A a;\n" " a.reset(g(std::move(a)));\n" " a.reset(g(std::move(a)));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -12020,7 +12766,7 @@ class TestOther : public TestFixture { " A c;\n" " b.reset(g(std::move(a)));\n" " c.reset(g(std::move(a)));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:25]: (warning) Access of moved variable 'a'. [accessMoved]\n", errout_str()); } @@ -12036,7 +12782,7 @@ class TestOther : public TestFixture { " h(a);\n" " a.reset(b);\n" " h(a);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:7]: (warning) Access of moved variable 'a'. [accessMoved]\n" "[test.cpp:8:7]: (warning) Access of moved variable 'a'. [accessMoved]\n", errout_str()); } @@ -12048,7 +12794,7 @@ class TestOther : public TestFixture { " A b = std::move(a);\n" " g(a);\n" " A c = a;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:7]: (warning) Access of moved variable 'a'. [accessMoved]\n" "[test.cpp:6:11]: (warning) Access of moved variable 'a'. [accessMoved]\n", errout_str()); } @@ -12060,7 +12806,7 @@ class TestOther : public TestFixture { " A b = std::move(a);\n" " g(a);\n" " A c = a;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -12071,7 +12817,7 @@ class TestOther : public TestFixture { " A b = std::move(a);\n" " g(a);\n" " A c = a;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:7]: (warning) Access of moved variable 'a'. [accessMoved]\n" "[test.cpp:6:11]: (warning) Access of moved variable 'a'. [accessMoved]\n", errout_str()); } @@ -12082,7 +12828,7 @@ class TestOther : public TestFixture { " A b = std::move(a);\n" " g(a);\n" " A c = a;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:7]: (warning, inconclusive) Access of moved variable 'a'. [accessMoved]\n" "[test.cpp:5:11]: (warning, inconclusive) Access of moved variable 'a'. [accessMoved]\n", errout_str()); } @@ -12095,7 +12841,7 @@ class TestOther : public TestFixture { " if (i)\n" " return g(std::move(b));\n" " return h(std::move(a),std::move(b));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:7:24]: (warning) Access of moved variable 'a'. [accessMoved]\n", errout_str()); } @@ -12105,7 +12851,7 @@ class TestOther : public TestFixture { " g(std::move(v));\n" " v.clear();\n" " if (v.empty()) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -12115,7 +12861,7 @@ class TestOther : public TestFixture { " g(std::move(p));\n" " x = p->x;\n" " y = p->y;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9]: (warning) Access of moved variable 'p'. [accessMoved]\n" "[test.cpp:5:9]: (warning) Access of moved variable 'p'. [accessMoved]\n", errout_str()); } @@ -12125,7 +12871,7 @@ class TestOther : public TestFixture { " std::string s1 = x;\n" " std::string s2 = std::move(s1);\n" " p = &s1;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -12134,16 +12880,16 @@ class TestOther : public TestFixture { " A a;\n" " gx(std::move(a).x());\n" " gy(std::move(a).y());\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void moveAndLambda() { check("void f() {\n" " A a;\n" - " auto h = [a=std::move(a)](){return g(std::move(a));};" + " auto h = [a=std::move(a)](){return g(std::move(a));};\n" " b = a;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -12163,9 +12909,25 @@ class TestOther : public TestFixture { " for (auto &j : g(std::move(l))) { (void)j; }\n" " }\n" "}\n"); - ASSERT_EQUALS("[test.cpp:4:20]: (style) Variable 'j' can be declared as reference to const [constVariableReference]\n" - "[test.cpp:4:36]: (warning) Access of moved variable 'l'. [accessMoved]\n", - errout_str()); + ASSERT_EQUALS("[test.cpp:4:36]: (warning) Access of moved variable 'l'. [accessMoved]\n", errout_str()); + + check("struct S {\n" // #13179 + " operator bool() const { return !m.empty(); }\n" + " std::string m;\n" + "};\n" + "S get();\n" + "void set(S);\n" + "void f() {\n" + " while (S s = get()) {\n" + " set(std::move(s));\n" + " }\n" + "}\n" + "void g() {\n" + " while (S s{ get() }) {\n" + " set(std::move(s));\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void moveCallback() @@ -12198,7 +12960,7 @@ class TestOther : public TestFixture { "void f(T && t) {\n" " g(std::forward(t));\n" " T s = t;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:11]: (warning) Access of forwarded variable 't'. [accessForwarded]\n", errout_str()); } @@ -12224,6 +12986,13 @@ class TestOther : public TestFixture { " cif::condition mWhere;\n" "};\n"); ASSERT_EQUALS("", errout_str()); + + check("void g(std::string);\n" // #14928 + "void f(std::string s) {\n" + " g(std::move(s));\n" + " for (char c : s) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:19]: (warning) Access of moved variable 's'. [accessMoved]\n", errout_str()); } void moveTernary() @@ -12253,6 +13022,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() @@ -12266,6 +13047,38 @@ class TestOther : public TestFixture { ASSERT_EQUALS("[test.cpp:5:8]: (warning) Access of moved variable '.'. [accessMoved]\n", errout_str()); } + void moveOutparam() + { + check("void f(std::vector& v) {\n" // #11300 + " std::string l;\n" + " while (std::getline(std::cin, l)) {\n" + " if (!l.empty()) {\n" + " v.emplace_back(std::move(l));\n" + " }\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + check("void f(std::ifstream& fin, std::set& s) {\n" + " std::string line;\n" + " while (std::getline(fin, line)) {\n" + " s.emplace(std::move(line));\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + + void moveTryEmplace() + { + check("void f(std::map& m, std::string& s) {\n" // #12773 + " bool b = m.try_emplace(\"a\", std::move(s)).second;\n" + " if (!b) {\n" + " std::cout << s;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void funcArgNamesDifferent() { check("void func1(int a, int b, int c);\n" "void func1(int a, int b, int c) { }\n" @@ -12280,7 +13093,7 @@ class TestOther : public TestFixture { "void Fred::func1(int a, int b, int c) { }\n" "void Fred::func2(int A, int B, int C) { }\n" "void Fred::func3(int a, int b, int c) { }\n" - "void Fred::func4(int A, int B, int C) { }"); + "void Fred::func4(int A, int B, int C) { }\n"); ASSERT_EQUALS("[test.cpp:3:16] -> [test.cpp:4:16]: (style, inconclusive) Function 'func2' argument 1 names different: declaration 'a' definition 'A'. [funcArgNamesDifferent]\n" "[test.cpp:3:23] -> [test.cpp:4:23]: (style, inconclusive) Function 'func2' argument 2 names different: declaration 'b' definition 'B'. [funcArgNamesDifferent]\n" "[test.cpp:3:30] -> [test.cpp:4:30]: (style, inconclusive) Function 'func2' argument 3 names different: declaration 'c' definition 'C'. [funcArgNamesDifferent]\n" @@ -12290,6 +13103,39 @@ class TestOther : public TestFixture { "[test.cpp:9:20] -> [test.cpp:14:22]: (style, inconclusive) Function 'func4' argument 1 names different: declaration 'a' definition 'A'. [funcArgNamesDifferent]\n" "[test.cpp:9:31] -> [test.cpp:14:29]: (style, inconclusive) Function 'func4' argument 2 names different: declaration 'b' definition 'B'. [funcArgNamesDifferent]\n" "[test.cpp:9:42] -> [test.cpp:14:36]: (style, inconclusive) Function 'func4' argument 3 names different: declaration 'c' definition 'C'. [funcArgNamesDifferent]\n", errout_str()); + + check("using F1 = void (*)();\n" // #14633 + "void f(F1 a);\n" + "void f(F1 b) {}\n" + "typedef void (*F2)();\n" + "void g(F2 a);\n" + "void g(F2 b) {}\n" + "void h(void (*a)());\n" + "void h(void (*b)()) {}\n"); + ASSERT_EQUALS( + "[test.cpp:2:11] -> [test.cpp:3:11]: (style, inconclusive) Function 'f' argument 1 names different: declaration 'a' definition 'b'. [funcArgNamesDifferent]\n" + "[test.cpp:5:11] -> [test.cpp:6:11]: (style, inconclusive) Function 'g' argument 1 names different: declaration 'a' definition 'b'. [funcArgNamesDifferent]\n" + "[test.cpp:7:15] -> [test.cpp:8:15]: (style, inconclusive) Function 'h' argument 1 names different: declaration 'a' definition 'b'. [funcArgNamesDifferent]\n", + errout_str()); + + check("void f(int a);\n" // #14632 + "void f(int) {}\n" + "void g(int);\n" + "void g(int b) {}\n" + "void h(int);\n" + "void h(int) {}\n"); + ASSERT_EQUALS( + "[test.cpp:1:12]: (style, inconclusive) Function 'f' argument 1 names different: declaration 'a' definition ''. [funcArgNamesDifferentUnnamed]\n" + "[test.cpp:4:12]: (style, inconclusive) Function 'g' argument 1 names different: declaration '' definition 'b'. [funcArgNamesDifferentUnnamed]\n", + errout_str()); + + 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() { @@ -12309,60 +13155,64 @@ class TestOther : public TestFixture { "void Fred::func2(int c, int b, int a) { }\n" "void Fred::func3(int c, int b, int a) { }\n" "void Fred::func4(int c, int b, int a) { }\n", - true, false); + dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("[test.cpp:3:16] -> [test.cpp:4:16]: (warning) Function 'func2' argument order different: declaration 'a, b, c' definition 'c, b, a' [funcArgOrderDifferent]\n" "[test.cpp:5:12] -> [test.cpp:6:16]: (warning) Function 'func3' argument order different: declaration ', b, c' definition 'c, b, a' [funcArgOrderDifferent]\n" "[test.cpp:9:20] -> [test.cpp:14:22]: (warning) Function 'func2' argument order different: declaration 'a, b, c' definition 'c, b, a' [funcArgOrderDifferent]\n" "[test.cpp:10:20] -> [test.cpp:15:22]: (warning) Function 'func3' argument order different: declaration 'a, b, c' definition 'c, b, a' [funcArgOrderDifferent]\n" "[test.cpp:11:16] -> [test.cpp:16:22]: (warning) Function 'func4' argument order different: declaration ', b, c' definition 'c, b, a' [funcArgOrderDifferent]\n", errout_str()); + + check("void f(int N, const int a[N], const int b[N]);\n" // #14710 + "void f(int N, const int a[N], const int b[N]) {}\n"); + ASSERT_EQUALS("", errout_str()); } // #7846 - Syntax error when using C++11 braced-initializer in default argument void cpp11FunctionArgInit() { // syntax error is not expected - ASSERT_NO_THROW(check("\n void foo(int declaration = {}) {" + ASSERT_NO_THROW(check("\n void foo(int declaration = {}) {\n" "\n for (int i = 0; i < 10; i++) {}\n" - "\n }" - "\n ")); + "\n }\n" + "\n")); ASSERT_EQUALS("", errout_str()); } void shadowVariables() { check("int x;\n" - "void f() { int x; }"); + "void f() { int x; }\n"); ASSERT_EQUALS("[test.cpp:1:5] -> [test.cpp:2:16]: (style) Local variable 'x' shadows outer variable [shadowVariable]\n", errout_str()); check("int x();\n" - "void f() { int x; }"); + "void f() { int x; }\n"); ASSERT_EQUALS("[test.cpp:1:5] -> [test.cpp:2:16]: (style) Local variable 'x' shadows outer function [shadowFunction]\n", errout_str()); check("struct C {\n" " C(int x) : x(x) {}\n" // <- we do not want a FP here " int x;\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " if (cond) {int x;}\n" // <- not a shadow variable " int x;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int size() {\n" " int size;\n" // <- not a shadow variable - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" // #8954 - lambda " int x;\n" - " auto f = [](){ int x; }" - "}"); + " auto f = [](){ int x; }\n" + "}\n"); ASSERT_EQUALS("", errout_str()); - check("void f(int x) { int x; }"); + check("void f(int x) { int x; }\n"); ASSERT_EQUALS("[test.cpp:1:12] -> [test.cpp:1:21]: (style) Local variable 'x' shadows outer argument [shadowArgument]\n", errout_str()); - check("class C { C(); void foo() { static int C = 0; } }"); // #9195 - shadow constructor + check("class C { C(); void foo() { static int C = 0; } }\n"); // #9195 - shadow constructor ASSERT_EQUALS("", errout_str()); check("struct C {\n" // #10091 - shadow destructor @@ -12371,7 +13221,7 @@ class TestOther : public TestFixture { " bool C{};\n" " }\n" "};\n" - "C::~C() = default;"); + "C::~C() = default;\n"); ASSERT_EQUALS("", errout_str()); // 10752 - no @@ -12382,21 +13232,21 @@ class TestOther : public TestFixture { " int i = 0;\n" " return i;\n" " }\n" - "};"); + "};\n"); ASSERT_EQUALS("", errout_str()); check("struct S {\n" " int i{};\n" " void f() { int i; }\n" "};\n"); - ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:20]: (style) Local variable 'i' shadows outer variable [shadowVariable]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:20]: (style) Local variable 'i' shadows outer member [shadowMember]\n", errout_str()); check("struct S {\n" " int i{};\n" " std::vector v;\n" " void f() const { for (const int& i : v) {} }\n" "};\n"); - ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:4:38]: (style) Local variable 'i' shadows outer variable [shadowVariable]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:4:38]: (style) Local variable 'i' shadows outer member [shadowMember]\n", errout_str()); check("struct S {\n" // #10405 " F* f{};\n" @@ -12406,14 +13256,14 @@ class TestOther : public TestFixture { "void S::f() const {\n" " for (const F& f : fl) {}\n" "};\n"); - ASSERT_EQUALS("[test.cpp:2:8] -> [test.cpp:7:19]: (style) Local variable 'f' shadows outer variable [shadowVariable]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:2:8] -> [test.cpp:7:19]: (style) Local variable 'f' shadows outer member [shadowMember]\n", errout_str()); check("extern int a;\n" "int a;\n" "static int f(void) {\n" " int a;\n" " return 0;\n" - "}\n", false); + "}\n", dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("[test.c:1:12] -> [test.c:4:9]: (style) Local variable 'a' shadows outer variable [shadowVariable]\n", errout_str()); check("int f() {\n" // #12591 @@ -12428,25 +13278,58 @@ class TestOther : public TestFixture { " friend int f() { int i = 5; return i; }\n" "};\n"); ASSERT_EQUALS("", errout_str()); + + check("int x;\n" + "void f(int x) {}\n"); + ASSERT_EQUALS("[test.cpp:1:5] -> [test.cpp:2:12]: (style) Argument 'x' shadows outer variable [shadowVariable]\n", errout_str()); + + check("void x() {}\n" + "void f(int x) {}\n"); + ASSERT_EQUALS("[test.cpp:1:6] -> [test.cpp:2:12]: (style) Argument 'x' shadows outer function [shadowFunction]\n", errout_str()); + + check("struct S { int v; void func(int v); };\n" + "void S::func(int v) { this->v = v; }\n"); + ASSERT_EQUALS("[test.cpp:1:16] -> [test.cpp:2:18]: (style) Argument 'v' shadows outer member [shadowMember]\n", errout_str()); + + check("struct S { int v; void func(void); };\n" + "void S::func() { int v = 0; }\n"); + ASSERT_EQUALS("[test.cpp:1:16] -> [test.cpp:2:22]: (style) Local variable 'v' shadows outer member [shadowMember]\n", errout_str()); + + check("struct S { int v; explicit S(int v); };\n" + "S::S(int v) : v(v) {}\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct S { int v(); explicit S(int v); };\n" + "S::S(int v) : v(v) {}\n"); + ASSERT_EQUALS("", errout_str()); + + 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() { check("void g(int);\n" "void f(int x) {\n" " g((x & 0x01) >> 7);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:17]: (style) Argument '(x&0x01)>>7' to function g is always 0. It does not matter what value 'x' has. [knownArgument]\n", errout_str()); check("void g(int);\n" "void f(int x) {\n" " g((int)((x & 0x01) >> 7));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:6]: (style) Argument '(int)((x&0x01)>>7)' to function g is always 0. It does not matter what value 'x' has. [knownArgument]\n", errout_str()); check("void g(int, int);\n" "void f(int x) {\n" " g(x, (x & 0x01) >> 7);\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:3:20]: (style) Argument '(x&0x01)>>7' to function g is always 0. It does not matter what value 'x' has. [knownArgument]\n", errout_str()); @@ -12454,65 +13337,65 @@ class TestOther : public TestFixture { check("void g(int);\n" "void f(int x) {\n" " g(0);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void g(int);\n" "void h() { return 1; }\n" "void f(int x) {\n" " g(h());\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void g(int);\n" "void f(int x) {\n" " g(std::strlen(\"a\"));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void g(int);\n" "void f(int x) {\n" " g((int)0);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void g(Foo *);\n" "void f() {\n" " g(reinterpret_cast(0));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void g(int);\n" "void f(int x) {\n" " x = 0;\n" " g(x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void g(int);\n" "void f() {\n" " const int x = 0;\n" " g(x + 1);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void g(int);\n" "void f() {\n" " char i = 1;\n" " g(static_cast(i));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("char *yytext;\n" "void re_init_scanner() {\n" " int size = 256;\n" " yytext = xmalloc(size * sizeof *yytext);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(const char *c) {\n" " if (*c == '+' && (operand || !isalnum(*c))) {}\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #8986 @@ -12520,14 +13403,14 @@ class TestOther : public TestFixture { "void g() {\n" " const int x[] = { 10, 10 };\n" " f(x[0]);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int);\n" "void g() {\n" " int x[] = { 10, 10 };\n" " f(x[0]);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:9]: (style) Variable 'x' can be declared as const array [constVariable]\n", errout_str()); check("struct A { int x; };" @@ -12536,21 +13419,21 @@ class TestOther : public TestFixture { " A y;\n" " y.x = 1;\n" " g(y.x);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // allow known argument value in assert call check("void g(int);\n" "void f(int x) {\n" " ASSERT((int)((x & 0x01) >> 7));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9905 - expression that does not use integer calculation at all check("void foo() {\n" " const std::string heading = \"Interval\";\n" " std::cout << std::setw(heading.length());\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9909 - struct member with known value @@ -12561,7 +13444,7 @@ class TestOther : public TestFixture { "void growLongStack(LongStack* self) {\n" " self->maxsize = 32;\n" " dostuff(self->maxsize * sizeof(intptr_t));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #11894 @@ -12656,7 +13539,7 @@ class TestOther : public TestFixture { " bar(P, N); \n" " if (c ? a : b)\n" " baz(P, N); \n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -12669,7 +13552,7 @@ class TestOther : public TestFixture { " diff = 1;\n" " }\n" " return diff;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:15] -> [test.cpp:5:8] -> [test.cpp:3:15] -> [test.cpp:5:14] -> [test.cpp:5:12]: (error) Comparing pointers that point to different objects [comparePointers]\n", errout_str()); @@ -12680,7 +13563,7 @@ class TestOther : public TestFixture { " int* xp = &x;\n" " int* yp = &y;\n" " return xp > yp;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:9] -> [test.cpp:4:15] -> [test.cpp:3:9] -> [test.cpp:5:15] -> [test.cpp:6:15]: (error) Comparing pointers that point to different objects [comparePointers]\n" "[test.cpp:4:10]: (style) Variable 'xp' can be declared as pointer to const [constVariablePointer]\n" @@ -12691,7 +13574,7 @@ class TestOther : public TestFixture { " int x = 0;\n" " int y = 1;\n" " return &x > &y;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:9] -> [test.cpp:4:12] -> [test.cpp:3:9] -> [test.cpp:4:17] -> [test.cpp:4:15]: (error) Comparing pointers that point to different objects [comparePointers]\n", errout_str()); @@ -12703,7 +13586,7 @@ class TestOther : public TestFixture { " int* xp = &x.data;\n" " int* yp = &y.data;\n" " return xp > yp;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:3:7] -> [test.cpp:5:15] -> [test.cpp:4:7] -> [test.cpp:6:15] -> [test.cpp:7:15]: (error) Comparing pointers that point to different objects [comparePointers]\n" "[test.cpp:5:10]: (style) Variable 'xp' can be declared as pointer to const [constVariablePointer]\n" @@ -12717,7 +13600,7 @@ class TestOther : public TestFixture { " int* xp = &x->data;\n" " int* yp = &y->data;\n" " return xp > yp;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:10] -> [test.cpp:3:12] -> [test.cpp:5:15] -> [test.cpp:2:16] -> [test.cpp:4:12] -> [test.cpp:6:15] -> [test.cpp:7:15]: (error) Comparing pointers that point to different objects [comparePointers]\n" "[test.cpp:5:10]: (style) Variable 'xp' can be declared as pointer to const [constVariablePointer]\n" @@ -12726,7 +13609,7 @@ class TestOther : public TestFixture { check("bool f(int * xp, int* yp) {\n" " return &xp > &yp;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:1:14] -> [test.cpp:2:12] -> [test.cpp:1:23] -> [test.cpp:2:18] -> [test.cpp:2:16]: (error) Comparing pointers that point to different objects [comparePointers]\n", errout_str()); @@ -12735,7 +13618,7 @@ class TestOther : public TestFixture { " int x = 0;\n" " int y = 1;\n" " return &x - &y;\n" - "}"); + "}\n"); ASSERT_EQUALS( "[test.cpp:2:9] -> [test.cpp:4:12] -> [test.cpp:3:9] -> [test.cpp:4:17] -> [test.cpp:4:15]: (error) Subtracting pointers that point to different objects [subtractPointers]\n", errout_str()); @@ -12745,19 +13628,19 @@ class TestOther : public TestFixture { " int* xp = &x[0];\n" " int* yp = &x[1];\n" " return xp > yp;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:10]: (style) Variable 'xp' can be declared as pointer to const [constVariablePointer]\n" "[test.cpp:4:10]: (style) Variable 'yp' can be declared as pointer to const [constVariablePointer]\n", errout_str()); check("bool f(const int * xp, const int* yp) {\n" " return xp > yp;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("bool f(const int & x, const int& y) {\n" " return &x > &y;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int& g();\n" @@ -12767,7 +13650,7 @@ class TestOther : public TestFixture { " const int* xp = &x;\n" " const int* yp = &y;\n" " return xp > yp;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("struct A {int data;};\n" @@ -12777,7 +13660,7 @@ class TestOther : public TestFixture { " int* xp = &x->data;\n" " int* yp = &y->data;\n" " return xp > yp;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:10]: (style) Variable 'xp' can be declared as pointer to const [constVariablePointer]\n" "[test.cpp:6:10]: (style) Variable 'yp' can be declared as pointer to const [constVariablePointer]\n", errout_str()); @@ -12828,21 +13711,21 @@ class TestOther : public TestFixture { " return A::Hash{}(a);\n" " }\n" " };\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } void moduloOfOne() { check("void f(unsigned int x) {\n" " int y = x % 1;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:13]: (style) Modulo of one is always equal to zero [moduloofone]\n", errout_str()); check("void f() {\n" " for (int x = 1; x < 10; x++) {\n" " int y = 100 % x;\n" " }\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(int i, int j) {\n" // #11191 @@ -12850,6 +13733,13 @@ class TestOther : public TestFixture { " if (j % c) {}\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + check("void f() {\n" + " int i = 0;\n" + " i %= 1;\n" + " (void)i;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:7]: (style) Modulo of one is always equal to zero [moduloofone]\n", errout_str()); } void sameExpressionPointers() { @@ -12868,44 +13758,44 @@ class TestOther : public TestFixture { " union { int i; float f; } u;\n" " u.i = 0;\n" " u.i = u.f;\n" // <- error - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:9]: (error) Overlapping read/write of union is undefined behavior [overlappingWriteUnion]\n", errout_str()); check("void foo() {\n" // #11013 " union { struct { uint8_t a; uint8_t b; }; uint16_t c; } u;\n" " u.a = u.b = 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // memcpy check("void foo() {\n" " char a[10];\n" " memcpy(&a[5], &a[4], 2u);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Overlapping read/write in memcpy() is undefined behavior [overlappingWriteFunction]\n", errout_str()); check("void foo() {\n" " char a[10];\n" " memcpy(a+5, a+4, 2u);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Overlapping read/write in memcpy() is undefined behavior [overlappingWriteFunction]\n", errout_str()); check("void foo() {\n" " char a[10];\n" " memcpy(a, a+1, 2u);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Overlapping read/write in memcpy() is undefined behavior [overlappingWriteFunction]\n", errout_str()); check("void foo() {\n" " char a[8];\n" " memcpy(&a[0], &a[4], 4u);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("_Bool a[10];\n" // #10350 "void foo() {\n" " memcpy(&a[5], &a[4], 2u * sizeof(a[0]));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Overlapping read/write in memcpy() is undefined behavior [overlappingWriteFunction]\n", errout_str()); check("int K[2];\n" // #12638 @@ -12914,7 +13804,7 @@ class TestOther : public TestFixture { " memcpy(&K[1], &K[0], sizeof(K[0]));\n" " memcpy(p, p + 1, sizeof(*p));\n" " memcpy(p + 1, p, sizeof(*p));\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("int K[2];\n" @@ -12923,7 +13813,7 @@ class TestOther : public TestFixture { " memcpy(&K[1], &K[0], 2 *sizeof(K[0]));\n" " memcpy(p, p + 1, 2 * sizeof(*p));\n" " memcpy(p + 1, p, 2 * sizeof(*p));\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Overlapping read/write in memcpy() is undefined behavior [overlappingWriteFunction]\n" "[test.cpp:4:5]: (error) Overlapping read/write in memcpy() is undefined behavior [overlappingWriteFunction]\n" "[test.cpp:5:5]: (error) Overlapping read/write in memcpy() is undefined behavior [overlappingWriteFunction]\n" @@ -12934,25 +13824,25 @@ class TestOther : public TestFixture { check("void foo() {\n" " wchar_t a[10];\n" " wmemcpy(&a[5], &a[4], 2u);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Overlapping read/write in wmemcpy() is undefined behavior [overlappingWriteFunction]\n", errout_str()); check("void foo() {\n" " wchar_t a[10];\n" " wmemcpy(a+5, a+4, 2u);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Overlapping read/write in wmemcpy() is undefined behavior [overlappingWriteFunction]\n", errout_str()); check("void foo() {\n" " wchar_t a[10];\n" " wmemcpy(a, a+1, 2u);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Overlapping read/write in wmemcpy() is undefined behavior [overlappingWriteFunction]\n", errout_str()); // strcpy check("void foo(char *ptr) {\n" " strcpy(ptr, ptr);\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:2:5]: (error) Overlapping read/write in strcpy() is undefined behavior [overlappingWriteFunction]\n", errout_str()); } @@ -12991,14 +13881,14 @@ class TestOther : public TestFixture { "}\n"); ASSERT_EQUALS("", errout_str()); - check("struct A { bool x; };\n" + check("struct A { bool x; };\n" // #14481 "bool f(A* a) {\n" " if (a) {\n" " return a->x;\n" " }\n" " return false;\n" "}\n"); - ASSERT_EQUALS("", errout_str()); + ASSERT_EQUALS("[test.cpp:2:11]: (style) Parameter 'a' can be declared as pointer to const [constParameterPointer]\n", errout_str()); check("struct A { int* x; };\n" "bool f(A a) {\n" @@ -13009,7 +13899,7 @@ class TestOther : public TestFixture { "}\n"); ASSERT_EQUALS("[test.cpp:4:17]: (style) Pointer expression 'a.x' converted to bool is always true. [knownPointerToBool]\n", errout_str()); - check("void f(bool* b) { if (b) *b = true; }"); + check("void f(bool* b) { if (b) *b = true; }\n"); ASSERT_EQUALS("", errout_str()); check("bool f() {\n" @@ -13057,7 +13947,7 @@ class TestOther : public TestFixture { "void f() {\n" " bool b[2] = {};\n" " g(b);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -13230,6 +14120,90 @@ class TestOther : public TestFixture { "[test.cpp:2:13] -> [test.cpp:3:11]: (style) The comparison 'i > +1' is always false. [knownConditionTrueFalse]\n", errout_str()); } + + void unionZeroInitBasic() { + check( + "union bad_union_0 {\n" + " char c;\n" + " long long i64;\n" + " void *p;\n" + "};\n" + "\n" + "typedef union {\n" + " char c;\n" + " int i;\n" + "} bad_union_1;\n" + "\n" + "extern void e(union bad_union_0 *);\n" + "\n" + "void\n" + "foo(void)\n" + "{\n" + " union { int i; char c; } good0 = {0};\n" + " union { int i; char c; } good1 = {};\n" + "\n" + " union { char c; int i; } bad0 = {0};\n" + " union bad_union_0 bad1 = {0};\n" + " e(&bad1);\n" + " bad_union_1 bad2 = {0};\n" + "}\n"); + const std::string exp = unionZeroInitMessage(20, 28, "bad0", "i") + + unionZeroInitMessage(21, 21, "bad1", "i64") + + unionZeroInitMessage(23, 15, "bad2", "i"); + ASSERT_EQUALS(exp, errout_str()); + } + + void unionZeroInitArrayMember() { + check( + "void foo(void) {\n" + " union { int c; char s8[2]; } u = {0};\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + + void unionZeroInitStructMember() { + check( + "void foo(void) {\n" + " union {\n" + " int c;\n" + " struct {\n" + " char x;\n" + " struct {\n" + " char y;\n" + " } s1;\n" + " } s0;\n" + " } u = {0};\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + + void unionZeroInitUnknownType() { + check( + "union u {\n" + " Unknown x;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + + void unionZeroInitBitfields() { + check( + "typedef union Evex {\n" + " int u32;\n" + " struct {\n" + " char mmm:3,\n" + " b4:1,\n" + " r4:1,\n" + " b3:1,\n" + " x3:1,\n" + " r3:1;\n" + " } extended;\n" + "} Evex;\n" + "\n" + "void foo(void) {\n" + " Evex evex = {0};\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } }; REGISTER_TEST(TestOther) diff --git a/test/testpath.cpp b/test/testpath.cpp index 44d5f10a30b..0ebe343685f 100644 --- a/test/testpath.cpp +++ b/test/testpath.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -57,6 +57,7 @@ class TestPath : public TestFixture { TEST_CASE(getAbsolutePath); TEST_CASE(exists); TEST_CASE(fromNativeSeparators); + TEST_CASE(isRelative); } void removeQuotationMarks() const { @@ -172,11 +173,38 @@ class TestPath : public TestFixture { } void join() const { + ASSERT_EQUALS("", Path::join("", "")); + ASSERT_EQUALS("b", Path::join("", "b")); + ASSERT_EQUALS("/b", Path::join("", "/b")); + ASSERT_EQUALS("/b", Path::join("", "\\b")); + ASSERT_EQUALS("a", Path::join("a", "")); - ASSERT_EQUALS("a", Path::join("", "a")); ASSERT_EQUALS("a/b", Path::join("a", "b")); - ASSERT_EQUALS("a/b", Path::join("a/", "b")); ASSERT_EQUALS("/b", Path::join("a", "/b")); + ASSERT_EQUALS("/b", Path::join("a", "\\b")); + + ASSERT_EQUALS("a/", Path::join("a/", "")); + ASSERT_EQUALS("a/b", Path::join("a/", "b")); + ASSERT_EQUALS("/b", Path::join("a/", "/b")); + ASSERT_EQUALS("/b", Path::join("a/", "\\b")); + + ASSERT_EQUALS("a/", Path::join("a\\", "")); + ASSERT_EQUALS("a/b", Path::join("a\\", "b")); + ASSERT_EQUALS("/b", Path::join("a\\", "/b")); + ASSERT_EQUALS("/b", Path::join("a\\", "\\b")); + + // TODO: how to absolute Windows path in path2? + //ASSERT_EQUALS("", Path::join("a", "s:/b")); + + //ASSERT_EQUALS("", Path::join("S:\\a", "S:/b")); + //ASSERT_EQUALS("", Path::join("S:\\a", "S:\\b")); + //ASSERT_EQUALS("", Path::join("S:\\a", "/b")); + + //ASSERT_EQUALS("", Path::join("S:/a", "S:/b")); + //ASSERT_EQUALS("", Path::join("S:/a", "S:\\b")); + //ASSERT_EQUALS("", Path::join("S:/a", "/b")); + + ASSERT_EQUALS("a/b/c", Path::join("a", "b", "c")); } void isDirectory() const { @@ -290,7 +318,7 @@ class TestPath : public TestFixture { ASSERT_EQUALS(Standards::Language::CPP, Path::identify("/mnt/c/foo/index.cpp", false)); ASSERT_EQUALS(Standards::Language::CPP, Path::identify("/mnt/c/foo/index.Cpp", false)); - // TODO: check for case-insenstive filesystem instead + // TODO: check for case-insensitive filesystem instead // In unix .C is considered C++ #if !defined(_WIN32) && !(defined(__APPLE__) && defined(__MACH__)) ASSERT_EQUALS(Standards::Language::CPP, Path::identify("index.C", false)); @@ -488,7 +516,8 @@ class TestPath : public TestFixture { ASSERT_EQUALS(expected, Path::getAbsoluteFilePath(Path::join(cwd, "testabspath.txt"))); std::string cwd_up = Path::getPathFromFilename(cwd); - cwd_up.pop_back(); // remove trailing slash + if (cwd_up != "/") + cwd_up.pop_back(); // remove trailing slash ASSERT_EQUALS(cwd_up, Path::getAbsoluteFilePath(Path::join(cwd, ".."))); ASSERT_EQUALS(cwd_up, Path::getAbsoluteFilePath(Path::join(cwd, "../"))); ASSERT_EQUALS(cwd_up, Path::getAbsoluteFilePath(Path::join(cwd, "..\\"))); @@ -508,7 +537,7 @@ class TestPath : public TestFixture { #ifndef _WIN32 // the underlying realpath() call only returns something if the path actually exists - ASSERT_THROW_EQUALS_2(Path::getAbsoluteFilePath("testabspath2.txt"), std::runtime_error, "path 'testabspath2.txt' does not exist"); + ASSERT_THROW_EQUALS(Path::getAbsoluteFilePath("testabspath2.txt"), std::runtime_error, "path 'testabspath2.txt' does not exist"); #else ASSERT_EQUALS(Path::toNativeSeparators(Path::join(cwd, "testabspath2.txt")), Path::getAbsoluteFilePath("testabspath2.txt")); #endif @@ -547,7 +576,7 @@ class TestPath : public TestFixture { #endif #ifndef _WIN32 - ASSERT_THROW_EQUALS_2(Path::getAbsoluteFilePath("C:\\path\\files.txt"), std::runtime_error, "path 'C:\\path\\files.txt' does not exist"); + ASSERT_THROW_EQUALS(Path::getAbsoluteFilePath("C:\\path\\files.txt"), std::runtime_error, "path 'C:\\path\\files.txt' does not exist"); #endif // TODO: test UNC paths @@ -593,6 +622,33 @@ class TestPath : public TestFixture { ASSERT_EQUALS("//lib/file.c", Path::fromNativeSeparators("\\\\lib\\file.c")); ASSERT_EQUALS("./lib/file.c", Path::fromNativeSeparators(".\\lib\\file.c")); } + + void isRelative() const { + ASSERT_EQUALS(true, Path::isRelative("dir/file")); + ASSERT_EQUALS(true, Path::isRelative("dir\\file")); + + // TODO: is this expected? + ASSERT_EQUALS(true, Path::isRelative("file/")); + ASSERT_EQUALS(true, Path::isRelative("file\\")); + + ASSERT_EQUALS(false, Path::isRelative("file")); + +#ifdef _WIN32 + // this is a relative path on Windows + ASSERT_EQUALS(true, Path::isRelative("/dir/file")); +#else + ASSERT_EQUALS(false, Path::isRelative("/dir/file")); +#endif + +#ifdef _WIN32 + // TODO: this is not detected as absolute path in _WIN32 builds + ASSERT_EQUALS(false, Path::isRelative("c:\\dir\\file")); + ASSERT_EQUALS(false, Path::isRelative("c:/dir/file")); +#else + ASSERT_EQUALS(true, Path::isRelative("c:\\dir\\file")); + ASSERT_EQUALS(true, Path::isRelative("c:/dir/file")); +#endif + } }; REGISTER_TEST(TestPath) diff --git a/test/testpathmatch.cpp b/test/testpathmatch.cpp index 2be6a943845..7e721502a11 100644 --- a/test/testpathmatch.cpp +++ b/test/testpathmatch.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,6 +28,11 @@ class TestPathMatch : public TestFixture { TestPathMatch() : TestFixture("TestPathMatch") {} private: + class PathMatchTest final : public PathMatch + { + friend class TestPathMatch; + }; + static constexpr auto unix = PathMatch::Syntax::unix; static constexpr auto windows = PathMatch::Syntax::windows; static constexpr auto ifreg = PathMatch::Filemode::regular; @@ -277,7 +282,7 @@ class TestPathMatch : public TestFixture { void pathiterator() const { /* See https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats * for information on Windows path syntax. */ - using PathIterator = PathMatch::PathIterator; + using PathIterator = PathMatchTest::PathIterator; ASSERT_EQUALS("/", PathIterator("/", nullptr, unix).read()); ASSERT_EQUALS("/", PathIterator("//", nullptr, unix).read()); ASSERT_EQUALS("/", PathIterator("/", "/", unix).read()); @@ -291,7 +296,7 @@ class TestPathMatch : public TestFixture { ASSERT_EQUALS("", PathIterator(nullptr, "", unix).read()); ASSERT_EQUALS("", PathIterator(nullptr, nullptr, unix).read()); ASSERT_EQUALS("c:", PathIterator("C:", nullptr, windows).read()); - /* C: without slash is a bit ambigous. It should probably not be considered a root because it's + /* C: without slash is a bit ambiguous. It should probably not be considered a root because it's * not fully qualified (it designates the current directory on the C drive), * so this test could be considered to be unspecified behavior. */ ASSERT_EQUALS("c:", PathIterator("C:", "../..", windows).read()); diff --git a/test/testplatform.cpp b/test/testplatform.cpp index d01eefcb812..ccb7d9b41a8 100644 --- a/test/testplatform.cpp +++ b/test/testplatform.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-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 @@ -37,11 +37,12 @@ class TestPlatform : public TestFixture { TEST_CASE(valid_config_win32w); TEST_CASE(valid_config_unix32); TEST_CASE(valid_config_win64); + // TODO: test native and unspecified TEST_CASE(valid_config_file_1); TEST_CASE(valid_config_file_2); - TEST_CASE(valid_config_file_3); TEST_CASE(valid_config_file_4); TEST_CASE(invalid_config_file_1); + TEST_CASE(invalid_config_file_2); TEST_CASE(empty_elements); TEST_CASE(default_platform); TEST_CASE(limitsDefines); @@ -50,7 +51,12 @@ class TestPlatform : public TestFixture { TEST_CASE(wrong_root_node); } - static bool readPlatform(Platform& platform, const char* xmldata) { + class PlatformTest final : public Platform + { + friend class TestPlatform; + }; + + static bool readPlatform(PlatformTest& platform, const char* xmldata) { tinyxml2::XMLDocument doc; return (doc.Parse(xmldata) == tinyxml2::XML_SUCCESS) && platform.loadFromXmlDocument(&doc); } @@ -58,7 +64,7 @@ class TestPlatform : public TestFixture { void empty() const { // An empty platform file does not change values, only the type. constexpr char xmldata[] = "\n"; - Platform platform; + PlatformTest platform; // TODO: this should fail - platform files need to be complete TODO_ASSERT(!readPlatform(platform, xmldata)); } @@ -80,7 +86,7 @@ class TestPlatform : public TestFixture { ASSERT_EQUALS(2, platform.sizeof_wchar_t); ASSERT_EQUALS(4, platform.sizeof_size_t); ASSERT_EQUALS(4, platform.sizeof_pointer); - ASSERT_EQUALS('\0', platform.defaultSign); + ASSERT_EQUALS('s', platform.defaultSign); ASSERT_EQUALS(8, platform.char_bit); ASSERT_EQUALS(16, platform.short_bit); ASSERT_EQUALS(32, platform.int_bit); @@ -105,12 +111,15 @@ class TestPlatform : public TestFixture { ASSERT_EQUALS(4, platform.sizeof_wchar_t); ASSERT_EQUALS(8, platform.sizeof_size_t); ASSERT_EQUALS(8, platform.sizeof_pointer); - ASSERT_EQUALS('\0', platform.defaultSign); + ASSERT_EQUALS('s', platform.defaultSign); ASSERT_EQUALS(8, platform.char_bit); ASSERT_EQUALS(16, platform.short_bit); ASSERT_EQUALS(32, platform.int_bit); ASSERT_EQUALS(64, platform.long_bit); ASSERT_EQUALS(64, platform.long_long_bit); + ASSERT_EQUALS(32, platform.float_bit); + ASSERT_EQUALS(64, platform.double_bit); + ASSERT_EQUALS(128, platform.long_double_bit); } void valid_config_win32w() const { @@ -130,12 +139,15 @@ class TestPlatform : public TestFixture { ASSERT_EQUALS(2, platform.sizeof_wchar_t); ASSERT_EQUALS(4, platform.sizeof_size_t); ASSERT_EQUALS(4, platform.sizeof_pointer); - ASSERT_EQUALS('\0', platform.defaultSign); + ASSERT_EQUALS('s', platform.defaultSign); ASSERT_EQUALS(8, platform.char_bit); ASSERT_EQUALS(16, platform.short_bit); ASSERT_EQUALS(32, platform.int_bit); ASSERT_EQUALS(32, platform.long_bit); ASSERT_EQUALS(64, platform.long_long_bit); + ASSERT_EQUALS(32, platform.float_bit); + ASSERT_EQUALS(64, platform.double_bit); + ASSERT_EQUALS(64, platform.long_double_bit); } void valid_config_unix32() const { @@ -155,12 +167,15 @@ class TestPlatform : public TestFixture { ASSERT_EQUALS(4, platform.sizeof_wchar_t); ASSERT_EQUALS(4, platform.sizeof_size_t); ASSERT_EQUALS(4, platform.sizeof_pointer); - ASSERT_EQUALS('\0', platform.defaultSign); + ASSERT_EQUALS('s', platform.defaultSign); ASSERT_EQUALS(8, platform.char_bit); ASSERT_EQUALS(16, platform.short_bit); ASSERT_EQUALS(32, platform.int_bit); ASSERT_EQUALS(32, platform.long_bit); ASSERT_EQUALS(64, platform.long_long_bit); + ASSERT_EQUALS(32, platform.float_bit); + ASSERT_EQUALS(64, platform.double_bit); + ASSERT_EQUALS(96, platform.long_double_bit); } void valid_config_win64() const { @@ -180,12 +195,15 @@ class TestPlatform : public TestFixture { ASSERT_EQUALS(2, platform.sizeof_wchar_t); ASSERT_EQUALS(8, platform.sizeof_size_t); ASSERT_EQUALS(8, platform.sizeof_pointer); - ASSERT_EQUALS('\0', platform.defaultSign); + ASSERT_EQUALS('s', platform.defaultSign); ASSERT_EQUALS(8, platform.char_bit); ASSERT_EQUALS(16, platform.short_bit); ASSERT_EQUALS(32, platform.int_bit); ASSERT_EQUALS(32, platform.long_bit); ASSERT_EQUALS(64, platform.long_long_bit); + ASSERT_EQUALS(32, platform.float_bit); + ASSERT_EQUALS(64, platform.double_bit); + ASSERT_EQUALS(64, platform.long_double_bit); } void valid_config_file_1() const { @@ -193,6 +211,7 @@ class TestPlatform : public TestFixture { // Similar to the avr8 platform file. constexpr char xmldata[] = "\n" "\n" + " false\n" " 8\n" " unsigned\n" " \n" @@ -209,7 +228,7 @@ class TestPlatform : public TestFixture { " 2\n" " \n" " "; - Platform platform; + PlatformTest platform; ASSERT(readPlatform(platform, xmldata)); ASSERT_EQUALS(Platform::Type::File, platform.type); ASSERT(!platform.isWindows()); @@ -237,6 +256,7 @@ class TestPlatform : public TestFixture { // char_bit > 8. constexpr char xmldata[] = "\n" "\n" + " true\n" " 20\n" " signed\n" " \n" @@ -253,10 +273,10 @@ class TestPlatform : public TestFixture { " 11\n" " \n" " "; - Platform platform; + PlatformTest platform; ASSERT(readPlatform(platform, xmldata)); ASSERT_EQUALS(Platform::Type::File, platform.type); - ASSERT(!platform.isWindows()); + ASSERT(platform.isWindows()); ASSERT_EQUALS(20, platform.char_bit); ASSERT_EQUALS('s', platform.defaultSign); ASSERT_EQUALS(1, platform.sizeof_bool); @@ -276,11 +296,12 @@ class TestPlatform : public TestFixture { ASSERT_EQUALS(100, platform.long_long_bit); } - void valid_config_file_3() const { - // Valid platform configuration without any usable information. + void invalid_config_file_2() const { + // Invalid platform configuration without any usable information. // Similar like an empty file. constexpr char xmldata[] = "\n" "\n" + " true\n" " 8\n" " unsigned\n" " \n" @@ -297,7 +318,7 @@ class TestPlatform : public TestFixture { " 11\n" " \n" " "; - Platform platform; + PlatformTest platform; // TODO: needs to fail - files need to be complete TODO_ASSERT(!readPlatform(platform, xmldata)); } @@ -307,6 +328,7 @@ class TestPlatform : public TestFixture { // set to 0. constexpr char xmldata[] = "\n" "\n" + " true\n" " 0\n" " z\n" " \n" @@ -323,10 +345,10 @@ class TestPlatform : public TestFixture { " 0\n" " \n" " "; - Platform platform; + PlatformTest platform; ASSERT(readPlatform(platform, xmldata)); ASSERT_EQUALS(Platform::Type::File, platform.type); - ASSERT(!platform.isWindows()); + ASSERT(platform.isWindows()); ASSERT_EQUALS(0, platform.char_bit); ASSERT_EQUALS('z', platform.defaultSign); ASSERT_EQUALS(0, platform.sizeof_bool); @@ -350,6 +372,7 @@ class TestPlatform : public TestFixture { // Invalid XML file: mismatching elements "boolt" vs "bool". constexpr char xmldata[] = "\n" "\n" + " false\n" " 8\n" " unsigned\n" " \n" @@ -366,7 +389,7 @@ class TestPlatform : public TestFixture { " 2\n" " \n" " "; - Platform platform; + PlatformTest platform; ASSERT(!readPlatform(platform, xmldata)); } @@ -375,6 +398,7 @@ class TestPlatform : public TestFixture { // Similar like an empty file. constexpr char xmldata[] = "\n" "\n" + " \n" " \n" " \n" " \n" @@ -391,7 +415,7 @@ class TestPlatform : public TestFixture { " \n" " \n" " "; - Platform platform; + PlatformTest platform; ASSERT(!readPlatform(platform, xmldata)); } @@ -422,14 +446,14 @@ class TestPlatform : public TestFixture { void no_root_node() const { constexpr char xmldata[] = ""; - Platform platform; + PlatformTest platform; ASSERT(!readPlatform(platform, xmldata)); } void wrong_root_node() const { constexpr char xmldata[] = "\n" ""; - Platform platform; + PlatformTest platform; ASSERT(!readPlatform(platform, xmldata)); } }; diff --git a/test/testpostfixoperator.cpp b/test/testpostfixoperator.cpp index 9e95fabc949..85568c974ac 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(); } @@ -72,7 +71,7 @@ class TestPostfixOperator : public TestFixture { " k--;\n" " std::cout << k << std::endl;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class K {};" @@ -83,7 +82,7 @@ class TestPostfixOperator : public TestFixture { " k++;\n" " std::cout << k << std::endl;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:5]: (performance) Prefer prefix ++/-- operators for non-primitive types. [postfixOperator]\n", errout_str()); check("struct K {};" @@ -91,14 +90,14 @@ class TestPostfixOperator : public TestFixture { "{\n" " K k(0);\n" " k++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:5]: (performance) Prefer prefix ++/-- operators for non-primitive types. [postfixOperator]\n", errout_str()); check("struct K {};\n" "void foo(K& k)\n" "{\n" " k++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:5]: (performance) Prefer prefix ++/-- operators for non-primitive types. [postfixOperator]\n", errout_str()); check("union K {};" @@ -106,7 +105,7 @@ class TestPostfixOperator : public TestFixture { "{\n" " K k(0);\n" " k++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:5]: (performance) Prefer prefix ++/-- operators for non-primitive types. [postfixOperator]\n", errout_str()); check("class K {};" @@ -119,7 +118,7 @@ class TestPostfixOperator : public TestFixture { " }\n" " std::cout << k << std::endl;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:9]: (performance) Prefer prefix ++/-- operators for non-primitive types. [postfixOperator]\n", errout_str()); check("class K {};" @@ -133,7 +132,7 @@ class TestPostfixOperator : public TestFixture { " k++;\n" " std::cout << k << std::endl;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:5]: (performance) Prefer prefix ++/-- operators for non-primitive types. [postfixOperator]\n", errout_str()); @@ -145,7 +144,7 @@ class TestPostfixOperator : public TestFixture { " k--;\n" " std::cout << k << std::endl;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:5:5]: (performance) Prefer prefix ++/-- operators for non-primitive types. [postfixOperator]\n", errout_str()); check("class K {};" @@ -156,7 +155,7 @@ class TestPostfixOperator : public TestFixture { " ++k;\n" " std::cout << k << std::endl;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class K {};" @@ -167,7 +166,7 @@ class TestPostfixOperator : public TestFixture { " --k;\n" " std::cout << k << std::endl;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); // #9042 @@ -178,7 +177,7 @@ class TestPostfixOperator : public TestFixture { "};\n" "template \n" "class s {};\n" - "using BOOL = char;"); + "using BOOL = char;\n"); ASSERT_EQUALS("", errout_str()); } @@ -189,7 +188,7 @@ class TestPostfixOperator : public TestFixture { " std::cout << i << std::endl;\n" " }\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class K {};\n" @@ -199,7 +198,7 @@ class TestPostfixOperator : public TestFixture { " std::cout << i << std::endl;\n" " }\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:28]: (performance) Prefer prefix ++/-- operators for non-primitive types. [postfixOperator]\n", errout_str()); check("class K {};\n" @@ -209,7 +208,7 @@ class TestPostfixOperator : public TestFixture { " std::cout << i << std::endl;\n" " }\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("class K {};\n" @@ -219,7 +218,7 @@ class TestPostfixOperator : public TestFixture { " std::cout << i << std::endl;\n" " }\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:27]: (performance) Prefer prefix ++/-- operators for non-primitive types. [postfixOperator]\n", errout_str()); check("class K {};\n" @@ -229,7 +228,7 @@ class TestPostfixOperator : public TestFixture { " std::cout << i << std::endl;\n" " }\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(const std::string &s) {\n" // #7731 @@ -247,7 +246,7 @@ class TestPostfixOperator : public TestFixture { " k++;\n" " std::cout << k << std::endl;\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:5]: (performance) Prefer prefix ++/-- operators for non-primitive types. [postfixOperator]\n", errout_str()); } @@ -262,7 +261,7 @@ class TestPostfixOperator : public TestFixture { " }\n" " v.clear();\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:6:64]: (performance) Prefer prefix ++/-- operators for non-primitive types. [postfixOperator]\n", errout_str()); check("int main() {\n" @@ -276,7 +275,7 @@ class TestPostfixOperator : public TestFixture { " it++;\n" " }\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:9:8]: (performance) Prefer prefix ++/-- operators for non-primitive types. [postfixOperator]\n", errout_str()); check("int main() {\n" @@ -289,7 +288,7 @@ class TestPostfixOperator : public TestFixture { " it++;\n" " }\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:8:8]: (performance) Prefer prefix ++/-- operators for non-primitive types. [postfixOperator]\n", errout_str()); check("int main() {\n" @@ -303,14 +302,14 @@ class TestPostfixOperator : public TestFixture { " rit--;\n" " }\n" " return 0;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:9:8]: (performance) Prefer prefix ++/-- operators for non-primitive types. [postfixOperator]\n", errout_str()); } void test2168() { ASSERT_THROW_INTERNAL(check("--> declare allocator lock here\n" - "int main(){}"), + "int main(){}\n"), AST); } @@ -318,7 +317,7 @@ class TestPostfixOperator : public TestFixture { check("void f(int* p){\n" " p++;\n" " std::cout << *p;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -328,7 +327,7 @@ class TestPostfixOperator : public TestFixture { "\n" "void f() {\n" " p++;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -336,7 +335,7 @@ class TestPostfixOperator : public TestFixture { check("bool foo() {\n" " std::vector::iterator aIter(aImport.begin());\n" " aIter++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:3:5]: (performance) Prefer prefix ++/-- operators for non-primitive types. [postfixOperator]\n", errout_str()); } @@ -345,14 +344,14 @@ class TestPostfixOperator : public TestFixture { " class A {}; class B {A a;};\n" " B b;\n" " b.a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:7]: (performance) Prefer prefix ++/-- operators for non-primitive types. [postfixOperator]\n", errout_str()); check("bool foo() {\n" " class A {}; class B {A a;};\n" " B b;\n" " foo(b.a++);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -361,7 +360,7 @@ class TestPostfixOperator : public TestFixture { " class A {};\n" " A a;\n" " i++, a++;\n" - "}"); + "}\n"); ASSERT_EQUALS("[test.cpp:4:10]: (performance) Prefer prefix ++/-- operators for non-primitive types. [postfixOperator]\n", errout_str()); check("bool foo(int i) {\n" @@ -369,7 +368,7 @@ class TestPostfixOperator : public TestFixture { " A a;\n" " foo(i, a++);\n" " foo(a++, i);\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } @@ -381,7 +380,7 @@ class TestPostfixOperator : public TestFixture { " a += i;\n" " }\n" " return a;\n" - "}"); + "}\n"); ASSERT_EQUALS("", errout_str()); } }; diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 171f9aa7105..01ae240fd1b 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,6 +21,7 @@ // the code for a known configuration, it generates the code for each configuration. #include "errortypes.h" +#include "library.h" #include "path.h" #include "platform.h" #include "preprocessor.h" @@ -31,7 +32,9 @@ #include "fixture.h" #include "helpers.h" +#include #include +#include #include #include #include @@ -49,19 +52,21 @@ 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; - const simplecpp::TokenList tokens1 = simplecpp::TokenList(code, size-1, files, "file.cpp", &outputList); - Preprocessor p(settingsDefault, errorLogger, Path::identify(tokens1.getFiles()[0], false)); - simplecpp::TokenList tokens2 = p.preprocess(tokens1, "", files, true); - p.reportOutput(outputList, true); + simplecpp::TokenList tokens1 = simplecpp::TokenList(code, files, "file.cpp", {}, &outputList); + Preprocessor p(tokens1, settingsDefault, errorLogger, Path::identify(tokens1.getFiles()[0], false)); + ASSERT_LOC(p.loadFiles(files), file, line); + simplecpp::TokenList tokens2 = p.preprocess("", files, outputList); + (void)p.reportOutput(outputList, true); return tokens2.stringify(); } template - static void preprocess(const char (&code)[size], std::vector &files, const std::string& file0, TokenList& tokenlist, const simplecpp::DUI& dui) + void preprocess(const char (&code)[size], std::vector &files, const std::string& file0, TokenList& tokenlist, const simplecpp::DUI& dui) { if (!files.empty()) throw std::runtime_error("file list not empty"); @@ -69,13 +74,15 @@ class TestPreprocessor : public TestFixture { if (tokenlist.front()) throw std::runtime_error("token list not empty"); - const simplecpp::TokenList tokens1(code, size-1, files, file0); + simplecpp::OutputList outputList; + const simplecpp::TokenList tokens1(code, files, file0, dui, &outputList); // Preprocess.. simplecpp::TokenList tokens2(files); simplecpp::FileDataCache cache; - // TODO: provide and handle outputList - simplecpp::preprocess(tokens2, tokens1, files, cache, dui); + simplecpp::preprocess(tokens2, tokens1, files, cache, dui, &outputList); + Preprocessor preprocessor(tokens2, settingsDefault, *this, Standards::Language::C); + (void)preprocessor.reportOutput(outputList, true); // Tokenizer.. tokenlist.createTokens(std::move(tokens2)); @@ -85,10 +92,68 @@ class TestPreprocessor : public TestFixture { std::vector getRemarkComments(const char (&code)[size], ErrorLogger& errorLogger) const { std::vector files; - const simplecpp::TokenList tokens1(code, size-1, files, "test.cpp"); + simplecpp::TokenList tokens1(code, files, "test.cpp"); + + const Preprocessor preprocessor(tokens1, settingsDefault, errorLogger, Path::identify(tokens1.getFiles()[0], false)); + return preprocessor.getRemarkComments(); + } - const Preprocessor preprocessor(settingsDefault, errorLogger, Path::identify(tokens1.getFiles()[0], false)); - return preprocessor.getRemarkComments(tokens1); + static std::string getcodeforcfg(const Settings& settings, ErrorLogger& errorlogger, const char* code, std::size_t size, const std::string &cfg, const std::string &filename, SuppressionList *inlineSuppression = nullptr) + { + std::map cfgcode = getcode(settings, errorlogger, code, size, std::set{cfg}, filename, inlineSuppression); + const auto it = cfgcode.find(cfg); + if (it == cfgcode.end()) + return ""; + return it->second; + } + + template + static std::string getcodeforcfg(const Settings& settings, ErrorLogger& errorlogger, const char (&code)[size], const std::string &cfg, const std::string &filename, SuppressionList *inlineSuppression = nullptr) + { + return getcodeforcfg(settings, errorlogger, code, size-1, cfg, filename, inlineSuppression); + } + + template + static std::map getcode(const Settings& settings, ErrorLogger& errorlogger, const char (&code)[size], const std::string &filename = "file.c") + { + return getcode(settings, errorlogger, code, size-1, {}, filename, nullptr); + } + + static std::map getcode(const Settings& settings, ErrorLogger& errorlogger, const char* code, std::size_t size, std::set cfgs, const std::string &filename, SuppressionList *inlineSuppression) + { + simplecpp::OutputList outputList; + std::vector files; + + simplecpp::TokenList tokens({code, size}, files, Path::simplifyPath(filename), {}, &outputList); + + // TODO: we should be using the actual Preprocessor implementation + Preprocessor preprocessor(tokens, settings, errorlogger, Path::identify(tokens.getFiles()[0], false)); + + // TODO: should be possible without a Preprocessor instance + if (preprocessor.reportOutput(outputList, true)) + return {}; + + if (inlineSuppression) + preprocessor.inlineSuppressions(*inlineSuppression); + preprocessor.removeComments(); + preprocessor.simplifyPragmaAsm(); + + std::map cfgcode; + if (cfgs.empty()) { + cfgs.insert(""); + std::set configDefines = { "__cplusplus" }; + preprocessor.getConfigs(configDefines, cfgs); + } + for (const std::string & config : cfgs) { + try { + const bool writeLocs = (strstr(code, "#include") != nullptr); + cfgcode[config] = preprocessor.getcode(config, files, writeLocs); + } catch (const simplecpp::Output &) { + cfgcode[config] = ""; + } + } + + return cfgcode; } const Settings settings0 = settingsBuilder().severity(Severity::information).build(); @@ -222,6 +287,7 @@ class TestPreprocessor : public TestFixture { // inline suppression, missingInclude/missingIncludeSystem TEST_CASE(inline_suppressions); + TEST_CASE(inline_suppressions_not_next_line); // remark comment TEST_CASE(remarkComment1); @@ -257,6 +323,17 @@ class TestPreprocessor : public TestFixture { TEST_CASE(getConfigs8); // #if A==1 => cfg: A=1 TEST_CASE(getConfigs10); // #5139 TEST_CASE(getConfigs11); // #9832 - include guards + TEST_CASE(getConfigs12); // #14222 + TEST_CASE(getConfigs13); // #14222 + TEST_CASE(getConfigs_gte); // #1059 + TEST_CASE(getConfigs_lte); // #1059 + TEST_CASE(getConfigs_gt); // #1059 + TEST_CASE(getConfigs_lt); // #1059 + TEST_CASE(getConfigs_eq_compound); // #1059 + TEST_CASE(getConfigs_gte_compound); // #1059 + TEST_CASE(getConfigs_lte_compound); // #1059 + TEST_CASE(getConfigs_gt_compound); // #1059 + TEST_CASE(getConfigs_lt_compound); // #1059 TEST_CASE(getConfigsError); TEST_CASE(getConfigsD1); @@ -269,6 +346,11 @@ class TestPreprocessor : public TestFixture { TEST_CASE(getConfigsU6); TEST_CASE(getConfigsU7); + TEST_CASE(getConfigsAndCodeIssue14317); + TEST_CASE(getConfigsMostGeneralConfigIssue14317); + + TEST_CASE(getConfigsInvalid); // #14732 + TEST_CASE(if_sizeof); TEST_CASE(invalid_ifs); // #5909 @@ -291,6 +373,8 @@ class TestPreprocessor : public TestFixture { TEST_CASE(testMissingIncludeMixed); TEST_CASE(testMissingIncludeCheckConfig); + TEST_CASE(testLazyInclude); + TEST_CASE(hasInclude); TEST_CASE(limitsDefines); @@ -298,21 +382,46 @@ class TestPreprocessor : public TestFixture { TEST_CASE(hashCalculation); TEST_CASE(standard); + + TEST_CASE(writeLocations); + + TEST_CASE(pragmaAsm); + + TEST_CASE(dumpPreprocessor); } template - std::string getConfigsStr(const char (&code)[size], const char *arg = nullptr) { + std::string getConfigsStr(const char (&code)[size], const char *arg = nullptr, const char *library = nullptr) { Settings settings; if (arg && std::strncmp(arg,"-D",2)==0) settings.userDefines = arg + 2; if (arg && std::strncmp(arg,"-U",2)==0) settings.userUndefs.insert(arg+2); + if (library) + ASSERT(settings.library.load("", library, false).errorcode == Library::ErrorCode::OK); std::vector files; - // TODO: this adds an empty filename - simplecpp::TokenList tokens(code,size-1,files); - tokens.removeComments(); - Preprocessor preprocessor(settings, *this, Standards::Language::C); // TODO: do we need to consider #file? - const std::set configs = preprocessor.getConfigs(tokens); + simplecpp::OutputList outputList; + simplecpp::TokenList tokens(code, files, "test.c", {}, &outputList); + 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, bool loaded) { + if (loaded) { + 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)); std::string ret; for (const std::string & config : configs) ret += config + '\n'; @@ -322,11 +431,16 @@ class TestPreprocessor : public TestFixture { template std::size_t getHash(const char (&code)[size]) { std::vector files; - // TODO: this adds an empty filename - simplecpp::TokenList tokens(code,size-1,files); - tokens.removeComments(); - Preprocessor preprocessor(settingsDefault, *this, Standards::Language::C); // TODO: do we need to consider #file? - return preprocessor.calculateHash(tokens, ""); + simplecpp::TokenList tokens(code,files,"test.c"); + Preprocessor preprocessor(tokens, settingsDefault, *this, Standards::Language::C); + preprocessor.setLoadCallback([](simplecpp::FileData &data, bool loaded) { + if (loaded) { + Preprocessor::removeComments(data.tokens); + } + }); + preprocessor.removeComments(); + ASSERT(preprocessor.loadFiles(files)); + return preprocessor.calculateHash(""); } void Bug2190219() { @@ -334,11 +448,11 @@ class TestPreprocessor : public TestFixture { "cpp\n" "#else\n" "c\n" - "#endif"; + "#endif\n"; { // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata, "file.cpp"); + const std::map actual = getcode(settings0, *this, filedata, "file.cpp"); // Compare results.. ASSERT_EQUALS(1U, actual.size()); @@ -348,7 +462,7 @@ class TestPreprocessor : public TestFixture { { // Ticket #7102 - skip __cplusplus in C code // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata, "file.c"); + const std::map actual = getcode(settings0, *this, filedata, "file.c"); // Compare results.. ASSERT_EQUALS(1U, actual.size()); @@ -362,7 +476,7 @@ class TestPreprocessor : public TestFixture { "#else\n" "#error abcd\n" "#endif\n"; - ASSERT_EQUALS("\nA\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nA=A\n", getConfigsStr(filedata)); } void error2() { @@ -379,27 +493,30 @@ class TestPreprocessor : public TestFixture { void error3() { const auto settings = dinit(Settings, $.userDefines = "__cplusplus"); - const std::string code("#error hello world!\n"); - (void)PreprocessorHelper::getcodeforcfg(settings, *this, code, "X", "test.c"); - ASSERT_EQUALS("[test.c:1:0]: (error) #error hello world! [preprocessorErrorDirective]\n", errout_str()); + const char code[] = "#error hello world!\n"; + (void)getcodeforcfg(settings, *this, code, "X", "test.c"); + ASSERT_EQUALS("[test.c:1:2]: (error) #error hello world! [preprocessorErrorDirective]\n", errout_str()); } // Ticket #2919 - wrong filename reported for #error void error4() { // In included file { + ScopedFile header("ab.h", "#error hello world!\n"); const auto settings = dinit(Settings, $.userDefines = "TEST"); - const std::string code("#file \"ab.h\"\n#error hello world!\n#endfile"); - (void)PreprocessorHelper::getcodeforcfg(settings, *this, code, "TEST", "test.c"); - ASSERT_EQUALS("[ab.h:1:0]: (error) #error hello world! [preprocessorErrorDirective]\n", errout_str()); + const char code[] = "#include \"ab.h\"\n"; + (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 std::string code("#file \"ab.h\"\n\n#endfile\n#error aaa"); - (void)PreprocessorHelper::getcodeforcfg(settings, *this, code, "TEST", "test.c"); - ASSERT_EQUALS("[test.c:2:0]: (error) #error aaa [preprocessorErrorDirective]\n", errout_str()); + const char code[] = "#include \"ab.h\"\n" + "#error aaa\n"; + (void)getcodeforcfg(settings, *this, code, "TEST", "test.c"); + ASSERT_EQUALS("[test.c:2:2]: (error) #error aaa [preprocessorErrorDirective]\n", errout_str()); } } @@ -408,8 +525,8 @@ class TestPreprocessor : public TestFixture { const auto settings = dinit(Settings, $.userDefines = "TEST", $.force = true); - const std::string code("#error hello world!\n"); - (void)PreprocessorHelper::getcodeforcfg(settings, *this, code, "X", "test.c"); + const char code[] = "#error hello world!\n"; + (void)getcodeforcfg(settings, *this, code, "X", "test.c"); ASSERT_EQUALS("", errout_str()); } @@ -422,7 +539,7 @@ class TestPreprocessor : public TestFixture { "#else\n" "#error 2\n" "#endif\n"; - ASSERT_EQUALS("\nA\nA;B\nB\n", getConfigsStr(filedata1)); + ASSERT_EQUALS("\nA=A\nA=A;B=B\nB=B\n", getConfigsStr(filedata1)); const char filedata2[] = "#ifndef A\n" "#error 1\n" @@ -454,7 +571,7 @@ class TestPreprocessor : public TestFixture { "#else\n" "#error \"2\"\n" "#endif\n"; - ASSERT_EQUALS("\nB\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nB=B\n", getConfigsStr(filedata)); } void error8() { @@ -466,8 +583,8 @@ class TestPreprocessor : public TestFixture { "\n" "#ifndef C\n" "#error aa\n" - "#endif"; - ASSERT_EQUALS("A;B;C\nA;C\nC\n", getConfigsStr(filedata)); + "#endif\n"; + ASSERT_EQUALS("A=A;B=B;C\nA=A;C\nC\n", getConfigsStr(filedata)); } void setPlatformInfo() { @@ -477,66 +594,68 @@ class TestPreprocessor : public TestFixture { "#else\n" "2\n" "#endif\n"; - std::vector files; - simplecpp::TokenList tokens(filedata, sizeof(filedata), files, "test.c"); // preprocess code with unix32 platform.. { + std::vector files; + simplecpp::TokenList tokens(filedata, files, "test.c"); const Settings settings = settingsBuilder().platform(Platform::Type::Unix32).build(); - Preprocessor::setPlatformInfo(tokens, settings); - Preprocessor preprocessor(settings, *this, Path::identify(tokens.getFiles()[0], false)); - ASSERT_EQUALS("\n1", preprocessor.getcode(tokens, "", files, false)); + Preprocessor preprocessor(tokens, settings, *this, Path::identify(tokens.getFiles()[0], false)); + preprocessor.setPlatformInfo(); + ASSERT_EQUALS("\n1", preprocessor.getcode("", files, false)); } // preprocess code with unix64 platform.. { + std::vector files; + simplecpp::TokenList tokens(filedata, files, "test.c"); const Settings settings = settingsBuilder().platform(Platform::Type::Unix64).build(); - Preprocessor::setPlatformInfo(tokens, settings); - Preprocessor preprocessor(settings, *this, Path::identify(tokens.getFiles()[0], false)); - ASSERT_EQUALS("\n\n\n2", preprocessor.getcode(tokens, "", files, false)); + Preprocessor preprocessor(tokens, settings, *this, Path::identify(tokens.getFiles()[0], false)); + preprocessor.setPlatformInfo(); + ASSERT_EQUALS("\n\n\n2", preprocessor.getcode("", files, false)); } } 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\n", getConfigsStr(filedata)); + "#endif\n"; + 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"; - ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata)); + 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"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Expected configurations: "" and "ABC" ASSERT_EQUALS(2, actual.size()); ASSERT_EQUALS("\n\n\nint main ( ) { }", actual.at("")); - ASSERT_EQUALS("\n#line 1 \"abc.h\"\nclass A { } ;\n#line 4 \"file.c\"\n int main ( ) { }", actual.at("ABC")); + ASSERT_EQUALS("\n#line 1 \"abc.h\"\nclass A { } ;\n#line 4 \"file.c\"\n int main ( ) { }", actual.at("ABC=ABC")); } void if0() { @@ -573,7 +692,7 @@ class TestPreprocessor : public TestFixture { "#else\n" "GHI\n" "#endif\n"; - ASSERT_EQUALS("\nDEF1\nDEF2\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nDEF1=DEF1\nDEF2=DEF2\n", getConfigsStr(filedata)); } } @@ -583,7 +702,7 @@ class TestPreprocessor : public TestFixture { "#else\n" " B\n" "#endif\n"; - TODO_ASSERT_EQUALS("\nLIBVER=101\n", "\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nLIBVER=101\n", getConfigsStr(filedata)); } void if_cond2() { @@ -593,7 +712,7 @@ class TestPreprocessor : public TestFixture { "#if defined(A) && defined(B)\n" "ab\n" "#endif\n"; - ASSERT_EQUALS("\nA\nA;B\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nA=A\nA=A;B=B\n", getConfigsStr(filedata)); if_cond2b(); if_cond2c(); @@ -610,7 +729,7 @@ class TestPreprocessor : public TestFixture { "#else\n" "a\n" "#endif\n"; - TODO_ASSERT_EQUALS("\nA;B\n", "\nA\nB\n", getConfigsStr(filedata)); + TODO_ASSERT_EQUALS("\nA;B=B\n", "\nA\nB=B\n", getConfigsStr(filedata)); } void if_cond2c() { @@ -624,7 +743,7 @@ class TestPreprocessor : public TestFixture { "#else\n" "a\n" "#endif\n"; - TODO_ASSERT_EQUALS("\nA\nA;B\n", "\nA\nB\n", getConfigsStr(filedata)); + TODO_ASSERT_EQUALS("\nA\nA;B=B\n", "\nA\nB=B\n", getConfigsStr(filedata)); } void if_cond2d() { @@ -643,7 +762,7 @@ class TestPreprocessor : public TestFixture { "!b\n" "#endif\n" "#endif\n"; - ASSERT_EQUALS("\nA\nA;B\nB\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nA\nA;B=B\nB=B\n", getConfigsStr(filedata)); } void if_cond2e() { @@ -662,7 +781,7 @@ class TestPreprocessor : public TestFixture { "abc\n" "#endif\n" "#endif\n"; - ASSERT_EQUALS("\nA\nA;B;C\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nA=A\nA=A;B=B;C=C\n", getConfigsStr(filedata)); } void if_cond4() { @@ -683,7 +802,7 @@ class TestPreprocessor : public TestFixture { "#endif\n" "}\n" "#endif\n"; - ASSERT_EQUALS("\nA\nA;B\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nA\nA;B=B\n", getConfigsStr(filedata)); } { @@ -718,20 +837,20 @@ class TestPreprocessor : public TestFixture { "#if defined(B) && defined(A)\n" "ef\n" "#endif\n"; - ASSERT_EQUALS("\nA;B\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nA=A;B=B\n", getConfigsStr(filedata)); } void if_cond6() { const char filedata[] = "\n" "#if defined(A) && defined(B))\n" "#endif\n"; - ASSERT_EQUALS("\nA;B\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nA=A;B=B\n", getConfigsStr(filedata)); } void if_cond8() { const char filedata[] = "#if defined(A) + defined(B) + defined(C) != 1\n" "#endif\n"; - TODO_ASSERT_EQUALS("\nA\n", "\nA;B;C\n", getConfigsStr(filedata)); + TODO_ASSERT_EQUALS("\nA=A\n", "\nA=A;B=B;C=C\n", getConfigsStr(filedata)); } @@ -749,7 +868,7 @@ class TestPreprocessor : public TestFixture { "#endif\n"; // Preprocess => don't crash.. - (void)PreprocessorHelper::getcode(settings0, *this, filedata); + (void)getcode(settings0, *this, filedata); } void if_cond11() { @@ -758,7 +877,7 @@ class TestPreprocessor : public TestFixture { "#elif FLT_MANT_DIG < W_TYPE_SIZE\n" "#endif\n" "#endif\n"; - (void)PreprocessorHelper::getcode(settings0, *this, filedata); + (void)getcode(settings0, *this, filedata); ASSERT_EQUALS("", errout_str()); } @@ -790,7 +909,7 @@ class TestPreprocessor : public TestFixture { const char filedata[] = "#if defined(DEF_10) || defined(DEF_11)\n" "a1;\n" "#endif\n"; - ASSERT_EQUALS("\nDEF_10;DEF_11\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nDEF_10=DEF_10;DEF_11=DEF_11\n", getConfigsStr(filedata)); } void if_or_2() { @@ -820,7 +939,7 @@ class TestPreprocessor : public TestFixture { "#endif\n" "#if YYDEBUG\n" "#endif\n"; - (void)PreprocessorHelper::getcode(settings0, *this, code); + (void)getcode(settings0, *this, code); // There's nothing to assert. It just needs to not hang. } @@ -832,7 +951,7 @@ class TestPreprocessor : public TestFixture { "#if !defined(_WIN32)\n" "#endif\n" "INLINE inline __forceinline\n"; - const std::map actual = PreprocessorHelper::getcode(settings0, *this, code); + const std::map actual = getcode(settings0, *this, code); // First, it must not hang. Second, inline must becomes inline, and __forceinline must become __forceinline. ASSERT_EQUALS("\n\n\n\n\n$__forceinline $inline $__forceinline", actual.at("")); @@ -841,8 +960,8 @@ class TestPreprocessor : public TestFixture { void ticket_4922() { // #4922 const char code[] = "__asm__ \n" "{ int extern __value) 0; (double return (\"\" } extern\n" - "__typeof __finite (__finite) __finite __inline \"__GI___finite\");"; - (void)PreprocessorHelper::getcode(settings0, *this, code); + "__typeof __finite (__finite) __finite __inline \"__GI___finite\");\n"; + (void)getcode(settings0, *this, code); } void macro_simple1() { @@ -952,7 +1071,7 @@ class TestPreprocessor : public TestFixture { void macro_simple16() { // # 4703 const char filedata[] = "#define MACRO( A, B, C ) class A##B##C##Creator {};\n" - "MACRO( B\t, U , G )"; + "MACRO( B\t, U , G )\n"; ASSERT_EQUALS("\nclass BUGCreator { } ;", expandMacros(filedata, *this)); } @@ -960,41 +1079,41 @@ class TestPreprocessor : public TestFixture { // It would probably be OK if the generated code was // "\n123+$123" since the first 123 comes from the source code const char filedata[] = "#define MACRO(A) A+123\n" - "MACRO(123)"; + "MACRO(123)\n"; ASSERT_EQUALS("\n123 + 123", expandMacros(filedata, *this)); } void macro_simple18() { // (1e-7) const char filedata1[] = "#define A (1e-7)\n" - "a=A;"; + "a=A;\n"; ASSERT_EQUALS("\na = ( 1e-7 ) ;", expandMacros(filedata1, *this)); const char filedata2[] = "#define A (1E-7)\n" - "a=A;"; + "a=A;\n"; ASSERT_EQUALS("\na = ( 1E-7 ) ;", expandMacros(filedata2, *this)); const char filedata3[] = "#define A (1e+7)\n" - "a=A;"; + "a=A;\n"; ASSERT_EQUALS("\na = ( 1e+7 ) ;", expandMacros(filedata3, *this)); const char filedata4[] = "#define A (1.e+7)\n" - "a=A;"; + "a=A;\n"; ASSERT_EQUALS("\na = ( 1.e+7 ) ;", expandMacros(filedata4, *this)); const char filedata5[] = "#define A (1.7f)\n" - "a=A;"; + "a=A;\n"; ASSERT_EQUALS("\na = ( 1.7f ) ;", expandMacros(filedata5, *this)); const char filedata6[] = "#define A (.1)\n" - "a=A;"; + "a=A;\n"; ASSERT_EQUALS("\na = ( .1 ) ;", expandMacros(filedata6, *this)); const char filedata7[] = "#define A (1.)\n" - "a=A;"; + "a=A;\n"; ASSERT_EQUALS("\na = ( 1. ) ;", expandMacros(filedata7, *this)); const char filedata8[] = "#define A (8.0E+007)\n" - "a=A;"; + "a=A;\n"; ASSERT_EQUALS("\na = ( 8.0E+007 ) ;", expandMacros(filedata8, *this)); } @@ -1166,8 +1285,8 @@ class TestPreprocessor : public TestFixture { void macro_NULL() { // See ticket #4482 - UB when passing NULL to variadic function - ASSERT_EQUALS("\n0", expandMacros("#define null 0\nnull", *this)); - TODO_ASSERT_EQUALS("\nNULL", "\n0", expandMacros("#define NULL 0\nNULL", *this)); // TODO: Let the tokenizer handle NULL? + ASSERT_EQUALS("\n0", expandMacros("#define null 0\nnull\n", *this)); + TODO_ASSERT_EQUALS("\nNULL\n", "\n0", expandMacros("#define NULL 0\nNULL\n", *this)); // TODO: Let the tokenizer handle NULL? } void string1() { @@ -1177,7 +1296,7 @@ class TestPreprocessor : public TestFixture { "}\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(1, actual.size()); @@ -1217,7 +1336,7 @@ class TestPreprocessor : public TestFixture { "#undef z\n" "int z;\n" "z = 0;\n"; - ASSERT_EQUALS("\n\nint z ;\nz = 0 ;", PreprocessorHelper::getcodeforcfg(settings0, *this, filedata, "", "test.c")); + ASSERT_EQUALS("\n\nint z ;\nz = 0 ;", getcodeforcfg(settings0, *this, filedata, "", "test.c")); } } @@ -1279,7 +1398,7 @@ class TestPreprocessor : public TestFixture { "}\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(1, actual.size()); @@ -1339,7 +1458,7 @@ class TestPreprocessor : public TestFixture { "}\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(1, actual.size()); @@ -1402,7 +1521,7 @@ class TestPreprocessor : public TestFixture { "}\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(1, actual.size()); @@ -1417,10 +1536,10 @@ class TestPreprocessor : public TestFixture { "#pragma asm foo\n" " mov r1, 11\n" "#pragma endasm bar\n" - "bbb"; + "bbb\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(1, actual.size()); @@ -1431,10 +1550,10 @@ class TestPreprocessor : public TestFixture { const char filedata[] = "#pragma asm\n" " mov @w1, 11\n" "#pragma endasm ( temp=@w1 )\n" - "bbb"; + "bbb\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(1, actual.size()); @@ -1448,13 +1567,13 @@ class TestPreprocessor : public TestFixture { "}\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(2, actual.size()); const std::string expected("void f ( ) {\n\n\n}"); ASSERT_EQUALS(expected, actual.at("")); - ASSERT_EQUALS(expected, actual.at("A")); + ASSERT_EQUALS(expected, actual.at("A=A")); } void handle_error() { @@ -1468,10 +1587,10 @@ class TestPreprocessor : public TestFixture { "}\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); ASSERT_EQUALS(0, actual.size()); - ASSERT_EQUALS("[file.c:2:0]: (error) No pair for character ('). Can't process file. File is either invalid or unicode, which is currently not supported. [preprocessorErrorDirective]\n", errout_str()); + ASSERT_EQUALS("[file.c:2:14]: (error) No pair for character ('). Can't process file. File is either invalid or unicode, which is currently not supported. [syntaxError]\n", errout_str()); } } @@ -1486,33 +1605,20 @@ class TestPreprocessor : public TestFixture { const std::string actual(expandMacros(filedata, *this)); ASSERT_EQUALS("", actual); - ASSERT_EQUALS("[file.cpp:3:0]: (error) No pair for character (\"). Can't process file. File is either invalid or unicode, which is currently not supported. [preprocessorErrorDirective]\n", errout_str()); + ASSERT_EQUALS("[file.cpp:3: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" - "\"\n" - "#endfile\n"; - - // expand macros.. - const std::string actual(expandMacros(filedata, *this)); - - ASSERT_EQUALS("", actual); - ASSERT_EQUALS("[abc.h:2:0]: (error) No pair for character (\"). Can't process file. File is either invalid or unicode, which is currently not supported. [preprocessorErrorDirective]\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.. const std::string actual(expandMacros(filedata, *this)); ASSERT_EQUALS("", actual); - ASSERT_EQUALS("[file.cpp:2:0]: (error) No pair for character (\"). Can't process file. File is either invalid or unicode, which is currently not supported. [preprocessorErrorDirective]\n", errout_str()); + ASSERT_EQUALS("[file.cpp: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()); } { @@ -1524,7 +1630,7 @@ class TestPreprocessor : public TestFixture { const std::string actual(expandMacros(filedata, *this)); ASSERT_EQUALS("", actual); - ASSERT_EQUALS("[file.cpp:2:0]: (error) No pair for character (\"). Can't process file. File is either invalid or unicode, which is currently not supported. [preprocessorErrorDirective]\n", errout_str()); + ASSERT_EQUALS("[file.cpp:2:11]: (error) No pair for character (\"). Can't process file. File is either invalid or unicode, which is currently not supported. [syntaxError]\n", errout_str()); } { @@ -1540,7 +1646,7 @@ class TestPreprocessor : public TestFixture { // expand macros.. (void)expandMacros(filedata, *this); - ASSERT_EQUALS("[file.cpp:7:0]: (error) No pair for character (\"). Can't process file. File is either invalid or unicode, which is currently not supported. [preprocessorErrorDirective]\n", errout_str()); + ASSERT_EQUALS("[file.cpp:7:12]: (error) No pair for character (\"). Can't process file. File is either invalid or unicode, which is currently not supported. [syntaxError]\n", errout_str()); } } @@ -1552,7 +1658,7 @@ class TestPreprocessor : public TestFixture { " }\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(1, actual.size()); @@ -1566,15 +1672,15 @@ class TestPreprocessor : public TestFixture { "#else\n" "#define N 20\n" "#endif\n" - "N"; + "N\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(2, actual.size()); ASSERT_EQUALS("\n\n\n\n\n$20", actual.at("")); - ASSERT_EQUALS("\n\n\n\n\n$10", actual.at("A")); + ASSERT_EQUALS("\n\n\n\n\n$10", actual.at("A=A")); ASSERT_EQUALS("", errout_str()); } @@ -1588,12 +1694,12 @@ class TestPreprocessor : public TestFixture { "}\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(1, actual.size()); ASSERT_EQUALS("", actual.at("")); - ASSERT_EQUALS("[file.c:6:0]: (error) failed to expand 'BC', Wrong number of parameters for macro 'BC'. [preprocessorErrorDirective]\n", errout_str()); + ASSERT_EQUALS("[file.c:6:3]: (error) failed to expand 'BC', Wrong number of parameters for macro 'BC'. [syntaxError]\n", errout_str()); } void newline_in_macro() { @@ -1604,7 +1710,7 @@ class TestPreprocessor : public TestFixture { "}\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(1, actual.size()); @@ -1621,12 +1727,12 @@ class TestPreprocessor : public TestFixture { "#endif\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(2, actual.size()); ASSERT_EQUALS("", actual.at("")); - ASSERT_EQUALS("\nA\n\n\nA", actual.at("ABC")); + ASSERT_EQUALS("\nA\n\n\nA", actual.at("ABC=ABC")); } void define_if1() { @@ -1634,15 +1740,15 @@ class TestPreprocessor : public TestFixture { const char filedata[] = "#define A 0\n" "#if A\n" "FOO\n" - "#endif"; - ASSERT_EQUALS("", PreprocessorHelper::getcodeforcfg(settings0, *this, filedata,"","test.c")); + "#endif\n"; + ASSERT_EQUALS("", getcodeforcfg(settings0, *this, filedata,"","test.c")); } { const char filedata[] = "#define A 1\n" "#if A==1\n" "FOO\n" - "#endif"; - ASSERT_EQUALS("\n\nFOO", PreprocessorHelper::getcodeforcfg(settings0, *this, filedata,"","test.c")); + "#endif\n"; + ASSERT_EQUALS("\n\nFOO", getcodeforcfg(settings0, *this, filedata,"","test.c")); } } @@ -1651,24 +1757,24 @@ class TestPreprocessor : public TestFixture { "#define B A\n" "#if (B==A) || (B==C)\n" "FOO\n" - "#endif"; - ASSERT_EQUALS("\n\n\nFOO", PreprocessorHelper::getcodeforcfg(settings0, *this, filedata,"","test.c")); + "#endif\n"; + ASSERT_EQUALS("\n\n\nFOO", getcodeforcfg(settings0, *this, filedata,"","test.c")); } void define_if3() { const char filedata[] = "#define A 0\n" "#if (A==0)\n" "FOO\n" - "#endif"; - ASSERT_EQUALS("\n\nFOO", PreprocessorHelper::getcodeforcfg(settings0, *this, filedata,"","test.c")); + "#endif\n"; + ASSERT_EQUALS("\n\nFOO", getcodeforcfg(settings0, *this, filedata,"","test.c")); } void define_if4() { const char filedata[] = "#define X +123\n" "#if X==123\n" "FOO\n" - "#endif"; - ASSERT_EQUALS("\n\nFOO", PreprocessorHelper::getcodeforcfg(settings0, *this, filedata,"","test.c")); + "#endif\n"; + ASSERT_EQUALS("\n\nFOO", getcodeforcfg(settings0, *this, filedata,"","test.c")); } void define_if5() { // #4516 - #define B (A & 0x00f0) @@ -1677,8 +1783,8 @@ class TestPreprocessor : public TestFixture { "#define B (A & 0x00f0)\n" "#if B==0x0010\n" "FOO\n" - "#endif"; - ASSERT_EQUALS("\n\n\nFOO", PreprocessorHelper::getcodeforcfg(settings0, *this, filedata,"","test.c")); + "#endif\n"; + ASSERT_EQUALS("\n\n\nFOO", getcodeforcfg(settings0, *this, filedata,"","test.c")); } { const char filedata[] = "#define A 0x00f0\n" @@ -1686,15 +1792,15 @@ class TestPreprocessor : public TestFixture { "#define C (B & A)\n" "#if C==0x0010\n" "FOO\n" - "#endif"; - ASSERT_EQUALS("\n\n\n\nFOO", PreprocessorHelper::getcodeforcfg(settings0, *this, filedata,"","test.c")); + "#endif\n"; + ASSERT_EQUALS("\n\n\n\nFOO", getcodeforcfg(settings0, *this, filedata,"","test.c")); } { const char filedata[] = "#define A (1+A)\n" // don't hang for recursive macros "#if A==1\n" "FOO\n" - "#endif"; - ASSERT_EQUALS("\n\nFOO", PreprocessorHelper::getcodeforcfg(settings0, *this, filedata,"","test.c")); + "#endif\n"; + ASSERT_EQUALS("\n\nFOO", getcodeforcfg(settings0, *this, filedata,"","test.c")); } } @@ -1710,10 +1816,10 @@ class TestPreprocessor : public TestFixture { "#if B >= 0\n" "456\n" "#endif\n"; - const std::string actualA0 = PreprocessorHelper::getcodeforcfg(settings0, *this, filedata, "A=0", "test.c"); + const std::string actualA0 = getcodeforcfg(settings0, *this, filedata, "A=0", "test.c"); ASSERT_EQUALS(true, actualA0.find("123") != std::string::npos); ASSERT_EQUALS(false, actualA0.find("456") != std::string::npos); - const std::string actualA1 = PreprocessorHelper::getcodeforcfg(settings0, *this, filedata, "A=1", "test.c"); + const std::string actualA1 = getcodeforcfg(settings0, *this, filedata, "A=1", "test.c"); ASSERT_EQUALS(false, actualA1.find("123") != std::string::npos); ASSERT_EQUALS(true, actualA1.find("456") != std::string::npos); } @@ -1728,7 +1834,7 @@ class TestPreprocessor : public TestFixture { "#endif\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(1, actual.size()); @@ -1742,7 +1848,7 @@ class TestPreprocessor : public TestFixture { "#endif\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(1, actual.size()); @@ -1756,7 +1862,7 @@ class TestPreprocessor : public TestFixture { "#endif\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(1, actual.size()); @@ -1770,7 +1876,7 @@ class TestPreprocessor : public TestFixture { "#endif\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(1, actual.size()); @@ -1785,7 +1891,7 @@ class TestPreprocessor : public TestFixture { "A\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(1, actual.size()); @@ -1800,7 +1906,7 @@ class TestPreprocessor : public TestFixture { "#endif\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(1U, actual.size()); @@ -1817,18 +1923,18 @@ class TestPreprocessor : public TestFixture { "B me;\n"; // Preprocess => actual result.. - ASSERT_EQUALS("\n\n\n\n\n\n$int me ;", PreprocessorHelper::getcodeforcfg(settings0, *this, filedata, "", "a.cpp")); - ASSERT_EQUALS("\n\n\n\n\n\n$char me ;", PreprocessorHelper::getcodeforcfg(settings0, *this, filedata, "A", "a.cpp")); + ASSERT_EQUALS("\n\n\n\n\n\n$int me ;", getcodeforcfg(settings0, *this, filedata, "", "a.cpp")); + ASSERT_EQUALS("\n\n\n\n\n\n$char me ;", getcodeforcfg(settings0, *this, filedata, "A", "a.cpp")); } void ifndef_define() { const char filedata[] = "#ifndef A\n" "#define A(x) x\n" "#endif\n" - "A(123);"; + "A(123);\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); ASSERT_EQUALS(1U, actual.size()); ASSERT_EQUALS("\n\n\n123 ;", actual.at("")); @@ -1841,8 +1947,8 @@ class TestPreprocessor : public TestFixture { "#endif\n"; // Preprocess => actual result.. - ASSERT_EQUALS("", PreprocessorHelper::getcodeforcfg(settings0, *this, filedata, "", "a.cpp")); - ASSERT_EQUALS("", PreprocessorHelper::getcodeforcfg(settings0, *this, filedata, "A", "a.cpp")); + ASSERT_EQUALS("", getcodeforcfg(settings0, *this, filedata, "", "a.cpp")); + ASSERT_EQUALS("", getcodeforcfg(settings0, *this, filedata, "A", "a.cpp")); } void redundant_config() { @@ -1862,14 +1968,14 @@ class TestPreprocessor : public TestFixture { // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(4, actual.size()); ASSERT(actual.find("") != actual.end()); - ASSERT(actual.find("BAR") != actual.end()); - ASSERT(actual.find("FOO") != actual.end()); - ASSERT(actual.find("BAR;FOO") != actual.end()); + ASSERT(actual.find("BAR=BAR") != actual.end()); + ASSERT(actual.find("FOO=FOO") != actual.end()); + ASSERT(actual.find("BAR=BAR;FOO=FOO") != actual.end()); } @@ -1879,7 +1985,7 @@ class TestPreprocessor : public TestFixture { "#include \"notfound.h\"\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // Compare results.. ASSERT_EQUALS(1, actual.size()); @@ -1897,38 +2003,38 @@ class TestPreprocessor : public TestFixture { "#endif\n"; // Preprocess => actual result.. - const std::map actual = PreprocessorHelper::getcode(settings0, *this, filedata); + const std::map actual = getcode(settings0, *this, filedata); // B will always be defined if A is defined; the following test // cases should be fixed whenever this other bug is fixed ASSERT_EQUALS(2U, actual.size()); - ASSERT_EQUALS_MSG(true, (actual.find("A") != actual.end()), "A is expected to be checked but it was not checked"); + ASSERT_EQUALS_MSG(true, (actual.find("A=A") != actual.end()), "A is expected to be checked but it was not checked"); - ASSERT_EQUALS_MSG(true, (actual.find("A;A;B") == actual.end()), "A;A;B is expected to NOT be checked but it was checked"); + ASSERT_EQUALS_MSG(true, (actual.find("A=A;A=A;B=B") == actual.end()), "A;A;B is expected to NOT be checked but it was checked"); } void invalid_define_1() { - (void)PreprocessorHelper::getcode(settings0, *this, "#define =\n"); - ASSERT_EQUALS("[file.c:1:0]: (error) Failed to parse #define [preprocessorErrorDirective]\n", errout_str()); + (void)getcode(settings0, *this, "#define =\n"); + ASSERT_EQUALS("[file.c:1:2]: (error) Failed to parse #define, bad macro syntax [syntaxError]\n", errout_str()); } void invalid_define_2() { // #4036 - (void)PreprocessorHelper::getcode(settings0, *this, "#define () {(int f(x) }\n"); - ASSERT_EQUALS("[file.c:1:0]: (error) Failed to parse #define [preprocessorErrorDirective]\n", errout_str()); + (void)getcode(settings0, *this, "#define () {(int f(x) }\n"); + ASSERT_EQUALS("[file.c:1:2]: (error) Failed to parse #define, bad macro syntax [syntaxError]\n", errout_str()); } void inline_suppressions() { - /*const*/ Settings settings; - settings.inlineSuppressions = true; - settings.checks.enable(Checks::missingInclude); - - const std::string code("// cppcheck-suppress missingInclude\n" - "#include \"missing.h\"\n" - "// cppcheck-suppress missingIncludeSystem\n" - "#include \n"); + const auto settings = dinit(Settings, + $.inlineSuppressions = true, + $.checks.enable (Checks::missingInclude)); + + const char code[] = "// cppcheck-suppress missingInclude\n" + "#include \"missing.h\"\n" + "// cppcheck-suppress missingIncludeSystem\n" + "#include \n"; SuppressionList inlineSuppr; - (void)PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.c", &inlineSuppr); + (void)getcodeforcfg(settings, *this, code, "", "test.c", &inlineSuppr); auto suppressions = inlineSuppr.getSuppressions(); ASSERT_EQUALS(2, suppressions.size()); @@ -1952,6 +2058,38 @@ class TestPreprocessor : public TestFixture { ignore_errout(); // we are not interested in the output } + void inline_suppressions_not_next_line() { + const auto settings = dinit(Settings, + $.inlineSuppressions = true, + $.checks.enable (Checks::missingInclude)); + + const char code[] = "// cppcheck-suppress missingInclude\n" + "// some other comment\n" + "#include \"missing.h\"\n" + "// cppcheck-suppress missingIncludeSystem\n" + "\n" // Empty line + "#include \n"; + SuppressionList inlineSuppr; + (void)getcodeforcfg(settings, *this, code, "", "test.c", &inlineSuppr); + + auto suppressions = inlineSuppr.getSuppressions(); + ASSERT_EQUALS(2, suppressions.size()); + + auto suppr = suppressions.front(); + suppressions.pop_front(); + ASSERT_EQUALS("missingInclude", suppr.errorId); + ASSERT_EQUALS("test.c", suppr.fileName); + ASSERT_EQUALS(3, suppr.lineNumber); + + suppr = suppressions.front(); + suppressions.pop_front(); + ASSERT_EQUALS("missingIncludeSystem", suppr.errorId); + ASSERT_EQUALS("test.c", suppr.fileName); + ASSERT_EQUALS(6, suppr.lineNumber); + + ignore_errout(); + } + void remarkComment1() { const char code[] = "// REMARK: assignment with 1\n" "x=1;\n"; @@ -1979,31 +2117,31 @@ class TestPreprocessor : public TestFixture { } void remarkComment4() { - const char code[] = "//REMARK /"; + const char code[] = "//REMARK /\n"; const auto remarkComments = getRemarkComments(code, *this); ASSERT_EQUALS(0, remarkComments.size()); } void predefine1() { - const std::string src("#if defined X || Y\n" - "Fred & Wilma\n" - "#endif\n"); - std::string actual = PreprocessorHelper::getcodeforcfg(settings0, *this, src, "X=1", "test.c"); + const char code[] = "#if defined X || Y\n" + "Fred & Wilma\n" + "#endif\n"; + std::string actual = getcodeforcfg(settings0, *this, code, "X=1", "test.c"); ASSERT_EQUALS("\nFred & Wilma", actual); } void predefine2() { - const std::string src("#if defined(X) && Y\n" - "Fred & Wilma\n" - "#endif\n"); + const char code[] = "#if defined(X) && Y\n" + "Fred & Wilma\n" + "#endif\n"; { - std::string actual = PreprocessorHelper::getcodeforcfg(settings0, *this, src, "X=1", "test.c"); + std::string actual = getcodeforcfg(settings0, *this, code, "X=1", "test.c"); ASSERT_EQUALS("", actual); } { - std::string actual = PreprocessorHelper::getcodeforcfg(settings0, *this, src, "X=1;Y=2", "test.c"); + std::string actual = getcodeforcfg(settings0, *this, code, "X=1;Y=2", "test.c"); ASSERT_EQUALS("\nFred & Wilma", actual); } } @@ -2015,53 +2153,53 @@ class TestPreprocessor : public TestFixture { "#if (X == Y)\n" "Fred & Wilma\n" "#endif\n"; - const std::string actual = PreprocessorHelper::getcodeforcfg(settings0, *this, code, "TEST", "test.c"); + const std::string actual = getcodeforcfg(settings0, *this, code, "TEST", "test.c"); ASSERT_EQUALS("\n\n\nFred & Wilma", actual); } void predefine4() { // #3577 const char code[] = "char buf[X];\n"; - const std::string actual = PreprocessorHelper::getcodeforcfg(settings0, *this, code, "X=123", "test.c"); + const std::string actual = getcodeforcfg(settings0, *this, code, "X=123", "test.c"); ASSERT_EQUALS("char buf [ $123 ] ;", actual); } void predefine5() { // #3737, #5119 - automatically define __cplusplus // #3737... - const char code[] = "#ifdef __cplusplus\n123\n#endif"; - ASSERT_EQUALS("", PreprocessorHelper::getcodeforcfg(settings0, *this, code, "", "test.c")); - ASSERT_EQUALS("\n123", PreprocessorHelper::getcodeforcfg(settings0, *this, code, "", "test.cpp")); + const char code[] = "#ifdef __cplusplus\n123\n#endif\n"; + ASSERT_EQUALS("", getcodeforcfg(settings0, *this, code, "", "test.c")); + ASSERT_EQUALS("\n123", getcodeforcfg(settings0, *this, code, "", "test.cpp")); } void predefine6() { // automatically define __STDC_VERSION__ - const char code[] = "#ifdef __STDC_VERSION__\n123\n#endif"; - ASSERT_EQUALS("\n123", PreprocessorHelper::getcodeforcfg(settings0, *this, code, "", "test.c")); - ASSERT_EQUALS("", PreprocessorHelper::getcodeforcfg(settings0, *this, code, "", "test.cpp")); + const char code[] = "#ifdef __STDC_VERSION__\n123\n#endif\n"; + ASSERT_EQUALS("\n123", getcodeforcfg(settings0, *this, code, "", "test.c")); + ASSERT_EQUALS("", getcodeforcfg(settings0, *this, code, "", "test.cpp")); } void strictAnsi() { - const char code[] = "#ifdef __STRICT_ANSI__\n123\n#endif"; + const char code[] = "#ifdef __STRICT_ANSI__\n123\n#endif\n"; Settings settings; settings.standards.setStd("gnu99"); - ASSERT_EQUALS("", PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.c")); + ASSERT_EQUALS("", getcodeforcfg(settings, *this, code, "", "test.c")); settings.standards.setStd("c99"); - ASSERT_EQUALS("\n123", PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.c")); + ASSERT_EQUALS("\n123", getcodeforcfg(settings, *this, code, "", "test.c")); settings.standards.setStd("gnu++11"); - ASSERT_EQUALS("", PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.cpp")); + ASSERT_EQUALS("", getcodeforcfg(settings, *this, code, "", "test.cpp")); settings.standards.setStd("c++11"); - ASSERT_EQUALS("\n123", PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.cpp")); + ASSERT_EQUALS("\n123", getcodeforcfg(settings, *this, code, "", "test.cpp")); } void invalidElIf() { // #2942 - segfault const char code[] = "#elif (){\n"; - const std::string actual = PreprocessorHelper::getcodeforcfg(settings0, *this, code, "TEST", "test.c"); + const std::string actual = getcodeforcfg(settings0, *this, code, "TEST", "test.c"); ASSERT_EQUALS("", actual); - ASSERT_EQUALS("[test.c:1:0]: (error) #elif without #if [preprocessorErrorDirective]\n", errout_str()); + ASSERT_EQUALS("[test.c:1:2]: (error) #elif without #if [syntaxError]\n", errout_str()); } void getConfigs1() { @@ -2071,7 +2209,7 @@ class TestPreprocessor : public TestFixture { " qwerty\n" "#endif \n"; - ASSERT_EQUALS("\nWIN32\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nWIN32=WIN32\n", getConfigsStr(filedata)); } void getConfigs2() { @@ -2092,7 +2230,7 @@ class TestPreprocessor : public TestFixture { "c\n" "#endif\n"; - ASSERT_EQUALS("\nABC\nABC;DEF\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nABC=ABC\nABC=ABC;DEF=DEF\n", getConfigsStr(filedata)); } void getConfigs4() { @@ -2102,7 +2240,7 @@ class TestPreprocessor : public TestFixture { "#ifdef ABC\n" "A\n" "#endif\n"; - ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } void getConfigs5() { @@ -2114,7 +2252,7 @@ class TestPreprocessor : public TestFixture { "C\n" "#endif\n" "#endif\n"; - ASSERT_EQUALS("\nABC\nDEF\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nABC=ABC\nDEF=DEF\n", getConfigsStr(filedata)); } void getConfigs7() { @@ -2124,7 +2262,7 @@ class TestPreprocessor : public TestFixture { "B\n" "#endif\n" "#endif\n"; - ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } void getConfigs7a() { @@ -2144,7 +2282,7 @@ class TestPreprocessor : public TestFixture { "B\n" "#endif\n" "#endif\n"; - ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } void getConfigs7c() { @@ -2154,7 +2292,7 @@ class TestPreprocessor : public TestFixture { "B\n" "#endif\n" "#endif\n"; - ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } void getConfigs7d() { @@ -2164,20 +2302,20 @@ class TestPreprocessor : public TestFixture { "B\n" "#endif\n" "#endif\n"; - ASSERT_EQUALS("\nABC\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } void getConfigs7e() { + 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\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nABC=ABC\n", getConfigsStr(filedata)); } void getConfigs8() { @@ -2192,20 +2330,289 @@ class TestPreprocessor : public TestFixture { "#define bar foo\n" "#define baz bar+0\n" "#if 0\n" - "#endif"; + "#endif\n"; ASSERT_EQUALS("\n", getConfigsStr(filedata)); } 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)); } + void getConfigs12() { // #14222 + const char filedata[] = "#ifdef INT8_MAX\n" + "INT8_MAX\n" + "#endif\n"; + ASSERT_EQUALS("\n", getConfigsStr(filedata, nullptr, "std.cfg")); + } + + void getConfigs13() { // #14222 + const char filedata[] = "#ifdef __builtin_bswap16\n" + "__builtin_bswap16(x);\n" + "#endif\n"; + ASSERT_EQUALS("\n", getConfigsStr(filedata, nullptr, "gnu.cfg")); + } + + void getConfigs_gte() { // #1059 + { + const char filedata[] = "#if A >= 1\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=1\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A >= 201112L\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=201112L\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A >= 12147483647\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=12147483647\n", getConfigsStr(filedata)); + } + } + + void getConfigs_lte() { // #1059 + { + const char filedata[] = "#if A <= 1\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=1\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A <= 201112L\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=201112L\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A <= 12147483647\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=12147483647\n", getConfigsStr(filedata)); + } + } + + void getConfigs_gt() { // #1059 + { + const char filedata[] = "#if A > 1\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=2\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A > 1L\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=2\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A > 1U\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=2\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A > 1UL\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=2\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A > 1Z\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=2\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A > 0x1\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=2\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A > 01\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=2\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A > 0b1\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=2\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A > 1t\n" + "1\n" + "#endif\n"; + ASSERT_THROW_INTERNAL_EQUALS(getConfigsStr(filedata), INTERNAL, "Internal Error. MathLib::toBigNumber: input was not completely consumed: 1t"); + } + { + const char filedata[] = "#if A > 1.0\n" + "1\n" + "#endif\n"; + TODO_ASSERT_THROW(getConfigsStr(filedata), InternalError); // floating point literals are not allowed + } + { + const char filedata[] = "#if A > 12147483647\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=12147483648\n", getConfigsStr(filedata)); + } + } + + void getConfigs_lt() { // #1059 + { + const char filedata[] = "#if A < 1\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=0\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A < 1L\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=0\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A < 1U\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=0\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A < 1UL\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=0\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A < 1Z\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=0\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A < 0x1\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=0\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A < 01\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=0\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A < 0b1\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=0\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A < 1t\n" + "1\n" + "#endif\n"; + ASSERT_THROW_INTERNAL_EQUALS(getConfigsStr(filedata), INTERNAL, "Internal Error. MathLib::toBigNumber: input was not completely consumed: 1t"); + } + { + const char filedata[] = "#if A < 1.0\n" + "1\n" + "#endif\n"; + TODO_ASSERT_THROW(getConfigsStr(filedata), InternalError); // floating point literals are not allowed + } + { + const char filedata[] = "#if A < 12147483647\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=12147483646\n", getConfigsStr(filedata)); + } + } + + void getConfigs_eq_compound() { // #1059 + { + const char filedata[] = "#if A == 1 && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=1;B=B\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A == 201112L && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=201112L;B=B\n", getConfigsStr(filedata)); + } + } + + void getConfigs_gte_compound() { // #1059 + { + const char filedata[] = "#if A >= 1 && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=1;B=B\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A >= 201112L && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=201112L;B=B\n", getConfigsStr(filedata)); + } + } + + void getConfigs_lte_compound() { // #1059 + { + const char filedata[] = "#if A <= 1 && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=1;B=B\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A <= 201112L && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=201112L;B=B\n", getConfigsStr(filedata)); + } + } + + void getConfigs_gt_compound() { // #1059 + { + const char filedata[] = "#if A > 1 && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=2;B=B\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A > 201112L && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=201113;B=B\n", getConfigsStr(filedata)); + } + } + + void getConfigs_lt_compound() { // #1059 + { + const char filedata[] = "#if A < 1 && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=0;B=B\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if A < 201112L && defined(B)\n" + "1\n" + "#endif\n"; + ASSERT_EQUALS("\nA=201111;B=B\n", getConfigsStr(filedata)); + } + } + void getConfigsError() { const char filedata1[] = "#ifndef X\n" "#error \"!X\"\n" @@ -2217,7 +2624,7 @@ class TestPreprocessor : public TestFixture { "#error \"!Y\"\n" "#endif\n" "#endif\n"; - ASSERT_EQUALS("\nX;Y\nY\n", getConfigsStr(filedata2)); + ASSERT_EQUALS("\nX=X;Y\nY\n", getConfigsStr(filedata2)); } void getConfigsD1() { @@ -2227,14 +2634,14 @@ class TestPreprocessor : public TestFixture { "#endif\n" "#endif\n"; ASSERT_EQUALS("\n", getConfigsStr(filedata, "-DX")); - ASSERT_EQUALS("\nX\nY\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nX=X\nY=Y\n", getConfigsStr(filedata)); } void getConfigsU1() { const char filedata[] = "#ifdef X\n" "#endif\n"; ASSERT_EQUALS("\n", getConfigsStr(filedata, "-UX")); - ASSERT_EQUALS("\nX\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nX=X\n", getConfigsStr(filedata)); } void getConfigsU2() { @@ -2258,8 +2665,8 @@ class TestPreprocessor : public TestFixture { const char filedata[] = "#if defined(X) || defined(Y) || defined(Z)\n" "#else\n" "#endif\n"; - ASSERT_EQUALS("\nY;Z\n", getConfigsStr(filedata, "-UX")); - ASSERT_EQUALS("\nX;Y;Z\n", getConfigsStr(filedata)); + ASSERT_EQUALS("\nY=Y;Z=Z\n", getConfigsStr(filedata, "-UX")); + ASSERT_EQUALS("\nX=X;Y=Y;Z=Z\n", getConfigsStr(filedata)); } void getConfigsU5() { @@ -2283,15 +2690,89 @@ class TestPreprocessor : public TestFixture { ASSERT_EQUALS("\nY\n", getConfigsStr(code, "-DX")); } + void getConfigsAndCodeIssue14317() { + const char filedata[] = "bool test() {\n" + "return\n" + "#if defined(isless)\n" + "0 != isless(1.0, 2.0)\n" + "#else\n" + "0\n" + "#endif\n" + ";\n" + "}\n"; + // Test getConfigsStr() + ASSERT_EQUALS("\nisless=isless\n", getConfigsStr(filedata)); + + // Test getcode() + // Preprocess => actual result.. + const std::map actual = getcode(settings0, *this, filedata); + + // Expected configurations: "" and "ABC" + ASSERT_EQUALS(2, actual.size()); + ASSERT_EQUALS("bool test ( ) {\nreturn\n\n\n\n0\n\n;\n}", actual.at("")); + ASSERT_EQUALS("bool test ( ) {\nreturn\n\n0 != $isless ( 1.0 , 2.0 )\n\n\n\n;\n}", actual.at("isless=isless")); + } + + void getConfigsMostGeneralConfigIssue14317() { + // Verifies that the most general X (out of X=X and X) and Y=Y is returned + // For Z: First Z=Z is added to ret, then the ifndef else branch replaces Z=Z with the more general Z + const char filedata[] = "#ifdef X\n" + "print(X);\n" + "#endif\n" + "#if X\n" + "print(X+1);\n" + "#endif\n" + "#if defined(Y)\n" + "print(Y);\n" + "#endif\n" + "#ifdef Z\n" + "print(Z);\n" + "#endif\n" + "#ifndef Z\n" + "print(Z+1);\n" + "#else\n" + "print(Z+2);\n" + "#endif\n"; + // Test getConfigsStr() + ASSERT_EQUALS("\nX\nY=Y\nZ\n", getConfigsStr(filedata)); + } + + void getConfigsInvalid() { // #14732 + { + const char filedata[] = "#if<\n"; + ASSERT_EQUALS("\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if>\n"; + ASSERT_EQUALS("\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if==\n"; + ASSERT_EQUALS("\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if<=\n"; + ASSERT_EQUALS("\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if>=\n"; + ASSERT_EQUALS("\n", getConfigsStr(filedata)); + } + { + const char filedata[] = "#if!\n"; + ASSERT_EQUALS("\n", getConfigsStr(filedata)); + } + } + void if_sizeof() { // #4071 const char code[] = "#if sizeof(unsigned short) == 2\n" "Fred & Wilma\n" "#elif sizeof(unsigned short) == 4\n" "Fred & Wilma\n" "#else\n" - "#endif"; + "#endif\n"; - const std::map actual = PreprocessorHelper::getcode(settings0, *this, code); + const std::map actual = getcode(settings0, *this, code); ASSERT_EQUALS("\nFred & Wilma", actual.at("")); } @@ -2308,232 +2789,246 @@ class TestPreprocessor : public TestFixture { "int x;\n"; // Preprocess => don't crash.. - (void)PreprocessorHelper::getcode(settings0, *this, filedata); + (void)getcode(settings0, *this, filedata); ASSERT_EQUALS( - "[file.c:1:0]: (error) Syntax error in #ifdef [preprocessorErrorDirective]\n" - "[file.c:1:0]: (error) Syntax error in #ifdef [preprocessorErrorDirective]\n", errout_str()); + "[file.c:1:2]: (error) Syntax error in #ifdef [syntaxError]\n" + "[file.c:1:2]: (error) Syntax error in #ifdef [syntaxError]\n", errout_str()); } void garbage() { const char filedata[] = "V\n" "#define X b #endif #line 0 \"x\" ;\n" - "#if ! defined ( Y ) #endif"; + "#if ! defined ( Y ) #endif\n"; // Preprocess => don't crash.. - (void)PreprocessorHelper::getcode(settings0, *this, filedata); + (void)getcode(settings0, *this, filedata); } void wrongPathOnErrorDirective() { const auto settings = dinit(Settings, $.userDefines = "foo"); - const std::string code("#error hello world!\n"); - (void)PreprocessorHelper::getcodeforcfg(settings, *this, code, "X", "./././test.c"); - ASSERT_EQUALS("[test.c:1:0]: (error) #error hello world! [preprocessorErrorDirective]\n", errout_str()); + const char code[] = "#error hello world!\n"; + (void)getcodeforcfg(settings, *this, code, "X", "./././test.c"); + ASSERT_EQUALS("[test.c:1:2]: (error) #error hello world! [preprocessorErrorDirective]\n", errout_str()); } // test for existing local include void testMissingInclude() { - /*const*/ Settings settings; - settings.clearIncludeCache = true; - settings.checks.enable(Checks::missingInclude); - settings.templateFormat = "simple"; // has no effect + const auto settings = dinit(Settings, + $.clearIncludeCache = true, + $.checks.enable (Checks::missingInclude), + $.templateFormat = "simple" // has no effect + ); setTemplateFormat("simple"); ScopedFile header("header.h", ""); - std::string code("#include \"header.h\""); - (void)PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.c"); + const char code[] = "#include \"header.h\"\n"; + (void)getcodeforcfg(settings, *this, code, "", "test.c"); ASSERT_EQUALS("", errout_str()); } // test for missing local include void testMissingInclude2() { - /*const*/ Settings settings; - settings.clearIncludeCache = true; - settings.checks.enable(Checks::missingInclude); - settings.templateFormat = "simple"; // has no effect + const auto settings = dinit(Settings, + $.clearIncludeCache = true, + $.checks.enable (Checks::missingInclude), + $.templateFormat = "simple" // has no effect + ); setTemplateFormat("simple"); - std::string code("#include \"header.h\""); - (void)PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.c"); + const char code[] = "#include \"header.h\"\n"; + (void)getcodeforcfg(settings, *this, code, "", "test.c"); - ASSERT_EQUALS("test.c:1:0: information: Include file: \"header.h\" not found. [missingInclude]\n", errout_str()); + ASSERT_EQUALS("test.c:1:2: information: Include file: \"header.h\" not found. [missingInclude]\n", errout_str()); } // test for missing local include - no include path given void testMissingInclude3() { - /*const*/ Settings settings; - settings.clearIncludeCache = true; - settings.checks.enable(Checks::missingInclude); - settings.templateFormat = "simple"; // has no effect + const auto settings = dinit(Settings, + $.clearIncludeCache = true, + $.checks.enable (Checks::missingInclude), + $.templateFormat = "simple" // has no effect + ); setTemplateFormat("simple"); ScopedFile header("header.h", "", "inc"); - std::string code("#include \"header.h\""); - (void)PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.c"); + const char code[] = "#include \"header.h\"\n"; + (void)getcodeforcfg(settings, *this, code, "", "test.c"); - ASSERT_EQUALS("test.c:1:0: information: Include file: \"header.h\" not found. [missingInclude]\n", errout_str()); + ASSERT_EQUALS("test.c:1:2: information: Include file: \"header.h\" not found. [missingInclude]\n", errout_str()); } // test for existing local include - include path provided void testMissingInclude4() { - /*const*/ Settings settings; - settings.clearIncludeCache = true; - settings.checks.enable(Checks::missingInclude); - settings.includePaths.emplace_back("inc"); - settings.templateFormat = "simple"; // has no effect + const auto settings = dinit(Settings, + $.clearIncludeCache = true, + $.checks.enable (Checks::missingInclude), + $.includePaths.emplace_back ("inc"), + $.templateFormat = "simple" // has no effect + ); setTemplateFormat("simple"); ScopedFile header("header.h", "", "inc"); - std::string code("#include \"inc/header.h\""); - (void)PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.c"); + const char code[] = "#include \"inc/header.h\"\n"; + (void)getcodeforcfg(settings, *this, code, "", "test.c"); ASSERT_EQUALS("", errout_str()); } // test for existing local include - absolute path void testMissingInclude5() { - /*const*/ Settings settings; - settings.clearIncludeCache = true; - settings.checks.enable(Checks::missingInclude); - settings.includePaths.emplace_back("inc"); - settings.templateFormat = "simple"; // has no effect + const auto settings = dinit(Settings, + $.clearIncludeCache = true, + $.checks.enable (Checks::missingInclude), + $.includePaths.emplace_back ("inc"), + $.templateFormat = "simple" // has no effect + ); setTemplateFormat("simple"); ScopedFile header("header.h", "", Path::getCurrentPath()); - std::string code("#include \"" + header.path() + "\""); - (void)PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.c"); + std::string code("#include \"" + header.path() + "\"\n"); + (void)getcodeforcfg(settings, *this, code.data(), code.size(), "", "test.c"); ASSERT_EQUALS("", errout_str()); } // test for missing local include - absolute path void testMissingInclude6() { - /*const*/ Settings settings; - settings.clearIncludeCache = true; - settings.checks.enable(Checks::missingInclude); - settings.templateFormat = "simple"; // has no effect + const auto settings = dinit(Settings, + $.clearIncludeCache = true, + $.checks.enable (Checks::missingInclude), + $.templateFormat = "simple" // has no effect + ); setTemplateFormat("simple"); const std::string header = Path::join(Path::getCurrentPath(), "header.h"); - std::string code("#include \"" + header + "\""); - (void)PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.c"); + std::string code("#include \"" + header + "\"\n"); + (void)getcodeforcfg(settings, *this, code.data(), code.size(), "", "test.c"); - ASSERT_EQUALS("test.c:1:0: information: Include file: \"" + header + "\" not found. [missingInclude]\n", errout_str()); + ASSERT_EQUALS("test.c:1:2: information: Include file: \"" + header + "\" not found. [missingInclude]\n", errout_str()); } // test for missing system include - system includes are not searched for in relative path void testMissingSystemInclude() { - /*const*/ Settings settings; - settings.clearIncludeCache = true; - settings.checks.enable(Checks::missingInclude); - settings.templateFormat = "simple"; // has no effect + const auto settings = dinit(Settings, + $.clearIncludeCache = true, + $.checks.enable (Checks::missingInclude), + $.templateFormat = "simple" // has no effect + ); setTemplateFormat("simple"); ScopedFile header("header.h", ""); - std::string code("#include "); - (void)PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.c"); + const char code[] = "#include \n"; + (void)getcodeforcfg(settings, *this, code, "", "test.c"); - ASSERT_EQUALS("test.c:1:0: information: Include file: not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]\n", errout_str()); + ASSERT_EQUALS("test.c:1:2: information: Include file: not found. Please note: Standard library headers do not need to be provided to get proper results. [missingIncludeSystem]\n", errout_str()); } // test for missing system include void testMissingSystemInclude2() { - /*const*/ Settings settings; - settings.clearIncludeCache = true; - settings.checks.enable(Checks::missingInclude); - settings.templateFormat = "simple"; // has no effect + const auto settings = dinit(Settings, + $.clearIncludeCache = true, + $.checks.enable (Checks::missingInclude), + $.templateFormat = "simple" // has no effect + ); setTemplateFormat("simple"); - std::string code("#include "); - (void)PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.c"); + const char code[] = "#include \n"; + (void)getcodeforcfg(settings, *this, code, "", "test.c"); - ASSERT_EQUALS("test.c:1:0: information: Include file: not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]\n", errout_str()); + ASSERT_EQUALS("test.c:1:2: information: Include file: not found. Please note: Standard library headers do not need to be provided to get proper results. [missingIncludeSystem]\n", errout_str()); } // test for existing system include in system include path void testMissingSystemInclude3() { - /*const*/ Settings settings; - settings.clearIncludeCache = true; - settings.checks.enable(Checks::missingInclude); - settings.templateFormat = "simple"; // has no effect + const auto settings = dinit(Settings, + $.clearIncludeCache = true, + $.checks.enable (Checks::missingInclude), + $.templateFormat = "simple", // has no effect + $.includePaths.emplace_back ("system") + ); setTemplateFormat("simple"); - settings.includePaths.emplace_back("system"); ScopedFile header("header.h", "", "system"); - std::string code("#include "); - (void)PreprocessorHelper::getcodeforcfg(settings0, *this, code, "", "test.c"); + const char code[] = "#include \n"; + (void)getcodeforcfg(settings, *this, code, "", "test.c"); ASSERT_EQUALS("", errout_str()); } // test for existing system include - absolute path void testMissingSystemInclude4() { - /*const*/ Settings settings; - settings.clearIncludeCache = true; - settings.checks.enable(Checks::missingInclude); - settings.includePaths.emplace_back("inc"); - settings.templateFormat = "simple"; // has no effect + const auto settings = dinit(Settings, + $.clearIncludeCache = true, + $.checks.enable (Checks::missingInclude), + $.includePaths.emplace_back ("inc"); + $.templateFormat = "simple" // has no effect + ); setTemplateFormat("simple"); ScopedFile header("header.h", "", Path::getCurrentPath()); - std::string code("#include <" + header.path() + ">"); - (void)PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.c"); + std::string code("#include <" + header.path() + ">\n"); + (void)getcodeforcfg(settings, *this, code.data(), code.size(), "", "test.c"); ASSERT_EQUALS("", errout_str()); } // test for missing system include - absolute path void testMissingSystemInclude5() { - /*const*/ Settings settings; - settings.clearIncludeCache = true; - settings.checks.enable(Checks::missingInclude); - settings.templateFormat = "simple"; // has no effect + const auto settings = dinit(Settings, + $.clearIncludeCache = true, + $.checks.enable (Checks::missingInclude), + $.templateFormat = "simple" // has no effect + ); setTemplateFormat("simple"); const std::string header = Path::join(Path::getCurrentPath(), "header.h"); - std::string code("#include <" + header + ">"); - (void)PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.c"); + std::string code("#include <" + header + ">\n"); + (void)getcodeforcfg(settings, *this, code.data(), code.size(), "", "test.c"); - ASSERT_EQUALS("test.c:1:0: information: Include file: <" + header + "> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]\n", errout_str()); + ASSERT_EQUALS("test.c:1:2: information: Include file: <" + header + "> not found. Please note: Standard library headers do not need to be provided to get proper results. [missingIncludeSystem]\n", errout_str()); } // test for missing local and system include void testMissingIncludeMixed() { - /*const*/ Settings settings; - settings.clearIncludeCache = true; - settings.checks.enable(Checks::missingInclude); - settings.templateFormat = "simple"; // has no effect + const auto settings = dinit(Settings, + $.clearIncludeCache = true, + $.checks.enable (Checks::missingInclude), + + $.templateFormat = "simple" // has no effect + ); setTemplateFormat("simple"); ScopedFile header("header.h", ""); ScopedFile header2("header2.h", ""); - std::string code("#include \"missing.h\"\n" - "#include \n" - "#include \n" - "#include \"header2.h\""); - (void)PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.c"); + const char code[] = "#include \"missing.h\"\n" + "#include \n" + "#include \n" + "#include \"header2.h\"\n"; + (void)getcodeforcfg(settings, *this, code, "", "test.c"); - ASSERT_EQUALS("test.c:1:0: information: Include file: \"missing.h\" not found. [missingInclude]\n" - "test.c:2:0: information: Include file: not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]\n" - "test.c:3:0: information: Include file: not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]\n", errout_str()); + ASSERT_EQUALS("test.c:1:2: information: Include file: \"missing.h\" not found. [missingInclude]\n" + "test.c:2:2: information: Include file: not found. Please note: Standard library headers do not need to be provided to get proper results. [missingIncludeSystem]\n" + "test.c:3:2: information: Include file: not found. Please note: Standard library headers do not need to be provided to get proper results. [missingIncludeSystem]\n", errout_str()); } void testMissingIncludeCheckConfig() { - /*const*/ Settings settings; - settings.clearIncludeCache = true; - settings.checks.enable(Checks::missingInclude); - settings.includePaths.emplace_back("system"); - settings.templateFormat = "simple"; // has no effect + const auto settings = dinit(Settings, + $.clearIncludeCache = true, + $.checks.enable (Checks::missingInclude), + $.includePaths.emplace_back ("system"); + $.templateFormat = "simple" // has no effect + ); setTemplateFormat("simple"); ScopedFile header("header.h", ""); @@ -2557,30 +3052,60 @@ class TestPreprocessor : public TestFixture { "#include \"" + missing3 + "\"\n" "#include <" + header6.path() + ">\n" "#include <" + missing4 + ">\n"); - (void)PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.c"); + (void)getcodeforcfg(settings, *this, code.data(), code.size(), "", "test.c"); + + ASSERT_EQUALS("test.c:1:2: information: Include file: \"missing.h\" not found. [missingInclude]\n" + "test.c:2:2: information: Include file: not found. Please note: Standard library headers do not need to be provided to get proper results. [missingIncludeSystem]\n" + "test.c:3:2: information: Include file: not found. Please note: Standard library headers do not need to be provided to get proper results. [missingIncludeSystem]\n" + "test.c:6:2: information: Include file: \"header4.h\" not found. [missingInclude]\n" + "test.c:9:2: information: Include file: \"" + missing3 + "\" not found. [missingInclude]\n" + "test.c:11:2: information: Include file: <" + missing4 + "> not found. Please note: 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\n"); + ScopedFile header2("header2.h", "2\n"); + + Settings settings; + Preprocessor preprocessor(tokens, settings, *this, Standards::Language::CPP); - ASSERT_EQUALS("test.c:1:0: information: Include file: \"missing.h\" not found. [missingInclude]\n" - "test.c:2:0: information: Include file: not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]\n" - "test.c:3:0: information: Include file: not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]\n" - "test.c:6:0: information: Include file: \"header4.h\" not found. [missingInclude]\n" - "test.c:9:0: information: Include file: \"" + missing3 + "\" not found. [missingInclude]\n" - "test.c:11:0: information: Include file: <" + missing4 + "> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]\n", errout_str()); + 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"; + const char code[] = "#if __has_include()\n123\n#endif\n"; Settings settings; settings.standards.setStd("c++11"); - ASSERT_EQUALS("", PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.cpp")); - ASSERT_EQUALS("[test.cpp:1:0]: (error) failed to evaluate #if condition, undefined function-like macro invocation: __has_include( ... ) [preprocessorErrorDirective]\n", errout_str()); + ASSERT_EQUALS("", getcodeforcfg(settings, *this, code, "", "test.cpp")); + ASSERT_EQUALS("[test.cpp:1:2]: (error) failed to evaluate #if condition, undefined function-like macro invocation: __has_include( ... ) [syntaxError]\n", errout_str()); // TODO: use individual ID settings.standards.setStd("c++17"); - ASSERT_EQUALS("", PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.cpp")); + ASSERT_EQUALS("", getcodeforcfg(settings, *this, code, "", "test.cpp")); ASSERT_EQUALS("", errout_str()); settings.standards.setStd("gnu++11"); - ASSERT_EQUALS("", PreprocessorHelper::getcodeforcfg(settings, *this, code, "", "test.cpp")); + ASSERT_EQUALS("", getcodeforcfg(settings, *this, code, "", "test.cpp")); ASSERT_EQUALS("", errout_str()); } @@ -2588,8 +3113,8 @@ class TestPreprocessor : public TestFixture { // #11928 / #10045 const char code[] = "void f(long l) {\n" " if (l > INT_MAX) {}\n" - "}"; - const std::string actual = PreprocessorHelper::getcodeforcfg(settings0, *this, code, "", "test.c"); + "}\n"; + const std::string actual = getcodeforcfg(settings0, *this, code, "", "test.c"); ASSERT_EQUALS("void f ( long l ) {\n" "if ( l > $2147483647 ) { }\n" "}", actual); @@ -2597,9 +3122,9 @@ class TestPreprocessor : public TestFixture { void hashCalculation() { // #12383 - const char code[] = "int a;"; - const char code2[] = "int a;"; // extra space - const char code3[] = "\n\nint a;"; // extra new line + const char code[] = "int a;\n"; + const char code2[] = "int a;\n"; // extra space + const char code3[] = "\n\nint a;\n"; // extra new line ASSERT_EQUALS(getHash(code), getHash(code)); ASSERT_EQUALS(getHash(code2), getHash(code2)); @@ -2609,9 +3134,9 @@ class TestPreprocessor : public TestFixture { ASSERT(getHash(code2) != getHash(code3)); } - void standard() const { + void standard() { - const char code[] = "int a;"; + const char code[] = "int a;\n"; // TODO: this bypasses the standard determined from the settings - the parameter should not be exposed simplecpp::DUI dui; @@ -2651,10 +3176,60 @@ class TestPreprocessor : public TestFixture { dui.std = "gnu77"; std::vector files; TokenList tokenlist{settingsDefault, Standards::Language::CPP}; - preprocess(code, files, "test.cpp", tokenlist, dui); + // TODO: can this happen from application code? if yes we need to turn it into a proper error + ASSERT_THROW_EQUALS(preprocess(code, files, "test.cpp", tokenlist, dui), std::runtime_error, "unexpected simplecpp::Output type 12"); ASSERT(!tokenlist.front()); // nothing is tokenized when an unknown standard is provided } } + + void writeLocations() + { + const char inc[] = "class A {\n" + "public:\n" + " void f() {}\n" + "};\n"; + const char code[] = "#include \"test.h\"\n"; + ScopedFile header("test.h", inc); + const std::string processed = getcodeforcfg(settingsDefault, *this, code, "", "test.cpp"); + ASSERT_EQUALS( + "\n" + "#line 1 \"test.h\"\n" + "class A {\n" + "public :\n" + "void f ( ) { }\n" + "} ;", + processed); + } + + void pragmaAsm() + { + const char code[] = "#pragma asm\n"; + ASSERT_THROW_INTERNAL(getcodeforcfg(settingsDefault, *this, code, "", "test.cpp"), InternalError::SYNTAX); + } + + void dumpPreprocessor() { + const char code[] = "#if M == 0\n" + "#endif\n;\n"; + std::vector files; + simplecpp::OutputList outputList; + + Settings settings; + settings.relativePaths = true; + settings.basePaths.emplace_back("/some/path"); + + simplecpp::TokenList tokens1(code, files, "/some/path/test.cpp", {}, &outputList); + Preprocessor preprocessor(tokens1, settings, *this, Standards::Language::CPP); + (void)preprocessor.preprocess("", files, outputList); + (void)preprocessor.reportOutput(outputList, true); + + std::ostringstream ostr; + preprocessor.dump(ostr); + ASSERT_EQUALS( + " \n" + " \n" + " \n", + ostr.str()); + } }; REGISTER_TEST(TestPreprocessor) diff --git a/test/testprocessexecutor.cpp b/test/testprocessexecutor.cpp index ff404f11c66..87b03d915f8 100644 --- a/test/testprocessexecutor.cpp +++ b/test/testprocessexecutor.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,8 +16,11 @@ * along with this program. If not, see . */ -#include "filesettings.h" +#include "config.h" #include "fixture.h" + +#ifdef HAS_THREADING_MODEL_FORK +#include "filesettings.h" #include "helpers.h" #include "processexecutor.h" #include "redirect.h" @@ -33,13 +36,22 @@ #include #include #include +#endif // HAS_THREADING_MODEL_FORK class TestProcessExecutorBase : public TestFixture { public: - TestProcessExecutorBase(const char * const name, bool useFS) : TestFixture(name), useFS(useFS) {} + TestProcessExecutorBase(const char * const name, bool useFS) + : TestFixture(name) +#ifdef HAS_THREADING_MODEL_FORK + , useFS(useFS) +#endif // HAS_THREADING_MODEL_FORK + { + (void)useFS; + } private: - /*const*/ Settings settings = settingsBuilder().library("std.cfg").build(); +#ifdef HAS_THREADING_MODEL_FORK + /*const*/ Settings settings; bool useFS; std::string fprefix() const @@ -51,9 +63,8 @@ class TestProcessExecutorBase : public TestFixture { struct CheckOptions { - CheckOptions() = default; bool quiet = true; - SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE; + Settings::ShowTime showtime = Settings::ShowTime::NONE; const char* plistOutput = nullptr; std::vector filesList; }; @@ -68,19 +79,19 @@ class TestProcessExecutorBase : public TestFixture { std::list filelist; if (opt.filesList.empty()) { for (int i = 1; i <= files; ++i) { - std::string f_s = fprefix() + "_" + std::to_string(i) + ".cpp"; - filelist.emplace_back(f_s, Standards::Language::CPP, data.size()); + std::string f_s = fprefix() + "_" + std::to_string(i) + ".c"; + filelist.emplace_back(f_s, Standards::Language::C, data.size()); if (useFS) { - fileSettings.emplace_back(std::move(f_s), Standards::Language::CPP, data.size()); + fileSettings.emplace_back(std::move(f_s), Standards::Language::C, data.size()); } } } else { for (const auto& f : opt.filesList) { - filelist.emplace_back(f, Standards::Language::CPP, data.size()); + filelist.emplace_back(f, Standards::Language::C, data.size()); if (useFS) { - fileSettings.emplace_back(f, Standards::Language::CPP, data.size()); + fileSettings.emplace_back(f, Standards::Language::C, data.size()); } } } @@ -93,6 +104,9 @@ class TestProcessExecutorBase : public TestFixture { s.plistOutput = opt.plistOutput; s.templateFormat = "{callstack}: ({severity}) {inconclusive:inconclusive: }{message}"; Suppressions supprs; + std::unique_ptr timerResults; + if (s.showtime != Settings::ShowTime::NONE) + timerResults.reset(new TimerResults); // NOLINTNEXTLINE(performance-unnecessary-value-param) auto executeFn = [](std::string,std::vector,std::string,std::string&){ @@ -108,13 +122,14 @@ class TestProcessExecutorBase : public TestFixture { if (useFS) filelist.clear(); - ProcessExecutor executor(filelist, fileSettings, s, supprs, *this, executeFn); + ProcessExecutor executor(filelist, fileSettings, s, supprs, *this, timerResults.get(), executeFn); ASSERT_EQUALS(result, executor.check()); } +#endif // HAS_THREADING_MODEL_FORK void run() override { -#if !defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) mNewTemplate = true; +#ifdef HAS_THREADING_MODEL_FORK TEST_CASE(deadlock_with_many_errors); TEST_CASE(many_threads); TEST_CASE(many_threads_showtime); @@ -125,25 +140,23 @@ class TestProcessExecutorBase : public TestFixture { TEST_CASE(one_error_less_files); TEST_CASE(one_error_several_files); TEST_CASE(showtime_top5_file); - TEST_CASE(showtime_top5_summary); TEST_CASE(showtime_file); - TEST_CASE(showtime_summary); TEST_CASE(showtime_file_total); TEST_CASE(suppress_error_library); TEST_CASE(unique_errors); -#endif // !WIN32 +#endif // HAS_THREADING_MODEL_FORK } +#ifdef HAS_THREADING_MODEL_FORK void deadlock_with_many_errors() { std::ostringstream oss; - oss << "int main()\n" + oss << "void f()\n" << "{\n"; const int num_err = 1; for (int i = 0; i < num_err; i++) { - oss << " {int i = *((int*)0);}\n"; + oss << " (void)(*((int*)0));\n"; } - oss << " return 0;\n" - << "}\n"; + oss << "}\n"; const int num_files = 3; check(2, num_files, num_files, oss.str()); ASSERT_EQUALS(1LL * num_err * num_files, cppcheck::count_all_of(errout_str(), "(error) Null pointer dereference: (int*)0")); @@ -152,10 +165,9 @@ class TestProcessExecutorBase : public TestFixture { void many_threads() { const int num_files = 100; check(16, num_files, num_files, - "int main()\n" + "void f()\n" "{\n" - " int i = *((int*)0);\n" - " return 0;\n" + " (void)(*((int*)0));\n" "}"); ASSERT_EQUALS(num_files, cppcheck::count_all_of(errout_str(), "(error) Null pointer dereference: (int*)0")); } @@ -164,11 +176,10 @@ class TestProcessExecutorBase : public TestFixture { void many_threads_showtime() { SUPPRESS; check(16, 100, 100, - "int main()\n" + "void f()\n" "{\n" - " int i = *((int*)0);\n" - " return 0;\n" - "}", dinit(CheckOptions, $.showtime = SHOWTIME_MODES::SHOWTIME_SUMMARY)); + " (void)(*((int*)0));\n" + "}", dinit(CheckOptions, $.showtime = Settings::ShowTime::SUMMARY)); // we are not interested in the results - so just consume them ignore_errout(); } @@ -178,10 +189,9 @@ class TestProcessExecutorBase : public TestFixture { ScopedFile plistFile("dummy", "", plistOutput); check(16, 100, 100, - "int main()\n" + "void f()\n" "{\n" - " int i = *((int*)0);\n" - " return 0;\n" + " (void)(*((int*)0));\n" "}", dinit(CheckOptions, $.plistOutput = plistOutput.c_str())); // we are not interested in the results - so just consume them ignore_errout(); @@ -213,21 +223,19 @@ class TestProcessExecutorBase : public TestFixture { void one_error_less_files() { check(2, 1, 1, - "int main()\n" + "void f()\n" "{\n" - " {int i = *((int*)0);}\n" - " return 0;\n" + " (void)(*((int*)0));\n" "}"); - ASSERT_EQUALS("[" + fprefix() + "_1.cpp:3:14]: (error) Null pointer dereference: (int*)0 [nullPointer]\n", errout_str()); + ASSERT_EQUALS("[" + fprefix() + "_1.c:3:12]: (error) Null pointer dereference: (int*)0 [nullPointer]\n", errout_str()); } void one_error_several_files() { const int num_files = 20; check(2, num_files, num_files, - "int main()\n" + "void f()\n" "{\n" - " {int i = *((int*)0);}\n" - " return 0;\n" + " (void)(*((int*)0));\n" "}"); ASSERT_EQUALS(num_files, cppcheck::count_all_of(errout_str(), "(error) Null pointer dereference: (int*)0")); } @@ -240,25 +248,10 @@ class TestProcessExecutorBase : public TestFixture { check(2, 2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = SHOWTIME_MODES::SHOWTIME_TOP5_FILE)); - // for each file: top5 results + overall + empty line + $.showtime = Settings::ShowTime::TOP5_FILE)); const std::string output_s = GET_REDIRECT_OUTPUT; - // for each file: top5 results + overall + empty line - TODO_ASSERT_EQUALS(static_cast(5 + 1 + 1) * 2, 0, cppcheck::count_all_of(output_s, '\n')); - } - - void showtime_top5_summary() { - REDIRECT; - check(2, 2, 0, - "int main() {}", - dinit(CheckOptions, - $.showtime = SHOWTIME_MODES::SHOWTIME_TOP5_SUMMARY)); - const std::string output_s = GET_REDIRECT_OUTPUT; - // once: top5 results + overall + empty line - TODO_ASSERT_EQUALS(5 + 1 + 1, 2, cppcheck::count_all_of(output_s, '\n')); - // should only report the top5 once - ASSERT(output_s.find("1 result(s)") == std::string::npos); - TODO_ASSERT(output_s.find("2 result(s)") != std::string::npos); + // for each file: top5 results + check time + TODO_ASSERT_EQUALS(static_cast(5 + 1) * 2, 0, cppcheck::count_all_of(output_s, '\n')); } void showtime_file() { @@ -266,44 +259,31 @@ class TestProcessExecutorBase : public TestFixture { check(2, 2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = SHOWTIME_MODES::SHOWTIME_FILE)); + $.showtime = Settings::ShowTime::FILE)); const std::string output_s = GET_REDIRECT_OUTPUT; TODO_ASSERT_EQUALS(2, 0, cppcheck::count_all_of(output_s, "Overall time:")); } - void showtime_summary() { - REDIRECT; // should not cause TSAN failures as the showtime logging is synchronized - check(2, 2, 0, - "int main() {}", - dinit(CheckOptions, - $.showtime = SHOWTIME_MODES::SHOWTIME_SUMMARY)); - const std::string output_s = GET_REDIRECT_OUTPUT; - // should only report the actual summary once - ASSERT(output_s.find("1 result(s)") == std::string::npos); - TODO_ASSERT(output_s.find("2 result(s)") != std::string::npos); - } - void showtime_file_total() { REDIRECT; // should not cause TSAN failures as the showtime logging is synchronized check(2, 2, 0, "int main() {}", dinit(CheckOptions, - $.showtime = SHOWTIME_MODES::SHOWTIME_FILE_TOTAL)); + $.showtime = Settings::ShowTime::FILE_TOTAL)); const std::string output_s = GET_REDIRECT_OUTPUT; - TODO_ASSERT(output_s.find("Check time: " + fprefix() + "_1.cpp: ") != std::string::npos); - TODO_ASSERT(output_s.find("Check time: " + fprefix() + "_2.cpp: ") != std::string::npos); + TODO_ASSERT(output_s.find("Check time: " + fprefix() + "_1.c: ") != std::string::npos); + TODO_ASSERT(output_s.find("Check time: " + fprefix() + "_2.c: ") != std::string::npos); } void suppress_error_library() { SUPPRESS; const Settings settingsOld = settings; // TODO: get rid of this - const char xmldata[] = R"()"; + const char xmldata[] = R"()"; settings = settingsBuilder().libraryxml(xmldata).build(); check(2, 1, 0, - "int main()\n" + "void f()\n" "{\n" - " int i = *((int*)0);\n" - " return 0;\n" + " (void)(*((int*)0));\n" "}"); ASSERT_EQUALS("", errout_str()); settings = settingsOld; @@ -314,15 +294,16 @@ class TestProcessExecutorBase : public TestFixture { ScopedFile inc_h(fprefix() + ".h", "inline void f()\n" "{\n" - " (void)*((int*)0);\n" + " (void)(*((int*)0));\n" "}"); check(2, 2, 2, "#include \"" + inc_h.name() +"\""); // this is made unique by the executor - ASSERT_EQUALS("[" + inc_h.name() + ":3:11]: (error) Null pointer dereference: (int*)0 [nullPointer]\n", errout_str()); + ASSERT_EQUALS("[" + inc_h.name() + ":3:12]: (error) Null pointer dereference: (int*)0 [nullPointer]\n", errout_str()); } // TODO: test whole program analysis +#endif // HAS_THREADING_MODEL_FORK }; class TestProcessExecutorFiles : public TestProcessExecutorBase { diff --git a/test/testprogrammemory.cpp b/test/testprogrammemory.cpp index 13a5f8e639a..c37431de608 100644 --- a/test/testprogrammemory.cpp +++ b/test/testprogrammemory.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-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 @@ -21,8 +21,11 @@ #include "helpers.h" #include "token.h" #include "programmemory.h" +#include "utils.h" #include "vfvalue.h" +#include + class TestProgramMemory : public TestFixture { public: TestProgramMemory() : TestFixture("TestProgramMemory") {} @@ -36,7 +39,7 @@ class TestProgramMemory : public TestFixture { } void copyOnWrite() const { - SimpleTokenList tokenlist("1+1;"); + SimpleTokenList tokenlist("1+1;\n"); Token* tok = tokenlist.front(); const nonneg int id = 123; tok->exprId(id); @@ -95,8 +98,8 @@ class TestProgramMemory : public TestFixture { void at() const { ProgramMemory pm; - ASSERT_THROW_EQUALS_2(pm.at(123), std::out_of_range, "ProgramMemory::at"); - ASSERT_THROW_EQUALS_2(utils::as_const(pm).at(123), std::out_of_range, "ProgramMemory::at"); + ASSERT_THROW_EQUALS(pm.at(123), std::out_of_range, "ProgramMemory::at"); + ASSERT_THROW_EQUALS(utils::as_const(pm).at(123), std::out_of_range, "ProgramMemory::at"); } }; diff --git a/test/testregex.cpp b/test/testregex.cpp new file mode 100644 index 00000000000..f26a9fee4fa --- /dev/null +++ b/test/testregex.cpp @@ -0,0 +1,208 @@ +/* + * 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 . + */ + +#ifdef HAVE_RULES + +#include "fixture.h" +#include "regex.h" + +#include +#include +#include +#include + +class TestRegExBase : public TestFixture { +public: + TestRegExBase(const char * const name, Regex::Engine engine) : TestFixture(name), mEngine(engine) {} + +private: + Regex::Engine mEngine; + + void run() override { + TEST_CASE(match); + TEST_CASE(nomatch); + TEST_CASE(compileError); + TEST_CASE(copy); + TEST_CASE(multimatch); + TEST_CASE(partialmatch); + TEST_CASE(exactmatch); + } + +#define assertRegex(...) assertRegex_(__FILE__, __LINE__, __VA_ARGS__) + std::shared_ptr assertRegex_(const char* file, int line, std::string pattern, const std::string& exp_err = "") const { + std::string regex_err; + auto r = Regex::create(std::move(pattern), mEngine, regex_err); + 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); + return r; + } + + void match() const { + const auto r = assertRegex("begin.*end"); + int called = 0; + int s = -1; + int e = -1; + auto f = [&](int start, int end) { + ++called; + s = start; + e = end; + }; + ASSERT_EQUALS("", r->match("begin-123-end", std::move(f))); + ASSERT_EQUALS(1, called); + ASSERT_EQUALS(0, s); + ASSERT_EQUALS(13, e); + } + + void nomatch() const { + const auto r = assertRegex("begin.*end"); + int called = 0; + auto f = [&](int /*start*/, int /*end*/) { + ++called; + }; + ASSERT_EQUALS("", r->match("end-123-begin", std::move(f))); + ASSERT_EQUALS(0, called); + } + + void compileError() const { + std::string exp; + if (mEngine == Regex::Engine::Pcre) + exp = "missing terminating ] for character class"; + + (void)assertRegex("[", exp); + } + + void copy() const { + const auto r = assertRegex("begin.*end"); + + int called = 0; + int s = -1; + int e = -1; + auto f = [&](int start, int end) { + ++called; + s = start; + e = end; + }; + + { + // NOLINTNEXTLINE(performance-unnecessary-copy-initialization) + auto r2 = r; + ASSERT_EQUALS("", r2->match("begin-123-end", f)); + ASSERT_EQUALS(1, called); + ASSERT_EQUALS(0, s); + ASSERT_EQUALS(13, e); + } + + called = 0; + s = -1; + e = -1; + ASSERT_EQUALS("", r->match("begin-123-end", f)); + ASSERT_EQUALS(1, called); + ASSERT_EQUALS(0, s); + ASSERT_EQUALS(13, e); + } + + void multimatch() const { + const auto r = assertRegex("info:.*"); + + std::string input = + "info: start\n" + "info: init\n" + "warn: missing\n" + "warn: invalid\n" + "info: done\n" + "error: notclean\n"; + + std::list matches; + auto f = [&](int start, int end) { + matches.push_back(input.substr(start, end - start)); + }; + ASSERT_EQUALS("", r->match(input, std::move(f))); + ASSERT_EQUALS(3, matches.size()); + auto it = matches.cbegin(); + ASSERT_EQUALS("info: start", *it); + ASSERT_EQUALS("info: init", *(++it)); + ASSERT_EQUALS("info: done", *(++it)); + } + + void partialmatch() const { + const auto r = assertRegex("123"); + int called = 0; + int s = -1; + int e = -1; + auto f = [&](int start, int end) { + ++called; + s = start; + e = end; + }; + ASSERT_EQUALS("", r->match("begin-123-end", std::move(f))); + ASSERT_EQUALS(1, called); + ASSERT_EQUALS(6, s); + ASSERT_EQUALS(9, e); + } + + void exactmatch() const { + const auto r = assertRegex("^123$"); + + int called = 0; + int s = -1; + int e = -1; + auto f = [&](int start, int end) { + ++called; + s = start; + e = end; + }; + + ASSERT_EQUALS("", r->match("begin-123-end", f)); + ASSERT_EQUALS(0, called); + ASSERT_EQUALS(-1, s); + ASSERT_EQUALS(-1, e); + + ASSERT_EQUALS("", r->match("123\n123", f)); + ASSERT_EQUALS(0, called); + ASSERT_EQUALS(-1, s); + ASSERT_EQUALS(-1, e); + + ASSERT_EQUALS("", r->match("123123", f)); + ASSERT_EQUALS(0, called); + ASSERT_EQUALS(-1, s); + ASSERT_EQUALS(-1, e); + + ASSERT_EQUALS("", r->match("123", f)); + ASSERT_EQUALS(1, called); + ASSERT_EQUALS(0, s); + ASSERT_EQUALS(3, e); + } + + // TODO: how to provoke a match() error? + +#undef assertRegex +}; + +class TestRegExPcre : public TestRegExBase { +public: + TestRegExPcre() : TestRegExBase("TestRegExPcre", Regex::Engine::Pcre) {} +}; + +REGISTER_TEST(TestRegExPcre) + +#endif // HAVE_RULES diff --git a/test/testrunner.vcxproj b/test/testrunner.vcxproj index 8e1ce01f07e..1c5230c5535 100755 --- a/test/testrunner.vcxproj +++ b/test/testrunner.vcxproj @@ -53,6 +53,7 @@ + @@ -86,6 +87,8 @@ + + @@ -201,11 +204,11 @@ - ..\cli;..\frontend;..\lib;..\externals;..\externals\picojson;..\externals\simplecpp;..\externals\tinyxml2;%(AdditionalIncludeDirectories) + ..\cli;..\frontend;..\lib;..\externals;..\externals\picojson;..\externals\simplecpp;..\externals\tinyxml2;$(BoostInclude);%(AdditionalIncludeDirectories) true ProgramDatabase Disabled - CPPCHECKLIB_IMPORT;SIMPLECPP_IMPORT;WIN32;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;_WIN64;%(PreprocessorDefinitions) + CPPCHECKLIB_IMPORT;SIMPLECPP_IMPORT;$(HaveBoost);_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) MultiThreadedDebugDLL Level4 4018;4127;4146;4244;4251;4267;4389;4701;4706;4800;4805 @@ -230,11 +233,11 @@ - ..\cli;..\frontend;..\lib;..\externals;..\externals\picojson;..\externals\simplecpp;..\externals\tinyxml2;%(AdditionalIncludeDirectories) + ..\cli;..\frontend;..\lib;..\externals;..\externals\picojson;..\externals\simplecpp;..\externals\tinyxml2;$(BoostInclude);%(AdditionalIncludeDirectories) true ProgramDatabase Disabled - CPPCHECKLIB_IMPORT;SIMPLECPP_IMPORT;WIN32;HAVE_RULES;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;_WIN64;%(PreprocessorDefinitions) + CPPCHECKLIB_IMPORT;SIMPLECPP_IMPORT;$(HaveBoost);HAVE_RULES;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) MultiThreadedDebugDLL Level4 4018;4127;4146;4244;4251;4267;4389;4701;4706;4800;4805 @@ -259,10 +262,10 @@ - ..\cli;..\frontend;..\lib;..\externals;..\externals\picojson;..\externals\simplecpp;..\externals\tinyxml2;%(AdditionalIncludeDirectories) + ..\cli;..\frontend;..\lib;..\externals;..\externals\picojson;..\externals\simplecpp;..\externals\tinyxml2;$(BoostInclude);%(AdditionalIncludeDirectories) false MaxSpeed - CPPCHECKLIB_IMPORT;SIMPLECPP_IMPORT;NDEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;_WIN64;%(PreprocessorDefinitions) + CPPCHECKLIB_IMPORT;SIMPLECPP_IMPORT;$(HaveBoost);NDEBUG;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) MultiThreadedDLL Level4 AnySuitable @@ -299,10 +302,10 @@ - ..\cli;..\frontend;..\lib;..\externals;..\externals\picojson;..\externals\simplecpp;..\externals\tinyxml2;%(AdditionalIncludeDirectories) + ..\cli;..\frontend;..\lib;..\externals;..\externals\picojson;..\externals\simplecpp;..\externals\tinyxml2;$(BoostInclude);%(AdditionalIncludeDirectories) false MaxSpeed - CPPCHECKLIB_IMPORT;SIMPLECPP_IMPORT;NDEBUG;WIN32;HAVE_RULES;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;_WIN64;%(PreprocessorDefinitions) + CPPCHECKLIB_IMPORT;SIMPLECPP_IMPORT;$(HaveBoost);NDEBUG;HAVE_RULES;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) MultiThreadedDLL Level4 AnySuitable diff --git a/test/testrunner.vcxproj.filters b/test/testrunner.vcxproj.filters index 6aa63768b24..b02e6b97fa6 100644 --- a/test/testrunner.vcxproj.filters +++ b/test/testrunner.vcxproj.filters @@ -274,6 +274,12 @@ Source Files + + Source Files + + + Source Files + diff --git a/test/testsarifreport.cpp b/test/testsarifreport.cpp new file mode 100644 index 00000000000..e9fc56d736d --- /dev/null +++ b/test/testsarifreport.cpp @@ -0,0 +1,906 @@ +/* + * 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 "sarifreport.h" +#include "errorlogger.h" +#include "errortypes.h" +#include "fixture.h" + +#include +#include +#include +#include + +#include "json.h" + +class TestSarifReport : public TestFixture +{ +public: + TestSarifReport() : TestFixture("TestSarifReport") + {} + +private: + void run() override + { + TEST_CASE(emptyReport); + TEST_CASE(singleError); + TEST_CASE(multipleErrors); + TEST_CASE(errorWithoutLocation); + TEST_CASE(errorWithMultipleLocations); + TEST_CASE(differentSeverityLevels); + TEST_CASE(securityRelatedErrors); + TEST_CASE(cweTagsPresent); + TEST_CASE(noCweNoSecurity); + TEST_CASE(inconclusiveCertainty); + TEST_CASE(criticalErrorId); + TEST_CASE(emptyDescriptions); + TEST_CASE(locationBoundaryValues); + TEST_CASE(duplicateRuleIds); + TEST_CASE(customProductName); + TEST_CASE(versionHandling); + TEST_CASE(securitySeverityMapping); + TEST_CASE(versionWithSpace); + TEST_CASE(customProductNameAndVersion); + TEST_CASE(normalizeLineColumnToOne); + TEST_CASE(internalAndDebugSeverity); + TEST_CASE(problemSeverityMapping); + TEST_CASE(mixedLocationAndNoLocation); + } + + // Helper to create an ErrorMessage + static ErrorMessage createErrorMessage(const std::string& id, + Severity severity, + const std::string& msg, + const std::string& file = "test.cpp", + int line = 10, + int column = 5, + int cweId = 0, + Certainty certainty = Certainty::normal) + { + ErrorMessage::FileLocation loc(file, line, column); + ErrorMessage errorMessage({loc}, file, severity, msg, id, certainty); + if (cweId > 0) + { + errorMessage.cwe = CWE(cweId); + } + return errorMessage; + } + + // Helper to parse JSON and validate structure + static bool parseAndValidateJson(const std::string& json, picojson::value& root) + { + std::string parseError = picojson::parse(root, json); + return parseError.empty() && root.is(); + } + + void emptyReport() + { + SarifReport report; + std::string sarif = report.serialize("TestProduct"); + + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + ASSERT_EQUALS("2.1.0", root.at("version").get()); + ASSERT(root.at("$schema").get().find("sarif-schema-2.1.0") != std::string::npos); + + // From SARIF specification (https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/sarif-v2.1.0-errata01-os-complete.html#_Toc141790730): + // Although the order in which properties appear in a JSON object value is not semantically significant, the version property SHOULD appear first. + ASSERT_EQUALS("{\n \"version\": \"2.1.0\"", sarif.substr(0,22)); + + const picojson::array& runs = root.at("runs").get(); + ASSERT_EQUALS(1U, runs.size()); + + const picojson::object& cur_run = runs[0].get(); + const picojson::array& results = cur_run.at("results").get(); + ASSERT_EQUALS(0U, results.size()); + + const picojson::object& tool = cur_run.at("tool").get(); + const picojson::object& driver = tool.at("driver").get(); + const picojson::array& rules = driver.at("rules").get(); + ASSERT_EQUALS(0U, rules.size()); + } + + void singleError() + { + SarifReport report; + report.addFinding(createErrorMessage("nullPointer", Severity::error, "Null pointer dereference")); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + + // Check results + const picojson::array& results = cur_run.at("results").get(); + ASSERT_EQUALS(1U, results.size()); + + const picojson::object& result = results[0].get(); + ASSERT_EQUALS("nullPointer", result.at("ruleId").get()); + ASSERT_EQUALS("error", result.at("level").get()); + + const picojson::object& message = result.at("message").get(); + ASSERT_EQUALS("Null pointer dereference", message.at("text").get()); + + // Check rules + const picojson::object& tool = cur_run.at("tool").get(); + const picojson::object& driver = tool.at("driver").get(); + const picojson::array& rules = driver.at("rules").get(); + ASSERT_EQUALS(1U, rules.size()); + + const picojson::object& rule = rules[0].get(); + ASSERT_EQUALS("nullPointer", rule.at("id").get()); + } + + void multipleErrors() + { + SarifReport report; + report.addFinding(createErrorMessage("error1", Severity::error, "Error 1", "file1.cpp", 10, 5)); + report.addFinding(createErrorMessage("error2", Severity::warning, "Error 2", "file2.cpp", 20, 10)); + report.addFinding(createErrorMessage("error3", Severity::style, "Error 3", "file3.cpp", 30, 15)); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + + const picojson::array& results = cur_run.at("results").get(); + ASSERT_EQUALS(3U, results.size()); + + const picojson::object& tool = cur_run.at("tool").get(); + const picojson::object& driver = tool.at("driver").get(); + const picojson::array& rules = driver.at("rules").get(); + ASSERT_EQUALS(3U, rules.size()); + } + + void errorWithoutLocation() + { + SarifReport report; + + // Create error without location (empty callStack) + ErrorMessage errorMessage( + {}, "test.cpp", Severity::error, "Error without location", "testError", Certainty::normal); + report.addFinding(errorMessage); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + + // Should have no results (GitHub doesn't support findings without locations) + const picojson::array& results = cur_run.at("results").get(); + ASSERT_EQUALS(0U, results.size()); + + const picojson::object& tool = cur_run.at("tool").get(); + const picojson::object& driver = tool.at("driver").get(); + const picojson::array& rules = driver.at("rules").get(); + ASSERT_EQUALS(0U, rules.size()); + } + + void errorWithMultipleLocations() + { + SarifReport report; + + ErrorMessage::FileLocation loc1("test1.cpp", 10, 5); + ErrorMessage::FileLocation loc2("test2.cpp", 20, 10); + ErrorMessage::FileLocation loc3("test3.cpp", 30, 15); + + ErrorMessage errorMessage({loc1, loc2, loc3}, + "test1.cpp", + Severity::error, + "Error with multiple locations", + "multiLocError", + Certainty::normal); + report.addFinding(errorMessage); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + const picojson::array& results = cur_run.at("results").get(); + + ASSERT_EQUALS(1U, results.size()); + + const picojson::object& result = results[0].get(); + const picojson::array& locations = result.at("locations").get(); + ASSERT_EQUALS(3U, locations.size()); + + // Verify each location + const picojson::object& loc1Obj = locations[0].get(); + const picojson::object& physLoc1 = loc1Obj.at("physicalLocation").get(); + const picojson::object& region1 = physLoc1.at("region").get(); + ASSERT_EQUALS(10, static_cast(region1.at("startLine").get())); + ASSERT_EQUALS(5, static_cast(region1.at("startColumn").get())); + } + + void differentSeverityLevels() + { + SarifReport report; + + report.addFinding(createErrorMessage("error1", Severity::error, "Error severity")); + report.addFinding(createErrorMessage("warning1", Severity::warning, "Warning severity")); + report.addFinding(createErrorMessage("style1", Severity::style, "Style severity")); + report.addFinding(createErrorMessage("perf1", Severity::performance, "Performance severity")); + report.addFinding(createErrorMessage("port1", Severity::portability, "Portability severity")); + report.addFinding(createErrorMessage("info1", Severity::information, "Information severity")); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + + const picojson::array& results = cur_run.at("results").get(); + ASSERT_EQUALS(6U, results.size()); + + // Check severity mappings + ASSERT_EQUALS("error", results[0].get().at("level").get()); // error + ASSERT_EQUALS("error", results[1].get().at("level").get()); // warning + ASSERT_EQUALS("warning", results[2].get().at("level").get()); // style + ASSERT_EQUALS("warning", results[3].get().at("level").get()); // performance + ASSERT_EQUALS("warning", results[4].get().at("level").get()); // portability + ASSERT_EQUALS("note", results[5].get().at("level").get()); // information + } + + void securityRelatedErrors() + { + SarifReport report; + + // Add errors with CWE IDs + report.addFinding(createErrorMessage("nullPointer", Severity::error, "Null pointer", "test.cpp", 10, 5, 476)); + report.addFinding( + createErrorMessage("bufferOverflow", Severity::error, "Buffer overflow", "test.cpp", 20, 5, 121)); + report.addFinding(createErrorMessage("memleak", Severity::warning, "Memory leak", "test.cpp", 30, 5, 401)); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + const picojson::object& tool = cur_run.at("tool").get(); + const picojson::object& driver = tool.at("driver").get(); + const picojson::array& rules = driver.at("rules").get(); + + for (const auto& rule : rules) + { + const picojson::object& r = rule.get(); + const picojson::object& props = r.at("properties").get(); + + // Should have security-severity + ASSERT(props.find("security-severity") != props.end()); + + // Should have tags with security and CWE + ASSERT(props.find("tags") != props.end()); + const picojson::array& tags = props.at("tags").get(); + + bool hasSecurityTag = false; + bool hasCweTag = false; + for (const auto& tag : tags) + { + const std::string& tagStr = tag.get(); + if (tagStr == "security") + hasSecurityTag = true; + if (tagStr.find("external/cwe/cwe-") == 0) + hasCweTag = true; + } + + ASSERT(hasSecurityTag); + ASSERT(hasCweTag); + } + } + + void cweTagsPresent() + { + SarifReport report; + + report.addFinding(createErrorMessage("testError", Severity::error, "Test error", "test.cpp", 10, 5, 119)); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + const picojson::object& tool = cur_run.at("tool").get(); + const picojson::object& driver = tool.at("driver").get(); + const picojson::array& rules = driver.at("rules").get(); + + ASSERT_EQUALS(1U, rules.size()); + + const picojson::object& rule = rules[0].get(); + const picojson::object& props = rule.at("properties").get(); + const picojson::array& tags = props.at("tags").get(); + + bool foundCwe119 = false; + for (const auto& tag : tags) + { + if (tag.get() == "external/cwe/cwe-119") + foundCwe119 = true; + } + + ASSERT(foundCwe119); + } + + void noCweNoSecurity() + { + SarifReport report; + + // Error without CWE ID should not have security properties + report.addFinding(createErrorMessage("styleError", Severity::style, "Style error", "test.cpp", 10, 5, 0)); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + const picojson::object& tool = cur_run.at("tool").get(); + const picojson::object& driver = tool.at("driver").get(); + const picojson::array& rules = driver.at("rules").get(); + + ASSERT_EQUALS(1U, rules.size()); + + const picojson::object& rule = rules[0].get(); + const picojson::object& props = rule.at("properties").get(); + + // Should NOT have security-severity + ASSERT(props.find("security-severity") == props.end()); + + // Should NOT have tags (or if present, no security tag) + if (props.find("tags") != props.end()) + { + const picojson::array& tags = props.at("tags").get(); + for (const auto& tag : tags) + { + ASSERT(tag.get() != "security"); + } + } + } + + void inconclusiveCertainty() + { + SarifReport report; + + report.addFinding( + createErrorMessage("test1", Severity::error, "Conclusive", "test.cpp", 10, 5, 0, Certainty::normal)); + report.addFinding(createErrorMessage( + "test2", Severity::error, "Inconclusive", "test.cpp", 20, 5, 0, Certainty::inconclusive)); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + const picojson::object& tool = cur_run.at("tool").get(); + const picojson::object& driver = tool.at("driver").get(); + const picojson::array& rules = driver.at("rules").get(); + + ASSERT_EQUALS(2U, rules.size()); + + // Check precision values + const picojson::object& rule1 = rules[0].get(); + const picojson::object& props1 = rule1.at("properties").get(); + ASSERT_EQUALS("high", props1.at("precision").get()); + + const picojson::object& rule2 = rules[1].get(); + const picojson::object& props2 = rule2.at("properties").get(); + ASSERT_EQUALS("medium", props2.at("precision").get()); + } + + void criticalErrorId() + { + SarifReport report; + + // Use a critical error ID (from ErrorLogger::isCriticalErrorId) + report.addFinding(createErrorMessage("syntaxError", Severity::error, "Syntax error")); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + const picojson::array& results = cur_run.at("results").get(); + + ASSERT_EQUALS(1U, results.size()); + + const picojson::object& result = results[0].get(); + // Critical errors should always map to "error" level + ASSERT_EQUALS("error", result.at("level").get()); + } + + void emptyDescriptions() + { + SarifReport report; + + report.addFinding(createErrorMessage("testError", Severity::error, "Test error")); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + const picojson::object& tool = cur_run.at("tool").get(); + const picojson::object& driver = tool.at("driver").get(); + const picojson::array& rules = driver.at("rules").get(); + + ASSERT_EQUALS(1U, rules.size()); + + const picojson::object& rule = rules[0].get(); + + // All descriptions should be empty for GitHub integration + ASSERT_EQUALS("", rule.at("name").get()); + ASSERT_EQUALS("", rule.at("shortDescription").get().at("text").get()); + ASSERT_EQUALS("", rule.at("fullDescription").get().at("text").get()); + ASSERT_EQUALS("", rule.at("help").get().at("text").get()); + } + + void locationBoundaryValues() + { + SarifReport report; + + // Test with line/column values that are 0 + // Note: Negative values don't work correctly if FileLocation uses unsigned types + ErrorMessage::FileLocation loc1("test.cpp", 0, 0); + ErrorMessage::FileLocation loc2("test.cpp", 1, 1); + + ErrorMessage errorMessage1({loc1}, "test.cpp", Severity::error, "Error at 0,0", "error1", Certainty::normal); + ErrorMessage errorMessage2({loc2}, "test.cpp", Severity::error, "Error at 1,1", "error2", Certainty::normal); + + report.addFinding(errorMessage1); + report.addFinding(errorMessage2); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + const picojson::array& results = cur_run.at("results").get(); + + ASSERT_EQUALS(2U, results.size()); + + // Check first result (0,0 should be normalized to 1,1) + { + const picojson::object& res = results[0].get(); + const picojson::array& locations = res.at("locations").get(); + const picojson::object& loc = locations[0].get(); + const picojson::object& physLoc = loc.at("physicalLocation").get(); + const picojson::object& region = physLoc.at("region").get(); + + int line = static_cast(region.at("startLine").get()); + int column = static_cast(region.at("startColumn").get()); + + // 0 should be normalized to 1 + ASSERT_EQUALS(1, line); + ASSERT_EQUALS(1, column); + } + + // Check second result (1,1 should stay as 1,1) + { + const picojson::object& res = results[1].get(); + const picojson::array& locations = res.at("locations").get(); + const picojson::object& loc = locations[0].get(); + const picojson::object& physLoc = loc.at("physicalLocation").get(); + const picojson::object& region = physLoc.at("region").get(); + + int line = static_cast(region.at("startLine").get()); + int column = static_cast(region.at("startColumn").get()); + + ASSERT_EQUALS(1, line); + ASSERT_EQUALS(1, column); + } + } + + void duplicateRuleIds() + { + SarifReport report; + + // Add multiple errors with the same rule ID + report.addFinding(createErrorMessage("duplicateId", Severity::error, "First error", "file1.cpp", 10, 5)); + report.addFinding(createErrorMessage("duplicateId", Severity::error, "Second error", "file2.cpp", 20, 10)); + report.addFinding(createErrorMessage("duplicateId", Severity::error, "Third error", "file3.cpp", 30, 15)); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + + // Should have 3 results but only 1 rule + const picojson::array& results = cur_run.at("results").get(); + ASSERT_EQUALS(3U, results.size()); + + const picojson::object& tool = cur_run.at("tool").get(); + const picojson::object& driver = tool.at("driver").get(); + const picojson::array& rules = driver.at("rules").get(); + ASSERT_EQUALS(1U, rules.size()); + + const picojson::object& rule = rules[0].get(); + ASSERT_EQUALS("duplicateId", rule.at("id").get()); + } + + void customProductName() + { + SarifReport report; + report.addFinding(createErrorMessage("testError", Severity::error, "Test error")); + + // Test with custom product name + std::string sarif = report.serialize("CustomChecker"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + const picojson::object& tool = cur_run.at("tool").get(); + const picojson::object& driver = tool.at("driver").get(); + + // Should use "Cppcheck" as default when custom name doesn't parse + ASSERT_EQUALS("Cppcheck", driver.at("name").get()); + } + + void versionHandling() + { + SarifReport report; + report.addFinding(createErrorMessage("testError", Severity::error, "Test error")); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + const picojson::object& tool = cur_run.at("tool").get(); + const picojson::object& driver = tool.at("driver").get(); + + // Should have a semantic version + ASSERT(driver.find("semanticVersion") != driver.end()); + const std::string version = driver.at("semanticVersion").get(); + + // Version should not contain spaces (they should be stripped) + ASSERT(version.find(' ') == std::string::npos); + } + + void securitySeverityMapping() + { + // Test the detailed security-severity mapping for different severity levels with CWE + SarifReport report; + + // Error with CWE should get 9.9 (critical) + report.addFinding(createErrorMessage("error1", Severity::error, "Error with CWE", "test.cpp", 10, 5, 119)); + + // Warning with CWE should get 8.5 (high) + report.addFinding( + createErrorMessage("warning1", Severity::warning, "Warning with CWE", "test.cpp", 20, 5, 120)); + + // Style/Performance/Portability with CWE should get 5.5 (medium) + report.addFinding(createErrorMessage("style1", Severity::style, "Style with CWE", "test.cpp", 30, 5, 398)); + report.addFinding( + createErrorMessage("perf1", Severity::performance, "Performance with CWE", "test.cpp", 40, 5, 407)); + report.addFinding( + createErrorMessage("port1", Severity::portability, "Portability with CWE", "test.cpp", 50, 5, 562)); + + // Information with CWE should get 2.0 (low) + report.addFinding(createErrorMessage("info1", Severity::information, "Info with CWE", "test.cpp", 60, 5, 561)); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + const picojson::object& tool = cur_run.at("tool").get(); + const picojson::object& driver = tool.at("driver").get(); + const picojson::array& rules = driver.at("rules").get(); + + // Check each rule's security-severity value + for (const auto& rule : rules) + { + const picojson::object& r = rule.get(); + const std::string& id = r.at("id").get(); + const picojson::object& props = r.at("properties").get(); + + ASSERT(props.find("security-severity") != props.end()); + const std::string& severity = props.at("security-severity").get(); + double severityValue = std::stod(severity); + + if (id == "error1") + { + // Use a tolerance for floating-point comparison to avoid warning + ASSERT(std::abs(severityValue - 9.9) < 0.01); + } + else if (id == "warning1") + { + ASSERT(std::abs(severityValue - 8.5) < 0.01); + } + else if (id == "style1" || id == "perf1" || id == "port1") + { + ASSERT(std::abs(severityValue - 5.5) < 0.01); + } + else if (id == "info1") + { + ASSERT(std::abs(severityValue - 2.0) < 0.01); + } + } + } + + void versionWithSpace() + { + // Test that version strings with spaces are properly truncated + SarifReport report; + report.addFinding(createErrorMessage("testError", Severity::error, "Test error")); + + // This test would need a way to inject a version with a space + // The current implementation gets version from CppCheck::version() + // This test verifies the space-trimming logic works + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + const picojson::object& tool = cur_run.at("tool").get(); + const picojson::object& driver = tool.at("driver").get(); + + const std::string& version = driver.at("semanticVersion").get(); + // Version should not contain any spaces + ASSERT(version.find(' ') == std::string::npos); + } + + void customProductNameAndVersion() + { + // Test custom product name that includes version info + SarifReport report; + report.addFinding(createErrorMessage("testError", Severity::error, "Test error")); + + // Test with product name that might parse differently + std::string sarif = report.serialize("MyChecker-1.0.0"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + const picojson::object& tool = cur_run.at("tool").get(); + const picojson::object& driver = tool.at("driver").get(); + + // Should have a name (either parsed or default) + ASSERT(driver.find("name") != driver.end()); + ASSERT(driver.find("semanticVersion") != driver.end()); + } + + void normalizeLineColumnToOne() + { + SarifReport report; + + // Test with 0 values + ErrorMessage::FileLocation loc0("test.cpp", 0, 0); + ErrorMessage errorMessage0({loc0}, "test.cpp", Severity::error, "Error at 0", "error0", Certainty::normal); + report.addFinding(errorMessage0); + + // Test with positive values + ErrorMessage::FileLocation locPos("test.cpp", 10, 5); + ErrorMessage errorMessagePos( + {locPos}, "test.cpp", Severity::error, "Error at positive", "errorPos", Certainty::normal); + report.addFinding(errorMessagePos); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + const picojson::array& results = cur_run.at("results").get(); + + ASSERT_EQUALS(2U, results.size()); + + // Check first result with 0,0 + const picojson::object& res0 = results[0].get(); + const picojson::array& locations0 = res0.at("locations").get(); + const picojson::object& loc0_obj = locations0[0].get(); + const picojson::object& physLoc0 = loc0_obj.at("physicalLocation").get(); + const picojson::object& region0 = physLoc0.at("region").get(); + + int line0 = static_cast(region0.at("startLine").get()); + int column0 = static_cast(region0.at("startColumn").get()); + + // 0 values should be normalized to 1 + ASSERT(line0 == 1); + ASSERT(column0 == 1); + + // Check second result with positive values + const picojson::object& res1 = results[1].get(); + const picojson::array& locations1 = res1.at("locations").get(); + const picojson::object& loc1_obj = locations1[0].get(); + const picojson::object& physLoc1 = loc1_obj.at("physicalLocation").get(); + const picojson::object& region1 = physLoc1.at("region").get(); + + ASSERT_EQUALS(10, static_cast(region1.at("startLine").get())); + ASSERT_EQUALS(5, static_cast(region1.at("startColumn").get())); + } + + void internalAndDebugSeverity() + { + // Test internal and debug severity levels + // Based on the implementation in sarifSeverity(): + // - internal -> error + // - debug -> note + // - none -> note + SarifReport report; + + // Create errors with internal and debug severities + ErrorMessage::FileLocation loc1("test.cpp", 10, 5); + ErrorMessage::FileLocation loc2("test.cpp", 20, 10); + ErrorMessage::FileLocation loc3("test.cpp", 30, 15); + + ErrorMessage internal( + {loc1}, "test.cpp", Severity::internal, "Internal message", "internalError", Certainty::normal); + ErrorMessage debug({loc2}, "test.cpp", Severity::debug, "Debug message", "debugError", Certainty::normal); + ErrorMessage none({loc3}, "test.cpp", Severity::none, "None message", "noneError", Certainty::normal); + + report.addFinding(internal); + report.addFinding(debug); + report.addFinding(none); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + const picojson::array& results = cur_run.at("results").get(); + + ASSERT_EQUALS(3U, results.size()); + + // Check the actual mapping + const picojson::object& res0 = results[0].get(); + const picojson::object& res1 = results[1].get(); + const picojson::object& res2 = results[2].get(); + + const std::string level0 = res0.at("level").get(); + const std::string level1 = res1.at("level").get(); + const std::string level2 = res2.at("level").get(); + + // Actual implementation behavior: + ASSERT_EQUALS("error", level0); // internal -> error + ASSERT_EQUALS("note", level1); // debug -> note + ASSERT_EQUALS("note", level2); // none -> note + } + + void problemSeverityMapping() + { + // Test that problem.severity property matches the SARIF severity + SarifReport report; + + report.addFinding(createErrorMessage("error1", Severity::error, "Error")); + report.addFinding(createErrorMessage("warning1", Severity::warning, "Warning")); + report.addFinding(createErrorMessage("style1", Severity::style, "Style")); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + const picojson::object& tool = cur_run.at("tool").get(); + const picojson::object& driver = tool.at("driver").get(); + const picojson::array& rules = driver.at("rules").get(); + + for (const auto& rule : rules) + { + const picojson::object& r = rule.get(); + const picojson::object& props = r.at("properties").get(); + const picojson::object& defaultConfig = r.at("defaultConfiguration").get(); + + // problem.severity should match defaultConfiguration.level + const std::string& problemSeverity = props.at("problem.severity").get(); + const std::string& defaultLevel = defaultConfig.at("level").get(); + + ASSERT_EQUALS(defaultLevel, problemSeverity); + } + } + + void mixedLocationAndNoLocation() + { + // Test a mix of findings with and without locations + SarifReport report; + + // Add findings with locations + report.addFinding(createErrorMessage("withLoc1", Severity::error, "Error with location", "test.cpp", 10, 5)); + report.addFinding( + createErrorMessage("withLoc2", Severity::warning, "Warning with location", "test.cpp", 20, 5)); + + // Add findings without locations + ErrorMessage noLoc1({}, "test.cpp", Severity::error, "Error without location", "noLoc1", Certainty::normal); + ErrorMessage noLoc2({}, "test.cpp", Severity::warning, "Warning without location", "noLoc2", Certainty::normal); + + report.addFinding(noLoc1); + report.addFinding(noLoc2); + + // Add more with locations + report.addFinding(createErrorMessage("withLoc3", Severity::style, "Style with location", "test.cpp", 30, 5)); + + std::string sarif = report.serialize("Cppcheck"); + picojson::value json; + ASSERT(parseAndValidateJson(sarif, json)); + + const picojson::object& root = json.get(); + const picojson::array& runs = root.at("runs").get(); + const picojson::object& cur_run = runs[0].get(); + + // Should only have results for findings with locations + const picojson::array& results = cur_run.at("results").get(); + ASSERT_EQUALS(3U, results.size()); + + // Should only have rules for findings with locations + const picojson::object& tool = cur_run.at("tool").get(); + const picojson::object& driver = tool.at("driver").get(); + const picojson::array& rules = driver.at("rules").get(); + ASSERT_EQUALS(3U, rules.size()); + + // Verify the rule IDs are only for findings with locations + std::set ruleIds; + for (const auto& rule : rules) + { + const picojson::object& r = rule.get(); + ruleIds.insert(r.at("id").get()); + } + + ASSERT(ruleIds.find("withLoc1") != ruleIds.end()); + ASSERT(ruleIds.find("withLoc2") != ruleIds.end()); + ASSERT(ruleIds.find("withLoc3") != ruleIds.end()); + ASSERT(ruleIds.find("noLoc1") == ruleIds.end()); + ASSERT(ruleIds.find("noLoc2") == ruleIds.end()); + } +}; + +REGISTER_TEST(TestSarifReport) diff --git a/test/testsettings.cpp b/test/testsettings.cpp index f4b5916fae9..ddd11de3273 100644 --- a/test/testsettings.cpp +++ b/test/testsettings.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,6 +34,14 @@ class TestSettings : public TestFixture { TEST_CASE(loadCppcheckCfgSafety); TEST_CASE(getNameAndVersion); TEST_CASE(checkLevelDefault); + + TEST_CASE(getMaxConfigsDefault); + TEST_CASE(getMaxConfigsOpt); + TEST_CASE(getMaxConfigsForce); + TEST_CASE(getMaxConfigsOptAndForce); + TEST_CASE(getMaxConfigsDefines); + TEST_CASE(getMaxConfigsDefinesAndOpt); + TEST_CASE(getMaxConfigsOptAndProject); } void simpleEnableGroup() const { @@ -228,6 +236,21 @@ class TestSettings : public TestFixture { R"({"suppressions": [1]}\n)"); ASSERT_EQUALS("'suppressions' array entry is not a string", Settings::loadCppcheckCfg(s, supprs)); } + { + Settings s; + Suppressions supprs; + ScopedFile file("cppcheck.cfg", + R"({"manualUrl": "https://docs.notcppcheck.com/manual.pdf"})"); + ASSERT_EQUALS("", Settings::loadCppcheckCfg(s, supprs)); + ASSERT_EQUALS("https://docs.notcppcheck.com/manual.pdf", s.manualUrl); + } + { + Settings s; + Suppressions supprs; + ScopedFile file("cppcheck.cfg", + R"({"manualUrl": 0}\n)"); + ASSERT_EQUALS("'manualUrl' is not a string", Settings::loadCppcheckCfg(s, supprs)); + } // TODO: test with FILESDIR } @@ -250,7 +273,7 @@ class TestSettings : public TestFixture { Suppressions supprs; ScopedFile file("cppcheck.cfg", "{\"safety\": false}"); ASSERT_EQUALS("", Settings::loadCppcheckCfg(s, supprs)); - ASSERT_EQUALS(true, s.safety); + ASSERT_EQUALS(false, s.safety); } { @@ -287,6 +310,52 @@ class TestSettings : public TestFixture { ASSERT_EQUALS(true, s.vfOptions.doConditionExpressionAnalysis); ASSERT_EQUALS(-1, s.vfOptions.maxForwardBranches); } + + void getMaxConfigsDefault() const { + Settings s; + ASSERT_EQUALS(12, s.getMaxConfigs()); + } + + void getMaxConfigsOpt() const { + Settings s; + s.maxConfigsOption = 1; + ASSERT_EQUALS(1, s.getMaxConfigs()); + } + + void getMaxConfigsForce() const { + Settings s; + s.force = true; + ASSERT(s.getMaxConfigs() > 1000); + } + + void getMaxConfigsOptAndForce() const { + Settings s; + s.maxConfigsOption = 1; + s.force = true; + ASSERT(s.getMaxConfigs() > 1000); + } + + void getMaxConfigsDefines() const { + Settings s; + s.userDefines = "X=1"; + ASSERT_EQUALS(1, s.getMaxConfigs()); + } + + void getMaxConfigsDefinesAndOpt() const { + Settings s; + s.userDefines = "X=1"; + s.maxConfigsOption = 3; + ASSERT_EQUALS(3, s.getMaxConfigs()); + } + + void getMaxConfigsOptAndProject() const { + Settings s; + s.maxConfigsOption = 3; + s.maxConfigsProject = 1; + ASSERT_EQUALS(3, s.getMaxConfigs()); + s.maxConfigsProject = 10; + ASSERT_EQUALS(3, s.getMaxConfigs()); + } }; REGISTER_TEST(TestSettings) diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index a1bd0023921..475d03c696d 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -1,6 +1,6 @@ /* * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2025 Cppcheck team. + * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,6 +32,8 @@ #include #include +class ErrorLogger; + class TestSimplifyTemplate : public TestFixture { public: TestSimplifyTemplate() : TestFixture("TestSimplifyTemplate") {} @@ -222,6 +224,8 @@ class TestSimplifyTemplate : public TestFixture { TEST_CASE(template180); TEST_CASE(template181); TEST_CASE(template182); // #13770 + TEST_CASE(template183); + TEST_CASE(template184); TEST_CASE(template_specialization_1); // #7868 - template specialization template struct S> {..}; TEST_CASE(template_specialization_2); // #7868 - template specialization template struct S> {..}; TEST_CASE(template_specialization_3); @@ -310,18 +314,34 @@ class TestSimplifyTemplate : public TestFixture { TEST_CASE(requires3); TEST_CASE(requires4); TEST_CASE(requires5); + TEST_CASE(requires6); TEST_CASE(explicitBool1); TEST_CASE(explicitBool2); TEST_CASE(templateArgPreserveType); // #13882 - type of template argument + TEST_CASE(template_shift_negative); // shift folding with a negative operand + TEST_CASE(dumpTemplateArgFrom); } + class TemplateSimplifierTest final : public TemplateSimplifier + { + friend class TestSimplifyTemplate; + }; + + class TokenizerTest final : public Tokenizer + { + friend class TestSimplifyTemplate; + public: + TokenizerTest(TokenList tokenList, ErrorLogger &errorLogger) + : Tokenizer(std::move(tokenList), errorLogger) + {} + }; + struct CheckOptions { - CheckOptions() = default; bool debugwarnings = false; }; @@ -352,7 +372,7 @@ class TestSimplifyTemplate : public TestFixture { void template1() { const char code[] = "template T f(T val) { T a; }\n" - "f(10);"; + "f(10);\n"; const char expected[] = "int f ( int val ) ; " "f ( 10 ) ; " @@ -363,7 +383,7 @@ class TestSimplifyTemplate : public TestFixture { void template2() { const char code[] = "template class Fred { T a; };\n" - "Fred fred;"; + "Fred fred;\n"; const char expected[] = "class Fred ; " "Fred fred ; " @@ -374,7 +394,7 @@ class TestSimplifyTemplate : public TestFixture { void template3() { const char code[] = "template class Fred { T data[sz]; };\n" - "Fred fred;"; + "Fred fred;\n"; const char expected[] = "class Fred ; " "Fred fred ; " @@ -385,7 +405,7 @@ class TestSimplifyTemplate : public TestFixture { void template4() { const char code[] = "template class Fred { Fred(); };\n" - "Fred fred;"; + "Fred fred;\n"; const char expected[] = "class Fred ; " "Fred fred ; " @@ -397,7 +417,7 @@ class TestSimplifyTemplate : public TestFixture { void template5() { const char code[] = "template class Fred { };\n" "template Fred::Fred() { }\n" - "Fred fred;"; + "Fred fred;\n"; const char expected[] = "class Fred ; " "Fred fred ; " @@ -410,7 +430,7 @@ class TestSimplifyTemplate : public TestFixture { void template6() { const char code[] = "template class Fred { };\n" "Fred fred1;\n" - "Fred fred2;"; + "Fred fred2;\n"; const char expected[] = "class Fred ; " "Fred fred1 ; " @@ -511,7 +531,7 @@ class TestSimplifyTemplate : public TestFixture { "template < typename T > class A { void f ( ) { B < T > a ; a = B < T > :: g ( ) ; T b ; b = 0 ; if ( b ) { b = 0 ; } } } ; " "template < typename T > B < T > h ( ) { return B < T > ( ) ; }", tok(code)); - ASSERT_EQUALS("class A { template < typename T > int foo ( T d ) ; } ;", tok("class A{ template int foo(T d);};")); + ASSERT_EQUALS("class A { template < typename T > int foo ( T d ) ; } ;", tok("class A{ template int foo(T d);};\n")); } void template9() { @@ -616,7 +636,7 @@ class TestSimplifyTemplate : public TestFixture { " y(AA::create(new CC(AA(), 0)))\n" " {}\n" "\n" - "int yy[AA::size()];"; + "int yy[AA::size()];\n"; const char expected[] = "class BB { } ; " "class AA ; " "class AA ; " @@ -692,7 +712,7 @@ class TestSimplifyTemplate : public TestFixture { " vec(const vec& v) {}\n" // <- never used don't instantiate "};\n" "\n" - "vec<4> v;"; + "vec<4> v;\n"; const char expected2[] = "struct vec<4> ; " "vec<4> v ; " "struct vec<4> { " @@ -750,7 +770,7 @@ class TestSimplifyTemplate : public TestFixture { void template18() { const char code[] = "template class foo { T a; };\n" - "foo *f;"; + "foo *f;\n"; const char expected[] = "class foo ; " "foo * f ; " @@ -795,7 +815,7 @@ class TestSimplifyTemplate : public TestFixture { void template21() { { const char code[] = "template struct Fred { T a; };\n" - "Fred fred;"; + "Fred fred;\n"; const char expected[] = "struct Fred ; " "Fred fred ; " @@ -806,7 +826,7 @@ class TestSimplifyTemplate : public TestFixture { { const char code[] = "template struct Fred { T data[sz]; };\n" - "Fred fred;"; + "Fred fred;\n"; const char expected[] = "struct Fred ; " "Fred fred ; " @@ -817,7 +837,7 @@ class TestSimplifyTemplate : public TestFixture { { const char code[] = "template struct Fred { Fred(); };\n" - "Fred fred;"; + "Fred fred;\n"; const char expected[] = "struct Fred ; " "Fred fred ; " @@ -829,7 +849,7 @@ class TestSimplifyTemplate : public TestFixture { { const char code[] = "template struct Fred { };\n" "Fred fred1;\n" - "Fred fred2;"; + "Fred fred2;\n"; const char expected[] = "struct Fred ; " "Fred fred1 ; " @@ -842,7 +862,7 @@ class TestSimplifyTemplate : public TestFixture { void template22() { const char code[] = "template struct Fred { T a; };\n" - "Fred fred;"; + "Fred fred;\n"; const char expected[] = "struct Fred ; " "Fred fred ; " @@ -855,7 +875,7 @@ class TestSimplifyTemplate : public TestFixture { const char code[] = "template void foo() { }\n" "void bar() {\n" " std::cout << (foo());\n" - "}"; + "}\n"; const char expected[] = "void foo ( ) ; " "void bar ( ) {" @@ -876,7 +896,7 @@ class TestSimplifyTemplate : public TestFixture { "template class bitset: B\n" "{};\n" "\n" - "bitset<1> z;"; + "bitset<1> z;\n"; const char expected[] = "struct B<4> ; " "class bitset<1> ; " "bitset<1> z ; " @@ -894,7 +914,7 @@ class TestSimplifyTemplate : public TestFixture { "template class bitset: B<((sizeof(int)) ? : 1)>\n" "{};\n" "\n" - "bitset<1> z;"; + "bitset<1> z;\n"; const char expected[] = "struct B<4> ; " "class bitset<1> ; " "bitset<1> z ; " @@ -917,7 +937,7 @@ class TestSimplifyTemplate : public TestFixture { void template27() { // #3350 - template inside macro call - const char code[] = "X(template class Fred);"; + const char code[] = "X(template class Fred);\n"; ASSERT_THROW_INTERNAL(tok(code), SYNTAX); } @@ -934,19 +954,19 @@ class TestSimplifyTemplate : public TestFixture { void template30() { // #3529 - template < template < .. - const char code[] = "template class A, class B> void f(){}"; + const char code[] = "template class A, class B> void f(){}\n"; ASSERT_EQUALS("template < template < class > class A , class B > void f ( ) { }", tok(code)); } void template31() { // #4010 - template reference type - const char code[] = "template struct A{}; A a;"; + const char code[] = "template struct A{}; A a;\n"; ASSERT_EQUALS("struct A ; " "A a ; " "struct A { } ;", tok(code)); // #7409 - rvalue - const char code2[] = "template struct A{}; A a;"; + const char code2[] = "template struct A{}; A a;\n"; ASSERT_EQUALS("struct A ; " "A a ; " "struct A { } ;", tok(code2)); @@ -976,7 +996,7 @@ class TestSimplifyTemplate : public TestFixture { const char code[] = "template struct A { };\n" "template struct B { };\n" "template struct C { A > > ab; };\n" - "C c;"; + "C c;\n"; ASSERT_EQUALS("struct A>> ; " "struct B> ; " "struct C ; " @@ -991,7 +1011,7 @@ class TestSimplifyTemplate : public TestFixture { const char code[] = "struct A { };\n" "template struct B { };\n" "template struct C { };\n" - "C< B > c;"; + "C< B > c;\n"; ASSERT_EQUALS("struct A { } ; " "template < class T > struct B { } ; " // <- redundant.. but nevermind "struct C> ; " @@ -1006,13 +1026,13 @@ class TestSimplifyTemplate : public TestFixture { const char code[] = "namespace abc {\n" "template struct X { void f(X &x) {} };\n" "}\n" - "template <> int X::Y(0);"; + "template <> int X::Y(0);\n"; (void)tok(code); } void template35() { // #4074 - "A<'x'> a;" is not recognized as template instantiation const char code[] = "template class A {};\n" - "A <'x'> a;"; + "A <'x'> a;\n"; ASSERT_EQUALS("class A<'x'> ; " "A<'x'> a ; " "class A<'x'> { } ;", tok(code)); @@ -1021,7 +1041,7 @@ class TestSimplifyTemplate : public TestFixture { void template36() { // #4310 - Passing unknown template instantiation as template argument const char code[] = "template struct X { T t; };\n" "template struct Y { Foo < X< Bar > > _foo; };\n" // <- Bar is unknown - "Y bar;"; + "Y bar;\n"; ASSERT_EQUALS("struct X> ; " "struct Y ; " "Y bar ; " @@ -1035,7 +1055,7 @@ class TestSimplifyTemplate : public TestFixture { const char code[] = "class A { };\n" "template class B {};\n" "B b1;\n" - "B b2;"; + "B b2;\n"; ASSERT_EQUALS("class A { } ; class B ; B b1 ; B b2 ; class B { } ;", tok(code)); } @@ -1043,7 +1063,7 @@ class TestSimplifyTemplate : public TestFixture { const char code[] = "struct A { };\n" "template class B {};\n" "B b1;\n" - "B b2;"; + "B b2;\n"; ASSERT_EQUALS("struct A { } ; class B ; B b1 ; B b2 ; class B { } ;", tok(code)); } @@ -1051,7 +1071,7 @@ class TestSimplifyTemplate : public TestFixture { const char code[] = "enum A { };\n" "template class B {};\n" "B b1;\n" - "B b2;"; + "B b2;\n"; ASSERT_EQUALS("enum A { } ; class B ; B b1 ; B b2 ; class B { } ;", tok(code)); } @@ -1059,7 +1079,7 @@ class TestSimplifyTemplate : public TestFixture { void template_unhandled() { // An unhandled template usage should not be simplified.. - ASSERT_EQUALS("x < int > ( ) ;", tok("x();")); + ASSERT_EQUALS("x < int > ( ) ;", tok("x();\n")); } void template38() { // #4832 - Crash on C++11 right angle brackets @@ -1093,21 +1113,21 @@ class TestSimplifyTemplate : public TestFixture { } void template39() { // #4742 - Used to freeze in 1.60 - const char code[] = "template struct vector {" - " operator T() const;" - "};" - "void f() {" - " vector> v;" - " const vector vi = static_cast>(v);" - "}"; + const char code[] = "template struct vector {\n" + " operator T() const;\n" + "};\n" + "void f() {\n" + " vector> v;\n" + " const vector vi = static_cast>(v);\n" + "}\n"; (void)tok(code); } void template40() { // #5055 - false negatives when there is template specialization outside struct - const char code[] = "struct A {" - " template struct X { T t; };" - "};" - "template<> struct A::X { int *t; };"; + const char code[] = "struct A {\n" + " template struct X { T t; };\n" + "};\n" + "template<> struct A::X { int *t; };\n"; const char expected[] = "struct A { " "struct X ; " "template < typename T > struct X { T t ; } ; " @@ -1118,13 +1138,13 @@ class TestSimplifyTemplate : public TestFixture { void template41() { // #4710 - const in template instantiation not handled perfectly const char code1[] = "template struct X { };\n" - "void f(const X x) { }"; + "void f(const X x) { }\n"; ASSERT_EQUALS("struct X ; " "void f ( const X x ) { } " "struct X { } ;", tok(code1)); const char code2[] = "template T f(T t) { return t; }\n" - "int x() { return f(123); }"; + "int x() { return f(123); }\n"; ASSERT_EQUALS("int f ( int t ) ; " "int x ( ) { return f ( 123 ) ; } " "int f ( int t ) { return t ; }", tok(code2)); @@ -1138,7 +1158,7 @@ class TestSimplifyTemplate : public TestFixture { " }() + ^ {\n" " return sizeof...(args);\n" " }();\n" - "}"; + "}\n"; ASSERT_THROW_INTERNAL(tok(code), SYNTAX); } @@ -1156,7 +1176,7 @@ class TestSimplifyTemplate : public TestFixture { "int main(void) {\n" " C ca;\n" " return 0;\n" - "}"; + "}\n"; const char expected[] = "struct E ; " "struct C> ; " "struct C ; " @@ -1195,14 +1215,14 @@ class TestSimplifyTemplate : public TestFixture { } void template44() { // #5297 - const char code[] = "template struct StackContainer {" - " void foo(int i) {" - " if (0 >= 1 && i<0) {}" - " }" - "};" - "template class ZContainer : public StackContainer {};" - "struct FGSTensor {};" - "class FoldedZContainer : public ZContainer {};"; + const char code[] = "template struct StackContainer {\n" + " void foo(int i) {\n" + " if (0 >= 1 && i<0) {}\n" + " }\n" + "};\n" + "template class ZContainer : public StackContainer {};\n" + "struct FGSTensor {};\n" + "class FoldedZContainer : public ZContainer {};\n"; const char expected[] = "struct StackContainer ; " "class ZContainer ; " "struct FGSTensor { } ; " @@ -1217,14 +1237,14 @@ class TestSimplifyTemplate : public TestFixture { } void template45() { // #5814 - const char code[] = "namespace Constants { const int fourtytwo = 42; } " - "template struct TypeMath { " - " static const int mult = sizeof(T) * U; " - "}; " - "template struct FOO { " - " enum { value = TypeMath::mult }; " - "}; " - "FOO foo;"; + const char code[] = "namespace Constants { const int fourtytwo = 42; }\n" + "template struct TypeMath {\n" + " static const int mult = sizeof(T) * U;\n" + "};\n" + "template struct FOO {\n" + " enum { value = TypeMath::mult };\n" + "};\n" + "FOO foo;\n"; const char expected[] = "namespace Constants { const int fourtytwo = 42 ; } " "struct TypeMath ; " "struct FOO ; " @@ -1240,32 +1260,32 @@ class TestSimplifyTemplate : public TestFixture { } void template46() { // #5816 - ASSERT_NO_THROW(tok("template struct A { static const int value = 0; }; " - "template struct B { " - " enum { value = A::value }; " - "};")); + ASSERT_NO_THROW(tok("template struct A { static const int value = 0; };\n" + "template struct B {\n" + " enum { value = A::value };\n" + "};\n")); ASSERT_EQUALS("", errout_str()); - ASSERT_NO_THROW(tok("template struct A {}; " - "enum { e = sizeof(A) }; " - "template struct B {};")); + ASSERT_NO_THROW(tok("template struct A {};\n" + "enum { e = sizeof(A) };\n" + "template struct B {};\n")); ASSERT_EQUALS("", errout_str()); - ASSERT_NO_THROW(tok("template struct A { static const int value = 0; }; " - "template struct B { typedef int type; }; " - "template struct C { " - " enum { value = A::type, int>::value }; " - "};")); + ASSERT_NO_THROW(tok("template struct A { static const int value = 0; };\n" + "template struct B { typedef int type; };\n" + "template struct C {\n" + " enum { value = A::type, int>::value };\n" + "};\n")); ASSERT_EQUALS("", errout_str()); } void template47() { // #6023 - ASSERT_NO_THROW(tok("template > class C1 {}; " - "class C2 : public C1 {};")); + ASSERT_NO_THROW(tok("template > class C1 {};\n" + "class C2 : public C1 {};\n")); ASSERT_EQUALS("", errout_str()); } void template48() { // #6134 (hang) - (void)tok("template int f( { } ); " - "int foo = f<1>(0);"); + (void)tok("template int f( { } );\n" + "int foo = f<1>(0);\n"); ASSERT_EQUALS("", errout_str()); } @@ -1307,17 +1327,17 @@ class TestSimplifyTemplate : public TestFixture { } void template52() { // #6437 - const char code[] = "template int sum() { " - " return value + sum(); " - "} " - "template int calculate_value() { " - " if (x != y) { " - " return sum(); " - " } else { " - " return 0; " - " } " - "} " - "int value = calculate_value<1,1>();"; + const char code[] = "template int sum() {\n" + " return value + sum();\n" + "}\n" + "template int calculate_value() {\n" + " if (x != y) {\n" + " return sum();\n" + " } else {\n" + " return 0;\n" + " }\n" + "}\n" + "int value = calculate_value<1,1>();\n"; const char expected[] = "int sum<0> ( ) ; " "int calculate_value<1,1> ( ) ; " "int value ; value = calculate_value<1,1> ( ) ; " @@ -1335,13 +1355,13 @@ class TestSimplifyTemplate : public TestFixture { } void template53() { // #4335 - const char code[] = "template struct Factorial { " - " enum { value = N * Factorial::value }; " - "};" - "template <> struct Factorial<0> { " - " enum { value = 1 }; " - "};" - "const int x = Factorial<4>::value;"; + const char code[] = "template struct Factorial {\n" + " enum { value = N * Factorial::value };\n" + "};\n" + "template <> struct Factorial<0> {\n" + " enum { value = 1 };\n" + "};\n" + "const int x = Factorial<4>::value;\n"; const char expected[] = "struct Factorial<0> ; " "struct Factorial<4> ; " "struct Factorial<3> ; " @@ -1368,12 +1388,12 @@ class TestSimplifyTemplate : public TestFixture { } void template54() { // #6587 (use-after-free) - (void)tok("template _Tp* fn(); " - "template struct A { " - " template ())> " - " struct B { }; " - "}; " - "A a;"); + (void)tok("template _Tp* fn();\n" + "template struct A {\n" + " template ())>\n" + " struct B { };\n" + "};\n" + "A a;\n"); } void template55() { // #6604 @@ -1387,7 +1407,7 @@ class TestSimplifyTemplate : public TestFixture { "{\n" " friend struct ConstCastHelper, T>;\n" " AtSmartPtr(const AtSmartPtr& r);\n" - "};")); + "};\n")); // Similar problem can also happen with ... ASSERT_EQUALS( @@ -1407,16 +1427,16 @@ class TestSimplifyTemplate : public TestFixture { " (A*)(p);\n" " }\n" "};\n" - "A a(0);")); + "A a(0);\n")); } void template56() { // #7117 - const char code[] = "template struct Foo { " - " std::array mfoo; " - "}; " - "void foo() { " - " Foo myFoo; " - "}"; + const char code[] = "template struct Foo {\n" + " std::array mfoo;\n" + "};\n" + "void foo() {\n" + " Foo myFoo;\n" + "}\n"; const char expected[] = "struct Foo ; " "void foo ( ) { " "Foo myFoo ; " @@ -1429,7 +1449,7 @@ class TestSimplifyTemplate : public TestFixture { void template57() { // #7891 const char code[] = "template struct Test { Test(T); };\n" - "Test test( 0 );"; + "Test test( 0 );\n"; const char exp[] = "struct Test ; " "Test test ( 0 ) ; " "struct Test { Test ( unsigned long ) ; } ;"; @@ -1443,7 +1463,7 @@ class TestSimplifyTemplate : public TestFixture { "}\n" "void foo() {\n" " TestArithmetic();\n" - "}"; + "}\n"; const char exp[] = "void TestArithmetic ( ) ; " "void foo ( ) {" " TestArithmetic ( ) ; " @@ -1469,7 +1489,7 @@ class TestSimplifyTemplate : public TestFixture { "}\n" "int main () {\n" " return diagonalGroupTest<4>();\n" - "}"; + "}\n"; const char exp[] = "struct Factorial<0> ; " "struct Factorial<4> ; " "struct Factorial<3> ; " @@ -1491,7 +1511,7 @@ class TestSimplifyTemplate : public TestFixture { "template void f() {}\n" "template void h() { f::type(0)>(); }\n" "\n" - "void j() { h(); }"; + "void j() { h(); }\n"; const char exp[] = "struct S ; " "void f::type(0)> ( ) ; " "void h ( ) ; " @@ -1514,7 +1534,7 @@ class TestSimplifyTemplate : public TestFixture { " void f1(Bar x) {}\n" " Foo> f2() { }\n" "};\n" - "Bar c;"; + "Bar c;\n"; const char exp[] = "struct Foo> ; " "struct Bar ; " "Bar c ; " @@ -1531,7 +1551,7 @@ class TestSimplifyTemplate : public TestFixture { "template void f() { x = y ? C1::allocate(1) : 0; }\n" "template class C3 {};\n" "template C3::C3(const C3 &v) { C1 c1; }\n" - "C3 c3;"; + "C3 c3;\n"; const char exp[] = "struct C1 ; " "template < class T > void f ( ) { x = y ? ( C1 < int > :: allocate ( 1 ) ) : 0 ; } " "class C3 ; " @@ -1543,8 +1563,8 @@ class TestSimplifyTemplate : public TestFixture { } void template63() { // #8576 - const char code[] = "template struct TestClass { T m_hi; };" - "TestClass> objTest3;"; + const char code[] = "template struct TestClass { T m_hi; };\n" + "TestClass> objTest3;\n"; const char exp[] = "struct TestClass> ; " "TestClass> objTest3 ; " "struct TestClass> { std :: auto_ptr < v > m_hi ; } ;"; @@ -1565,7 +1585,7 @@ class TestSimplifyTemplate : public TestFixture { " t_func<0>();\n" " t_func<1>();\n" "}\n" - "};"; + "};\n"; const char exp[] = "bool foo ( ) ; " "struct A { " "void t_func<0> ( ) ; " @@ -1603,7 +1623,7 @@ class TestSimplifyTemplate : public TestFixture { "int main() {\n" " AssociationDAGlobalGraphObserver grObs;\n" " return 1;\n" - "}"; + "}\n"; const char exp[] = "namespace bpp " "{ " "class AssociationDAGraphImplObserver ; " @@ -1623,7 +1643,7 @@ class TestSimplifyTemplate : public TestFixture { " const int ** foo();\n" "};\n" "template const int ** Fred::foo() { return nullptr; }\n" - "Fred fred;"; + "Fred fred;\n"; const char exp[] = "struct Fred ; " "Fred fred ; " "struct Fred { " @@ -1646,7 +1666,7 @@ class TestSimplifyTemplate : public TestFixture { "template Container::Container(const Container & x) { nElements = x.nElements; c = x.c; }\n" "template Container & Container::operator = (const Container & x) { mElements = x.mElements; c = x.c; return *this; }\n" "template Container::~Container() {}\n" - "Container intContainer;"; + "Container intContainer;\n"; const char expected[] = "struct Container ; " "Container intContainer ; " @@ -1671,7 +1691,7 @@ class TestSimplifyTemplate : public TestFixture { " char dummy[sizeof(T)];\n" " T value;\n" "};\n" - "Fred fred;"; + "Fred fred;\n"; const char exp[] = "union Fred ; " "Fred fred ; " "union Fred { " @@ -1686,7 +1706,7 @@ class TestSimplifyTemplate : public TestFixture { " int test;\n" " template T lookup() { return test; }\n" " int Fun() { return lookup(); }\n" - "};"; + "};\n"; const char exp[] = "class Test { " "int test ; " "int lookup ( ) ; " @@ -1704,7 +1724,7 @@ class TestSimplifyTemplate : public TestFixture { "template\n" "class Bar : private Bar {\n" " void foo() { }\n" - "};"; + "};\n"; const char exp[] = "template < typename T , typename V , int KeySize = 0 > class Bar ; " "class Bar ; " "class Bar { " @@ -1736,7 +1756,7 @@ class TestSimplifyTemplate : public TestFixture { " return f1(pInterface, interface_type::static_type());\n" "}\n" "\n" - "Reference< class XPropertyList > dostuff();"; + "Reference< class XPropertyList > dostuff();\n"; const char exp[] = "int f1 ( int * pInterface , int x ) { return 0 ; } " "class Reference ; " "Reference dostuff ( ) ; " @@ -1749,7 +1769,7 @@ class TestSimplifyTemplate : public TestFixture { const char code[] = "template class Tokenizer;\n" "const Tokenizer *tokenizer() const;\n" "template \n" - "Tokenizer::Tokenizer() { }"; + "Tokenizer::Tokenizer() { }\n"; const char exp[] = "template < typename N , typename P > class Tokenizer ; " "const Tokenizer < Node , Path > * tokenizer ( ) const ; " "template < typename N , typename P > " @@ -1761,7 +1781,7 @@ class TestSimplifyTemplate : public TestFixture { const char code[] = "template\n" "void keep_range(T& value, const T mini, const T maxi){}\n" "template void keep_range(float& v, const float l, const float u);\n" - "template void keep_range(int& v, const int l, const int u);"; + "template void keep_range(int& v, const int l, const int u);\n"; const char exp[] = "void keep_range ( float & value , const float mini , const float maxi ) ; " "void keep_range ( int & value , const int mini , const int maxi ) ; " "void keep_range ( float & value , const float mini , const float maxi ) { } " @@ -1774,7 +1794,7 @@ class TestSimplifyTemplate : public TestFixture { "class PushBackStreamBuf {\n" "public:\n" " void pushBack(const BTlist &vec);\n" - "};"; + "};\n"; const char exp[] = "class BTlist ; " "class PushBackStreamBuf { " "public: " @@ -1787,7 +1807,7 @@ class TestSimplifyTemplate : public TestFixture { void template75() { const char code[] = "template\n" "T foo(T& value){ return value; }\n" - "template std::vector> foo>>(std::vector>& v);"; + "template std::vector> foo>>(std::vector>& v);\n"; const char exp[] = "std :: vector < std :: vector < int > > foo>> ( std :: vector < std :: vector < int > > & value ) ; " "std :: vector < std :: vector < int > > foo>> ( std :: vector < std :: vector < int > > & value ) { return value ; }"; ASSERT_EQUALS(exp, tok(code)); @@ -1817,7 +1837,7 @@ class TestSimplifyTemplate : public TestFixture { "int main() {\n" " std::cout << is_void::value << std::endl;\n" " std::cout << is_void::value << std::endl;\n" - "}"; + "}\n"; const char exp[] = "struct is_void ; " "struct is_void ; " "struct is_void : std :: true_type { } ; " @@ -1832,7 +1852,7 @@ class TestSimplifyTemplate : public TestFixture { void template78() { const char code[] = "template \n" "struct Base { };\n" - "struct S : Base ::Type { };"; + "struct S : Base ::Type { };\n"; const char exp[] = "struct Base ; " "struct S : Base :: Type { } ; " "struct Base { } ;"; @@ -1850,7 +1870,7 @@ class TestSimplifyTemplate : public TestFixture { "void some_func() {\n" " Foo x;\n" " x.foo();\n" - "}"; + "}\n"; const char exp[] = "class Foo { " "public: " "void foo ( ) ; " @@ -1871,7 +1891,7 @@ class TestSimplifyTemplate : public TestFixture { const char code[] = "class Fred {\n" " template T foo(T t) const { return t; }\n" "};\n" - "const void * p = Fred::foo(nullptr);"; + "const void * p = Fred::foo(nullptr);\n"; const char exp[] = "class Fred { " "const void * foo ( const void * t ) const ; " "} ; " @@ -1889,7 +1909,7 @@ class TestSimplifyTemplate : public TestFixture { "SortWith::SortWith(Type) {}\n" "int main() {\n" " SortWith(0);\n" - "}"; + "}\n"; const char exp[] = "template < typename Type > " "struct SortWith { " "SortWith ( Type ) ; " @@ -1919,7 +1939,7 @@ class TestSimplifyTemplate : public TestFixture { " swizzle<1>(tt2);\n" " tvec3 tt3;\n" " swizzle<2,3>(tt3);\n" - "}"; + "}\n"; const char exp[] = "const int f16 = 16 ; " "class tvec2 ; " "class tvec3 ; " @@ -1950,7 +1970,7 @@ class TestSimplifyTemplate : public TestFixture { "MultiConsumer::MultiConsumer() : sizeBuffer(0) {}\n" "MultiReads::MultiReads() {\n" " mc = new MultiConsumer();\n" - "}"; + "}\n"; const char exp[] = "template < typename Task > " // TODO: this should be expanded "class MultiConsumer { " "MultiConsumer ( ) ; " @@ -1968,7 +1988,7 @@ class TestSimplifyTemplate : public TestFixture { const char code[] = "template \n" "auto d() -> typename a::e {\n" " d();\n" - "}"; + "}\n"; const char exp[] = "template < class b , int c , class > " "auto d ( ) . a < decltype ( b { } ) > :: e { " "d < int , c , int > ( ) ; " @@ -1979,8 +1999,8 @@ class TestSimplifyTemplate : public TestFixture { const char code[] = "template \n" "auto d() -> typename a::e {\n" " d();\n" - "}" - "void foo() { d(); }"; + "}\n" + "void foo() { d(); }\n"; const char exp[] = "auto d ( ) . a < char > :: e ; " "auto d ( ) . a < int > :: e ; " "void foo ( ) { d ( ) ; } " @@ -2004,7 +2024,7 @@ class TestSimplifyTemplate : public TestFixture { "extern template void C::foo();\n" "template\n" "template::value)>::type>\n" - "void C::foo() {}"; + "void C::foo() {}\n"; // @todo the output is very wrong but we are only worried about the crash for now (void)tok(code); } @@ -2020,7 +2040,7 @@ class TestSimplifyTemplate : public TestFixture { "template \n" "S U::u;\n" "template S U::u;\n" - "S &i = U::u;"; + "S &i = U::u;\n"; (void)tok(code); } @@ -2028,7 +2048,7 @@ class TestSimplifyTemplate : public TestFixture { const char code[] = "template\n" "T f1(T t) { return t; }\n" "template const char * f1(const char *);\n" - "template const char & f1(const char &);"; + "template const char & f1(const char &);\n"; const char exp[] = "const char * f1 ( const char * t ) ; " "const char & f1 ( const char & t ) ; " "const char * f1 ( const char * t ) { return t ; } " @@ -2055,7 +2075,7 @@ class TestSimplifyTemplate : public TestFixture { "int main() {\n" " CTest::Greeting(true);\n" " return 0;\n" - "}"; + "}\n"; const char exp[] = "class CTest { " "public: " "static void Greeting ( bool ) ; " @@ -2085,7 +2105,7 @@ class TestSimplifyTemplate : public TestFixture { "template void Fred::foo();\n" "template void Fred::foo();\n" "template <> void Fred::foo() { }\n" - "template <> void Fred::foo() { }"; + "template <> void Fred::foo() { }\n"; const char exp[] = "struct Fred { " "static void foo ( ) ; " "static void foo ( ) ; " @@ -2103,7 +2123,7 @@ class TestSimplifyTemplate : public TestFixture { const char code[] = "template struct S1 {};\n" "void f(S1) {}\n" "template \n" - "decltype(S1().~S1()) fun1() {};"; + "decltype(S1().~S1()) fun1() {};\n"; const char exp[] = "struct S1 ; " "void f ( S1 ) { } " "template < typename T > " @@ -2118,7 +2138,7 @@ class TestSimplifyTemplate : public TestFixture { "template<> char foo(char a) { return a; }\n" "template<> int foo(int a) { return a; }\n" "template float foo(float);\n" - "template double foo(double);"; + "template double foo(double);\n"; const char exp[] = "int foo ( int a ) ; " "char foo ( char a ) ; " "float foo ( float t ) ; " @@ -2136,7 +2156,7 @@ class TestSimplifyTemplate : public TestFixture { " template<> int foo(int a) { return a; }\n" "};\n" "template float Fred::foo(float);\n" - "template double Fred::foo(double);"; + "template double Fred::foo(double);\n"; const char exp[] = "struct Fred { " "int foo ( int a ) ; " "char foo ( char a ) ; " @@ -2161,7 +2181,7 @@ class TestSimplifyTemplate : public TestFixture { " template float NS2::foo(float);\n" " template bool NS1::NS2::foo(bool);\n" "}\n" - "template double NS1::NS2::foo(double);"; + "template double NS1::NS2::foo(double);\n"; const char exp[] = "namespace NS1 { " "namespace NS2 { " "int foo ( int a ) ; " @@ -2194,7 +2214,7 @@ class TestSimplifyTemplate : public TestFixture { " template float NS::foo(float);\n" " template bool NS1::NS::foo(bool);\n" "}\n" - "template double NS1::NS::foo(double);"; + "template double NS1::NS::foo(double);\n"; const char exp[] = "namespace NS1 { " "namespace NS { " "int foo ( int a ) ; " @@ -2225,7 +2245,7 @@ class TestSimplifyTemplate : public TestFixture { " foo(2);\n" " foo(3.14);\n" " foo(3.14f);\n" - "}"; + "}\n"; const char exp[] = "void foo ( const double & d ) ; " "void foo ( const float & t ) ; " "void foo ( const int & t ) ; " @@ -2254,7 +2274,7 @@ class TestSimplifyTemplate : public TestFixture { "void Vector2::process() {\n" " ForEach();\n" "}\n" - "Vector2 c;"; + "Vector2 c;\n"; const char exp[] = "void ForEach ( ) ; " "class Vector2 ; " "Vector2 c ; " @@ -2284,7 +2304,7 @@ class TestSimplifyTemplate : public TestFixture { "Array matmul() {\n" " return foo( );\n" "}\n" - "template Array> matmul>();"; + "template Array> matmul>();\n"; const char exp[] = "class Array ; " "class Array> ; " "class Array ; " @@ -2312,7 +2332,7 @@ class TestSimplifyTemplate : public TestFixture { "template<>\n" "int Value = 456;\n" "float f = Value;\n" - "int i = Value;"; + "int i = Value;\n"; const char exp[] = "float Value ; Value = 123 ; " "int Value ; Value = 456 ; " "float f ; f = Value ; " @@ -2331,7 +2351,7 @@ class TestSimplifyTemplate : public TestFixture { "long f0 = fib<0>;\n" "long f1 = fib<1>;\n" "long f2 = fib<2>;\n" - "long f3 = fib<3>;"; + "long f3 = fib<3>;\n"; const char exp[] = "constexpr long fib<2> = fib<1> + fib<0> ; " "constexpr long fib<3> = fib<2> + fib<1> ; " "constexpr long fib<0> = 0 ; " @@ -2391,7 +2411,7 @@ class TestSimplifyTemplate : public TestFixture { "}\n" "using namespace NS1::NS2::NS3::NS4;\n" "Fred fred_bool1;\n" - "NS1::NS2::NS3::NS4::Fred fred_int1;"; + "NS1::NS2::NS3::NS4::Fred fred_int1;\n"; const char exp[] = "namespace NS1 { " "namespace NS2 { " "namespace NS3 { " @@ -2469,7 +2489,7 @@ class TestSimplifyTemplate : public TestFixture { " unique_ptr_with_deleter tmp(new A(), [](A* a) {\n" " delete a;\n" " });\n" - "}"; + "}\n"; const char exp[] = "class A { } ; " "static void func ( ) { " "std :: unique_ptr < A , std :: function < void ( A * ) > > tmp ( new A ( ) , [ ] ( A * a ) { " @@ -2517,7 +2537,7 @@ class TestSimplifyTemplate : public TestFixture { " using ArrayType = std::vector;\n" " void func(typename ArrayType::size_type i) {\n" " }\n" - "};"; + "};\n"; const char exp[] = "class A { " "public: " @@ -2538,7 +2558,7 @@ class TestSimplifyTemplate : public TestFixture { "}\n" "void f() {\n" " if(std::is_floating_point::value) {}\n" - "}"; + "}\n"; const char exp[] = "namespace ns { " "template < class T > " "struct is_floating_point " @@ -2563,7 +2583,7 @@ class TestSimplifyTemplate : public TestFixture { " return t;\n" " }\n" "}\n" - "sample::Sample s1;"; + "sample::Sample s1;\n"; const char exp[] = "namespace sample { " "class Sample ; " "} " @@ -2589,7 +2609,7 @@ class TestSimplifyTemplate : public TestFixture { " BOOST_HANA_CONSTANT_CHECK ( hana :: equal (\n" " hana :: at_key ( hana :: make_map ( p < 0 , 0 > ( ) ) , key < 0 > ( ) ) ,\n" " val < 0 > ( ) ) ) ;\n" - "}"; + "}\n"; const char exp[] = "auto key<0> ( ) ; " "auto val<0> ( ) ; " "auto p<0,0> ( ) ; " @@ -2609,7 +2629,7 @@ class TestSimplifyTemplate : public TestFixture { "template