diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index f0b16dd9c..31aec423d 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -915,6 +915,21 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) } } + else if (std::strncmp(argv[i], "--valueflow-max-iterations=", 27) == 0) { + long tmp; + try { + tmp = std::stol(argv[i] + 27); + } catch (const std::invalid_argument &) { + printError("argument to '--valueflow-max-iteration' is invalid."); + return false; + } + if (tmp < 0) { + printError("argument to '--valueflow-max-iteration' needs to be at least 0."); + return false; + } + mSettings->valueFlowMaxIterations = static_cast(tmp); + } + else if (std::strcmp(argv[i], "-v") == 0 || std::strcmp(argv[i], "--verbose") == 0) mSettings->verbose = true; diff --git a/lib/settings.cpp b/lib/settings.cpp index 54a98644d..f2b6191ad 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -66,6 +66,7 @@ Settings::Settings() relativePaths(false), reportProgress(false), showtime(SHOWTIME_MODES::SHOWTIME_NONE), + valueFlowMaxIterations(4), verbose(false), xml(false), xml_version(2) diff --git a/lib/settings.h b/lib/settings.h index 1d7b268ea..db31f7a55 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -351,6 +351,9 @@ public: /** @brief forced includes given by the user */ std::list userIncludes; + /** @brief the maximum iterations of valueflow (--valueflow-max-iterations=T) */ + std::size_t valueFlowMaxIterations; + /** @brief Is --verbose given? */ bool verbose; diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 618ab8411..f09508599 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -8986,7 +8986,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase, const std::uint64_t stopTime = getValueFlowStopTime(settings); std::size_t values = 0; - std::size_t n = 4; + std::size_t n = settings->valueFlowMaxIterations; while (n > 0 && values != getTotalValues(tokenlist)) { values = getTotalValues(tokenlist); @@ -9048,6 +9048,18 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase, n--; } + if (settings->debugwarnings) { + if (n == 0 && values != getTotalValues(tokenlist)) { + ErrorMessage errmsg({}, + emptyString, + Severity::debug, + "ValueFlow maximum iterations exceeded", + "valueFlowMaxIterations", + Certainty::normal); + errorLogger->reportErr(errmsg); + } + } + if (std::time(nullptr) < stopTime) valueFlowDynamicBufferSize(tokenlist, symboldatabase, settings); diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index d13060ed1..5bddf8ba6 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -153,6 +153,11 @@ private: TEST_CASE(clang); TEST_CASE(clang2); TEST_CASE(clangInvalid); + TEST_CASE(valueFlowMaxIterations); + TEST_CASE(valueFlowMaxIterations2); + TEST_CASE(valueFlowMaxIterationsInvalid); + TEST_CASE(valueFlowMaxIterationsInvalid2); + TEST_CASE(valueFlowMaxIterationsInvalid3); // TODO // Disabling these tests since they use relative paths to the @@ -1260,6 +1265,45 @@ private: ASSERT_EQUALS("cppcheck: error: unrecognized command line option: \"--clang-foo\".\n", GET_REDIRECT_OUTPUT); } + void valueFlowMaxIterations() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--valueflow-max-iterations=0"}; + settings.valueFlowMaxIterations = -1; + ASSERT(defParser.parseFromArgs(2, argv)); + ASSERT_EQUALS(0, settings.valueFlowMaxIterations); + ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); + } + + void valueFlowMaxIterations2() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--valueflow-max-iterations=11"}; + settings.valueFlowMaxIterations = -1; + ASSERT(defParser.parseFromArgs(2, argv)); + ASSERT_EQUALS(11, settings.valueFlowMaxIterations); + ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); + } + + void valueFlowMaxIterationsInvalid() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--valueflow-max-iterations"}; + ASSERT(!defParser.parseFromArgs(2, argv)); + ASSERT_EQUALS("cppcheck: error: unrecognized command line option: \"--valueflow-max-iterations\".\n", GET_REDIRECT_OUTPUT); + } + + void valueFlowMaxIterationsInvalid2() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--valueflow-max-iterations=seven"}; + ASSERT(!defParser.parseFromArgs(2, argv)); + ASSERT_EQUALS("cppcheck: error: argument to '--valueflow-max-iteration' is invalid.\n", GET_REDIRECT_OUTPUT); + } + + void valueFlowMaxIterationsInvalid3() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--valueflow-max-iterations=-1"}; + ASSERT(!defParser.parseFromArgs(2, argv)); + ASSERT_EQUALS("cppcheck: error: argument to '--valueflow-max-iteration' needs to be at least 0.\n", GET_REDIRECT_OUTPUT); + } + /* void ignorepaths1() { REDIRECT;