diff --git a/.github/workflows/CI-unixish.yml b/.github/workflows/CI-unixish.yml index cf555a8ecc6..3251a6b5adb 100644 --- a/.github/workflows/CI-unixish.yml +++ b/.github/workflows/CI-unixish.yml @@ -679,6 +679,12 @@ jobs: test -z "$(nm processexecutor.o)" # TODO: test NO_* defines + - name: Test execinfo.h detection + run: | + make clean + make cli/stacktrace.o | grep HAVE_EXECINFO_H=1 + test -n "$(nm cli/stacktrace.o)" + - name: Test testrunner inclusion/exclusion run: | ! ./testrunner -d TestUtils | grep -v TestUtils > /dev/null diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index 7b462c688f0..c54d47da4f1 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -10,7 +10,7 @@ permissions: jobs: Fuzzing: runs-on: ubuntu-latest - if: ${{ github.repository_owner == 'danmar' }} + if: ${{ github.repository_owner == 'cppcheck-opensource' }} steps: - name: Build Fuzzers id: build diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index 3c07b61d7c7..006160c7779 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -12,7 +12,7 @@ permissions: jobs: scan: runs-on: ubuntu-latest - if: ${{ github.repository_owner == 'danmar' }} + if: ${{ github.repository_owner == 'cppcheck-opensource' }} steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/cppcheck-premium.yml b/.github/workflows/cppcheck-premium.yml index 5cb63ca4d5e..ed0f2a1bcd5 100644 --- a/.github/workflows/cppcheck-premium.yml +++ b/.github/workflows/cppcheck-premium.yml @@ -33,7 +33,7 @@ jobs: run: | premium_version=${{ inputs.premium_version }} if [ -z $premium_version ]; then - premium_version=25.8.3 + premium_version=26.3.0 #wget https://files.cppchecksolutions.com/devdrop/cppcheckpremium-$premium_version-amd64.tar.gz -O cppcheckpremium.tar.gz wget https://files.cppchecksolutions.com/$premium_version/ubuntu-24.04/cppcheckpremium-$premium_version-amd64.tar.gz -O cppcheckpremium.tar.gz else diff --git a/.github/workflows/iwyu.yml b/.github/workflows/iwyu.yml index ed6971128f5..05d5643bdf7 100644 --- a/.github/workflows/iwyu.yml +++ b/.github/workflows/iwyu.yml @@ -30,7 +30,7 @@ jobs: fail-fast: false runs-on: ${{ matrix.os }} - if: ${{ github.repository_owner == 'danmar' }} + if: ${{ github.repository_owner == 'cppcheck-opensource' }} container: image: ${{ matrix.image }} @@ -192,7 +192,7 @@ jobs: fail-fast: false runs-on: ubuntu-22.04 - if: ${{ github.repository_owner == 'danmar' }} + if: ${{ github.repository_owner == 'cppcheck-opensource' }} env: QT_VERSION: 6.10.0 diff --git a/.github/workflows/release-windows.yml b/.github/workflows/release-windows.yml index 607c8434baa..3b5036ff29e 100644 --- a/.github/workflows/release-windows.yml +++ b/.github/workflows/release-windows.yml @@ -22,7 +22,7 @@ jobs: build: runs-on: windows-2025 - if: ${{ github.repository_owner == 'danmar' }} + if: ${{ github.repository_owner == 'cppcheck-opensource' }} env: PYTHON_VERSION: 3.14 diff --git a/.github/workflows/selfcheck.yml b/.github/workflows/selfcheck.yml index 389e39371ba..cfd1107e92d 100644 --- a/.github/workflows/selfcheck.yml +++ b/.github/workflows/selfcheck.yml @@ -172,7 +172,7 @@ 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) 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 cd7a56377e2..02735d36ee8 100644 --- a/Makefile +++ b/Makefile @@ -155,7 +155,13 @@ else ifneq ($(HAVE_RULES),) $(error invalid HAVE_RULES value '$(HAVE_RULES)') endif -HAVE_EXECINFO_H=$(shell echo "\#include " | $(CXX) -c -xc - 2> /dev/null && echo "1" || echo "0") +# 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) diff --git a/addons/README.md b/addons/README.md index 8df8229b970..05502f547b6 100644 --- a/addons/README.md +++ b/addons/README.md @@ -4,19 +4,19 @@ Addons are scripts that analyses Cppcheck dump files to check compatibility with ## Supported addons -+ [misra.py](https://github.com/danmar/cppcheck/blob/main/addons/misra.py) - Used to verify compliance with MISRA C 2012 - a proprietary set of guidelines to avoid such questionable code, developed for embedded systems. Since this standard is proprietary, cppcheck does not display error text by specifying only the number of violated rules (for example, [c2012-21.3]). If you want to display full texts for violated rules, you will need to create a text file containing MISRA rules, which you will have to pass when calling the script with `--rule-texts` key. Some examples of rule texts files available in [tests directory](https://github.com/danmar/cppcheck/blob/main/addons/test/misra/). -+ [y2038.py](https://github.com/danmar/cppcheck/blob/main/addons/y2038.py) - Checks code for [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) safety. See complete description [here](https://github.com/danmar/cppcheck/blob/main/addons/doc/y2038.md). -+ [threadsafety.py](https://github.com/danmar/cppcheck/blob/main/addons/threadsafety.py) ++ [misra.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/misra.py) + Used to verify compliance with MISRA C 2012 - a proprietary set of guidelines to avoid such questionable code, developed for embedded systems. Since this standard is proprietary, cppcheck does not display error text by specifying only the number of violated rules (for example, [c2012-21.3]). If you want to display full texts for violated rules, you will need to create a text file containing MISRA rules, which you will have to pass when calling the script with `--rule-texts` key. Some examples of rule texts files available in [tests directory](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/test/misra/). ++ [y2038.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/y2038.py) + Checks code for [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) safety. See complete description [here](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/doc/y2038.md). ++ [threadsafety.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/threadsafety.py) Analyse Cppcheck dump files to locate threadsafety issues like static local objects used by multiple threads. -+ [naming.py](https://github.com/danmar/cppcheck/blob/main/addons/naming.py) ++ [naming.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/naming.py) Enforces naming conventions across the code. -+ [namingng.py](https://github.com/danmar/cppcheck/blob/main/addons/namingng.py) ++ [namingng.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/namingng.py) Enforces naming conventions across the code. Enhanced version with support for type prefixes in variable and function names. -+ [findcasts.py](https://github.com/danmar/cppcheck/blob/main/addons/findcasts.py) ++ [findcasts.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/findcasts.py) Locates casts in the code. -+ [misc.py](https://github.com/danmar/cppcheck/blob/main/addons/misc.py) ++ [misc.py](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/misc.py) Performs miscellaneous checks. ### Other files @@ -68,5 +68,5 @@ This allows you to add additional parameters when calling the script (for exampl When using the graphical interface `cppcheck-gui`, the selection and configuration of addons is carried out on the tab `Addons and tools` in the project settings (`Edit Project File`): -![Screenshot](https://raw.githubusercontent.com/danmar/cppcheck/main/addons/doc/img/cppcheck-gui-addons.png) +![Screenshot](https://raw.githubusercontent.com/cppcheck-opensource/cppcheck/main/addons/doc/img/cppcheck-gui-addons.png) diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 69f3e842785..680f7387c70 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -267,8 +267,9 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) return EXIT_SUCCESS; } - TimerResults overallTimerResults; - Timer realTimeClock("Overall time", settings.showtime, &overallTimerResults, Timer::Type::OVERALL); + std::unique_ptr overallTimer; + if (settings.showtime == ShowTime::SUMMARY || settings.showtime == ShowTime::TOP5_SUMMARY) + overallTimer.reset(new OneShotTimer("Overall time", settings.showtime)); settings.loadSummaries(); @@ -277,9 +278,6 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) const int ret = check_wrapper(settings, supprs); - realTimeClock.stop(); - overallTimerResults.showResults(settings.showtime, false, true); - return ret; } diff --git a/createrelease b/createrelease index 9dd79333119..de85d64395b 100755 --- a/createrelease +++ b/createrelease @@ -52,7 +52,7 @@ # Create 2.18.x branch # git checkout -b 2.18.x ; git push -u origin 2.18.x # in fork: -# * add upstream: git remote add upstream git@github.com:danmar/cppcheck.git +# * add upstream: git remote add upstream git@github.com:/cppcheck-opensource//cppcheck.git # * add branch: git fetch upstream 2.19.x # # Release notes: @@ -124,7 +124,7 @@ # * daca: cd /var && nice tar -cJf ~/daca.tar.xz daca@home # * git: git checkout -f && git checkout main && git pull && tar -cJf git.tar.xz .git # * git log 2.16.0..2.17.0 > Changelog -# * mkdir out && python3 ~/cppchecksolutions/release/getWorkflowAndIssueLogs.py -r danmar/cppcheck -t 2.15.0 -p out +# * mkdir out && python3 ~/cppchecksolutions/release/getWorkflowAndIssueLogs.py -r /cppcheck-opensource//cppcheck -t 2.15.0 -p out # Folder/tag to use folder=$1 diff --git a/gui/manualtest/projectfiledialog.md b/gui/manualtest/projectfiledialog.md index eb76109e53e..f11b030f246 100644 --- a/gui/manualtest/projectfiledialog.md +++ b/gui/manualtest/projectfiledialog.md @@ -4,8 +4,7 @@ Some manual testing in the project file dialog interface - -## Test: Platform files +## Test: Platform file pic8.xml Ticket: #14489 @@ -14,6 +13,14 @@ EXPECTED: In the project file dialog it should be possible to select xml files i TODO: can this test be automated +## Test: Custom cfg file + +Ticket: #14672 + +1. Copy addons/avr.cfg to a file "aa.cfg" in same folder as a cppcheck GUI project file + +EXPECTED: It should not be possible to activate "aa.cfg" in the project file dialog, it should appear in alphabetical order. + ## Test: Misra C checkbox diff --git a/gui/projectfile.cpp b/gui/projectfile.cpp index d2b468443fa..a77c1a0fc94 100644 --- a/gui/projectfile.cpp +++ b/gui/projectfile.cpp @@ -1207,5 +1207,5 @@ QStringList ProjectFile::getSearchPaths(const QString& dir) const { const QString applicationFilePath = QCoreApplication::applicationFilePath(); const QString appPath = QFileInfo(applicationFilePath).canonicalPath(); const QString datadir = getDataDir(); - return getSearchPaths(inf.canonicalFilePath(), appPath, datadir, dir); + return getSearchPaths(inf.canonicalPath(), appPath, datadir, dir); } diff --git a/gui/resultsview.cpp b/gui/resultsview.cpp index 698b6e82018..496c0793157 100644 --- a/gui/resultsview.cpp +++ b/gui/resultsview.cpp @@ -123,6 +123,7 @@ void ResultsView::clear(bool results) } mUI->mDetails->setText(QString()); + mUI->mCode->clear(); mStatistics->clear(); delete mCheckSettings; diff --git a/htmlreport/setup.py b/htmlreport/setup.py index 3e049181ce6..9f85000a090 100755 --- a/htmlreport/setup.py +++ b/htmlreport/setup.py @@ -16,7 +16,7 @@ ), long_description=readme, author="Cppcheck Team", - url="https://github.com/danmar/cppcheck", + url="https://github.com/cppcheck-opensource/cppcheck", license="GPL", packages=find_packages(exclude=("tests", "docs")), use_scm_version={"root": ".."}, diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index 04532e1ecb9..6dd98de078e 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -565,7 +565,7 @@ static const Token* doAssignment(Variables &variables, const Token *tok, bool de variables.readAll(varid2, tok); } } - } else if (var1->mType == Variables::reference) { + } else if (var1->mType == Variables::reference || var1->mType == Variables::referenceArray) { variables.alias(varid1, varid2, true); } else if (var1->mType == Variables::standard && addressOf) { variables.alias(varid1, varid2, true); @@ -738,6 +738,8 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const if (type == Variables::none || isPartOfClassStructUnion(i->typeStartToken())) continue; const Token* defValTok = i->nameToken()->next(); + if (Token::Match(i->nameToken()->previous(), "& %var% )")) + defValTok = defValTok->next(); while (defValTok && defValTok->str() == "[") defValTok = defValTok->link()->next(); if (Token::simpleMatch(defValTok, ") (")) diff --git a/lib/config.h b/lib/config.h index 960c2c91aa4..c88c431288c 100644 --- a/lib/config.h +++ b/lib/config.h @@ -203,7 +203,7 @@ #if HAVE_EXECINFO_H #define USE_UNIX_BACKTRACE_SUPPORT #endif -#elif defined(__GNUC__) && !defined(__APPLE__) && !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__SVR4) && !defined(__QNX__) && !defined(_AIX) +#elif __has_include() #define USE_UNIX_BACKTRACE_SUPPORT #endif #endif diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 0a8e721936b..db2b2e5091a 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -923,8 +923,9 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str if (Settings::terminated()) return mLogger->exitcode(); - TimerResults checkTimeResults; - Timer fileTotalTimer{"Check time: " + file.spath(), mSettings.showtime, &checkTimeResults, Timer::Type::FILE}; + std::unique_ptr checkTimeTimer; + if (mSettings.showtime == ShowTime::FILE || mSettings.showtime == ShowTime::FILE_TOTAL || mSettings.showtime == ShowTime::TOP5_FILE) + checkTimeTimer.reset(new OneShotTimer("Check time: " + file.spath(), mSettings.showtime)); if (!mSettings.quiet) { std::string fixedpath = Path::toNativeSeparators(file.spath()); @@ -1296,9 +1297,6 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str if (mTimerResults && (mSettings.showtime == ShowTime::FILE || mSettings.showtime == ShowTime::TOP5_FILE)) mTimerResults->showResults(mSettings.showtime); - fileTotalTimer.stop(); - checkTimeResults.showResults(mSettings.showtime, false, true); - return mLogger->exitcode(); } diff --git a/lib/timer.cpp b/lib/timer.cpp index 5a18953767a..f4025fb3427 100644 --- a/lib/timer.cpp +++ b/lib/timer.cpp @@ -38,7 +38,7 @@ namespace { // TODO: this does not include any file context when SHOWTIME_FILE thus rendering it useless - should we include the logging with the progress logging? // that could also get rid of the broader locking -void TimerResults::showResults(ShowTime mode, bool metrics, bool format) const +void TimerResults::showResults(ShowTime mode, bool metrics) const { if (mode == ShowTime::NONE) return; @@ -57,28 +57,26 @@ void TimerResults::showResults(ShowTime mode, bool metrics, bool format) const size_t ordinal = 1; // maybe it would be nice to have an ordinal in output later! for (auto iter=data.cbegin(); iter!=data.cend(); ++iter) { - const double sec = iter->second.getSeconds().count(); - const double secAverage = sec / static_cast(iter->second.mNumberOfResults); if ((mode != ShowTime::TOP5_FILE && mode != ShowTime::TOP5_SUMMARY) || (ordinal<=5)) { - std::cout << iter->first << ": "; - if (format) - std::cout << TimerResultsData::durationToString(iter->second.mDuration); - else - std::cout << sec << "s"; - if (metrics) - std::cout << " (avg. " << secAverage << "s - " << iter->second.mNumberOfResults << " result(s))"; + const double sec = iter->second.getSeconds().count(); + std::cout << iter->first << ": " << sec << "s"; + if (metrics) { + const double secAverage = sec / static_cast(iter->second.mResults.size()); + const double secMin = asSeconds(*std::min_element(iter->second.mResults.cbegin(), iter->second.mResults.cend())).count(); + const double secMax = asSeconds(*std::max_element(iter->second.mResults.cbegin(), iter->second.mResults.cend())).count(); + std::cout << " (avg. " << secAverage << "s / min " << secMin << "s / max " << secMax << "s - " << iter->second.mResults.size() << " result(s))"; + } std::cout << std::endl; } ++ordinal; } } -void TimerResults::addResults(const std::string& str, std::chrono::milliseconds duration) +void TimerResults::addResults(const std::string& name, std::chrono::milliseconds duration) { std::lock_guard l(mResultsSync); - mResults[str].mDuration += duration; - mResults[str].mNumberOfResults++; + mResults[name].mResults.push_back(duration); } void TimerResults::reset() @@ -87,10 +85,9 @@ void TimerResults::reset() mResults.clear(); } -Timer::Timer(std::string str, ShowTime showtimeMode, TimerResultsIntf* timerResults, Type type) +Timer::Timer(std::string str, ShowTime showtimeMode, TimerResultsIntf* timerResults) : mName(std::move(str)) , mMode(showtimeMode) - , mType(type) , mStart(Clock::now()) , mResults(timerResults) {} @@ -104,14 +101,6 @@ void Timer::stop() { if (mMode == ShowTime::NONE) return; - if (mType == Type::OVERALL && mMode != ShowTime::TOP5_SUMMARY && mMode != ShowTime::SUMMARY) { - mMode = ShowTime::NONE; - return; - } - if (mType == Type::FILE && mMode != ShowTime::TOP5_FILE && mMode != ShowTime::FILE && mMode != ShowTime::FILE_TOTAL) { - mMode = ShowTime::NONE; - return; - } if (mStart != TimePoint{}) { if (!mResults) { assert(false); @@ -124,7 +113,7 @@ void Timer::stop() mMode = ShowTime::NONE; // prevent multiple stops } -std::string TimerResultsData::durationToString(std::chrono::milliseconds duration) +static std::string durationToString(std::chrono::milliseconds duration) { // Extract hours auto hours = std::chrono::duration_cast(duration); @@ -148,3 +137,24 @@ std::string TimerResultsData::durationToString(std::chrono::milliseconds duratio secondsStr.resize(pos + 4); // keep three decimal return (ellapsedTime + secondsStr + "s"); } + +OneShotTimer::OneShotTimer(std::string name, ShowTime showtime) +{ + if (showtime == ShowTime::NONE) + return; + + class MyResults : public TimerResultsIntf + { + private: + void addResults(const std::string &name, std::chrono::milliseconds duration) override + { + std::lock_guard l(stdCoutLock); + + // TODO: do not use std::cout directly + std::cout << name << ": " << durationToString(duration) << std::endl; + } + }; + + mResults.reset(new MyResults); + mTimer.reset(new Timer(std::move(name), showtime, mResults.get())); +} diff --git a/lib/timer.h b/lib/timer.h index e0c4ee2d45f..5611bc5304b 100644 --- a/lib/timer.h +++ b/lib/timer.h @@ -25,9 +25,12 @@ #include #include #include +#include #include +#include #include #include +#include enum class ShowTime : std::uint8_t { NONE, @@ -42,26 +45,29 @@ class CPPCHECKLIB TimerResultsIntf { public: virtual ~TimerResultsIntf() = default; - virtual void addResults(const std::string& timerName, std::chrono::milliseconds duation) = 0; + virtual void addResults(const std::string& name, std::chrono::milliseconds duration) = 0; + + static std::chrono::duration asSeconds(std::chrono::milliseconds ms) { + return std::chrono::duration_cast>(ms); + } }; struct TimerResultsData { - std::chrono::milliseconds mDuration; - long mNumberOfResults{}; + std::vector mResults; std::chrono::duration getSeconds() const { - return std::chrono::duration_cast>(mDuration); + return std::accumulate(mResults.cbegin(), mResults.cend(), std::chrono::duration{}, [](std::chrono::duration secs, std::chrono::milliseconds duration) { + return secs + TimerResultsIntf::asSeconds(duration); + }); } - - static std::string durationToString(std::chrono::milliseconds duration); }; class CPPCHECKLIB WARN_UNUSED TimerResults : public TimerResultsIntf { public: TimerResults() = default; - void showResults(ShowTime mode, bool metrics = true, bool format = false) const; - void addResults(const std::string& str, std::chrono::milliseconds duration) override; + void showResults(ShowTime mode, bool metrics = true) const; + void addResults(const std::string& name, std::chrono::milliseconds duration) override; void reset(); @@ -75,13 +81,7 @@ class CPPCHECKLIB Timer { using Clock = std::chrono::high_resolution_clock; using TimePoint = std::chrono::time_point; - enum class Type : std::uint8_t { - FILE, - OVERALL, - OTHER - }; - - Timer(std::string str, ShowTime showtimeMode, TimerResultsIntf* timerResults = nullptr, Type type = Type::OTHER); + Timer(std::string str, ShowTime showtimeMode, TimerResultsIntf* timerResults = nullptr); ~Timer(); Timer(const Timer&) = delete; @@ -98,10 +98,18 @@ class CPPCHECKLIB Timer { private: const std::string mName; ShowTime mMode{}; - Type mType{}; TimePoint mStart; TimerResultsIntf* mResults{}; }; +class CPPCHECKLIB OneShotTimer +{ +public: + OneShotTimer(std::string name, ShowTime showtime); +private: + std::unique_ptr mResults; + std::unique_ptr mTimer; +}; + //--------------------------------------------------------------------------- #endif // timerH diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 34cb997a636..4cce2a71434 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -1115,14 +1115,18 @@ void Tokenizer::simplifyTypedef() syntaxError(t.second.getTypedefToken()); } else { const Token* const typedefToken = t.second.getTypedefToken(); + const Token* const nameToken = t.second.nameToken(); TypedefInfo typedefInfo; typedefInfo.name = t.second.name(); - typedefInfo.filename = list.file(typedefToken); - typedefInfo.lineNumber = typedefToken->linenr(); - typedefInfo.column = typedefToken->column(); - if (Token::Match(typedefToken->next(), "struct|enum|class|union %name% {") && typedefToken->strAt(2) == typedefInfo.name) { - typedefInfo.tagLine = typedefToken->tokAt(2)->linenr(); - typedefInfo.tagColumn = typedefToken->tokAt(2)->column(); + typedefInfo.filename = list.file(nameToken); + typedefInfo.lineNumber = nameToken->linenr(); + typedefInfo.column = nameToken->column(); + if (Token::Match(typedefToken->next(), "struct|enum|class|union %name% {")) { + typedefInfo.originalName = typedefToken->strAt(2); + if (typedefToken->strAt(2) == typedefInfo.name) { + typedefInfo.tagLine = typedefToken->tokAt(2)->linenr(); + typedefInfo.tagColumn = typedefToken->tokAt(2)->column(); + } } typedefInfo.used = t.second.isUsed(); typedefInfo.isFunctionPointer = isFunctionPointer(t.second.nameToken()); @@ -4496,6 +4500,10 @@ static void setVarIdStructMembers(Token *&tok1, tok->varId(it->second); } } + if (Token::Match(tok, "%name% = { . %name% =|{")) { + setVarIdStructMembers(tok, structMembers, varId); + tok = tok->linkAt(2); + } tok = tok->next(); } @@ -6376,6 +6384,12 @@ std::string Tokenizer::dumpTypedefInfo() const outs += typedefInfo.name; outs += "\""; + if (!typedefInfo.originalName.empty()) { + outs += " originalName=\""; + outs += typedefInfo.originalName; + outs += "\""; + } + outs += " file=\""; outs += ErrorLogger::toxml(typedefInfo.filename); outs += "\""; @@ -9000,7 +9014,7 @@ void Tokenizer::findGarbageCode() const syntaxError(tok); if (Token::Match(tok, "[;([{] %comp%|%oror%|%or%|%|/")) syntaxError(tok); - if (Token::Match(tok, "%cop%|= ]") && !Token::simpleMatch(tok, "*") && !(cpp && Token::Match(tok->previous(), "%type%|[|,|%num% &|=|> ]"))) + if (Token::Match(tok, "%cop%|= ]") && !Token::simpleMatch(tok, "*") && !(cpp && Token::Match(tok->previous(), "<|%type%|[|,|%num% &|=|> ]"))) syntaxError(tok); if (Token::Match(tok, "[+-] [;,)]}]") && !(cpp && Token::simpleMatch(tok->previous(), "operator"))) syntaxError(tok); @@ -10330,6 +10344,13 @@ static bool isStdSmartPointer(const Token* tok, const Settings& settings) return ptr && startsWith(ptr->name, "std::"); } +static bool isLibraryType(const Token* tok, const Settings& settings) +{ + return settings.library.hasAnyTypeCheck("std::" + tok->str()) || + settings.library.podtype("std::" + tok->str()) || + isStdContainerOrIterator(tok, settings); +} + // Add std:: in front of std classes, when using namespace std; was given void Tokenizer::simplifyNamespaceStd() { @@ -10357,14 +10378,13 @@ void Tokenizer::simplifyNamespaceStd() if (start != tok && start->isName() && !start->isKeyword() && (!start->previous() || Token::Match(start->previous(), "[;{}]"))) userFunctions.insert(tok->str()); } - if (userFunctions.find(tok->str()) == userFunctions.end() && mSettings.library.matchArguments(tok, "std::" + tok->str())) + if ((userFunctions.find(tok->str()) == userFunctions.end() && mSettings.library.matchArguments(tok, "std::" + tok->str())) || + (tok->tokAt(-1)->isKeyword() && isLibraryType(tok, mSettings))) insert = true; } else if (Token::simpleMatch(tok->next(), "<") && (isStdContainerOrIterator(tok, mSettings) || isStdSmartPointer(tok, mSettings))) insert = true; - else if (mSettings.library.hasAnyTypeCheck("std::" + tok->str()) || - mSettings.library.podtype("std::" + tok->str()) || - isStdContainerOrIterator(tok, mSettings)) + else if (isLibraryType(tok, mSettings)) insert = true; else if (Token::simpleMatch(tok, "aligned_storage")) insert = true; diff --git a/lib/tokenize.h b/lib/tokenize.h index 9ee4b29466f..16cd88fa30e 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -698,6 +698,7 @@ class CPPCHECKLIB Tokenizer { }; struct TypedefInfo { std::string name; + std::string originalName; std::string filename; int lineNumber; int column; diff --git a/lib/utils.h b/lib/utils.h index 14f5382a8bf..3f9c4ab949f 100644 --- a/lib/utils.h +++ b/lib/utils.h @@ -220,7 +220,7 @@ bool strToInt(const std::string& str, T &num, std::string* err = nullptr) tmp = std::stoll(str, &idx); if (idx != str.size()) { if (err) - *err = "not an integer"; + *err = "not an integer (pos)"; return false; } } catch (const std::out_of_range&) { @@ -229,7 +229,7 @@ bool strToInt(const std::string& str, T &num, std::string* err = nullptr) return false; } catch (const std::invalid_argument &) { if (err) - *err = "not an integer"; + *err = "not an integer (invalid_argument)"; return false; } if (str.front() == '-' && std::numeric_limits::min() == 0) { @@ -237,6 +237,16 @@ bool strToInt(const std::string& str, T &num, std::string* err = nullptr) *err = "needs to be positive"; return false; } + if (str.front() != '+' && str.front() != '-' && isdigit(str.front()) == 0) { + if (err) + *err = "not an integer"; + return false; + } + if (str.size() > 1 && str.front() == '0') { + if (err) + *err = "not an integer"; + return false; + } if (tmp < std::numeric_limits::min() || tmp > std::numeric_limits::max()) { if (err) *err = "out of range (limits)"; @@ -255,7 +265,7 @@ bool strToInt(const std::string& str, T &num, std::string* err = nullptr) tmp = std::stoull(str, &idx); if (idx != str.size()) { if (err) - *err = "not an integer"; + *err = "not an integer (pos)"; return false; } } catch (const std::out_of_range&) { @@ -264,7 +274,7 @@ bool strToInt(const std::string& str, T &num, std::string* err = nullptr) return false; } catch (const std::invalid_argument &) { if (err) - *err = "not an integer"; + *err = "not an integer (invalid_argument)"; return false; } if (str.front() == '-') { @@ -272,6 +282,16 @@ bool strToInt(const std::string& str, T &num, std::string* err = nullptr) *err = "needs to be positive"; return false; } + if (str.front() != '+' && isdigit(str.front()) == 0) { + if (err) + *err = "not an integer"; + return false; + } + if (str.size() > 1 && str.front() == '0') { + if (err) + *err = "not an integer"; + return false; + } if (tmp > std::numeric_limits::max()) { if (err) *err = "out of range (limits)"; diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 74763fde027..614d568ea80 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -430,12 +430,7 @@ static void valueFlowNumber(TokenList &tokenlist, const Settings& settings) if (tokenlist.isCPP() || settings.standards.c >= Standards::C23) { for (Token *tok = tokenlist.front(); tok; tok = tok->next()) { - if (tok->isName() && !tok->varId() && Token::Match(tok, "%bool%")) { - ValueFlow::Value value(tok->str() == "true"); - if (!tok->isTemplateArg()) - value.setKnown(); - setTokenValue(tok, std::move(value), settings); - } else if (Token::Match(tok, "[(,] NULL [,)]")) { + if (Token::Match(tok, "[(,] NULL [,)]")) { // NULL function parameters are not simplified in the // normal tokenlist ValueFlow::Value value(0); @@ -4966,6 +4961,24 @@ static void valueFlowCondition(const ValuePtr& handler, handler->afterCondition(tokenlist, symboldatabase, errorLogger, settings, skippedFunctions); } +static const Token* getConditionVariable(const Token* tok) +{ + if (tok->str() == "!") + return tok->astOperand1(); + + if (const Token* parent = tok->astParent()) { + if (Token::Match(parent, "%oror%|&&|?") || + Token::Match(parent->previous(), "if|while (") || + (parent->str() == ";" && astIsLHS(tok) && Token::simpleMatch(parent->astParent(), ";"))) { // for loop condition + if (Token::simpleMatch(tok, "=")) + return tok->astOperand1(); + if (!Token::Match(tok, "%comp%|%assign%")) + return tok; + } + } + return nullptr; +} + struct SimpleConditionHandler : ConditionHandler { std::vector parse(const Token* tok, const Settings& /*settings*/) const override { @@ -4984,19 +4997,7 @@ struct SimpleConditionHandler : ConditionHandler { if (!conds.empty()) return conds; - const Token* vartok = nullptr; - - if (tok->str() == "!") { - vartok = tok->astOperand1(); - - } else if (tok->astParent() && (Token::Match(tok->astParent(), "%oror%|&&|?") || - Token::Match(tok->astParent()->previous(), "if|while ("))) { - if (Token::simpleMatch(tok, "=")) - vartok = tok->astOperand1(); - else if (!Token::Match(tok, "%comp%|%assign%")) - vartok = tok; - } - + const Token* vartok = getConditionVariable(tok); if (!vartok) return {}; Condition cond; @@ -5163,9 +5164,9 @@ struct SymbolicConditionHandler : SimpleConditionHandler { }; static bool valueFlowForLoop2(const Token *tok, - ProgramMemory *memory1, - ProgramMemory *memory2, - ProgramMemory *memoryAfter, + ProgramMemory &memory1, + ProgramMemory &memory2, + ProgramMemory &memoryAfter, const Settings& settings) { // for ( firstExpression ; secondExpression ; thirdExpression ) @@ -5208,13 +5209,10 @@ static bool valueFlowForLoop2(const Token *tok, } // TODO: add bailout message - if (memory1) - memory1->swap(startMemory); + memory1.swap(startMemory); if (!error) { - if (memory2) - memory2->swap(endMemory); - if (memoryAfter) - memoryAfter->swap(programMemory); + memory2.swap(endMemory); + memoryAfter.swap(programMemory); } return true; @@ -5389,7 +5387,7 @@ static void valueFlowForLoop(const TokenList &tokenlist, const SymbolDatabase& s valueFlowForLoopSimplifyAfter(tok, varid, afterValue, tokenlist, errorLogger, settings); } else { ProgramMemory mem1, mem2, memAfter; - if (valueFlowForLoop2(tok, &mem1, &mem2, &memAfter, settings)) { + if (valueFlowForLoop2(tok, mem1, mem2, memAfter, settings)) { for (const auto& p : mem1) { if (!p.second.isIntValue()) continue; diff --git a/lib/vf_common.cpp b/lib/vf_common.cpp index ab01acc0f16..d6c6088b34b 100644 --- a/lib/vf_common.cpp +++ b/lib/vf_common.cpp @@ -154,6 +154,11 @@ namespace ValueFlow if (!tok->isTemplateArg()) value.setKnown(); setTokenValue(tok, std::move(value), settings); + } else if ((tok->isCpp() || settings.standards.c >= Standards::C23) && (tok->isName() && tok->varId() == 0 && Token::Match(tok, "%bool%"))) { + Value value(tok->str() == "true"); + if (!tok->isTemplateArg()) + value.setKnown(); + setTokenValue(tok, std::move(value), settings); } else if (Token::simpleMatch(tok, "sizeof (")) { if (tok->next()->astOperand2() && !tok->next()->astOperand2()->isLiteral() && tok->next()->astOperand2()->valueType() && (tok->next()->astOperand2()->valueType()->pointer == 0 || // <- TODO this is a bailout, abort when there are array->pointer conversions diff --git a/man/manual-ja.docbook b/man/manual-ja.docbook index 1c13d3d0526..0b2a39cc59e 100644 --- a/man/manual-ja.docbook +++ b/man/manual-ja.docbook @@ -1702,11 +1702,11 @@ Checking unusedvar.cpp... - Cppcheck プロジェクトはいくつかのアドオンを以下の場所で提供しています。: http://github.com/danmar/cppcheck/blob/master/addons + Cppcheck プロジェクトはいくつかのアドオンを以下の場所で提供しています。: http://github.com/cppcheck-opensource/cppcheck/blob/master/addons - ublinterは規格で定義されていない未定義動作に注力した"lint"です。: http://github.com/danmar/ublinter + ublinterは規格で定義されていない未定義動作に注力した"lint"です。: http://github.com/cppcheck-opensource/ublinter diff --git a/man/manual-premium.md b/man/manual-premium.md index 8acfb3c0130..4c30dc6d4b3 100644 --- a/man/manual-premium.md +++ b/man/manual-premium.md @@ -1044,7 +1044,7 @@ Cppcheck is distributed with a few addons which are listed below. ### `namingng.py` -[`namingng.py`](https://github.com/danmar/cppcheck/blob/main/addons/namingng.py) allows you to configure and check naming conventions. +[`namingng.py`](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/namingng.py) allows you to configure and check naming conventions. You need to have a configuration file that defines your naming conventions. By default the filename `namingng.config.json` is used but there is an option so you can use any filename you want. @@ -1070,11 +1070,11 @@ Example configuration of naming conventions: ### `threadsafety.py` -[`threadsafety.py`](https://github.com/danmar/cppcheck/blob/main/addons/threadsafety.py) analyses Cppcheck dump files to locate thread safety issues like static local objects used by multiple threads. +[`threadsafety.py`](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/threadsafety.py) analyses Cppcheck dump files to locate thread safety issues like static local objects used by multiple threads. ### `y2038.py` -[`y2038.py`](https://github.com/danmar/cppcheck/blob/main/addons/y2038.py) checks source code for [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) safety. +[`y2038.py`](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/y2038.py) checks source code for [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) safety. ## Running addons diff --git a/man/manual.md b/man/manual.md index de59afe562c..8d8d5b22350 100644 --- a/man/manual.md +++ b/man/manual.md @@ -1045,7 +1045,7 @@ Cppcheck is distributed with a few addons which are listed below. ### `misra.py` -[`misra.py`](https://github.com/danmar/cppcheck/blob/main/addons/misra.py) is used to verify compliance with MISRA C 2012, a proprietary set of guidelines to avoid questionable code, developed for embedded systems. +[`misra.py`](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/misra.py) is used to verify compliance with MISRA C 2012, a proprietary set of guidelines to avoid questionable code, developed for embedded systems. The `misra.py` script does not provide rule texts, those should be downloaded from [MISRA](https://gitlab.com/MISRA/MISRA-C/MISRA-C-2012/tools). @@ -1067,7 +1067,7 @@ Misra checkers in open source Cppcheck only cover MISRA rules partially and for ### `namingng.py` -[`namingng.py`](https://github.com/danmar/cppcheck/blob/main/addons/namingng.py) allows you to configure and check naming conventions. +[`namingng.py`](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/namingng.py) allows you to configure and check naming conventions. You need to have a configuration file that defines your naming conventions. By default the filename `namingng.config.json` is used but there is an option so you can use any filename you want. @@ -1093,11 +1093,11 @@ Example configuration of naming conventions: ### `threadsafety.py` -[`threadsafety.py`](https://github.com/danmar/cppcheck/blob/main/addons/threadsafety.py) analyses Cppcheck dump files to locate thread safety issues like static local objects used by multiple threads. +[`threadsafety.py`](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/threadsafety.py) analyses Cppcheck dump files to locate thread safety issues like static local objects used by multiple threads. ### `y2038.py` -[`y2038.py`](https://github.com/danmar/cppcheck/blob/main/addons/y2038.py) checks source code for [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) safety. +[`y2038.py`](https://github.com/cppcheck-opensource/cppcheck/blob/main/addons/y2038.py) checks source code for [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) safety. ## Running addons diff --git a/readme.md b/readme.md index 7bacadd3456..25db9d2513e 100644 --- a/readme.md +++ b/readme.md @@ -2,7 +2,7 @@ |release-windows|OSS-Fuzz|Coverity Scan Build Status|include-what-you-use|License| |:--:|:--:|:--:|:--:|:--:| -|[![release-windows](https://github.com/danmar/cppcheck/actions/workflows/release-windows.yml/badge.svg?branch=main)](https://github.com/danmar/cppcheck/actions/workflows/release-windows.yml)|[![OSS-Fuzz](https://oss-fuzz-build-logs.storage.googleapis.com/badges/cppcheck.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:cppcheck)|[![Coverity Scan Build Status](https://img.shields.io/coverity/scan/512.svg)](https://scan.coverity.com/projects/512)|[![include-what-you-use](https://github.com/danmar/cppcheck/actions/workflows/iwyu.yml/badge.svg?branch=main)](https://github.com/danmar/cppcheck/actions/workflows/iwyu.yml)|[![License](https://img.shields.io/badge/license-GPL3.0-blue.svg)](https://opensource.org/licenses/GPL-3.0)| +|[![release-windows](https://github.com/cppcheck-opensource/cppcheck/actions/workflows/release-windows.yml/badge.svg?branch=main)](https://github.com/cppcheck-opensource/cppcheck/actions/workflows/release-windows.yml)|[![OSS-Fuzz](https://oss-fuzz-build-logs.storage.googleapis.com/badges/cppcheck.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:cppcheck)|[![Coverity Scan Build Status](https://img.shields.io/coverity/scan/512.svg)](https://scan.coverity.com/projects/512)|[![include-what-you-use](https://github.com/cppcheck-opensource/cppcheck/actions/workflows/iwyu.yml/badge.svg?branch=main)](https://github.com/cppcheck-opensource/cppcheck/actions/workflows/iwyu.yml)|[![License](https://img.shields.io/badge/license-GPL3.0-blue.svg)](https://opensource.org/licenses/GPL-3.0)| ## About the name @@ -263,7 +263,7 @@ Besides building yourself on the platform of your choice there are also several Official packages are maintained by the Cppcheck team. * (Windows) An official Windows installer is available via the official Cppcheck SourceForge page: . -* (Windows) Official builds of the current development versions are available via the [release-windows](https://github.com/danmar/cppcheck/actions/workflows/release-windows.yml) workflow. They are built nightly for the `main` branch and for each commit for release branches. As these are development versions please refrain from using these in production environments! +* (Windows) Official builds of the current development versions are available via the [release-windows](https://github.com/cppcheck-opensource/cppcheck/actions/workflows/release-windows.yml) workflow. They are built nightly for the `main` branch and for each commit for release branches. As these are development versions please refrain from using these in production environments! * A portable package (i.e. does not require installation) is available as the `portable` artifact. This is still a work-in-progress - see for details. * An installer is available via the `installer` artifact. * (Multi-Platform) A premium version with additional features provided by the original author of Cppcheck is available for purchase via . @@ -274,7 +274,7 @@ Third-party packages are ***not*** maintained by the Cppcheck team but their res *Note:* The following list is purely informational and listed in no particular order. -*Note:* Please always try to obtain the package from the primary official source of your operating system/distro first and make sure you are getting the latest released/tagged version (see ). Some packages might not carry the latest patch version though. +*Note:* Please always try to obtain the package from the primary official source of your operating system/distro first and make sure you are getting the latest released/tagged version (see ). Some packages might not carry the latest patch version though. *Note:* Some issues might be related to additional patches carried by the builds in these packages or by the packaging itself. Please try to verify the issue with an official build before reporting it upstream. Otherwise you might need toreport it to the respective maintainer of the package. diff --git a/readmeja.md b/readmeja.md index 6d9dae60c95..7299d61745c 100644 --- a/readmeja.md +++ b/readmeja.md @@ -2,7 +2,7 @@ | Linux ビルド状態 | Windows ビルド状態 | Coverity Scan Build 状態 | |:--:|:--:|:--:| -| [![Linux ビルド状態](https://img.shields.io/travis/danmar/cppcheck/master.svg?label=Linux%20build)](https://travis-ci.org/danmar/cppcheck) | [![Windows ビルド状態](https://img.shields.io/appveyor/ci/danmar/cppcheck/master.svg?label=Windows%20build)](https://ci.appveyor.com/project/danmar/cppcheck/branch/master) | [![Coverity Scan Build 状態](https://img.shields.io/coverity/scan/512.svg)](https://scan.coverity.com/projects/512) | +| [![Linux ビルド状態](https://img.shields.io/travis/cppcheck-opensource/cppcheck/master.svg?label=Linux%20build)](https://travis-ci.org/cppcheck-opensource/cppcheck) | [![Windows ビルド状態](https://img.shields.io/appveyor/ci/cppcheck-opensource/cppcheck/master.svg?label=Windows%20build)](https://ci.appveyor.com/project/cppcheck-opensource/cppcheck/branch/master) | [![Coverity Scan Build 状態](https://img.shields.io/coverity/scan/512.svg)](https://scan.coverity.com/projects/512) | ## 名前について diff --git a/releasenotes.txt b/releasenotes.txt index 38a9e1a41ae..d2ff9c94044 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -23,5 +23,5 @@ Infrastructure & dependencies: Other: - Make it possible to specify the regular expression engine using the `engine` element in a rule XML. - Added CLI option `--exitcode-suppress` to specify an error ID which should not result in a non-zero exitcode. -- +- Moved source code from https://github.com/danmar/cppcheck to https://github.com/cppcheck-opensource/cppcheck - diff --git a/test/cli/other_test.py b/test/cli/other_test.py index e28a7305ce9..9735c94482b 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -9,7 +9,7 @@ import subprocess import shutil -from testutils import cppcheck, assert_cppcheck, cppcheck_ex, __lookup_cppcheck_exe +from testutils import cppcheck, assert_cppcheck, cppcheck_ex, __lookup_cppcheck_exe, create_compile_commands from xml.etree import ElementTree @@ -420,7 +420,7 @@ def test_addon_misra(tmpdir): assert lines == [ 'Checking {} ...'.format(test_file) ] - assert stderr == '{}:2:1: style: misra violation (use --rule-texts= to get proper output) [misra-c2012-2.3]\ntypedef int MISRA_5_6_VIOLATION;\n^\n'.format(test_file) + assert stderr == '{}:2:13: style: misra violation (use --rule-texts= to get proper output) [misra-c2012-2.3]\ntypedef int MISRA_5_6_VIOLATION;\n ^\n'.format(test_file) def test_addon_y2038(tmpdir): @@ -956,10 +956,9 @@ def test_unused_function_include(tmpdir): # TODO: test with clang-tidy # TODO: test with --addon -# TODO: test with FileSettings # TODO: test with multiple files -def __test_showtime(tmp_path, showtime, exp_res, exp_last, extra_args=None): - test_file = tmp_path / 'test.cpp' +def __test_showtime(tmp_path, showtime, exp_res, exp_last, use_compdb, extra_args=None): + test_file = tmp_path / 'test.cpp' # the use of C++ is intentional with open(test_file, 'wt') as f: f.write( """ @@ -972,10 +971,17 @@ def __test_showtime(tmp_path, showtime, exp_res, exp_last, extra_args=None): args = [ f'--showtime={showtime}', '--quiet', - '--inline-suppr', - str(test_file) + '--inline-suppr' ] + if use_compdb: + compdb_file = tmp_path / 'compile_commands.json' + create_compile_commands(compdb_file, [test_file]) + + args.append(f'--project={compdb_file}') + else: + args.append(str(test_file)) + if extra_args: args += extra_args @@ -994,50 +1000,122 @@ def __test_showtime(tmp_path, showtime, exp_res, exp_last, extra_args=None): assert stderr == '' +def __test_showtime_top5_file(tmp_path, use_compdb): + __test_showtime(tmp_path, 'top5_file', 5, 'Check time: ', use_compdb) + + def test_showtime_top5_file(tmp_path): - __test_showtime(tmp_path, 'top5_file', 5, 'Check time: ') + __test_showtime_top5_file(tmp_path, False) + + +def test_showtime_top5_file_compdb(tmp_path): + __test_showtime_top5_file(tmp_path, True) + + +# TODO: remove extra args when --executor=process works +def __test_showtime_top5_summary(tmp_path, use_compdb): + __test_showtime(tmp_path, 'top5_summary', 5, 'Overall time: ', use_compdb, ['-j1']) -# TODO: remove extra args when --executor=process works works def test_showtime_top5_summary(tmp_path): - __test_showtime(tmp_path, 'top5_summary', 5, 'Overall time: ', ['-j1']) + __test_showtime_top5_summary(tmp_path, False) + +def test_showtime_top5_summary_compdb(tmp_path): + __test_showtime_top5_summary(tmp_path, True) -# TODO: remove when --executor=process works works + +# TODO: remove when --executor=process works def test_showtime_top5_summary_j_thread(tmp_path): - __test_showtime(tmp_path, 'top5_summary', 5, 'Overall time: ', ['-j2', '--executor=thread']) + __test_showtime(tmp_path, 'top5_summary', 5, 'Overall time: ', False, ['-j2', '--executor=thread']) + + +# TODO: remove when --executor=process works +def test_showtime_top5_summary_compdb_j_thread(tmp_path): + __test_showtime(tmp_path, 'top5_summary', 5, 'Overall time: ', True, ['-j2', '--executor=thread']) # TODO: remove override when fixed @pytest.mark.skipif(sys.platform == 'win32', reason="requires ProcessExecutor") @pytest.mark.xfail(strict=True) # TODO: need to transfer the timer results to parent process - see #4452 def test_showtime_top5_summary_j_process(tmp_path): - __test_showtime(tmp_path, 'top5_summary', 5, 'Overall time: ', ['-j2', '--executor=process']) + __test_showtime(tmp_path, 'top5_summary', 5, 'Overall time: ', False, ['-j2', '--executor=process']) + + +# TODO: remove override when fixed +@pytest.mark.skipif(sys.platform == 'win32', reason="requires ProcessExecutor") +@pytest.mark.xfail(strict=True) # TODO: need to transfer the timer results to parent process - see #4452 +def test_showtime_top5_summary_compdb_j_process(tmp_path): + __test_showtime(tmp_path, 'top5_summary', 5, 'Overall time: ', True, ['-j2', '--executor=process']) + + +def __test_showtime_file(tmp_path, use_compdb): + exp_res = 79 + # project analysis does not call Preprocessor::getConfig() + if use_compdb: + exp_res -= 1 + __test_showtime(tmp_path, 'file', exp_res, 'Check time: ', use_compdb) def test_showtime_file(tmp_path): - __test_showtime(tmp_path, 'file', 79, 'Check time: ') + __test_showtime_file(tmp_path, False) + + +def test_showtime_file_compdb(tmp_path): + __test_showtime_file(tmp_path, True) + + +# TODO: remove extra args when --executor=process works +def __test_showtime_summary(tmp_path, use_compdb): + exp_res = 79 + # project analysis does not call Preprocessor::getConfig() + if use_compdb: + exp_res -= 1 + __test_showtime(tmp_path, 'summary', exp_res, 'Overall time: ', use_compdb, ['-j1']) -# TODO: remove extra args when --executor=process works works def test_showtime_summary(tmp_path): - __test_showtime(tmp_path, 'summary', 79, 'Overall time: ', ['-j1']) + __test_showtime_summary(tmp_path, False,) + +def test_showtime_summary_compdb(tmp_path): + __test_showtime_summary(tmp_path, True) -# TODO: remove when --executor=process works works + +# TODO: remove when --executor=process works def test_showtime_summary_j_thread(tmp_path): - __test_showtime(tmp_path, 'summary', 79, 'Overall time: ', ['-j2', '--executor=thread']) + __test_showtime(tmp_path, 'summary', 79, 'Overall time: ', False, ['-j2', '--executor=thread']) + + +# TODO: remove when --executor=process works +def test_showtime_summary_compdb_j_thread(tmp_path): + __test_showtime(tmp_path, 'summary', 78, 'Overall time: ', True, ['-j2', '--executor=thread']) # TODO: remove override when fixed @pytest.mark.skipif(sys.platform == 'win32', reason="requires ProcessExecutor") @pytest.mark.xfail(strict=True) # TODO: need to transfer the timer results to parent process - see #4452 def test_showtime_summary_j_process(tmp_path): - __test_showtime(tmp_path, 'summary', 79, 'Overall time: ', ['-j2', '--executor=process']) + __test_showtime(tmp_path, 'summary', 79, 'Overall time: ', False, ['-j2', '--executor=process']) + + +# TODO: remove override when fixed +@pytest.mark.skipif(sys.platform == 'win32', reason="requires ProcessExecutor") +@pytest.mark.xfail(strict=True) # TODO: need to transfer the timer results to parent process - see #4452 +def test_showtime_summary_compdb_j_process(tmp_path): + __test_showtime(tmp_path, 'summary', 78, 'Overall time: ', True, ['-j2', '--executor=process']) + + +def __test_showtime_file_total(tmp_path, use_compdb): + __test_showtime(tmp_path, 'file-total', 0, 'Check time: ', use_compdb) def test_showtime_file_total(tmp_path): - __test_showtime(tmp_path, 'file-total', 0, 'Check time: ') + __test_showtime_file_total(tmp_path, False) + + +def test_showtime_file_total_compdb(tmp_path): + __test_showtime_file_total(tmp_path, True) def test_showtime_unique(tmp_path): @@ -2674,7 +2752,7 @@ def __test_addon_suppr(tmp_path, extra_args): assert exitcode == 0, stdout assert stdout == '' assert stderr.splitlines() == [ - '{}:4:1: style: misra violation (use --rule-texts= to get proper output) [misra-c2012-2.3]'.format(test_file), + '{}:4:13: style: misra violation (use --rule-texts= to get proper output) [misra-c2012-2.3]'.format(test_file), ] diff --git a/test/cli/testutils.py b/test/cli/testutils.py index f352af49f15..2140c42205b 100644 --- a/test/cli/testutils.py +++ b/test/cli/testutils.py @@ -5,6 +5,7 @@ import subprocess import time import tempfile +import json # Create Cppcheck project file import sys @@ -45,6 +46,22 @@ def create_gui_project_file(project_file, root_path=None, import_project=None, p f.write(cppcheck_xml) +def create_compile_commands(compdb_file, files): + compdb = [] + # TODO: bail out on empty list + for f in files: + compdb.append( + { + "file": str(f), + "directory": os.path.dirname(f), + "command": "gcc -c {}".format(os.path.basename(f)) + } + ) + compdb_j = json.dumps(compdb) + with open(compdb_file, 'wt') as f: + f.write(compdb_j) + + def __lookup_cppcheck_exe(): # path the script is located in script_path = os.path.dirname(os.path.realpath(__file__)) diff --git a/test/options.cpp b/test/options.cpp index bdb4f553ac8..9db2bce8563 100644 --- a/test/options.cpp +++ b/test/options.cpp @@ -59,10 +59,8 @@ options::options(int argc, const char* const argv[]) options::~options() { // TODO: allow more than 5 results to be shown - // TODO: provide higher resolution in output - // TODO: disable the metrics if (mTimerResults) - mTimerResults->showResults(ShowTime::TOP5_FILE); + mTimerResults->showResults(ShowTime::TOP5_FILE, false); } bool options::quiet() const diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index 71dd068b39e..06ee30837d6 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -1236,7 +1236,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "--error-exitcode=", "file.cpp"}; // Fails since exit code not given ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--error-exitcode=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--error-exitcode=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void errorExitcodeStr() { @@ -1244,7 +1244,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "--error-exitcode=foo", "file.cpp"}; // Fails since invalid exit code ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--error-exitcode=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--error-exitcode=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void exitcodeSuppressionsOld() { @@ -1395,7 +1395,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "-j", "file.cpp"}; // Fails since -j is missing thread count ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '-j' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '-j' is not valid - not an integer (invalid_argument).\n", logger->str()); } void jobsInvalid() { @@ -1403,7 +1403,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "-j", "e", "file.cpp"}; // Fails since invalid count given for -j ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '-j' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '-j' is not valid - not an integer (invalid_argument).\n", logger->str()); } void jobsNoJobs() { @@ -1433,7 +1433,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "--max-configs=", "file.cpp"}; // Fails since --max-configs= is missing limit ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--max-configs=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--max-configs=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void maxConfigsInvalid() { @@ -1441,7 +1441,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "--max-configs=e", "file.cpp"}; // Fails since invalid count given for --max-configs= ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); - ASSERT_EQUALS("cppcheck: error: argument to '--max-configs=' is not valid - not an integer.\n", logger->str()); + ASSERT_EQUALS("cppcheck: error: argument to '--max-configs=' is not valid - not an integer (invalid_argument).\n", logger->str()); } void maxConfigsTooSmall() { @@ -1672,7 +1672,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() { @@ -2172,7 +2172,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() { @@ -2395,7 +2395,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() { @@ -2423,7 +2423,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 @@ -2445,7 +2445,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() { @@ -2482,7 +2482,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() { @@ -2496,7 +2496,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() { @@ -2510,7 +2510,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() { @@ -2524,7 +2524,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() { @@ -2545,7 +2545,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() { @@ -3235,7 +3235,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() { diff --git a/test/testerrorlogger.cpp b/test/testerrorlogger.cpp index 812ea500299..23b3233995c 100644 --- a/test/testerrorlogger.cpp +++ b/test/testerrorlogger.cpp @@ -599,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 @@ -615,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/testgarbage.cpp b/test/testgarbage.cpp index 5f6b67867f7..68715b78ae8 100644 --- a/test/testgarbage.cpp +++ b/test/testgarbage.cpp @@ -320,7 +320,6 @@ class TestGarbage : public TestFixture { void final_class_x() { - const char code[] = "class __declspec(dllexport) x final { };"; SimpleTokenizer tokenizer(settings, *this); ASSERT(tokenizer.tokenize(code)); @@ -1897,6 +1896,12 @@ class TestGarbage : public TestFixture { // #13892 ASSERT_NO_THROW(checkCode("void foovm(int x[const *]);")); + + // #14676 + ASSERT_NO_THROW(checkCode("int main() {\n" + " auto value = m[1 + qRow<>];\n" + "}\n")); + ignore_errout(); } }; diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 83a19c40805..967cd0d2315 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -3723,6 +3723,13 @@ class TestNullPointer : public TestFixture { 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() { diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 4e227bfca17..88d1a4b2725 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -2207,6 +2207,7 @@ class TestSimplifyTokens : public TestFixture { "for ( i = 0 ; ( i < sz ) && ( sz > 3 ) ; ++ i ) { }\n" "}"; ASSERT_EQUALS(expected, tokenizeAndStringify(code, dinit(TokenizeAndStringifyOptions, $.cpp = false))); + ignore_errout(); } void simplifyKnownVariables49() { // #3691 diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 092c9e9df75..342cda59dc8 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -4615,7 +4615,7 @@ class TestSimplifyTypedef : public TestFixture { void typedefInfo1() { const std::string xml = dumpTypedefInfo("typedef int A;\nA x;"); ASSERT_EQUALS(" \n" - " \n" + " \n" " \n", xml); } @@ -4627,7 +4627,7 @@ class TestSimplifyTypedef : public TestFixture { " typedef fp16 ( *pfp16 ) ( void );\n" "}\n"); ASSERT_EQUALS(" \n" - " \n" + " \n" " \n" " \n" " \n" @@ -4639,7 +4639,7 @@ class TestSimplifyTypedef : public TestFixture { " \n" " \n" " \n" - " \n" + " \n" " \n" " \n" " \n" @@ -4677,7 +4677,7 @@ class TestSimplifyTypedef : public TestFixture { "} coord;\n" "coord c;"); ASSERT_EQUALS(" \n" - " \n" + " \n" " \n", xml); } }; diff --git a/test/testsuppressions.cpp b/test/testsuppressions.cpp index 3233a5918c7..49d46149c90 100644 --- a/test/testsuppressions.cpp +++ b/test/testsuppressions.cpp @@ -188,12 +188,12 @@ class TestSuppressions : public TestFixture { ASSERT_THROW_EQUALS(SuppressionList::parseLine("id::1"), std::runtime_error, "filename is missing"); // missing/invalid line - ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer)"); - ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:\n"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer)"); - ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:\n1"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer)"); - ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:#1"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer)"); // TODO: looks like a valid filename - ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c://1"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer)"); - ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:zero"), std::runtime_error, "invalid line number (converting 'zero' to integer failed - not an integer)"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer (invalid_argument))"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:\n"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer (invalid_argument))"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:\n1"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer (invalid_argument))"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:#1"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer (invalid_argument))"); // TODO: looks like a valid filename + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c://1"), std::runtime_error, "invalid line number (converting '' to integer failed - not an integer (invalid_argument))"); + ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:zero"), std::runtime_error, "invalid line number (converting 'zero' to integer failed - not an integer (invalid_argument))"); // invalid extras ASSERT_THROW_EQUALS(SuppressionList::parseLine("id:1.c:1\n"), std::runtime_error, "unexpected extra ''"); diff --git a/test/testtimer.cpp b/test/testtimer.cpp index c8d468b1afb..3f160c0c2b7 100644 --- a/test/testtimer.cpp +++ b/test/testtimer.cpp @@ -33,7 +33,7 @@ class TestTimer : public TestFixture { void result() const { TimerResultsData t1; - t1.mDuration = std::chrono::milliseconds{1234}; + t1.mResults.emplace_back(1234); ASSERT(t1.getSeconds().count() > 1.233 && t1.getSeconds().count() < 1.235); // TODO : more tests diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 0798983c079..9b816a357b7 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -5288,12 +5288,7 @@ class TestTokenizer : public TestFixture { "if ( ! p ) {\n" "throw std :: runtime_error ( \"abc\" ) ; }\n" "}"; - TODO_ASSERT_EQUALS(expected, - "void f ( const std :: unique_ptr < int > & p ) {\n" - "if ( ! p ) {\n" - "throw runtime_error ( \"abc\" ) ; }\n" - "}", - tokenizeAndStringify(code)); + ASSERT_EQUALS(expected, tokenizeAndStringify(code)); } { @@ -5315,6 +5310,17 @@ class TestTokenizer : public TestFixture { "}"; ASSERT_EQUALS(expected, tokenizeAndStringify(code)); } + + { + const char code[] = "using namespace std;\n" + "string_view f() { return string(); }\n" + "void move() {}\n" + "void string() {}\n"; + expected = "std :: string_view f ( ) { return std :: string ( ) ; }\n" + "void move ( ) { }\n" + "void string ( ) { }"; + ASSERT_EQUALS(expected, tokenizeAndStringify(code)); + } } void microsoftMemory() { diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 9a116bdaa2b..13d288a3fdd 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -198,6 +198,7 @@ class TestUnusedVar : public TestFixture { TEST_CASE(localvarreturn); // ticket #9167 TEST_CASE(localvarmaybeunused); TEST_CASE(localvarrvalue); // ticket #13977 + TEST_CASE(localvarreferencearray); // ticket #14637 TEST_CASE(localvarthrow); // ticket #3687 @@ -249,6 +250,7 @@ class TestUnusedVar : public TestFixture { TEST_CASE(localvarDelete); TEST_CASE(localvarLambda); // #8941, #8948 TEST_CASE(localvarStructuredBinding); // #10368 + TEST_CASE(localvarPtrToPtr); TEST_CASE(localvarCppInitialization); TEST_CASE(localvarCpp11Initialization); @@ -6557,6 +6559,16 @@ class TestUnusedVar : public TestFixture { ASSERT_EQUALS("[test.cpp:3:21]: (style) Variable 'm' is assigned a value that is never used. [unreadVariable]\n", errout_str()); } + void localvarreferencearray() { // ticket #14637 + functionVariableUsage("int f() {\n" + " int a[1];\n" + " int(&r)[1] = a;\n" + " r[0] = 0;\n" + " return r[0];\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void localvarthrow() { // ticket #3687 functionVariableUsage("void foo() {\n" " try {}" @@ -6958,6 +6970,16 @@ class TestUnusedVar : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void localvarPtrToPtr() { + functionVariableUsage("int main() {\n" + " int *p, **pp = &p;\n" + " int i = 123;\n" + " *pp = &i;\n" + " return *p;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void localvarCppInitialization() { functionVariableUsage("void foo() {\n" " int buf[6];\n" diff --git a/test/testutils.cpp b/test/testutils.cpp index 85da8c6c595..8e91108c3f4 100644 --- a/test/testutils.cpp +++ b/test/testutils.cpp @@ -223,19 +223,57 @@ class TestUtils : public TestFixture { void strToInt() { ASSERT_EQUALS(1, ::strToInt("1")); + ASSERT_EQUALS(1, ::strToInt("+1")); ASSERT_EQUALS(-1, ::strToInt("-1")); ASSERT_EQUALS(1, ::strToInt("1")); - ASSERT_THROW_EQUALS(::strToInt(""), std::runtime_error, "converting '' to integer failed - not an integer"); - ASSERT_THROW_EQUALS(::strToInt(""), std::runtime_error, "converting '' to integer failed - not an integer"); - ASSERT_THROW_EQUALS(::strToInt(" "), std::runtime_error, "converting ' ' to integer failed - not an integer"); - ASSERT_THROW_EQUALS(::strToInt(" "), std::runtime_error, "converting ' ' to integer failed - not an integer"); + ASSERT_EQUALS(1, ::strToInt("+1")); + ASSERT_EQUALS(0, ::strToInt("0")); + ASSERT_EQUALS(0, ::strToInt("+0")); + ASSERT_EQUALS(0, ::strToInt("-0")); + ASSERT_EQUALS(0, ::strToInt("0")); + ASSERT_EQUALS(0, ::strToInt("+0")); + ASSERT_THROW_EQUALS(::strToInt(""), std::runtime_error, "converting '' to integer failed - not an integer (invalid_argument)"); + ASSERT_THROW_EQUALS(::strToInt(""), std::runtime_error, "converting '' to integer failed - not an integer (invalid_argument)"); + ASSERT_THROW_EQUALS(::strToInt(" "), std::runtime_error, "converting ' ' to integer failed - not an integer (invalid_argument)"); + ASSERT_THROW_EQUALS(::strToInt(" "), std::runtime_error, "converting ' ' to integer failed - not an integer (invalid_argument)"); ASSERT_THROW_EQUALS(::strToInt("-1"), std::runtime_error, "converting '-1' to integer failed - needs to be positive"); - ASSERT_THROW_EQUALS(::strToInt("1ms"), std::runtime_error, "converting '1ms' to integer failed - not an integer"); - ASSERT_THROW_EQUALS(::strToInt("1.0"), std::runtime_error, "converting '1.0' to integer failed - not an integer"); - ASSERT_THROW_EQUALS(::strToInt("one"), std::runtime_error, "converting 'one' to integer failed - not an integer"); - ASSERT_THROW_EQUALS(::strToInt("1ms"), std::runtime_error, "converting '1ms' to integer failed - not an integer"); - ASSERT_THROW_EQUALS(::strToInt("1.0"), std::runtime_error, "converting '1.0' to integer failed - not an integer"); - ASSERT_THROW_EQUALS(::strToInt("one"), std::runtime_error, "converting 'one' to integer failed - not an integer"); + ASSERT_THROW_EQUALS(::strToInt("-0"), std::runtime_error, "converting '-0' to integer failed - needs to be positive"); + ASSERT_THROW_EQUALS(::strToInt("-1"), std::runtime_error, "converting '-1' to integer failed - needs to be positive"); + ASSERT_THROW_EQUALS(::strToInt("-0"), std::runtime_error, "converting '-0' to integer failed - needs to be positive"); + ASSERT_THROW_EQUALS(::strToInt("1ms"), std::runtime_error, "converting '1ms' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("1.0"), std::runtime_error, "converting '1.0' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("+1.0"), std::runtime_error, "converting '+1.0' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("-1.0"), std::runtime_error, "converting '-1.0' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("1U"), std::runtime_error, "converting '1U' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("1L"), std::runtime_error, "converting '1L' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("1Z"), std::runtime_error, "converting '1Z' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("01"), std::runtime_error, "converting '01' to integer failed - not an integer"); + ASSERT_THROW_EQUALS(::strToInt("0x1"), std::runtime_error, "converting '0x1' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("0b1"), std::runtime_error, "converting '0b1' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("one"), std::runtime_error, "converting 'one' to integer failed - not an integer (invalid_argument)"); + ASSERT_THROW_EQUALS(::strToInt(" 1"), std::runtime_error, "converting ' 1' to integer failed - not an integer"); + ASSERT_THROW_EQUALS(::strToInt("\t1"), std::runtime_error, "converting '\t1' to integer failed - not an integer"); + ASSERT_THROW_EQUALS(::strToInt("1 "), std::runtime_error, "converting '1 ' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("1\t"), std::runtime_error, "converting '1\t' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("+ 1"), std::runtime_error, "converting '+ 1' to integer failed - not an integer (invalid_argument)"); + ASSERT_THROW_EQUALS(::strToInt("O1"), std::runtime_error, "converting 'O1' to integer failed - not an integer (invalid_argument)"); + ASSERT_THROW_EQUALS(::strToInt("1ms"), std::runtime_error, "converting '1ms' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("1.0"), std::runtime_error, "converting '1.0' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("+1.0"), std::runtime_error, "converting '+1.0' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("-1.0"), std::runtime_error, "converting '-1.0' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("1U"), std::runtime_error, "converting '1U' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("1L"), std::runtime_error, "converting '1L' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("1Z"), std::runtime_error, "converting '1Z' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("01"), std::runtime_error, "converting '01' to integer failed - not an integer"); + ASSERT_THROW_EQUALS(::strToInt("0x1"), std::runtime_error, "converting '0x1' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("0b1"), std::runtime_error, "converting '0b1' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("one"), std::runtime_error, "converting 'one' to integer failed - not an integer (invalid_argument)"); + ASSERT_THROW_EQUALS(::strToInt(" 1"), std::runtime_error, "converting ' 1' to integer failed - not an integer"); + ASSERT_THROW_EQUALS(::strToInt("\t1"), std::runtime_error, "converting '\t1' to integer failed - not an integer"); + ASSERT_THROW_EQUALS(::strToInt("1 "), std::runtime_error, "converting '1 ' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("1\t"), std::runtime_error, "converting '1\t' to integer failed - not an integer (pos)"); + ASSERT_THROW_EQUALS(::strToInt("- 1"), std::runtime_error, "converting '- 1' to integer failed - not an integer (invalid_argument)"); + ASSERT_THROW_EQUALS(::strToInt("O1"), std::runtime_error, "converting 'O1' to integer failed - not an integer (invalid_argument)"); ASSERT_THROW_EQUALS(::strToInt(std::to_string(static_cast(std::numeric_limits::max()) + 1)), std::runtime_error, "converting '2147483648' to integer failed - out of range (limits)"); ASSERT_THROW_EQUALS(::strToInt(std::to_string(static_cast(std::numeric_limits::min()) - 1)), std::runtime_error, "converting '-2147483649' to integer failed - out of range (limits)"); ASSERT_THROW_EQUALS(::strToInt(std::to_string(static_cast(std::numeric_limits::max()) + 1)), std::runtime_error, "converting '128' to integer failed - out of range (limits)"); @@ -311,25 +349,25 @@ class TestUtils : public TestFixture { long tmp; std::string err; ASSERT(!::strToInt("1ms", tmp, &err)); - ASSERT_EQUALS("not an integer", err); + ASSERT_EQUALS("not an integer (pos)", err); } { long tmp; std::string err; ASSERT(!::strToInt("1.0", tmp, &err)); - ASSERT_EQUALS("not an integer", err); + ASSERT_EQUALS("not an integer (pos)", err); } { long tmp; std::string err; ASSERT(!::strToInt("one", tmp, &err)); - ASSERT_EQUALS("not an integer", err); + ASSERT_EQUALS("not an integer (invalid_argument)", err); } { std::size_t tmp; std::string err; ASSERT(!::strToInt("1ms", tmp, &err)); - ASSERT_EQUALS("not an integer", err); + ASSERT_EQUALS("not an integer (pos)", err); } { long tmp; diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index b8b31e8d248..d8a5b533bf3 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -1207,6 +1207,16 @@ class TestValueFlow : public TestFixture { ASSERT_EQUALS(1U, values.size()); ASSERT_EQUALS(123, values.empty() ? 0 : values.front().intvalue); + code = "x = true ? 2 : 3;\n"; // #14369 + values = tokenValues(code, "?"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(2, values.empty() ? 0 : values.front().intvalue); + + code = "x = false ? 2 : 3;\n"; // #14369 + values = tokenValues(code, "?"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(3, values.empty() ? 0 : values.front().intvalue); + code = "int f() {\n" " const int i = 1;\n" " int x = i < 0 ? 0 : 1;\n" diff --git a/test/testvarid.cpp b/test/testvarid.cpp index 007e16ffb29..64b7b6664be 100644 --- a/test/testvarid.cpp +++ b/test/testvarid.cpp @@ -4500,7 +4500,7 @@ class TestVarID : public TestFixture { "2: struct T { struct S s ; } ;\n" "3: struct U { struct T t ; } ;\n" "4: void f ( ) {\n" - "5: struct U u@4 ; u@4 = { .@UNIQUE t@5 = { . s = { . s = 1 } } } ;\n" + "5: struct U u@4 ; u@4 = { .@UNIQUE t@5 = { .@UNIQUE s@6 = { .@UNIQUE s@7 = 1 } } } ;\n" "6: }\n"; ASSERT_EQUALS(exp, tokenizeExpr(code)); } diff --git a/tools/bisect/bisect.sh b/tools/bisect/bisect.sh index cf0d4cd5b96..067cd9606aa 100644 --- a/tools/bisect/bisect.sh +++ b/tools/bisect/bisect.sh @@ -26,7 +26,7 @@ mkdir -p "$bisect_dir" || exit 1 cd "$bisect_dir" || exit 1 if [ ! -d 'cppcheck' ]; then - git clone https://github.com/danmar/cppcheck.git || exit 1 + git clone https://github.com/cppcheck-opensource/cppcheck.git || exit 1 fi bisect_repo_dir="$bisect_dir/cppcheck" diff --git a/tools/dmake/dmake.cpp b/tools/dmake/dmake.cpp index 82754f1df11..80f3aa35b83 100644 --- a/tools/dmake/dmake.cpp +++ b/tools/dmake/dmake.cpp @@ -771,8 +771,13 @@ int main(int argc, char **argv) << " $(error invalid HAVE_RULES value '$(HAVE_RULES)')\n" << "endif\n\n"; - // the # needs to be escaped on older make versions - fout << "HAVE_EXECINFO_H=$(shell echo \"\\#include \" | $(CXX) -c -xc - 2> /dev/null && echo \"1\" || echo \"0\")\n" + fout << "# older make versions do not support # in $(shell) and newer ones handle the escape sequence literally\n" + << "REQUIRE_ESCAPE=$(shell echo \"\\#define DEF\" | $(CXX) -c -xc - 2> /dev/null && echo \"1\" || echo \"0\")\n" + << "ifeq ($(REQUIRE_ESCAPE),1)\n" + << " HAVE_EXECINFO_H=$(shell echo \"\\#include \" | $(CXX) -c -xc - 2> /dev/null && echo \"1\" || echo \"0\")\n" + << "else\n" + << " HAVE_EXECINFO_H=$(shell echo \"#include \" | $(CXX) -c -xc - 2> /dev/null && echo \"1\" || echo \"0\")\n" + << "endif\n" << "override CPPFLAGS += -DHAVE_EXECINFO_H=$(HAVE_EXECINFO_H)\n\n"; fout << "override CXXFLAGS += $(CXXOPTS)\n"; diff --git a/tools/donate_cpu_lib.py b/tools/donate_cpu_lib.py index 44d3157bc40..c292d2b9a13 100644 --- a/tools/donate_cpu_lib.py +++ b/tools/donate_cpu_lib.py @@ -16,12 +16,12 @@ # Version scheme (MAJOR.MINOR.PATCH) should orientate on "Semantic Versioning" https://semver.org/ # Every change in this script should result in increasing the version number accordingly (exceptions may be cosmetic # changes) -CLIENT_VERSION = "1.3.70" +CLIENT_VERSION = "1.4.0" # Timeout for analysis with Cppcheck in seconds CPPCHECK_TIMEOUT = 30 * 60 -CPPCHECK_REPO_URL = "https://github.com/danmar/cppcheck.git" +CPPCHECK_REPO_URL = "https://github.com/cppcheck-opensource/cppcheck.git" # Return code that is used to mark a timed out analysis RETURN_CODE_TIMEOUT = -999 @@ -133,7 +133,7 @@ def checkout_cppcheck_version(repo_path, version, cppcheck_path): hash_old = subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD'], cwd=cppcheck_path).strip() print('Pulling {}'.format(version)) - # --rebase is a workaround for a dropped commit - see https://github.com/danmar/cppcheck/pull/6904 + # --rebase is a workaround for a dropped commit - see https://github.com/cppcheck-opensource/cppcheck/pull/6904 # TODO: drop the commit in question # TOD: remove --rebase subprocess.check_call(['git', 'pull', '--rebase'], cwd=cppcheck_path) diff --git a/tools/test-my-pr.py b/tools/test-my-pr.py index 4a40f544ee1..e0ed773afef 100755 --- a/tools/test-my-pr.py +++ b/tools/test-my-pr.py @@ -8,9 +8,13 @@ import donate_cpu_lib as lib import argparse import glob +import gzip +import natsort import os import sys import random +import re +import requests import subprocess @@ -20,6 +24,100 @@ def format_float(a, b=1): return 'N/A' +def ftp_get(url): + try: + response = requests.get(url, timeout=300) + response.raise_for_status() + return response.content + except requests.RequestException as err: + print('Failed to fetch {}: {}'.format(url, err)) + return None + + +def latestvername(names): + s = natsort.natsorted(names, key=lambda x: x[x.index('_')+1:x.index('.orig.tar')]) + return s[-1] + + +def getpackages(): + debian = 'https://ftp.debian.org/debian/' + + data = ftp_get(debian + 'ls-lR.gz') + if data is None: + print('Failed to fetch ls-lR.gz') + sys.exit(1) + + lines = gzip.decompress(data).decode('utf-8', errors='replace').splitlines() + + # Example content in ls-lR: + #./pool/main/0/0xffff: + #total 1452 + #-rw-r--r-- 2 dak debadmin 6524 Dec 25 2016 0xffff_0.7-2.debian.tar.xz + #-rw-r--r-- 2 dak debadmin 1791 Dec 25 2016 0xffff_0.7-2.dsc + #-rw-r--r-- 2 dak debadmin 57168 Dec 25 2016 0xffff_0.7-2_amd64.deb + #-rw-r--r-- 2 dak debadmin 48578 Dec 26 2016 0xffff_0.7-2_arm64.deb + #-rw-r--r-- 2 dak debadmin 56730 Dec 26 2016 0xffff_0.7-2_armel.deb + #-rw-r--r-- 2 dak debadmin 57296 Dec 26 2016 0xffff_0.7-2_armhf.deb + #-rw-r--r-- 2 dak debadmin 60254 Dec 26 2016 0xffff_0.7-2_i386.deb + #-rw-r--r-- 2 dak debadmin 53130 Dec 26 2016 0xffff_0.7-2_mips.deb + #-rw-r--r-- 2 dak debadmin 52542 Dec 26 2016 0xffff_0.7-2_mips64el.deb + #-rw-r--r-- 2 dak debadmin 53712 Dec 26 2016 0xffff_0.7-2_mipsel.deb + #-rw-r--r-- 2 dak debadmin 51908 Dec 26 2016 0xffff_0.7-2_ppc64el.deb + #-rw-r--r-- 2 dak debadmin 53548 Dec 26 2016 0xffff_0.7-2_s390x.deb + #-rw-r--r-- 2 dak debadmin 65248 Dec 25 2016 0xffff_0.7.orig.tar.gz + #-rw-r--r-- 2 dak debadmin 6884 Jul 19 19:08 0xffff_0.8-1.debian.tar.xz + #-rw-r--r-- 2 dak debadmin 1807 Jul 19 19:08 0xffff_0.8-1.dsc + #-rw-r--r-- 2 dak debadmin 58908 Jul 19 19:08 0xffff_0.8-1_amd64.deb + #-rw-r--r-- 2 dak debadmin 51340 Jul 19 19:58 0xffff_0.8-1_arm64.deb + #-rw-r--r-- 2 dak debadmin 57612 Jul 19 20:13 0xffff_0.8-1_armel.deb + #-rw-r--r-- 2 dak debadmin 58584 Jul 19 19:58 0xffff_0.8-1_armhf.deb + #-rw-r--r-- 2 dak debadmin 57544 Jul 19 20:23 0xffff_0.8-1_hurd-i386.deb + #-rw-r--r-- 2 dak debadmin 62048 Jul 19 23:54 0xffff_0.8-1_i386.deb + #-rw-r--r-- 2 dak debadmin 55080 Jul 23 19:07 0xffff_0.8-1_kfreebsd-amd64.deb + #-rw-r--r-- 2 dak debadmin 58392 Jul 23 19:07 0xffff_0.8-1_kfreebsd-i386.deb + #-rw-r--r-- 2 dak debadmin 54144 Jul 19 22:28 0xffff_0.8-1_mips.deb + #-rw-r--r-- 2 dak debadmin 53648 Jul 20 00:56 0xffff_0.8-1_mips64el.deb + #-rw-r--r-- 2 dak debadmin 54740 Jul 19 22:58 0xffff_0.8-1_mipsel.deb + #-rw-r--r-- 2 dak debadmin 57424 Jul 19 19:58 0xffff_0.8-1_ppc64el.deb + #-rw-r--r-- 2 dak debadmin 53764 Jul 19 22:28 0xffff_0.8-1_s390x.deb + #-rw-r--r-- 2 dak debadmin 64504 Jul 19 19:08 0xffff_0.8.orig.tar.gz + # + + path = None + previous_path = '' + archives = [] + filename = None + filenames = [] + for line in lines: + line = line.strip() + if len(line) < 4: + if filename: + res1 = re.match(r'(.*)-[0-9.]+$', path) + if res1 is None: + res1 = re.match(r'(.*)[-.][0-9.]+$', path) + res2 = re.match(r'(.*)-[0-9.]+$', previous_path) + if res2 is None: + res2 = re.match(r'(.*)[-.][0-9.]+$', previous_path) + if res1 is None or res2 is None or res1.group(1) != res2.group(1): + archives.append(path + '/' + latestvername(filenames)) + else: + archives[-1] = path + '/' + latestvername(filenames) + if path: + previous_path = path + path = None + filename = None + filenames = [] + elif line.startswith('./pool/main/'): + path = debian + line[2:-1] + elif path and line.endswith(('.orig.tar.gz', '.orig.tar.bz2', '.orig.tar.xz')): + filename = line[1 + line.rfind(' '):] + filenames.append(filename) + + return archives + + + + if __name__ == "__main__": __my_script_name = os.path.splitext(os.path.basename(sys.argv[0]))[0] __work_path = os.path.expanduser(os.path.join('~', 'cppcheck-' + __my_script_name + '-workfolder')) @@ -40,6 +138,16 @@ def format_float(a, b=1): print(args) + if args.packages_path: + # You can download packages using daca2-download.py + args.packages = glob.glob(os.path.join(args.packages_path, '*.tar.xz')) + random.shuffle(args.packages) + elif args.packages is None: + args.packages = getpackages() + random.shuffle(args.packages) + + print('\n'.join(args.packages[:20])) + if not lib.check_requirements(): print("Error: Check requirements") sys.exit(1) @@ -100,35 +208,14 @@ def format_float(a, b=1): print('Failed to compile your version of Cppcheck') sys.exit(1) - if args.packages_path: - # You can download packages using daca2-download.py - args.packages = glob.glob(os.path.join(args.packages_path, '*.tar.xz')) - args.p = len(args.packages) - packages_idxs = list(range(args.p)) - random.shuffle(packages_idxs) - elif args.packages: - args.p = len(args.packages) - packages_idxs = [] - else: - packages_count = lib.get_packages_count() - if not packages_count: - print("network or server might be temporarily down..") - sys.exit(1) - - packages_idxs = list(range(packages_count)) - random.shuffle(packages_idxs) - packages_processed = 0 crashes = [] timeouts = [] - while (packages_processed < args.p and len(packages_idxs) > 0) or args.packages: - if args.packages: - package = args.packages.pop() - else: - package = lib.get_package(packages_idxs.pop()) + while packages_processed < args.p and args.packages: + package = args.packages.pop() - if package.startswith('ftp://') or package.startswith('http://'): + if package.startswith('ftp://') or package.startswith('https://'): tgz = lib.download_package(work_path, package, None) if tgz is None: print("No package downloaded")