diff --git a/.github/workflows/selfcheck.yml b/.github/workflows/selfcheck.yml index d0c0f233dd2..804de21a0b4 100644 --- a/.github/workflows/selfcheck.yml +++ b/.github/workflows/selfcheck.yml @@ -121,7 +121,7 @@ jobs: - name: Self check (unusedFunction / no test / no gui) run: | - supprs="--suppress=unusedFunction:lib/errorlogger.h:196 --suppress=unusedFunction:lib/importproject.cpp:1531 --suppress=unusedFunction:lib/importproject.cpp:1555" + supprs="--suppress=unusedFunction:lib/errorlogger.h:197 --suppress=unusedFunction:lib/importproject.cpp:1531 --suppress=unusedFunction:lib/importproject.cpp:1555" ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib -D__CPPCHECK__ -D__GNUC__ --enable=unusedFunction,information --exception-handling -rp=. --project=cmake.output.notest_nogui/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr $supprs env: DISABLE_VALUEFLOW: 1 diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index de3bcd1530a..a3d2bb0f161 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -1316,6 +1316,8 @@ void CppCheck::internalError(const std::string &filename, const std::string &msg void CppCheck::checkNormalTokens(const Tokenizer &tokenizer, AnalyzerInformation* analyzerInformation, const std::string& currentConfig) { + const ProgressReporter progressReporter(mErrorLogger, mSettings.reportProgress, tokenizer.list.getSourceFilePath(), "Run checkers"); + CheckUnusedFunctions unusedFunctionsChecker; // TODO: this should actually be the behavior if only "--enable=unusedFunction" is specified - see #10648 @@ -1514,6 +1516,8 @@ void CppCheck::executeAddons(const std::vector& files, const std::s if (isCtuInfo && addonInfo.name != "misra" && !addonInfo.ctu) continue; + ProgressReporter progressReporter(mErrorLogger, mSettings.reportProgress, files.front(), "addon:" + addonInfo.name + (isCtuInfo ? " (ctu)" : "")); + std::vector results; try { diff --git a/lib/errorlogger.h b/lib/errorlogger.h index f8806bbbdca..19d423f7f02 100644 --- a/lib/errorlogger.h +++ b/lib/errorlogger.h @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -286,6 +287,41 @@ class CPPCHECKLIB ErrorLogger { static const std::set mCriticalErrorIds; }; +/// RAII class for reporting progress messages +class CPPCHECKLIB ProgressReporter { +public: + ProgressReporter(ErrorLogger& e, int reportProgressInterval, std::string filename, std::string stage) : + mErrorLogger(e), + mReportProgressInterval(reportProgressInterval), + mFilename(std::move(filename)), + mStage(std::move(stage)) { + report(0); + } + + ~ProgressReporter() { + mErrorLogger.reportProgress(mFilename, mStage.c_str(), 100); + } + + void report(int value) { + if (mReportProgressInterval < 0 || value == mLastValue) + return; + const std::time_t t = std::time(nullptr); + if (t >= mLastTime + mReportProgressInterval) { + mErrorLogger.reportProgress(mFilename, mStage.c_str(), value); + mLastTime = t; + mLastValue = value; + } + } + +private: + ErrorLogger& mErrorLogger; + const int mReportProgressInterval; + const std::string mFilename; + const std::string mStage; + std::time_t mLastTime{0}; + int mLastValue{-1}; +}; + /** Replace substring. Example replaceStr("1,NR,3", "NR", "2") => "1,2,3" */ std::string replaceStr(std::string s, const std::string &from, const std::string &to); diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index f5ffa4e1604..3ac133ac716 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -174,8 +174,6 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() // Store current access in each scope (depends on evaluation progress) std::map access; - const bool doProgress = (mSettings.reportProgress != -1); - std::map> forwardDecls; const std::function findForwardDeclScope = [&](const Token *tok, Scope *startScope) { @@ -200,13 +198,14 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() return it->second.count(tok->str()) > 0 ? startScope : nullptr; }; + ProgressReporter progressReporter(mErrorLogger, mSettings.reportProgress, mTokenizer.list.getSourceFilePath(), "SymbolDatabase (find all scopes)"); + // find all scopes for (const Token *tok = mTokenizer.tokens(); tok; tok = tok ? tok->next() : nullptr) { // #5593 suggested to add here: - if (doProgress) - mErrorLogger.reportProgress(mTokenizer.list.getSourceFilePath(), - "SymbolDatabase", - tok->progressValue()); + + progressReporter.report(tok->progressValue()); + // Locate next class if ((tok->isCpp() && tok->isKeyword() && ((Token::Match(tok, "class|struct|union|namespace ::| %name% final| {|:|::|<") && diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 7c15be961bc..e68f27e619c 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -1167,11 +1167,10 @@ void Tokenizer::simplifyTypedefCpp() std::vector spaceInfo(1); const std::time_t maxTime = mSettings.typedefMaxTime > 0 ? std::time(nullptr) + mSettings.typedefMaxTime: 0; - const bool doProgress = (mSettings.reportProgress != -1) && !list.getFiles().empty(); + ProgressReporter progressReporter(mErrorLogger, mSettings.reportProgress, list.getSourceFilePath(), "Tokenize (typedef)"); for (Token *tok = list.front(); tok; tok = tok->next()) { - if (doProgress) - mErrorLogger.reportProgress(list.getFiles()[0], "Tokenize (typedef)", tok->progressValue()); + progressReporter.report(tok->progressValue()); if (Settings::terminated()) return; @@ -2932,11 +2931,10 @@ bool Tokenizer::simplifyUsing() }; std::list usingList; - const bool doProgress = (mSettings.reportProgress != -1) && !list.getFiles().empty(); + ProgressReporter progressReporter(mErrorLogger, mSettings.reportProgress, list.getSourceFilePath(), "Tokenize (using)"); for (Token *tok = list.front(); tok; tok = tok->next()) { - if (doProgress) - mErrorLogger.reportProgress(list.getFiles()[0], "Tokenize (using)", tok->progressValue()); + progressReporter.report(tok->progressValue()); if (Settings::terminated()) return substitute; diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 7aa0ce4aac6..53b15089975 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -7202,7 +7202,9 @@ struct ValueFlowPassRunner { std::size_t n = state.settings.vfOptions.maxIterations; while (n > 0 && values != getTotalValues()) { values = getTotalValues(); + const std::string passnum = std::to_string(state.settings.vfOptions.maxIterations - n + 1); if (std::any_of(passes.begin(), passes.end(), [&](const ValuePtr& pass) { + ProgressReporter progressReporter(state.errorLogger, state.settings.reportProgress >= 0, state.tokenlist.getSourceFilePath(), std::string("ValueFlow::") + pass->name() + (' ' + passnum)); return run(pass); })) return true; @@ -7346,6 +7348,8 @@ void ValueFlow::setValues(TokenList& tokenlist, const Settings& settings, TimerResultsIntf* timerResults) { + ProgressReporter progressReporter(errorLogger, settings.reportProgress, tokenlist.getSourceFilePath(), "ValueFlow"); + for (Token* tok = tokenlist.front(); tok; tok = tok->next()) tok->clearValueFlow(); diff --git a/test/cli/other_test.py b/test/cli/other_test.py index 86a5c023bbc..aca118456b2 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -169,9 +169,67 @@ def test_progress(tmpdir): "progress: Tokenize (typedef) 62%\n" "progress: Tokenize (typedef) 75%\n" "progress: Tokenize (typedef) 87%\n" - "progress: SymbolDatabase 0%\n" - "progress: SymbolDatabase 12%\n" - "progress: SymbolDatabase 87%\n" + "progress: Tokenize (typedef) 100%\n" + "progress: SymbolDatabase (find all scopes) 0%\n" + "progress: SymbolDatabase (find all scopes) 12%\n" + "progress: SymbolDatabase (find all scopes) 87%\n" + "progress: SymbolDatabase (find all scopes) 100%\n" + "progress: ValueFlow 0%\n" + "progress: ValueFlow::valueFlowImpossibleValues(tokenlist, settings) 1 0%\n" + "progress: ValueFlow::valueFlowImpossibleValues(tokenlist, settings) 1 100%\n" + "progress: ValueFlow::valueFlowSymbolicOperators(symboldatabase, settings) 1 0%\n" + "progress: ValueFlow::valueFlowSymbolicOperators(symboldatabase, settings) 1 100%\n" + "progress: ValueFlow::valueFlowCondition(SymbolicConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 0%\n" + "progress: ValueFlow::valueFlowCondition(SymbolicConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 100%\n" + "progress: ValueFlow::valueFlowSymbolicInfer(symboldatabase, settings) 1 0%\n" + "progress: ValueFlow::valueFlowSymbolicInfer(symboldatabase, settings) 1 100%\n" + "progress: ValueFlow::valueFlowArrayBool(tokenlist, settings) 1 0%\n" + "progress: ValueFlow::valueFlowArrayBool(tokenlist, settings) 1 100%\n" + "progress: ValueFlow::valueFlowArrayElement(tokenlist, settings) 1 0%\n" + "progress: ValueFlow::valueFlowArrayElement(tokenlist, settings) 1 100%\n" + "progress: ValueFlow::valueFlowRightShift(tokenlist, settings) 1 0%\n" + "progress: ValueFlow::valueFlowRightShift(tokenlist, settings) 1 100%\n" + "progress: ValueFlow::valueFlowCondition(ContainerConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 0%\n" + "progress: ValueFlow::valueFlowCondition(ContainerConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 100%\n" + "progress: ValueFlow::valueFlowAfterAssign(tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 0%\n" + "progress: ValueFlow::valueFlowAfterAssign(tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 100%\n" + "progress: ValueFlow::valueFlowAfterSwap(tokenlist, symboldatabase, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowAfterSwap(tokenlist, symboldatabase, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowCondition(SimpleConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 0%\n" + "progress: ValueFlow::valueFlowCondition(SimpleConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 100%\n" + "progress: ValueFlow::valueFlowInferCondition(tokenlist, settings) 1 0%\n" + "progress: ValueFlow::valueFlowInferCondition(tokenlist, settings) 1 100%\n" + "progress: ValueFlow::valueFlowSwitchVariable(tokenlist, symboldatabase, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowSwitchVariable(tokenlist, symboldatabase, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowForLoop(tokenlist, symboldatabase, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowForLoop(tokenlist, symboldatabase, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowSubFunction(tokenlist, symboldatabase, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowSubFunction(tokenlist, symboldatabase, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowFunctionReturn(tokenlist, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowFunctionReturn(tokenlist, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowLifetime(tokenlist, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowLifetime(tokenlist, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowFunctionDefaultParameter(tokenlist, symboldatabase, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowFunctionDefaultParameter(tokenlist, symboldatabase, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowUninit(tokenlist, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowUninit(tokenlist, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowAfterMove(tokenlist, symboldatabase, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowAfterMove(tokenlist, symboldatabase, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowSmartPointer(tokenlist, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowSmartPointer(tokenlist, errorLogger, settings) 1 100%\n" + "progress: ValueFlow::valueFlowIterators(tokenlist, settings) 1 0%\n" + "progress: ValueFlow::valueFlowIterators(tokenlist, settings) 1 100%\n" + "progress: ValueFlow::valueFlowCondition(IteratorConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 0%\n" + "progress: ValueFlow::valueFlowCondition(IteratorConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 100%\n" + "progress: ValueFlow::valueFlowIteratorInfer(tokenlist, settings) 1 0%\n" + "progress: ValueFlow::valueFlowIteratorInfer(tokenlist, settings) 1 100%\n" + "progress: ValueFlow::valueFlowContainerSize(tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 0%\n" + "progress: ValueFlow::valueFlowContainerSize(tokenlist, symboldatabase, errorLogger, settings, skippedFunctions) 1 100%\n" + "progress: ValueFlow::valueFlowSafeFunctions(tokenlist, symboldatabase, errorLogger, settings) 1 0%\n" + "progress: ValueFlow::valueFlowSafeFunctions(tokenlist, symboldatabase, errorLogger, settings) 1 100%\n" + "progress: ValueFlow 100%\n" + "progress: Run checkers 0%\n" + "progress: Run checkers 100%\n" ) assert stderr == ""