diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 27cfe08d871..1c8ee8e8e65 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -1027,6 +1027,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a else if (std::strcmp(argv[i], "--no-safety") == 0) mSettings.safety = false; + else if (std::strcmp(argv[i], "--no-whole-program") == 0) + mSettings.wholeProgram = false; + // Write results in file else if (std::strncmp(argv[i], "--output-file=", 14) == 0) mSettings.outputFile = Path::simplifyPath(argv[i] + 14); @@ -1566,6 +1569,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a else if (std::strcmp(argv[i], "-v") == 0 || std::strcmp(argv[i], "--verbose") == 0) mSettings.verbose = true; + else if (std::strcmp(argv[i], "--whole-program") == 0) + mSettings.wholeProgram = true; + // Write results in results.xml else if (std::strcmp(argv[i], "--xml") == 0) { if (outputFormatOptionProvided) { @@ -1633,12 +1639,15 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a // TODO: bail out instead? if (mSettings.checks.isEnabled(Checks::unusedFunction)) { - mLogger.printMessage("unusedFunction check requires --cppcheck-build-dir to be active with -j."); + mLogger.printMessage("disabling unusedFunction check as it requires --cppcheck-build-dir to be active with -j"); mSettings.checks.disable(Checks::unusedFunction); // TODO: is there some later logic to remove? } - // TODO: enable - //mLogger.printMessage("whole program analysis requires --cppcheck-build-dir to be active with -j."); + // TODO: bail out instead? + if (mSettings.wholeProgram) { + mLogger.printMessage("disabling whole program analysis as it requires --cppcheck-build-dir to be active with -j."); + mSettings.wholeProgram = false; + } } if (!mSettings.checks.isEnabled(Checks::unusedFunction)) diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index f39e64a938f..1287d642879 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -1820,7 +1820,7 @@ bool CppCheck::analyseWholeProgram() if (!Settings::unusedFunctionOnly()) { // Analyse the tokens CTU::FileInfo ctu; - if (mSettings.useSingleJob() || !mSettings.buildDir.empty()) + if (mSettings.wholeProgram) { for (const Check::FileInfo *fi : mFileInfo) { const auto *fi2 = dynamic_cast(fi); @@ -1843,6 +1843,10 @@ bool CppCheck::analyseWholeProgram() unsigned int CppCheck::analyseWholeProgram(const std::string &buildDir, const std::list &files, const std::list& fileSettings, const std::string& ctuInfo) { + // TODO: is this bailout correct? what happened when builddir was empty? + if (!mSettings.wholeProgram) + return mLogger->exitcode(); + if (mSettings.checks.isEnabled(Checks::unusedFunction)) CheckUnusedFunctions::analyseWholeProgram(mSettings, mErrorLogger, buildDir); diff --git a/lib/settings.h b/lib/settings.h index 6c12c509701..0159b92e7b4 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -525,6 +525,9 @@ class CPPCHECKLIB WARN_UNUSED Settings { /** @brief Is --verbose given? */ bool verbose{}; + /** @brief Is the whole program analysis enabled? */ + bool wholeProgram{true}; + /** @brief XML version (--xml-version=..) */ int xml_version = 2; // TODO: integrate into outputFormat enum? diff --git a/test/cli/other_test.py b/test/cli/other_test.py index 243f600b5a6..1fa75dad0fd 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -143,7 +143,7 @@ def test_message_j(tmpdir): with open(test_file, 'wt') as f: f.write("") - args = ['-j2', test_file] + args = ['-j2', '--no-whole-program', test_file] _, stdout, _ = cppcheck(args) assert stdout == "Checking {} ...\n".format(test_file) # we were adding stray \0 characters at the end @@ -251,7 +251,15 @@ def test_progress_j(tmpdir): } """) - args = ['--report-progress=0', '--enable=all', '--inconclusive', '-j2', '--disable=unusedFunction', test_file] + args = [ + '--report-progress=0', + '--enable=all', + '--inconclusive', + '-j2', + '--disable=unusedFunction', + '--no-whole-program', + test_file + ] exitcode, stdout, stderr = cppcheck(args) assert exitcode == 0, stdout if stdout else stderr @@ -1303,7 +1311,7 @@ def test_markup_j(tmpdir): with open(test_file_4, 'wt'): pass - args = ['--library=qt', '-j2', test_file_1, test_file_2, test_file_3, test_file_4] + args = ['--library=qt', '-j2', '--no-whole-program', test_file_1, test_file_2, test_file_3, test_file_4] exitcode, stdout, stderr = cppcheck(args) assert exitcode == 0, stdout if stdout else stderr @@ -2539,7 +2547,7 @@ def test_inline_suppr(tmp_path): def test_inline_suppr_j(tmp_path): - __test_inline_suppr(tmp_path, ['-j2']) + __test_inline_suppr(tmp_path, ['-j2', '--no-whole-program']) def test_inline_suppr_builddir(tmp_path): @@ -2768,7 +2776,7 @@ def test_addon_suppr_inline(tmp_path): # TODO: remove override when all issues are fixed def test_addon_suppr_inline_j(tmp_path): - __test_addon_suppr(tmp_path, ['--inline-suppr', '-j2']) + __test_addon_suppr(tmp_path, ['--inline-suppr', '-j2', '--no-whole-program']) def test_addon_suppr_cli_line(tmp_path): @@ -4648,6 +4656,7 @@ def test_ipc(tmp_path): '-j2', '--executor=process', '--no-cppcheck-build-dir', + '--no-whole-program', str(test_file) ] @@ -4680,6 +4689,7 @@ def test_ipc_suppressions(tmp_path): '-j2', '--executor=process', '--no-cppcheck-build-dir', + '--no-whole-program', '--suppress=id0:test1.c', str(tmp_path) ] @@ -4724,6 +4734,7 @@ def test_ipc_inline_suppressions(tmp_path): '-j2', '--executor=process', '--no-cppcheck-build-dir', + '--no-whole-program', '--inline-suppr', str(tmp_path) ] diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index 135b7c782be..e906603f300 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -499,6 +499,8 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(noSafetyOverride); TEST_CASE(debugAnalyzerinfo); TEST_CASE(debugIpc); + TEST_CASE(wholeProgram); + TEST_CASE(noWholeProgram); TEST_CASE(ignorepaths1); TEST_CASE(ignorepaths2); @@ -1381,6 +1383,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "-j", "3", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS(3, settings->jobs); + ASSERT_EQUALS("cppcheck: disabling whole program analysis as it requires --cppcheck-build-dir to be active with -j.\n", logger->str()); } void jobs2() { @@ -1388,6 +1391,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "-j3", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS(3, settings->jobs); + ASSERT_EQUALS("cppcheck: disabling whole program analysis as it requires --cppcheck-build-dir to be active with -j.\n", logger->str()); } void jobsMissingCount() { @@ -3057,6 +3061,7 @@ class TestCmdlineParser : public TestFixture { #elif defined(HAS_THREADING_MODEL_THREAD) ASSERT_EQUALS_ENUM(Settings::ExecutorType::Thread, settings->executor); #endif + ASSERT_EQUALS("cppcheck: disabling whole program analysis as it requires --cppcheck-build-dir to be active with -j.\n", logger->str()); } void executorAutoNoJobs() { @@ -3076,6 +3081,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "-j2", "--executor=thread", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS_ENUM(Settings::ExecutorType::Thread, settings->executor); + ASSERT_EQUALS("cppcheck: disabling whole program analysis as it requires --cppcheck-build-dir to be active with -j.\n", logger->str()); } void executorThreadNoJobs() { @@ -3100,6 +3106,7 @@ class TestCmdlineParser : public TestFixture { const char * const argv[] = {"cppcheck", "-j2", "--executor=process", "file.cpp"}; ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS_ENUM(Settings::ExecutorType::Process, settings->executor); + ASSERT_EQUALS("cppcheck: disabling whole program analysis as it requires --cppcheck-build-dir to be active with -j.\n", logger->str()); } void executorProcessNoJobs() { @@ -3495,6 +3502,20 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS(true, settings->debugipc); } + void wholeProgram() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--whole-program", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS(true, settings->wholeProgram); + } + + void noWholeProgram() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--no-whole-program", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS(false, settings->wholeProgram); + } + void ignorepaths1() { REDIRECT; const char * const argv[] = {"cppcheck", "-isrc", "file.cpp"};