From b5599311e83febf959f347b550cdcab8295f3d91 Mon Sep 17 00:00:00 2001 From: firewave Date: Sun, 6 Jul 2025 21:15:25 +0200 Subject: [PATCH 1/7] refs #13982 - cppcheck.cpp: do not crash if `mExecuteCommand` is empty --- lib/cppcheck.cpp | 13 +++++++++++++ lib/cppcheck.h | 1 + 2 files changed, 14 insertions(+) diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 181551e05f6..60e98bbc94f 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -432,6 +432,9 @@ static std::vector executeAddon(const AddonInfo &addonInfo, const std::string &premiumArgs, const CppCheck::ExecuteCmdFn &executeCommand) { + if (!executeCommand) + throw InternalError(nullptr, "Failed to execute addon - no command callback provided"); + std::string pythonExe; if (!addonInfo.executable.empty()) @@ -686,6 +689,11 @@ unsigned int CppCheck::checkClang(const FileWithDetails &file, int fileIndex) mErrorLogger.reportOut(exe + " " + args2, Color::Reset); } + if (!mExecuteCommand) { + std::cerr << "Failed to execute '" << exe << " " << args2 << " " << redirect2 << "' - (no command callback provided)" << std::endl; + return 0; // TODO: report as failure? + } + std::string output2; const int exitcode = mExecuteCommand(exe,split(args2),redirect2,output2); if (mSettings.debugClangOutput) { @@ -1954,6 +1962,11 @@ void CppCheck::analyseClangTidy(const FileSettings &fileSettings) } #endif + if (!mExecuteCommand) { + std::cerr << "Failed to execute '" << exe << "' (no command callback provided)" << std::endl; + return; + } + // TODO: log this call // TODO: get rid of hard-coded checks const std::string args = "-quiet -checks=*,-clang-analyzer-*,-llvm* \"" + fileSettings.filename() + "\" -- " + allIncludes + allDefines; diff --git a/lib/cppcheck.h b/lib/cppcheck.h index d56d7fa6b4f..27a0e46b02e 100644 --- a/lib/cppcheck.h +++ b/lib/cppcheck.h @@ -60,6 +60,7 @@ class CPPCHECKLIB CppCheck { friend class TestCppcheck; public: + // exe, args, redirect, output using ExecuteCmdFn = std::function,std::string,std::string&)>; /** From 085679adf1cea0d93c9601d4fbd73ad89a0dd38c Mon Sep 17 00:00:00 2001 From: firewave Date: Mon, 7 Jul 2025 12:54:06 +0200 Subject: [PATCH 2/7] fixture.h: added `ASSERT_MSG` --- test/fixture.h | 1 + 1 file changed, 1 insertion(+) diff --git a/test/fixture.h b/test/fixture.h index 7be1d2d9237..6c06dc6282c 100644 --- a/test/fixture.h +++ b/test/fixture.h @@ -320,6 +320,7 @@ class TestInstance { #define TEST_CASE( NAME ) do { if (prepareTest(#NAME)) { setVerbose(false); try { NAME(); teardownTest(); } catch (const AssertFailedError&) {} catch (...) { assertNoThrowFail(__FILE__, __LINE__, false); } } } while (false) #define ASSERT( CONDITION ) assert_(__FILE__, __LINE__, (CONDITION)) +#define ASSERT_MSG( CONDITION, MSG ) assert_(__FILE__, __LINE__, (CONDITION), MSG) #define ASSERT_LOC( CONDITION, FILE_, LINE_ ) assert_(FILE_, LINE_, (CONDITION)) #define ASSERT_LOC_MSG( CONDITION, MSG, FILE_, LINE_ ) assert_(FILE_, LINE_, (CONDITION), MSG) // *INDENT-OFF* From b16cde96cf28372338aa93cb7a732f989fc667af Mon Sep 17 00:00:00 2001 From: firewave Date: Mon, 7 Jul 2025 12:54:21 +0200 Subject: [PATCH 3/7] added/moved testing of tool invocation to `TestCppcheck` --- Makefile | 2 +- lib/cppcheck.cpp | 2 +- test/redirect.h | 1 + test/testcppcheck.cpp | 196 +++++++++++++++++++++++++++++++++-- test/testprocessexecutor.cpp | 48 +-------- test/testsingleexecutor.cpp | 47 +-------- test/testthreadexecutor.cpp | 47 +-------- 7 files changed, 192 insertions(+), 151 deletions(-) diff --git a/Makefile b/Makefile index 188529d82a9..ba22fdbe660 100644 --- a/Makefile +++ b/Makefile @@ -753,7 +753,7 @@ test/testcondition.o: test/testcondition.cpp lib/addoninfo.h lib/check.h lib/che test/testconstructors.o: test/testconstructors.cpp lib/addoninfo.h lib/check.h lib/checkclass.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testconstructors.cpp -test/testcppcheck.o: test/testcppcheck.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testcppcheck.o: test/testcppcheck.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcppcheck.cpp test/testerrorlogger.o: test/testerrorlogger.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/xml.h test/fixture.h test/helpers.h diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 60e98bbc94f..d986454dba7 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -444,7 +444,7 @@ static std::vector executeAddon(const AddonInfo &addonInfo, else if (!defaultPythonExe.empty()) pythonExe = cmdFileName(defaultPythonExe); else { - // store in static variable so we only look this up once + // store in static variable so we only look this up once - TODO: do not cache globally static const std::string detectedPythonExe = detectPython(executeCommand); if (detectedPythonExe.empty()) throw InternalError(nullptr, "Failed to auto detect python"); diff --git a/test/redirect.h b/test/redirect.h index cf0d1d822be..9f67dc591a1 100644 --- a/test/redirect.h +++ b/test/redirect.h @@ -43,6 +43,7 @@ class RedirectOutputError { std::cerr.rdbuf(_err.rdbuf()); // assign streambuf to cerr } + // TODO: if an assert failed previously this will mask that failure /** Revert cout and cerr behaviour */ ~RedirectOutputError() noexcept(false) { std::cout.rdbuf(_oldCout); // restore cout's original streambuf diff --git a/test/testcppcheck.cpp b/test/testcppcheck.cpp index b085cdcedf5..e8f2e6ee2b9 100644 --- a/test/testcppcheck.cpp +++ b/test/testcppcheck.cpp @@ -25,15 +25,19 @@ #include "helpers.h" #include "path.h" #include "preprocessor.h" +#include "redirect.h" #include "settings.h" #include "standards.h" #include "suppressions.h" #include #include +#include #include #include #include +#include +#include #include #include @@ -66,7 +70,11 @@ class TestCppcheck : public TestFixture { void run() override { TEST_CASE(getErrorMessages); TEST_CASE(checkWithFile); + TEST_CASE(checkWithFileWithTools); + TEST_CASE(checkWithFileWithToolsNoCommand); TEST_CASE(checkWithFS); + TEST_CASE(checkWithFSWithTools); + TEST_CASE(checkWithFSWithToolsNoCommand); TEST_CASE(suppress_error_library); TEST_CASE(unique_errors); TEST_CASE(unique_errors_2); @@ -114,8 +122,52 @@ class TestCppcheck : public TestFixture { ASSERT(foundMissingIncludeSystem); } - void checkWithFile() const + static std::string exename(std::string exe) { +#ifdef _WIN32 + return exe + ".exe"; +#else + return exe; +#endif + } + + CppCheck::ExecuteCmdFn getExecuteCommand(int& called) const + { + // NOLINTNEXTLINE(performance-unnecessary-value-param) + return [&](std::string exe, std::vector args, std::string redirect, std::string& /*output*/) -> int { + ++called; + if (exe == exename("clang-tidy")) + { + ASSERT_EQUALS(4, args.size()); + ASSERT_EQUALS("-quiet", args[0]); + ASSERT_EQUALS("-checks=*,-clang-analyzer-*,-llvm*", args[1]); + ASSERT_EQUALS("test.cpp", args[2]); + ASSERT_EQUALS("--", args[3]); + ASSERT_EQUALS("2>&1", redirect); + return EXIT_SUCCESS; + } + if (exe == exename("python3")) + { + ASSERT_EQUALS(1, args.size()); + ASSERT_EQUALS("--version", args[0]); + ASSERT_EQUALS("2>&1", redirect); + return EXIT_SUCCESS; + } + if (exe == exename("python")) + { + ASSERT_EQUALS(1, args.size()); + ASSERT_EQUALS("--version", args[0]); + ASSERT_EQUALS("2>&1", redirect); + return EXIT_SUCCESS; + } + ASSERT_MSG(false, "unhandled exe: " + exe); + return EXIT_FAILURE; + }; + } + + void checkWithFileInternal(bool tools, bool nocmd = false) const + { + REDIRECT; ScopedFile file("test.cpp", "int main()\n" "{\n" @@ -123,21 +175,84 @@ class TestCppcheck : public TestFixture { " return 0;\n" "}"); - const auto s = dinit(Settings, $.templateFormat = templateFormat); + int called = 0; + std::unordered_set addons; + std::vector addonInfo; + if (tools) + { + addons.emplace("testcppcheck"); + addonInfo.emplace_back(AddonInfo()); + } + const auto s = dinit(Settings, + $.templateFormat = templateFormat, + $.clangTidy = tools, + $.addons = std::move (addons), + $.addonInfos = std::move (addonInfo)); Suppressions supprs; ErrorLogger2 errorLogger; - CppCheck cppcheck(s, supprs, errorLogger, false, {}); + CppCheck::ExecuteCmdFn f; + if (tools && !nocmd) { + f = getExecuteCommand(called); + } + CppCheck cppcheck(s, supprs, errorLogger, false, f); ASSERT_EQUALS(1, cppcheck.check(FileWithDetails(file.path(), Path::identify(file.path(), false), 0))); // TODO: how to properly disable these warnings? errorLogger.ids.erase(std::remove_if(errorLogger.ids.begin(), errorLogger.ids.end(), [](const std::string& id) { return id == "logChecker"; }), errorLogger.ids.end()); - ASSERT_EQUALS(1, errorLogger.ids.size()); - ASSERT_EQUALS("nullPointer", *errorLogger.ids.cbegin()); + errorLogger.errmsgs.erase(std::remove_if(errorLogger.errmsgs.begin(), errorLogger.errmsgs.end(), [](const ErrorMessage& msg) { + return msg.id == "logChecker"; + }), errorLogger.errmsgs.end()); + if (tools) + { + ASSERT_EQUALS(2, errorLogger.ids.size()); + auto it = errorLogger.errmsgs.cbegin(); + ASSERT_EQUALS("nullPointer", it->id); + ++it; + + if (nocmd) + { + ASSERT_EQUALS("internalError", it->id); + ASSERT_EQUALS("Bailing out from analysis: Checking file failed: Failed to execute addon - no command callback provided", it->shortMessage()); // TODO: add addon name + + // TODO: clang-tidy is currently not invoked for file inputs - see #12053 + // TODO: needs to become a proper error + TODO_ASSERT_EQUALS("Failed to execute '" + exename("clang-tidy") + "' (no command callback provided)\n", "", GET_REDIRECT_ERROUT); + + ASSERT_EQUALS(0, called); // not called because we check if the callback exists + } + else + { + ASSERT_EQUALS("internalError", it->id); + ASSERT_EQUALS("Bailing out from analysis: Checking file failed: Failed to auto detect python", it->shortMessage()); // TODO: clarify what python is used for + + // TODO: we cannot check this because the python detection is cached globally so this result will different dependent on how the test is called + //ASSERT_EQUALS(2, called); + } + } + else + { + ASSERT_EQUALS(0, called); + ASSERT_EQUALS(1, errorLogger.ids.size()); + ASSERT_EQUALS("nullPointer", *errorLogger.ids.cbegin()); + } + } + + void checkWithFile() { + checkWithFileInternal(false); } - void checkWithFS() const + void checkWithFileWithTools() { + checkWithFileInternal(true); + } + + void checkWithFileWithToolsNoCommand() { + checkWithFileInternal(true, true); + } + + void checkWithFSInternal(bool tools, bool nocmd = false) const { + REDIRECT; ScopedFile file("test.cpp", "int main()\n" "{\n" @@ -145,18 +260,79 @@ class TestCppcheck : public TestFixture { " return 0;\n" "}"); - const auto s = dinit(Settings, $.templateFormat = templateFormat); + int called = 0; + std::unordered_set addons; + std::vector addonInfo; + if (tools) + { + addons.emplace("testcppcheck"); + addonInfo.emplace_back(AddonInfo()); + } + const auto s = dinit(Settings, + $.templateFormat = templateFormat, + $.clangTidy = tools, + $.addons = std::move (addons), + $.addonInfos = std::move (addonInfo)); Suppressions supprs; ErrorLogger2 errorLogger; - CppCheck cppcheck(s, supprs, errorLogger, false, {}); + CppCheck::ExecuteCmdFn f; + if (tools && !nocmd) { + f = getExecuteCommand(called); + } + CppCheck cppcheck(s, supprs, errorLogger, false, f); FileSettings fs{file.path(), Path::identify(file.path(), false), 0}; ASSERT_EQUALS(1, cppcheck.check(fs)); // TODO: how to properly disable these warnings? errorLogger.ids.erase(std::remove_if(errorLogger.ids.begin(), errorLogger.ids.end(), [](const std::string& id) { return id == "logChecker"; }), errorLogger.ids.end()); - ASSERT_EQUALS(1, errorLogger.ids.size()); - ASSERT_EQUALS("nullPointer", *errorLogger.ids.cbegin()); + errorLogger.errmsgs.erase(std::remove_if(errorLogger.errmsgs.begin(), errorLogger.errmsgs.end(), [](const ErrorMessage& msg) { + return msg.id == "logChecker"; + }), errorLogger.errmsgs.end()); + if (tools) + { + ASSERT_EQUALS(2, errorLogger.ids.size()); + auto it = errorLogger.errmsgs.cbegin(); + ASSERT_EQUALS("nullPointer", it->id); + ++it; + + if (nocmd) + { + ASSERT_EQUALS("internalError", it->id); + ASSERT_EQUALS("Bailing out from analysis: Checking file failed: Failed to execute addon - no command callback provided", it->shortMessage()); // TODO: add addon name + + // TODO: needs to become a proper error + ASSERT_EQUALS("Failed to execute '" + exename("clang-tidy") + "' (no command callback provided)\n", GET_REDIRECT_ERROUT); + + ASSERT_EQUALS(0, called); // not called because we check if the callback exists + } + else + { + ASSERT_EQUALS("internalError", it->id); + ASSERT_EQUALS("Bailing out from analysis: Checking file failed: Failed to auto detect python", it->shortMessage()); // TODO: clarify what python is used for + + // TODO: we cannot check this because the python detection is cached globally so this result will different dependent on how the test is called + //ASSERT_EQUALS(3, called); + } + } + else + { + ASSERT_EQUALS(0, called); + ASSERT_EQUALS(1, errorLogger.ids.size()); + ASSERT_EQUALS("nullPointer", *errorLogger.ids.cbegin()); + } + } + + void checkWithFS() { + checkWithFSInternal(false); + } + + void checkWithFSWithTools() { + checkWithFSInternal(true); + } + + void checkWithFSWithToolsNoCommand() { + checkWithFSInternal(true, true); } void suppress_error_library() const diff --git a/test/testprocessexecutor.cpp b/test/testprocessexecutor.cpp index f634587e76c..ff404f11c66 100644 --- a/test/testprocessexecutor.cpp +++ b/test/testprocessexecutor.cpp @@ -56,10 +56,6 @@ class TestProcessExecutorBase : public TestFixture { SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE; const char* plistOutput = nullptr; std::vector filesList; - bool clangTidy = false; - bool executeCommandCalled = false; - std::string exe; - std::vector args; }; /** @@ -98,14 +94,8 @@ class TestProcessExecutorBase : public TestFixture { s.templateFormat = "{callstack}: ({severity}) {inconclusive:inconclusive: }{message}"; Suppressions supprs; - bool executeCommandCalled = false; - std::string exe; - std::vector args; // NOLINTNEXTLINE(performance-unnecessary-value-param) - auto executeFn = [&executeCommandCalled, &exe, &args](std::string e,std::vector a,std::string,std::string&){ - executeCommandCalled = true; - exe = std::move(e); - args = std::move(a); + auto executeFn = [](std::string,std::vector,std::string,std::string&){ return EXIT_SUCCESS; }; @@ -120,13 +110,6 @@ class TestProcessExecutorBase : public TestFixture { ProcessExecutor executor(filelist, fileSettings, s, supprs, *this, executeFn); ASSERT_EQUALS(result, executor.check()); - ASSERT_EQUALS(opt.executeCommandCalled, executeCommandCalled); - ASSERT_EQUALS(opt.exe, exe); - ASSERT_EQUALS(opt.args.size(), args.size()); - for (std::size_t i = 0; i < args.size(); ++i) - { - ASSERT_EQUALS(opt.args[i], args[i]); - } } void run() override { @@ -141,7 +124,6 @@ class TestProcessExecutorBase : public TestFixture { TEST_CASE(no_errors_equal_amount_files); TEST_CASE(one_error_less_files); TEST_CASE(one_error_several_files); - TEST_CASE(clangTidy); TEST_CASE(showtime_top5_file); TEST_CASE(showtime_top5_summary); TEST_CASE(showtime_file); @@ -250,34 +232,6 @@ class TestProcessExecutorBase : public TestFixture { ASSERT_EQUALS(num_files, cppcheck::count_all_of(errout_str(), "(error) Null pointer dereference: (int*)0")); } - void clangTidy() { - // TODO: we currently only invoke it with ImportProject::FileSettings - if (!useFS) - return; - -#ifdef _WIN32 - constexpr char exe[] = "clang-tidy.exe"; -#else - constexpr char exe[] = "clang-tidy"; -#endif - (void)exe; - - const std::string file = fprefix() + "_1.cpp"; - // TODO: the invocation cannot be checked as the code is called in the forked process - check(2, 1, 0, - "int main()\n" - "{\n" - " return 0;\n" - "}", - dinit(CheckOptions, - $.quiet = false, - $.clangTidy = true /*, - $.executeCommandCalled = true, - $.exe = exe, - $.args = {"-quiet", "-checks=*,-clang-analyzer-*,-llvm*", file, "--"}*/)); - ASSERT_EQUALS("Checking " + file + " ...\n", output_str()); - } - // TODO: provide data which actually shows values above 0 // TODO: should this be logged only once like summary? diff --git a/test/testsingleexecutor.cpp b/test/testsingleexecutor.cpp index 1c5c9c159d9..25eb43ac4bc 100644 --- a/test/testsingleexecutor.cpp +++ b/test/testsingleexecutor.cpp @@ -65,10 +65,6 @@ class TestSingleExecutorBase : public TestFixture { SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE; const char* plistOutput = nullptr; std::vector filesList; - bool clangTidy = false; - bool executeCommandCalled = false; - std::string exe; - std::vector args; }; void check(int files, int result, const std::string &data, const CheckOptions& opt = make_default_obj{}) { @@ -99,19 +95,12 @@ class TestSingleExecutorBase : public TestFixture { s.quiet = opt.quiet; if (opt.plistOutput) s.plistOutput = opt.plistOutput; - s.clangTidy = opt.clangTidy; s.templateFormat = "{callstack}: ({severity}) {inconclusive:inconclusive: }{message}"; // TODO: remove when we only longer rely on toString() in unique message handling? Suppressions supprs; - bool executeCommandCalled = false; - std::string exe; - std::vector args; // NOLINTNEXTLINE(performance-unnecessary-value-param) - CppCheck cppcheck(s, supprs, *this, true, [&executeCommandCalled, &exe, &args](std::string e,std::vector a,std::string,std::string&){ - executeCommandCalled = true; - exe = std::move(e); - args = std::move(a); + CppCheck cppcheck(s, supprs, *this, true, [](std::string,std::vector,std::string,std::string&){ return EXIT_SUCCESS; }); @@ -126,13 +115,6 @@ class TestSingleExecutorBase : public TestFixture { SingleExecutor executor(cppcheck, filelist, fileSettings, s, supprs, *this); ASSERT_EQUALS(result, executor.check()); - ASSERT_EQUALS(opt.executeCommandCalled, executeCommandCalled); - ASSERT_EQUALS(opt.exe, exe); - ASSERT_EQUALS(opt.args.size(), args.size()); - for (std::size_t i = 0; i < args.size(); ++i) - { - ASSERT_EQUALS(opt.args[i], args[i]); - } } void run() override { @@ -145,7 +127,6 @@ class TestSingleExecutorBase : public TestFixture { TEST_CASE(no_errors_equal_amount_files); TEST_CASE(one_error_less_files); TEST_CASE(one_error_several_files); - TEST_CASE(clangTidy); TEST_CASE(showtime_top5_file); TEST_CASE(showtime_top5_summary); TEST_CASE(showtime_file); @@ -258,32 +239,6 @@ class TestSingleExecutorBase : public TestFixture { } } - void clangTidy() { - // TODO: we currently only invoke it with ImportProject::FileSettings - if (!useFS) - return; - -#ifdef _WIN32 - constexpr char exe[] = "clang-tidy.exe"; -#else - constexpr char exe[] = "clang-tidy"; -#endif - - const std::string file = fprefix() + "_001.cpp"; - check(1, 0, - "int main()\n" - "{\n" - " return 0;\n" - "}", - dinit(CheckOptions, - $.quiet = false, - $.clangTidy = true, - $.executeCommandCalled = true, - $.exe = exe, - $.args = {"-quiet", "-checks=*,-clang-analyzer-*,-llvm*", file, "--"})); - ASSERT_EQUALS("Checking " + file + " ...\n", output_str()); - } - // TODO: provide data which actually shows values above 0 void showtime_top5_file() { diff --git a/test/testthreadexecutor.cpp b/test/testthreadexecutor.cpp index 31c30ed9ebf..d96e219153a 100644 --- a/test/testthreadexecutor.cpp +++ b/test/testthreadexecutor.cpp @@ -56,10 +56,6 @@ class TestThreadExecutorBase : public TestFixture { SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE; const char* plistOutput = nullptr; std::vector filesList; - bool clangTidy = false; - bool executeCommandCalled = false; - std::string exe; - std::vector args; }; /** @@ -95,19 +91,12 @@ class TestThreadExecutorBase : public TestFixture { s.quiet = opt.quiet; if (opt.plistOutput) s.plistOutput = opt.plistOutput; - s.clangTidy = opt.clangTidy; s.templateFormat = "{callstack}: ({severity}) {inconclusive:inconclusive: }{message}"; // TODO: remove when we only longer rely on toString() in unique message handling? Suppressions supprs; - bool executeCommandCalled = false; - std::string exe; - std::vector args; // NOLINTNEXTLINE(performance-unnecessary-value-param) - auto executeFn = [&executeCommandCalled, &exe, &args](std::string e,std::vector a,std::string,std::string&){ - executeCommandCalled = true; - exe = std::move(e); - args = std::move(a); + auto executeFn = [](std::string,std::vector,std::string,std::string&){ return EXIT_SUCCESS; }; @@ -122,13 +111,6 @@ class TestThreadExecutorBase : public TestFixture { ThreadExecutor executor(filelist, fileSettings, s, supprs, *this, executeFn); ASSERT_EQUALS(result, executor.check()); - ASSERT_EQUALS(opt.executeCommandCalled, executeCommandCalled); - ASSERT_EQUALS(opt.exe, exe); - ASSERT_EQUALS(opt.args.size(), args.size()); - for (std::size_t i = 0; i < args.size(); ++i) - { - ASSERT_EQUALS(opt.args[i], args[i]); - } } void run() override { @@ -142,7 +124,6 @@ class TestThreadExecutorBase : public TestFixture { TEST_CASE(no_errors_equal_amount_files); TEST_CASE(one_error_less_files); TEST_CASE(one_error_several_files); - TEST_CASE(clangTidy); TEST_CASE(showtime_top5_file); TEST_CASE(showtime_top5_summary); TEST_CASE(showtime_file); @@ -250,32 +231,6 @@ class TestThreadExecutorBase : public TestFixture { ASSERT_EQUALS(num_files, cppcheck::count_all_of(errout_str(), "(error) Null pointer dereference: (int*)0")); } - void clangTidy() { - // TODO: we currently only invoke it with ImportProject::FileSettings - if (!useFS) - return; - -#ifdef _WIN32 - constexpr char exe[] = "clang-tidy.exe"; -#else - constexpr char exe[] = "clang-tidy"; -#endif - - const std::string file = fprefix() + "_1.cpp"; - check(2, 1, 0, - "int main()\n" - "{\n" - " return 0;\n" - "}", - dinit(CheckOptions, - $.quiet = false, - $.clangTidy = true, - $.executeCommandCalled = true, - $.exe = exe, - $.args = {"-quiet", "-checks=*,-clang-analyzer-*,-llvm*", file, "--"})); - ASSERT_EQUALS("Checking " + file + " ...\n", output_str()); - } - // TODO: provide data which actually shows values above 0 // TODO: should this be logged only once like summary? From 93a1ffdc2d83e9b5448b6287d5f3b7a6cf64092a Mon Sep 17 00:00:00 2001 From: firewave Date: Mon, 7 Jul 2025 13:34:20 +0200 Subject: [PATCH 4/7] testcppcheck.cpp: fixed `modernize-use-emplace` clang-tidy warnings --- test/testcppcheck.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/testcppcheck.cpp b/test/testcppcheck.cpp index e8f2e6ee2b9..7c47485f13e 100644 --- a/test/testcppcheck.cpp +++ b/test/testcppcheck.cpp @@ -181,7 +181,7 @@ class TestCppcheck : public TestFixture { if (tools) { addons.emplace("testcppcheck"); - addonInfo.emplace_back(AddonInfo()); + addonInfo.emplace_back(/*AddonInfo()*/); } const auto s = dinit(Settings, $.templateFormat = templateFormat, @@ -266,7 +266,7 @@ class TestCppcheck : public TestFixture { if (tools) { addons.emplace("testcppcheck"); - addonInfo.emplace_back(AddonInfo()); + addonInfo.emplace_back(/*AddonInfo()*/); } const auto s = dinit(Settings, $.templateFormat = templateFormat, From eb958f6f238c7627f632843bf90fbeea7f8d5056 Mon Sep 17 00:00:00 2001 From: firewave Date: Mon, 7 Jul 2025 14:54:58 +0200 Subject: [PATCH 5/7] testcppcheck.cpp: fixed `functionConst` selfcheck warnings --- test/testcppcheck.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/testcppcheck.cpp b/test/testcppcheck.cpp index 7c47485f13e..db49883c50b 100644 --- a/test/testcppcheck.cpp +++ b/test/testcppcheck.cpp @@ -238,15 +238,15 @@ class TestCppcheck : public TestFixture { } } - void checkWithFile() { + void checkWithFile() const { checkWithFileInternal(false); } - void checkWithFileWithTools() { + void checkWithFileWithTools() const { checkWithFileInternal(true); } - void checkWithFileWithToolsNoCommand() { + void checkWithFileWithToolsNoCommand() const { checkWithFileInternal(true, true); } @@ -323,15 +323,15 @@ class TestCppcheck : public TestFixture { } } - void checkWithFS() { + void checkWithFS() const { checkWithFSInternal(false); } - void checkWithFSWithTools() { + void checkWithFSWithTools() const { checkWithFSInternal(true); } - void checkWithFSWithToolsNoCommand() { + void checkWithFSWithToolsNoCommand() const { checkWithFSInternal(true, true); } From bb39b5488b3611706ddcb9a7db0e2de17eb5107a Mon Sep 17 00:00:00 2001 From: firewave Date: Mon, 7 Jul 2025 14:56:00 +0200 Subject: [PATCH 6/7] testcppcheck.cpp: mitigated `passedByValue` selfcheck warnings --- test/testcppcheck.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/testcppcheck.cpp b/test/testcppcheck.cpp index db49883c50b..f7b2f939582 100644 --- a/test/testcppcheck.cpp +++ b/test/testcppcheck.cpp @@ -122,7 +122,7 @@ class TestCppcheck : public TestFixture { ASSERT(foundMissingIncludeSystem); } - static std::string exename(std::string exe) + static std::string exename(const std::string& exe) { #ifdef _WIN32 return exe + ".exe"; @@ -133,7 +133,8 @@ class TestCppcheck : public TestFixture { CppCheck::ExecuteCmdFn getExecuteCommand(int& called) const { - // NOLINTNEXTLINE(performance-unnecessary-value-param) + // cppcheck-suppress passedByValue - used as callback so we need to preserve the signature + // NOLINTNEXTLINE(performance-unnecessary-value-param) - used as callback so we need to preserve the signature return [&](std::string exe, std::vector args, std::string redirect, std::string& /*output*/) -> int { ++called; if (exe == exename("clang-tidy")) From b748ab0fe4488fcdf8ae1e4a39afa0d89a7219e9 Mon Sep 17 00:00:00 2001 From: firewave Date: Mon, 7 Jul 2025 14:57:28 +0200 Subject: [PATCH 7/7] testcppcheck.cpp: fixed `unusedPrivateFunction` selfcheck warning (it shadowed a base member variable) --- test/testcppcheck.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/testcppcheck.cpp b/test/testcppcheck.cpp index f7b2f939582..37eebcc8a84 100644 --- a/test/testcppcheck.cpp +++ b/test/testcppcheck.cpp @@ -122,7 +122,7 @@ class TestCppcheck : public TestFixture { ASSERT(foundMissingIncludeSystem); } - static std::string exename(const std::string& exe) + static std::string exename_(const std::string& exe) { #ifdef _WIN32 return exe + ".exe"; @@ -137,7 +137,7 @@ class TestCppcheck : public TestFixture { // NOLINTNEXTLINE(performance-unnecessary-value-param) - used as callback so we need to preserve the signature return [&](std::string exe, std::vector args, std::string redirect, std::string& /*output*/) -> int { ++called; - if (exe == exename("clang-tidy")) + if (exe == exename_("clang-tidy")) { ASSERT_EQUALS(4, args.size()); ASSERT_EQUALS("-quiet", args[0]); @@ -147,14 +147,14 @@ class TestCppcheck : public TestFixture { ASSERT_EQUALS("2>&1", redirect); return EXIT_SUCCESS; } - if (exe == exename("python3")) + if (exe == exename_("python3")) { ASSERT_EQUALS(1, args.size()); ASSERT_EQUALS("--version", args[0]); ASSERT_EQUALS("2>&1", redirect); return EXIT_SUCCESS; } - if (exe == exename("python")) + if (exe == exename_("python")) { ASSERT_EQUALS(1, args.size()); ASSERT_EQUALS("--version", args[0]); @@ -218,7 +218,7 @@ class TestCppcheck : public TestFixture { // TODO: clang-tidy is currently not invoked for file inputs - see #12053 // TODO: needs to become a proper error - TODO_ASSERT_EQUALS("Failed to execute '" + exename("clang-tidy") + "' (no command callback provided)\n", "", GET_REDIRECT_ERROUT); + TODO_ASSERT_EQUALS("Failed to execute '" + exename_("clang-tidy") + "' (no command callback provided)\n", "", GET_REDIRECT_ERROUT); ASSERT_EQUALS(0, called); // not called because we check if the callback exists } @@ -303,7 +303,7 @@ class TestCppcheck : public TestFixture { ASSERT_EQUALS("Bailing out from analysis: Checking file failed: Failed to execute addon - no command callback provided", it->shortMessage()); // TODO: add addon name // TODO: needs to become a proper error - ASSERT_EQUALS("Failed to execute '" + exename("clang-tidy") + "' (no command callback provided)\n", GET_REDIRECT_ERROUT); + ASSERT_EQUALS("Failed to execute '" + exename_("clang-tidy") + "' (no command callback provided)\n", GET_REDIRECT_ERROUT); ASSERT_EQUALS(0, called); // not called because we check if the callback exists }