diff --git a/.github/workflows/CI-unixish.yml b/.github/workflows/CI-unixish.yml index cd7779ec937..898781f2537 100644 --- a/.github/workflows/CI-unixish.yml +++ b/.github/workflows/CI-unixish.yml @@ -309,30 +309,37 @@ jobs: run: | tools/generate_and_run_more_tests.sh - # do not use pushd in this step since we go below the working directory - name: Run test/cli run: | - cd test/cli - python3 -m pytest -Werror --strict-markers -vv - cd ../../.. + python3 -m pytest -Werror --strict-markers -vv test/cli + + # TODO: use the step below instead + # do not use pushd in this step since we go below the working directory + - name: Run test/cli (symlink) + run: | + cd .. ln -s cppcheck 'cpp check' cd 'cpp check/test/cli' python3 -m pytest -Werror --strict-markers -vv - # do not use pushd in this step since we go below the working directory + # FIXME: proj2_test.py fails because of the relative path cleanups in ImportProject::setRelativePaths() + # It fails because the application path used as base path has its symlink resolved by getcwd(). + - name: Run test/cli (symlink) + if: false + run: | + ln -s . 'cpp check' + python3 -m pytest -Werror --strict-markers -vv 'cpp check/test/cli' + - name: Run test/cli (-j2) run: | - cd test/cli - python3 -m pytest -Werror --strict-markers -vv + python3 -m pytest -Werror --strict-markers -vv test/cli env: TEST_CPPCHECK_INJECT_J: 2 - # do not use pushd in this step since we go below the working directory - name: Run test/cli (--clang) if: false run: | - cd test/cli - python3 -m pytest -Werror --strict-markers -vv + python3 -m pytest -Werror --strict-markers -vv test/cli env: TEST_CPPCHECK_INJECT_CLANG: clang diff --git a/.github/workflows/CI-windows.yml b/.github/workflows/CI-windows.yml index de3a56b2f5e..731c639f6b1 100644 --- a/.github/workflows/CI-windows.yml +++ b/.github/workflows/CI-windows.yml @@ -27,7 +27,7 @@ jobs: strategy: matrix: os: [windows-2019, windows-2022] - qt_ver: [5.15.2, 6.7.3] + qt_ver: [5.15.2, 6.8.0] fail-fast: false runs-on: ${{ matrix.os }} @@ -172,14 +172,12 @@ jobs: - name: Run test/cli if: matrix.config == 'release' run: | - cd test/cli || exit /b !errorlevel! - python -m pytest -Werror --strict-markers -vv || exit /b !errorlevel! + python -m pytest -Werror --strict-markers -vv test/cli || exit /b !errorlevel! - name: Run test/cli (-j2) if: matrix.config == 'release' run: | - cd test/cli || exit /b !errorlevel! - python -m pytest -Werror --strict-markers -vv || exit /b !errorlevel! + python -m pytest -Werror --strict-markers -vv test/cli || exit /b !errorlevel! env: TEST_CPPCHECK_INJECT_J: 2 @@ -187,8 +185,7 @@ jobs: - name: Run test/cli (--clang) if: false # matrix.config == 'release' run: | - cd test/cli || exit /b !errorlevel! - python -m pytest -Werror --strict-markers -vv || exit /b !errorlevel! + python -m pytest -Werror --strict-markers -vv test/cli || exit /b !errorlevel! env: TEST_CPPCHECK_INJECT_CLANG: clang diff --git a/.github/workflows/asan.yml b/.github/workflows/asan.yml index 01bb06199d9..ecbce274e9a 100644 --- a/.github/workflows/asan.yml +++ b/.github/workflows/asan.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-22.04 env: - QT_VERSION: 6.7.3 + QT_VERSION: 6.8.0 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 @@ -100,14 +100,12 @@ jobs: - name: Run test/cli run: | pwd=$(pwd) - cd test/cli - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv + TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv test/cli - name: Run test/cli (-j2) run: | pwd=$(pwd) - cd test/cli - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv + TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv test/cli env: TEST_CPPCHECK_INJECT_J: 2 @@ -115,8 +113,7 @@ jobs: if: false run: | pwd=$(pwd) - cd test/cli - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv + TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv test/cli env: TEST_CPPCHECK_INJECT_CLANG: clang diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index a6bc25e97ee..b67268d6f3d 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-22.04 env: - QT_VERSION: 6.7.3 + QT_VERSION: 6.8.0 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/iwyu.yml b/.github/workflows/iwyu.yml index 71d83a24ef0..d01a7000e03 100644 --- a/.github/workflows/iwyu.yml +++ b/.github/workflows/iwyu.yml @@ -16,6 +16,13 @@ jobs: strategy: matrix: image: ["fedora:latest"] # "opensuse/tumbleweed:latest" / "fedora:latest" / "debian:unstable" / "archlinux:latest" + stdlib: [libstdc++, libc++] + include: + - stdlib: libstdc++ + use_libcxx: Off + - stdlib: libc++ + use_libcxx: On + fail-fast: false runs-on: ubuntu-22.04 if: ${{ github.repository_owner == 'danmar' }} @@ -24,7 +31,7 @@ jobs: image: ${{ matrix.image }} env: - QT_VERSION: 6.7.3 + QT_VERSION: 6.8.0 steps: - uses: actions/checkout@v4 @@ -65,6 +72,11 @@ jobs: dnf install -y iwyu ln -s iwyu_tool.py /usr/bin/iwyu_tool + - name: Install missing software on Fedora (libc++) + if: contains(matrix.image, 'fedora') && matrix.stdlib == 'libc++' + run: | + dnf install -y libcxx-devel + - name: Install missing software on OpenSUSE if: contains(matrix.image, 'opensuse') run: | @@ -86,7 +98,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 -DUSE_QT6=On -DWITH_QCHART=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off -DEXTERNALS_AS_SYSTEM=On + # TODO: why does it build dmake in the next step? + cmake -S . -B cmake.output -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DUSE_QT6=On -DWITH_QCHART=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=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 CXX: clang++ @@ -110,27 +123,38 @@ jobs: run: | PWD=$(pwd) # -isystem/usr/lib/clang/17/include - iwyu_tool -p cmake.output -j $(nproc) -- -w -Xiwyu --max_line_length=1024 -Xiwyu --comment_style=long -Xiwyu --quoted_includes_first -Xiwyu --update_comments > iwyu.log + # 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 }} > iwyu.log - uses: actions/upload-artifact@v4 if: success() || failure() with: - name: Compilation Database + name: Compilation Database (include-what-you-use - ${{ matrix.stdlib }}) path: ./cmake.output/compile_commands.json - uses: actions/upload-artifact@v4 if: success() || failure() with: - name: Logs (include-what-you-use) + name: Logs (include-what-you-use - ${{ matrix.stdlib }}) path: ./*.log clang-include-cleaner: + strategy: + matrix: + stdlib: [libstdc++, libc++] + include: + - stdlib: libstdc++ + use_libcxx: Off + - stdlib: libc++ + use_libcxx: On + fail-fast: false + runs-on: ubuntu-22.04 if: ${{ github.repository_owner == 'danmar' }} env: - QT_VERSION: 6.7.3 + QT_VERSION: 6.8.0 steps: - uses: actions/checkout@v4 @@ -150,6 +174,11 @@ jobs: sudo ./llvm.sh 19 sudo apt-get install -y clang-tools-19 + - name: Install libc++ + if: matrix.stdlib == 'libc++' + run: | + sudo apt-get install -y libc++-19-dev + - name: Install Qt ${{ env.QT_VERSION }} uses: jurplel/install-qt-action@v4 with: @@ -160,7 +189,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 -DUSE_QT6=On -DWITH_QCHART=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off -DEXTERNALS_AS_SYSTEM=On + # TODO: why does it build dmake in the next step? + cmake -S . -B cmake.output -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DUSE_QT6=On -DWITH_QCHART=On -DENABLE_CHECK_INTERNAL=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=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-19 CXX: clang++-19 @@ -180,9 +210,16 @@ 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-19 --print=changes --extra-arg=-w -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-19 --print=changes --extra-arg=-w --extra-arg=-stdlib=${{ matrix.stdlib }} -p cmake.output > clang-include-cleaner.log 2>&1 - uses: actions/upload-artifact@v4 + if: success() || failure() + with: + name: Compilation Database (clang-include-cleaner - ${{ matrix.stdlib }}) + path: ./cmake.output/compile_commands.json + + - uses: actions/upload-artifact@v4 + if: success() || failure() with: - name: Logs (clang-include-cleaner) + name: Logs (clang-include-cleaner - ${{ matrix.stdlib }}) path: ./*.log diff --git a/.github/workflows/scriptcheck.yml b/.github/workflows/scriptcheck.yml index e3ef5f234ba..ff37edc5c08 100644 --- a/.github/workflows/scriptcheck.yml +++ b/.github/workflows/scriptcheck.yml @@ -18,7 +18,7 @@ permissions: jobs: build: - # 'ubuntu-22.04' removes Python 3.5 and 3.6 so keep the previous LTS version + # 'ubuntu-22.04' removes Python 3.6 so keep the previous LTS version runs-on: ubuntu-20.04 steps: @@ -44,7 +44,7 @@ jobs: scriptcheck: needs: build - # 'ubuntu-22.04' removes Python 3.5 and 3.6 so keep the previous LTS version + # 'ubuntu-22.04' removes Python 3.6 so keep the previous LTS version runs-on: ubuntu-20.04 strategy: matrix: @@ -58,6 +58,7 @@ jobs: steps: - uses: actions/checkout@v4 + # TODO: bailout on error - name: Restore Cppcheck uses: actions/cache@v4 with: @@ -101,7 +102,7 @@ jobs: if: matrix.python-latest run: | shopt -s globstar - pylint --jobs $(nproc) addons/**/*.py htmlreport/cppcheck-htmlreport htmlreport/**/*.py test/**/*.py tools/**/*.py + pylint --jobs $(nproc) --py-version 3.6 addons/**/*.py htmlreport/cppcheck-htmlreport htmlreport/**/*.py test/**/*.py tools/**/*.py - name: check .json files if: matrix.python-latest diff --git a/.github/workflows/selfcheck.yml b/.github/workflows/selfcheck.yml index 1d2702bc6da..df84c7719a3 100644 --- a/.github/workflows/selfcheck.yml +++ b/.github/workflows/selfcheck.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-22.04 env: - QT_VERSION: 6.7.3 + QT_VERSION: 6.8.0 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/tsan.yml b/.github/workflows/tsan.yml index 6284de0743b..13cc99566a2 100644 --- a/.github/workflows/tsan.yml +++ b/.github/workflows/tsan.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-22.04 env: - QT_VERSION: 6.7.3 + QT_VERSION: 6.8.0 TSAN_OPTIONS: halt_on_error=1 # TODO: figure out why there are cache misses with PCH enabled CCACHE_SLOPPINESS: pch_defines,time_macros @@ -99,16 +99,14 @@ jobs: - name: Run test/cli run: | pwd=$(pwd) - cd test/cli - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv + TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv test/cli env: TEST_CPPCHECK_INJECT_EXECUTOR: thread - name: Run test/cli (-j2) run: | pwd=$(pwd) - cd test/cli - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv + TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv test/cli env: TEST_CPPCHECK_INJECT_J: 2 @@ -116,8 +114,7 @@ jobs: if: false run: | pwd=$(pwd) - cd test/cli - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv + TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv test/cli env: TEST_CPPCHECK_INJECT_CLANG: clang diff --git a/.github/workflows/ubsan.yml b/.github/workflows/ubsan.yml index 4df9378cf15..21e90751000 100644 --- a/.github/workflows/ubsan.yml +++ b/.github/workflows/ubsan.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-22.04 env: - QT_VERSION: 6.7.3 + QT_VERSION: 6.8.0 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 @@ -99,14 +99,12 @@ jobs: - name: Run test/cli run: | pwd=$(pwd) - cd test/cli - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv + TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv test/cli - name: Run test/cli (-j2) run: | pwd=$(pwd) - cd test/cli - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv + TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv test/cli env: TEST_CPPCHECK_INJECT_J: 2 @@ -114,8 +112,7 @@ jobs: if: false run: | pwd=$(pwd) - cd test/cli - TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv + TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv test/cli env: TEST_CPPCHECK_INJECT_CLANG: clang diff --git a/CMakeLists.txt b/CMakeLists.txt index aeaff548fc9..94c7cc40318 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,6 +69,12 @@ if(LIBXML2_XMLLINT_EXECUTABLE) add_custom_target(validateRules ${LIBXML2_XMLLINT_EXECUTABLE} --noout ${CMAKE_SOURCE_DIR}/rules/*.xml) endif() +# TODO: add the following Makefile features: +# - "man/cppcheck.1" target +# - "tags" target +# - Cygwin handling +# - MinGW handling + if(BUILD_TESTS) enable_testing() endif() diff --git a/addons/naming.py b/addons/naming.py index 42a4237489e..2893779f2e0 100755 --- a/addons/naming.py +++ b/addons/naming.py @@ -37,6 +37,7 @@ def validate_regex(expr): elif arg[:11] == '--function=': RE_FUNCTIONNAME = arg[11:] validate_regex(RE_FUNCTIONNAME) + # TODO: bail out on unknown parameter def reportError(token, severity, msg, errorId): diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index f2baaf39713..af9925b5e41 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -1094,6 +1094,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a // --project-configuration else if (std::strncmp(argv[i], "--project-configuration=", 24) == 0) { mVSConfig = argv[i] + 24; + // TODO: provide error when this does nothing if (!mVSConfig.empty() && (project.projectType == ImportProject::Type::VS_SLN || project.projectType == ImportProject::Type::VS_VCXPROJ)) project.ignoreOtherConfigs(mVSConfig); } diff --git a/cmake/findDependencies.cmake b/cmake/findDependencies.cmake index 98421a02ee4..20441101111 100644 --- a/cmake/findDependencies.cmake +++ b/cmake/findDependencies.cmake @@ -64,9 +64,15 @@ else() endif() endif() -if(NOT Python_Interpreter_FOUND AND NOT USE_MATCHCOMPILER_OPT STREQUAL "Off") - message(WARNING "No python interpreter found - disabling matchcompiler.") - set(USE_MATCHCOMPILER_OPT "Off") +if(NOT Python_Interpreter_FOUND) + if(NOT USE_MATCHCOMPILER_OPT STREQUAL "Off") + message(WARNING "No python interpreter found - disabling matchcompiler.") + set(USE_MATCHCOMPILER_OPT "Off") + endif() +else() + if(${Python_VERSION} VERSION_LESS 3.6) + message(FATAL_ERROR "The minimum supported Python version is 3.6 - found ${Python_VERSION}") + endif() endif() if(NOT USE_BUNDLED_TINYXML2) diff --git a/cppcheck.sln b/cppcheck.sln index 8ea1af26aa8..ca26e06f2bd 100644 --- a/cppcheck.sln +++ b/cppcheck.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29020.237 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35506.116 d17.12 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cli", "cli\cli.vcxproj", "{35CBDF51-2456-3EC3-99ED-113C30858883}" ProjectSection(ProjectDependencies) = postProject @@ -15,8 +15,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testrunner", "test\testrunn EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cppcheck", "lib\cppcheck.vcxproj", "{C183DB5B-AD6C-423D-80CA-1F9549555A1A}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dmake", "tools\dmake\dmake.vcxproj", "{19EC86CD-0004-4917-B852-E6BD110B6E6F}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -49,10 +47,6 @@ Global {C183DB5B-AD6C-423D-80CA-1F9549555A1A}.Release|x64.Build.0 = Release|x64 {C183DB5B-AD6C-423D-80CA-1F9549555A1A}.Release-PCRE|x64.ActiveCfg = Release-PCRE|x64 {C183DB5B-AD6C-423D-80CA-1F9549555A1A}.Release-PCRE|x64.Build.0 = Release-PCRE|x64 - {19EC86CD-0004-4917-B852-E6BD110B6E6F}.Debug|x64.ActiveCfg = Debug|x64 - {19EC86CD-0004-4917-B852-E6BD110B6E6F}.Debug-PCRE|x64.ActiveCfg = Debug|x64 - {19EC86CD-0004-4917-B852-E6BD110B6E6F}.Release|x64.ActiveCfg = Release|x64 - {19EC86CD-0004-4917-B852-E6BD110B6E6F}.Release-PCRE|x64.ActiveCfg = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/gui/projectfile.h b/gui/projectfile.h index 9647256195a..8b10220931d 100644 --- a/gui/projectfile.h +++ b/gui/projectfile.h @@ -224,6 +224,7 @@ class ProjectFile : public QObject { QStringList getAddonsAndTools() const; bool getClangAnalyzer() const { + // TODO return false; //mClangAnalyzer; } diff --git a/lib/check.cpp b/lib/check.cpp index c5e6368f1fc..12b42a82cab 100644 --- a/lib/check.cpp +++ b/lib/check.cpp @@ -63,6 +63,7 @@ void Check::writeToErrorList(const ErrorMessage &errmsg) void Check::reportError(const std::list &callstack, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe, Certainty certainty) { + // TODO: report debug warning when error is for a disabled severity const ErrorMessage errmsg(callstack, mTokenizer ? &mTokenizer->list : nullptr, severity, id, msg, cwe, certainty); if (mErrorLogger) mErrorLogger->reportErr(errmsg); @@ -72,6 +73,7 @@ void Check::reportError(const std::list &callstack, Severity seve void Check::reportError(const ErrorPath &errorPath, Severity severity, const char id[], const std::string &msg, const CWE &cwe, Certainty certainty) { + // TODO: report debug warning when error is for a disabled severity const ErrorMessage errmsg(errorPath, mTokenizer ? &mTokenizer->list : nullptr, severity, id, msg, cwe, certainty); if (mErrorLogger) mErrorLogger->reportErr(errmsg); diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 39562d9e847..4b308a5fe64 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -2119,6 +2119,8 @@ void CheckClass::checkConst() continue; if (func.functionPointerUsage) continue; + if (func.hasRvalRefQualifier()) + continue; // don't suggest const when returning non-const pointer/reference, but still suggest static auto isPointerOrReference = [this](const Token* start, const Token* end) -> bool { diff --git a/lib/checktype.cpp b/lib/checktype.cpp index 5fc65b9a7c8..f80eea9ec1a 100644 --- a/lib/checktype.cpp +++ b/lib/checktype.cpp @@ -199,9 +199,12 @@ void CheckType::checkIntegerOverflow() const MathLib::bigint maxvalue = (((MathLib::biguint)1) << (bits - 1)) - 1; // is there a overflow result value + bool isOverflow = true; const ValueFlow::Value *value = tok->getValueGE(maxvalue + 1, *mSettings); - if (!value) + if (!value) { value = tok->getValueLE(-maxvalue - 2, *mSettings); + isOverflow = false; + } if (!value || !mSettings->isEnabled(value,false)) continue; @@ -209,25 +212,26 @@ void CheckType::checkIntegerOverflow() if (tok->str() == "<<" && value->intvalue > 0 && value->intvalue < (((MathLib::bigint)1) << bits)) continue; - integerOverflowError(tok, *value); + integerOverflowError(tok, *value, isOverflow); } } -void CheckType::integerOverflowError(const Token *tok, const ValueFlow::Value &value) +void CheckType::integerOverflowError(const Token *tok, const ValueFlow::Value &value, bool isOverflow) { const std::string expr(tok ? tok->expressionString() : ""); + const std::string type = isOverflow ? "overflow" : "underflow"; std::string msg; if (value.condition) msg = ValueFlow::eitherTheConditionIsRedundant(value.condition) + - " or there is signed integer overflow for expression '" + expr + "'."; + " or there is signed integer " + type + " for expression '" + expr + "'."; else - msg = "Signed integer overflow for expression '" + expr + "'."; + msg = "Signed integer " + type + " for expression '" + expr + "'."; if (value.safe) msg = "Safe checks: " + msg; - reportError(getErrorPath(tok, &value, "Integer overflow"), + reportError(getErrorPath(tok, &value, "Integer " + type), value.errorSeverity() ? Severity::error : Severity::warning, getMessageId(value, "integerOverflow").c_str(), msg, diff --git a/lib/checktype.h b/lib/checktype.h index 57c0dedbfbf..e76276c4ccf 100644 --- a/lib/checktype.h +++ b/lib/checktype.h @@ -81,7 +81,7 @@ class CPPCHECKLIB CheckType : public Check { // Error messages.. void tooBigBitwiseShiftError(const Token *tok, int lhsbits, const ValueFlow::Value &rhsbits); void tooBigSignedBitwiseShiftError(const Token *tok, int lhsbits, const ValueFlow::Value &rhsbits); - void integerOverflowError(const Token *tok, const ValueFlow::Value &value); + void integerOverflowError(const Token *tok, const ValueFlow::Value &value, bool isOverflow = true); void signConversionError(const Token *tok, const ValueFlow::Value *negativeValue, bool constvalue); void longCastAssignError(const Token *tok, const ValueType* src = nullptr, const ValueType* tgt = nullptr); void longCastReturnError(const Token *tok, const ValueType* src = nullptr, const ValueType* tgt = nullptr); diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index dce67605121..8668db48a3f 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -493,14 +493,14 @@ unsigned int CppCheck::checkClang(const FileWithDetails &file) reportErr(errorMessage); }; if (reportClangErrors(fin, reportError, compilerWarnings)) - return 0; + return 0; // TODO: report as failure? } else { std::istringstream istr(output2); auto reportError = [this](const ErrorMessage& errorMessage) { reportErr(errorMessage); }; if (reportClangErrors(istr, reportError, compilerWarnings)) - return 0; + return 0; // TODO: report as failure? } if (!mSettings.buildDir.empty()) { @@ -1056,6 +1056,7 @@ void CppCheck::checkNormalTokens(const Tokenizer &tokenizer) CheckUnusedFunctions unusedFunctionsChecker; // TODO: this should actually be the behavior if only "--enable=unusedFunction" is specified - see #10648 + // TODO: log message when this is active? const char* unusedFunctionOnly = std::getenv("UNUSEDFUNCTION_ONLY"); const bool doUnusedFunctionOnly = unusedFunctionOnly && (std::strcmp(unusedFunctionOnly, "1") == 0); diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index ffd1c656666..23c758f3997 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -47,7 +47,6 @@ namespace { struct ForwardTraversal { enum class Progress : std::uint8_t { Continue, Break, Skip }; - enum class Terminate : std::uint8_t { None, Bail, Inconclusive }; ForwardTraversal(const ValuePtr& analyzer, const TokenList& tokenList, ErrorLogger& errorLogger, const Settings& settings) : analyzer(analyzer), tokenList(tokenList), errorLogger(errorLogger), settings(settings) {} @@ -337,11 +336,6 @@ namespace { return r; } - enum class Status : std::uint8_t { - None, - Inconclusive, - }; - Analyzer::Action analyzeScope(const Token* endBlock) const { return analyzeRange(endBlock->link(), endBlock); } diff --git a/lib/library.cpp b/lib/library.cpp index fb02787662e..dae95a93b89 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -347,10 +347,12 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc) } } if (allocationId == 0) { - if (nodename == "memory") - while (!ismemory(++mData->mAllocId)); - else - while (!isresource(++mData->mAllocId)); + if (nodename == "memory") { + while (!ismemory(++mData->mAllocId)) {} + } + else { + while (!isresource(++mData->mAllocId)) {} + } allocationId = mData->mAllocId; } diff --git a/lib/path.cpp b/lib/path.cpp index 8b0b75c8ca0..ebe15e45649 100644 --- a/lib/path.cpp +++ b/lib/path.cpp @@ -61,6 +61,7 @@ static constexpr bool caseInsensitiveFilesystem() return true; #else // TODO: Non-windows filesystems might be case insensitive + // needs to be determined per filesystem and location - e.g. /sys/fs/ext4/features/casefold return false; #endif } diff --git a/lib/platform.cpp b/lib/platform.cpp index 06e2fd49ba7..d0eb992b0a0 100644 --- a/lib/platform.cpp +++ b/lib/platform.cpp @@ -329,24 +329,24 @@ std::string Platform::getLimitsDefines(bool c99) const s += ";USHRT_MAX="; s += std::to_string(max_value(short_bit+1)); s += ";INT_MIN="; - s += std::to_string(min_value(int_bit)); + s += "(-" + std::to_string(max_value(int_bit)) + " - 1)"; s += ";INT_MAX="; s += std::to_string(max_value(int_bit)); s += ";UINT_MAX="; s += std::to_string(max_value(int_bit+1)); s += ";LONG_MIN="; - s += std::to_string(min_value(long_bit)); + s += "(-" + std::to_string(max_value(long_bit)) + "L - 1L)"; s += ";LONG_MAX="; - s += std::to_string(max_value(long_bit)); + s += std::to_string(max_value(long_bit)) + "L"; s += ";ULONG_MAX="; - s += std::to_string(max_value(long_bit+1)); + s += std::to_string(max_value_unsigned(long_bit)) + "UL"; if (c99) { s += ";LLONG_MIN="; - s += std::to_string(min_value(long_long_bit)); + s += "(-" + std::to_string(max_value(long_long_bit)) + "LL - 1LL)"; s += ";LLONG_MAX="; - s += std::to_string(max_value(long_long_bit)); + s += std::to_string(max_value(long_long_bit)) + "LL"; s += ";ULLONG_MAX="; - s += std::to_string(max_value(long_long_bit + 1)); + s += std::to_string(max_value_unsigned(long_long_bit)) + "ULL"; } // cstdint / stdint.h diff --git a/lib/platform.h b/lib/platform.h index 24e61aecc98..feb5b7714f2 100644 --- a/lib/platform.h +++ b/lib/platform.h @@ -55,6 +55,12 @@ class CPPCHECKLIB Platform { return (1LL << (bit-1)) - 1LL; } + static unsigned long long max_value_unsigned(int bit) { + if (bit >= 64) + return ~0ULL; + return (1ULL << bit) - 1ULL; + } + /** provides list of defines specified by the limit.h/climits includes */ std::string getLimitsDefines(bool c99) const; public: diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index c22af0c35f9..193f484288f 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -468,10 +468,8 @@ static ProgramMemory getInitialProgramState(const Token* tok, return pm; } -ProgramMemoryState::ProgramMemoryState(const Settings* s) : settings(s) -{ - assert(settings != nullptr); -} +ProgramMemoryState::ProgramMemoryState(const Settings& s) : settings(s) +{} void ProgramMemoryState::replace(ProgramMemory pm, const Token* origin) { @@ -493,9 +491,9 @@ void ProgramMemoryState::addState(const Token* tok, const ProgramMemory::Map& va { ProgramMemory pm = state; addVars(pm, vars); - fillProgramMemoryFromConditions(pm, tok, *settings); + fillProgramMemoryFromConditions(pm, tok, settings); ProgramMemory local = pm; - fillProgramMemoryFromAssignments(pm, tok, *settings, local, vars); + fillProgramMemoryFromAssignments(pm, tok, settings, local, vars); addVars(pm, vars); replace(std::move(pm), tok); } @@ -506,7 +504,7 @@ void ProgramMemoryState::assume(const Token* tok, bool b, bool isEmpty) if (isEmpty) pm.setContainerSizeValue(tok, 0, b); else - programMemoryParseCondition(pm, tok, nullptr, *settings, b); + programMemoryParseCondition(pm, tok, nullptr, settings, b); const Token* origin = tok; const Token* top = tok->astTop(); if (Token::Match(top->previous(), "for|while|if (") && !Token::simpleMatch(tok->astParent(), "?")) { @@ -523,7 +521,7 @@ void ProgramMemoryState::removeModifiedVars(const Token* tok) const ProgramMemory& pm = state; auto eval = [&](const Token* cond) -> std::vector { ProgramMemory pm2 = pm; - auto result = execute(cond, pm2, *settings); + auto result = execute(cond, pm2, settings); if (isTrue(result)) return {1}; if (isFalse(result)) @@ -533,7 +531,7 @@ void ProgramMemoryState::removeModifiedVars(const Token* tok) state.erase_if([&](const ExprIdToken& e) { const Token* start = origins[e.getExpressionId()]; const Token* expr = e.tok; - if (!expr || findExpressionChangedSkipDeadCode(expr, start, tok, *settings, eval)) { + if (!expr || findExpressionChangedSkipDeadCode(expr, start, tok, settings, eval)) { origins.erase(e.getExpressionId()); return true; } @@ -1276,14 +1274,14 @@ static void pruneConditions(std::vector& conds, namespace { struct Executor { - ProgramMemory* pm = nullptr; - const Settings* settings = nullptr; + ProgramMemory* pm; + const Settings& settings; int fdepth = 4; int depth = 10; - Executor(ProgramMemory* pm, const Settings* settings) : pm(pm), settings(settings) + Executor(ProgramMemory* pm, const Settings& settings) : pm(pm), settings(settings) { - assert(settings != nullptr); + assert(pm != nullptr); } static ValueFlow::Value unknown() { @@ -1395,7 +1393,7 @@ namespace { continue; for (const Token* cond1 : diffConditions1) { auto it = std::find_if(diffConditions2.begin(), diffConditions2.end(), [&](const Token* cond2) { - return evalSameCondition(*pm, cond2, cond1, *settings); + return evalSameCondition(*pm, cond2, cond1, settings); }); if (it == diffConditions2.end()) break; @@ -1584,7 +1582,7 @@ namespace { } if (expr->exprId() > 0 && pm->hasValue(expr->exprId())) { ValueFlow::Value result = utils::as_const(*pm).at(expr->exprId()); - if (result.isImpossible() && result.isIntValue() && result.intvalue == 0 && isUsedAsBool(expr, *settings)) { + if (result.isImpossible() && result.isIntValue() && result.intvalue == 0 && isUsedAsBool(expr, settings)) { result.intvalue = !result.intvalue; result.setKnown(); } @@ -1595,7 +1593,7 @@ namespace { const Token* ftok = expr->previous(); const Function* f = ftok->function(); ValueFlow::Value result = unknown(); - if (settings && expr->str() == "(") { + if (expr->str() == "(") { std::vector tokArgs = getArguments(expr); std::vector args(tokArgs.size()); std::transform( @@ -1623,7 +1621,7 @@ namespace { BuiltinLibraryFunction lf = getBuiltinLibraryFunction(ftok->str()); if (lf) return lf(args); - const std::string& returnValue = settings->library.returnValue(ftok); + const std::string& returnValue = settings.library.returnValue(ftok); if (!returnValue.empty()) { std::unordered_map arg_map; int argn = 0; @@ -1632,7 +1630,7 @@ namespace { arg_map[argn] = v; argn++; } - return evaluateLibraryFunction(arg_map, returnValue, *settings, ftok->isCpp()); + return evaluateLibraryFunction(arg_map, returnValue, settings, ftok->isCpp()); } } } @@ -1640,12 +1638,11 @@ namespace { visitAstNodes(expr->astOperand2(), [&](const Token* child) { if (child->exprId() > 0 && pm->hasValue(child->exprId())) { ValueFlow::Value& v = pm->at(child->exprId()); - assert(settings != nullptr); if (v.valueType == ValueFlow::Value::ValueType::CONTAINER_SIZE) { - if (ValueFlow::isContainerSizeChanged(child, v.indirect, *settings)) + if (ValueFlow::isContainerSizeChanged(child, v.indirect, settings)) v = unknown(); } else if (v.valueType != ValueFlow::Value::ValueType::UNINIT) { - if (isVariableChanged(child, v.indirect, *settings)) + if (isVariableChanged(child, v.indirect, settings)) v = unknown(); } } @@ -1777,13 +1774,13 @@ namespace { static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Settings& settings) { - Executor ex{&pm, &settings}; + Executor ex{&pm, settings}; return ex.execute(expr); } std::vector execute(const Scope* scope, ProgramMemory& pm, const Settings& settings) { - Executor ex{&pm, &settings}; + Executor ex{&pm, settings}; return ex.execute(scope); } diff --git a/lib/programmemory.h b/lib/programmemory.h index 5d8b2632908..36b453b71de 100644 --- a/lib/programmemory.h +++ b/lib/programmemory.h @@ -157,9 +157,9 @@ struct CPPCHECKLIB ProgramMemory { struct ProgramMemoryState { ProgramMemory state; std::map origins; - const Settings* settings; + const Settings& settings; - explicit ProgramMemoryState(const Settings* s); + explicit ProgramMemoryState(const Settings& s); void replace(ProgramMemory pm, const Token* origin = nullptr); diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index db4386d6401..f0193e32725 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -2320,7 +2320,6 @@ void Variable::evaluate(const Settings& settings) const Library & lib = settings.library; - // TODO: ValueType::parseDecl() is also performing a container lookup bool isContainer = false; if (mNameToken) setFlag(fIsArray, arrayDimensions(settings, isContainer)); @@ -5717,6 +5716,15 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst, Referen const Function *func = it->second; if (ref == Reference::LValue && func->hasRvalRefQualifier()) continue; + if (ref == Reference::None && func->hasRvalRefQualifier()) { + if (Token::simpleMatch(tok->astParent(), ".")) { + const Token* obj = tok->astParent()->astOperand1(); + while (obj && obj->str() == "[") + obj = obj->astOperand1(); + if (!obj || obj->isName()) + continue; + } + } if (func->isDestructor() && !Token::simpleMatch(tok->tokAt(-1), "~")) continue; if (!isCall || args == func->argCount() || diff --git a/lib/token.cpp b/lib/token.cpp index ebf8d591d2f..2a1733ece81 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -1141,8 +1141,10 @@ Token* Token::insertToken(const std::string& tokenStr, const std::string& origin newToken->mImpl->mScopeInfo = mImpl->mScopeInfo; } if (newToken->str() == ";") { - const Token* statementStart; - for (statementStart = newToken; statementStart->previous() && !Token::Match(statementStart->previous(), ";|{"); statementStart = statementStart->previous()); + const Token* statementStart = newToken; + while (statementStart->previous() && !Token::Match(statementStart->previous(), ";|{")) { + statementStart = statementStart->previous(); + } if (Token::Match(statementStart, "using namespace %name% ::|;")) { const Token * tok1 = statementStart->tokAt(2); std::string nameSpace; diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index c00d98e47ac..59a11e0aa5c 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -1180,6 +1180,7 @@ void Tokenizer::simplifyTypedef() simplifyTypedefCpp(); } +// TODO: rename - it is not C++ specific void Tokenizer::simplifyTypedefCpp() { const bool cpp = isCPP(); @@ -3477,6 +3478,7 @@ bool Tokenizer::simplifyTokens1(const std::string &configuration) // TODO: apply this through Settings::ValueFlowOptions // TODO: do not run valueflow if no checks are being performed at all - e.g. unusedFunctions only + // TODO: log message when this is active? const char* disableValueflowEnv = std::getenv("DISABLE_VALUEFLOW"); const bool doValueFlow = !disableValueflowEnv || (std::strcmp(disableValueflowEnv, "1") != 0); diff --git a/lib/vf_analyzers.cpp b/lib/vf_analyzers.cpp index 5dddda0039a..32b06eb96e4 100644 --- a/lib/vf_analyzers.cpp +++ b/lib/vf_analyzers.cpp @@ -51,7 +51,7 @@ struct ValueFlowAnalyzer : Analyzer { const Settings& settings; ProgramMemoryState pms; - explicit ValueFlowAnalyzer(const Settings& s) : settings(s), pms(&settings) {} + explicit ValueFlowAnalyzer(const Settings& s) : settings(s), pms(settings) {} virtual const ValueFlow::Value* getValue(const Token* tok) const = 0; virtual ValueFlow::Value* getValue(const Token* tok) = 0; diff --git a/readme.md b/readme.md index 29f5c2e1fd1..f7f1d8552b1 100644 --- a/readme.md +++ b/readme.md @@ -47,6 +47,8 @@ There are multiple compilation choices: * GCC (g++) * Clang (clang++) +The minimum required Python version is 3.6. + ### CMake The minimum required version is CMake 3.5. diff --git a/test/fixture.cpp b/test/fixture.cpp index f9414f0fd58..aaa891917d4 100644 --- a/test/fixture.cpp +++ b/test/fixture.cpp @@ -380,6 +380,7 @@ std::size_t TestFixture::runTests(const options& args) countTests = 0; errmsg.str(""); + // TODO: bail out when given class/test is not found? for (std::string classname : args.which_test()) { std::string testname; if (classname.find("::") != std::string::npos) { diff --git a/test/testclass.cpp b/test/testclass.cpp index 64913601b65..5fd45925183 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -186,6 +186,7 @@ class TestClass : public TestFixture { TEST_CASE(const92); TEST_CASE(const93); TEST_CASE(const94); + TEST_CASE(const95); // #13320 - do not warn about r-value ref method TEST_CASE(const_handleDefaultParameters); TEST_CASE(const_passThisToMemberOfOtherClass); @@ -6705,6 +6706,14 @@ class TestClass : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void const95() { // #13320 + checkConst("class C {\n" + " std::string x;\n" + " std::string get() && { return x; }\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); + } + void const_handleDefaultParameters() { checkConst("struct Foo {\n" " void foo1(int i, int j = 0) {\n" diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index e7e6d3b047a..016fc9e252c 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -690,6 +690,7 @@ class TestMathLib : public TestFixture { //ASSERT_THROW_INTERNAL_EQUALS(MathLib::toDoubleNumber("1.0LL"), INTERNAL, "Internal Error. MathLib::toDoubleNumber: input was not completely consumed: 1.0LL"); // verify: string --> double --> string conversion + // TODO: add L, min/max ASSERT_EQUALS("1.0", MathLib::toString(MathLib::toDoubleNumber("1.0f"))); ASSERT_EQUALS("1.0", MathLib::toString(MathLib::toDoubleNumber("1.0"))); ASSERT_EQUALS("0.0", MathLib::toString(MathLib::toDoubleNumber("0.0f"))); diff --git a/test/testplatform.cpp b/test/testplatform.cpp index 3507ce18cb6..d01eefcb812 100644 --- a/test/testplatform.cpp +++ b/test/testplatform.cpp @@ -403,8 +403,8 @@ class TestPlatform : public TestFixture { void limitsDefines() const { Platform platform; ASSERT_EQUALS(true, platform.set(Platform::Unix64)); - const std::string defs = "CHAR_BIT=8;SCHAR_MIN=-128;SCHAR_MAX=127;UCHAR_MAX=255;CHAR_MIN=0;CHAR_MAX=127;SHRT_MIN=-32768;SHRT_MAX=32767;USHRT_MAX=65535;INT_MIN=-2147483648;INT_MAX=2147483647;UINT_MAX=4294967295;LONG_MIN=-9223372036854775808;LONG_MAX=9223372036854775807;ULONG_MAX=9223372036854775807"; - const std::string defs_c99 = "CHAR_BIT=8;SCHAR_MIN=-128;SCHAR_MAX=127;UCHAR_MAX=255;CHAR_MIN=0;CHAR_MAX=127;SHRT_MIN=-32768;SHRT_MAX=32767;USHRT_MAX=65535;INT_MIN=-2147483648;INT_MAX=2147483647;UINT_MAX=4294967295;LONG_MIN=-9223372036854775808;LONG_MAX=9223372036854775807;ULONG_MAX=9223372036854775807;LLONG_MIN=-9223372036854775808;LLONG_MAX=9223372036854775807;ULLONG_MAX=9223372036854775807"; + const std::string defs = "CHAR_BIT=8;SCHAR_MIN=-128;SCHAR_MAX=127;UCHAR_MAX=255;CHAR_MIN=0;CHAR_MAX=127;SHRT_MIN=-32768;SHRT_MAX=32767;USHRT_MAX=65535;INT_MIN=(-2147483647 - 1);INT_MAX=2147483647;UINT_MAX=4294967295;LONG_MIN=(-9223372036854775807L - 1L);LONG_MAX=9223372036854775807L;ULONG_MAX=18446744073709551615UL"; + const std::string defs_c99 = "CHAR_BIT=8;SCHAR_MIN=-128;SCHAR_MAX=127;UCHAR_MAX=255;CHAR_MIN=0;CHAR_MAX=127;SHRT_MIN=-32768;SHRT_MAX=32767;USHRT_MAX=65535;INT_MIN=(-2147483647 - 1);INT_MAX=2147483647;UINT_MAX=4294967295;LONG_MIN=(-9223372036854775807L - 1L);LONG_MAX=9223372036854775807L;ULONG_MAX=18446744073709551615UL;LLONG_MIN=(-9223372036854775807LL - 1LL);LLONG_MAX=9223372036854775807LL;ULLONG_MAX=18446744073709551615ULL"; ASSERT_EQUALS(defs, platform.getLimitsDefines(Standards::cstd_t::C89)); ASSERT_EQUALS(defs_c99, platform.getLimitsDefines(Standards::cstd_t::C99)); ASSERT_EQUALS(defs_c99, platform.getLimitsDefines(Standards::cstd_t::CLatest)); diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index de4e519ac5b..f2486df823c 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -522,6 +522,7 @@ class TestSymbolDatabase : public TestFixture { TEST_CASE(findFunction56); TEST_CASE(findFunction57); TEST_CASE(findFunctionRef1); + TEST_CASE(findFunctionRef2); // #13328 TEST_CASE(findFunctionContainer); TEST_CASE(findFunctionExternC); TEST_CASE(findFunctionGlobalScope); // ::foo @@ -8394,6 +8395,25 @@ class TestSymbolDatabase : public TestFixture { ASSERT_EQUALS(2, f->function()->tokenDef->linenr()); } + void findFunctionRef2() { + GET_SYMBOL_DB("struct X {\n" + " const int& foo() const &;\n" // <- this function is called + " int foo() &&;\n" + "}\n" + "\n" + "void foo() {\n" + " X x;\n" + " x.foo();\n" + "}\n"); + const Token* x = Token::findsimplematch(tokenizer.tokens(), "x . foo ( ) ;"); + ASSERT(x); + const Token* f = x->tokAt(2); + ASSERT(f); + ASSERT(f->function()); + ASSERT(f->function()->tokenDef); + ASSERT_EQUALS(2, f->function()->tokenDef->linenr()); + } + void findFunctionContainer() { { GET_SYMBOL_DB("void dostuff(std::vector v);\n" diff --git a/test/testtype.cpp b/test/testtype.cpp index f6a2fd36d29..ac602dc4bde 100644 --- a/test/testtype.cpp +++ b/test/testtype.cpp @@ -291,7 +291,7 @@ class TestType : public TestFixture { " if (x==123456) {}\n" " return -123456 * x;\n" "}",settings); - ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (warning) Either the condition 'x==123456' is redundant or there is signed integer overflow for expression '-123456*x'.\n", errout_str()); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (warning) Either the condition 'x==123456' is redundant or there is signed integer underflow for expression '-123456*x'.\n", errout_str()); check("int foo(signed int x) {\n" " if (x==123456) {}\n" @@ -303,6 +303,16 @@ class TestType : public TestFixture { " return (i == 31) ? 1 << i : 0;\n" "}", settings); ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:2]: (warning) Shifting signed 32-bit value by 31 bits is undefined behaviour. See condition at line 2.\n", errout_str()); + + check("void f() {\n" // #13092 + " int n = 0;\n" + " for (int i = 0; i < 10; i++) {\n" + " n = n * 47163 - 57412;\n" + " }\n" + "}", settings); + ASSERT_EQUALS("[test.cpp:4]: (error) Signed integer underflow for expression 'n*47163'.\n" + "[test.cpp:4]: (error) Signed integer underflow for expression 'n*47163-57412'.\n", + errout_str()); } void signConversion() { @@ -352,6 +362,11 @@ class TestType : public TestFixture { " return -2 * x;\n" "}", settingsDefault); ASSERT_EQUALS("[test.cpp:2]: (warning) Expression '-2' has a negative value. That is converted to an unsigned value and used in an unsigned calculation.\n", errout_str()); + + checkP("void f() {\n" // #12110 FP signConversion with integer overflow + " if (LLONG_MIN / (-1)) {}\n" + "}\n", settingsDefault); + ASSERT_EQUALS("", errout_str()); } void longCastAssign() { diff --git a/tools/dmake/CMakeLists.txt b/tools/dmake/CMakeLists.txt index 4f9ea9d7007..5af693eb179 100644 --- a/tools/dmake/CMakeLists.txt +++ b/tools/dmake/CMakeLists.txt @@ -1,5 +1,5 @@ # TODO: when using ccache and matchcompiler this will accessed before the file was generated and thus the build fails -set(srcs_lib pathmatch.cpp path.cpp) +set(srcs_lib pathmatch.cpp path.cpp utils.cpp) foreach(file ${srcs_lib}) if (NOT USE_MATCHCOMPILER_OPT STREQUAL "Off") set(src "${CMAKE_BINARY_DIR}/lib/build/mc_${file}") @@ -14,7 +14,6 @@ add_executable(dmake EXCLUDE_FROM_ALL dmake.cpp ${CMAKE_SOURCE_DIR}/cli/filelister.cpp ${srcs_tools} - ${CMAKE_SOURCE_DIR}/lib/utils.cpp $ ) target_include_directories(dmake PRIVATE ${CMAKE_SOURCE_DIR}/cli ${CMAKE_SOURCE_DIR}/lib) diff --git a/tools/dmake/dmake.vcxproj b/tools/dmake/dmake.vcxproj deleted file mode 100644 index b582ba44121..00000000000 --- a/tools/dmake/dmake.vcxproj +++ /dev/null @@ -1,113 +0,0 @@ - - - - - Debug - x64 - - - Release - x64 - - - - {19EC86CD-0004-4917-B852-E6BD110B6E6F} - dmake - 10.0 - - - - Application - v142 - NotSet - true - - - Application - v142 - NotSet - - - - - - - - - - - - - <_ProjectFileVersion>11.0.61030.0 - - - ..\Build\$(Configuration)\ - ..\BuildTmp\$(TargetName)\$(Configuration)\ - true - - - - ..\Build\$(Configuration)\ - ..\BuildTmp\$(TargetName)\$(Configuration)\ - false - - - - Disabled - ..\lib;..\externals\simplecpp;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;%(PreprocessorDefinitions) - true - Default - MultiThreadedDebugDLL - false - - $(IntDir) - Level4 - ProgramDatabase - - - shlwapi.lib;%(AdditionalDependencies) - $(OutDir)dmake.exe - true - Console - - - - - MaxSpeed - true - ..\lib;..\externals\simplecpp;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;%(PreprocessorDefinitions) - MultiThreadedDLL - true - - $(IntDir) - Level4 - ProgramDatabase - - - shlwapi.lib;%(AdditionalDependencies) - $(OutDir)dmake.exe - true - Console - true - true - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/tools/donate-cpu-server.py b/tools/donate-cpu-server.py index b4929ad75ad..c041f38383e 100755 --- a/tools/donate-cpu-server.py +++ b/tools/donate-cpu-server.py @@ -28,6 +28,7 @@ # changes) SERVER_VERSION = "1.3.63" +# TODO: fetch from GitHub tags OLD_VERSION = '2.16.0' HEAD_MARKER = 'head results:' diff --git a/tools/donate-cpu.py b/tools/donate-cpu.py index c59f9ed6f0a..35ae295d20c 100755 --- a/tools/donate-cpu.py +++ b/tools/donate-cpu.py @@ -125,10 +125,10 @@ print('Unhandled argument: ' + arg) sys.exit(1) -if sys.version_info.major < 3 or (sys.version_info.major == 3 and sys.version_info.minor < 4): +if sys.version_info.major < 3 or (sys.version_info.major == 3 and sys.version_info.minor < 6): print("#" * 80) print("IMPORTANT") - print("Please run the client with at least Python 3.4, thanks!") + print("Please run the client with at least Python 3.6, thanks!") print("#" * 80) time.sleep(2) sys.exit(1) diff --git a/tools/triage/triage.pro b/tools/triage/triage.pro new file mode 100644 index 00000000000..1bda43f40a7 --- /dev/null +++ b/tools/triage/triage.pro @@ -0,0 +1,17 @@ +lessThan(QT_MAJOR_VERSION, 5): error(requires >= Qt 5 (You used: $$QT_VERSION)) +QT += core gui widgets +TARGET = triage +TEMPLATE = app +QMAKE_CXXFLAGS += -std=c++11 +INCLUDEPATH += ../../gui +MOC_DIR = temp +OBJECTS_DIR = temp +UI_DIR = temp +SOURCES += main.cpp\ + mainwindow.cpp \ + ../../gui/codeeditorstyle.cpp \ + ../../gui/codeeditor.cpp +HEADERS += mainwindow.h \ + ../../gui/codeeditorstyle.h \ + ../../gui/codeeditor.h +FORMS += mainwindow.ui