From b3f9abd6d6197fb7833653333c053945c4d34d2d Mon Sep 17 00:00:00 2001 From: firewave Date: Tue, 14 Jan 2025 14:51:47 +0100 Subject: [PATCH 01/10] other_test.py: split up `test_ignore_project_2` --- test/cli/other_test.py | 93 ++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 58 deletions(-) diff --git a/test/cli/other_test.py b/test/cli/other_test.py index 01c2adaaf4e..0283e76ef6e 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -2222,89 +2222,66 @@ def __write_compdb(tmpdir, test_file): return compile_commands -# TODO: -i appears to be ignored -@pytest.mark.xfail(strict=True) -def test_ignore_project_2(tmpdir): +def __test_ignore_project_2(tmpdir, extra_args, append=False, inject_path=False): os.mkdir(os.path.join(tmpdir, 'src')) test_file = os.path.join(tmpdir, 'src', 'test.cpp') with open(test_file, 'wt'): pass lines_exp = [ - 'cppcheck: error: could not find or open any of the paths given.', - 'cppcheck: Maybe all paths were ignored?' + 'cppcheck: error: no C or C++ source files found.', + 'cppcheck: all paths were ignored' ] - project_file = __write_compdb(tmpdir, test_file) args = [ - '-itest.cpp', + '-q', '--project={}'.format(project_file) ] - exitcode, stdout, _ = cppcheck(args, cwd=tmpdir) - assert exitcode == 1, stdout + if inject_path: + extra_args = [ extra_args[0].replace('$path', str(test_file)) ] + if append: + args += extra_args + else: + args = extra_args + args + print(args) + + exitcode, stdout, stderr = cppcheck(args, cwd=tmpdir) + assert exitcode == 1, stdout if stdout else stderr assert stdout.splitlines() == lines_exp - # make sure it also matches when specified after project - project_file = __write_compdb(tmpdir, test_file) - args = [ - '--project={}'.format(project_file), - '-itest.cpp' - ] - exitcode, stdout, _ = cppcheck(args, cwd=tmpdir) - assert exitcode == 1, stdout - assert stdout.splitlines() == lines_exp +@pytest.mark.xfail(strict=True) # TODO: -i appears to be ignored +def test_ignore_project_2_file(tmpdir): + __test_ignore_project_2(tmpdir, ['-itest.cpp']) - project_file = __write_compdb(tmpdir, test_file) - args = [ - '-isrc/test.cpp', - '--project={}'.format(project_file) - ] - exitcode, stdout, _ = cppcheck(args, cwd=tmpdir) - assert exitcode == 1, stdout - assert stdout.splitlines() == lines_exp +@pytest.mark.xfail(strict=True) # TODO: -i appears to be ignored +def test_ignore_project_2_file_append(tmpdir): + # make sure it also matches when specified after project + __test_ignore_project_2(tmpdir, ['-itest.cpp'], append=True) - project_file = __write_compdb(tmpdir, test_file) - args = [ - '-isrc\\test.cpp', - '--project={}'.format(project_file) - ] - exitcode, stdout, _ = cppcheck(args, cwd=tmpdir) - assert exitcode == 1, stdout - assert stdout.splitlines() == lines_exp +@pytest.mark.xfail(strict=True) # TODO: -i appears to be ignored +def test_ignore_project_2_file_relative(tmpdir): + __test_ignore_project_2(tmpdir, ['-isrc/test.cpp']) - project_file = __write_compdb(tmpdir, test_file) - args = [ - '-isrc/', - '--project={}'.format(project_file) - ] - exitcode, stdout, _ = cppcheck(args, cwd=tmpdir) - assert exitcode == 1, stdout - assert stdout.splitlines() == lines_exp +@pytest.mark.xfail(strict=True) # TODO: -i appears to be ignored +def test_ignore_project_2_file_relative_backslash(tmpdir): + __test_ignore_project_2(tmpdir, ['-isrc\\test.cpp']) - project_file = __write_compdb(tmpdir, test_file) - args = [ - '-isrc\\', - '--project={}'.format(project_file) - ] - exitcode, stdout, _ = cppcheck(args, cwd=tmpdir) - assert exitcode == 1, stdout - assert stdout.splitlines() == lines_exp +def test_ignore_project_2_path_relative(tmpdir): + __test_ignore_project_2(tmpdir, ['-isrc/']) - project_file = __write_compdb(tmpdir, test_file) - args = [ - '-i{}'.format(test_file), - '--project={}'.format(project_file) - ] - exitcode, stdout, _ = cppcheck(args, cwd=tmpdir) - assert exitcode == 1, stdout - assert stdout.splitlines() == lines_exp +def test_ignore_project_2_path_relative_backslash(tmpdir): + __test_ignore_project_2(tmpdir, ['-isrc\\']) + + +def test_ignore_project_2_abspath(tmpdir): + __test_ignore_project_2(tmpdir, ['-i$path'], inject_path=True) def test_dumpfile_platform(tmpdir): From 69f3cdddc4cb393ee34f9255cdb2adf9da93fd23 Mon Sep 17 00:00:00 2001 From: firewave Date: Tue, 14 Jan 2025 14:52:07 +0100 Subject: [PATCH 02/10] more-projects_test.py: fixed xfail annotation --- test/cli/more-projects_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cli/more-projects_test.py b/test/cli/more-projects_test.py index f61b0c42e9f..51290a7d6a3 100644 --- a/test/cli/more-projects_test.py +++ b/test/cli/more-projects_test.py @@ -705,7 +705,7 @@ def test_project_file_ignore_3(tmpdir): assert_cppcheck(args, ec_exp=1, err_exp=[], out_exp=out_lines) -@pytest.mark.xfail +@pytest.mark.xfail(strict=True) def test_json_file_ignore(tmpdir): test_file = os.path.join(tmpdir, 'test.cpp') with open(test_file, 'wt') as f: From dccaff1735e8b248dbce3b261517c2d011cdac32 Mon Sep 17 00:00:00 2001 From: firewave Date: Tue, 14 Jan 2025 14:53:44 +0100 Subject: [PATCH 03/10] other_test.py: added TODO --- test/cli/other_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/cli/other_test.py b/test/cli/other_test.py index 0283e76ef6e..58313336f29 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -2033,6 +2033,7 @@ def test_ignore(tmpdir): with open(test_file, 'wt'): pass + # TODO: this should say that all paths are ignored lines_exp = [ 'cppcheck: error: could not find or open any of the paths given.', 'cppcheck: Maybe all paths were ignored?' From 7cc9f27afa9d3ceb84567bbdf642a8a85580d671 Mon Sep 17 00:00:00 2001 From: firewave Date: Sun, 28 Jul 2024 09:42:38 +0200 Subject: [PATCH 04/10] add CLI option `--debug-ignore` to print ignored paths --- cli/cmdlineparser.cpp | 28 +++++++++----- cli/filelister.cpp | 76 ++++++++++++++++++++++++++------------ cli/filelister.h | 6 ++- lib/importproject.cpp | 7 +++- lib/importproject.h | 2 +- lib/settings.h | 3 ++ test/testcmdlineparser.cpp | 8 ++++ 7 files changed, 92 insertions(+), 38 deletions(-) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 79b7e0ae4f7..7bda11b3e9b 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -276,7 +276,7 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[]) // TODO: verbose log which files were ignored? const PathMatch matcher(ignored, caseSensitive); for (const std::string &pathname : pathnamesRef) { - const std::string err = FileLister::recursiveAddFiles(filesResolved, Path::toNativeSeparators(pathname), mSettings.library.markupExtensions(), matcher); + const std::string err = FileLister::recursiveAddFiles(filesResolved, Path::toNativeSeparators(pathname), mSettings.library.markupExtensions(), matcher, mSettings.debugignore); if (!err.empty()) { // TODO: bail out? mLogger.printMessage(err); @@ -619,6 +619,10 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a else if (std::strcmp(argv[i], "--debug-clang-output") == 0) mSettings.debugClangOutput = true; + // Show debug messages for ignored files + else if (std::strcmp(argv[i], "--debug-ignore") == 0) + mSettings.debugignore = true; + // Show --debug output after the first simplifications else if (std::strcmp(argv[i], "--debug") == 0 || std::strcmp(argv[i], "--debug-normal") == 0) @@ -823,13 +827,6 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a if (!path.empty()) { path = Path::removeQuotationMarks(std::move(path)); path = Path::simplifyPath(std::move(path)); - - // TODO: this only works when it exists - if (Path::isDirectory(path)) { - // If directory name doesn't end with / or \, add it - if (!endsWith(path, '/')) - path += '/'; - } mIgnoredPaths.emplace_back(std::move(path)); } } @@ -1590,11 +1587,24 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a return Result::Fail; } + for (auto& path : mIgnoredPaths) + { + bool isdir = false; + if (!Path::exists(path, &isdir) && mSettings.debugignore) + std::cout << "path to ignore does not exist: " << path << std::endl; + // TODO: this only works when it exists + if (isdir) { + // If directory name doesn't end with / or \, add it + if (!endsWith(path, '/')) + path += '/'; + } + } + if (!project.guiProject.pathNames.empty()) mPathNames = project.guiProject.pathNames; if (!project.fileSettings.empty()) { - project.ignorePaths(mIgnoredPaths); + project.ignorePaths(mIgnoredPaths, mSettings.debugignore); if (project.fileSettings.empty()) { mLogger.printError("no C or C++ source files found."); mLogger.printMessage("all paths were ignored"); // TODO: log this differently? diff --git a/cli/filelister.cpp b/cli/filelister.cpp index f1b6d97feda..684ed10c328 100644 --- a/cli/filelister.cpp +++ b/cli/filelister.cpp @@ -29,6 +29,7 @@ #include "utils.h" #include +#include #include #include @@ -45,7 +46,7 @@ // When compiling Unicode targets WinAPI automatically uses *W Unicode versions // of called functions. Thus, we explicitly call *A versions of the functions. -static std::string addFiles2(std::list&files, const std::string &path, const std::set &extra, bool recursive, const PathMatch& ignored) +static std::string addFiles2(std::list&files, const std::string &path, const std::set &extra, bool recursive, const PathMatch& ignored, bool debug = false) { const std::string cleanedPath = Path::toNativeSeparators(path); @@ -106,17 +107,23 @@ static std::string addFiles2(std::list&files, const std::string if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { // File Standards::Language lang = Standards::Language::None; - if ((!checkAllFilesInDir || Path::acceptFile(fname, extra, &lang)) && !ignored.match(fname)) { - std::string nativename = Path::fromNativeSeparators(fname); + if ((!checkAllFilesInDir || Path::acceptFile(fname, extra, &lang))) { + if (!ignored.match(fname)) { + std::string nativename = Path::fromNativeSeparators(fname); - // Limitation: file sizes are assumed to fit in a 'size_t' + // Limitation: file sizes are assumed to fit in a 'size_t' #ifdef _WIN64 - const std::size_t filesize = (static_cast(ffd.nFileSizeHigh) << 32) | ffd.nFileSizeLow; + const std::size_t filesize = (static_cast(ffd.nFileSizeHigh) << 32) | ffd.nFileSizeLow; #else - const std::size_t filesize = ffd.nFileSizeLow; + const std::size_t filesize = ffd.nFileSizeLow; #endif - files.emplace_back(std::move(nativename), lang, filesize); + files.emplace_back(std::move(nativename), lang, filesize); + } + else if (debug) + { + std::cout << "ignored path: " << fname << std::endl; + } } } else { // Directory @@ -135,6 +142,10 @@ static std::string addFiles2(std::list&files, const std::string files.insert(files.end(), std::make_move_iterator(filesSorted.begin()), std::make_move_iterator(filesSorted.end())); } + else if (debug) + { + std::cout << "ignored path: " << fname << std::endl; + } } } } @@ -151,14 +162,14 @@ static std::string addFiles2(std::list&files, const std::string return ""; } -std::string FileLister::addFiles(std::list &files, const std::string &path, const std::set &extra, bool recursive, const PathMatch& ignored) +std::string FileLister::addFiles(std::list &files, const std::string &path, const std::set &extra, bool recursive, const PathMatch& ignored, bool debug) { if (path.empty()) return "no path specified"; std::list filesSorted; - std::string err = addFiles2(filesSorted, path, extra, recursive, ignored); + std::string err = addFiles2(filesSorted, path, extra, recursive, ignored, debug); // files need to be sorted as the filesystems dosn't provide a stable order filesSorted.sort([](const FileWithDetails& a, const FileWithDetails& b) { @@ -183,11 +194,15 @@ static std::string addFiles2(std::list &files, const std::string &path, const std::set &extra, bool recursive, - const PathMatch& ignored - ) + const PathMatch& ignored, + bool debug) { if (ignored.match(path)) + { + if (debug) + std::cout << "ignored path: " << path << std::endl; return ""; + } struct stat file_stat; if (stat(path.c_str(), &file_stat) == -1) @@ -224,20 +239,33 @@ static std::string addFiles2(std::list &files, const bool path_is_directory = Path::isDirectory(new_path); #endif if (path_is_directory) { - if (recursive && !ignored.match(new_path)) { - std::string err = addFiles2(files, new_path, extra, recursive, ignored); - if (!err.empty()) { - return err; + if (recursive) { + if (!ignored.match(new_path)) { + std::string err = addFiles2(files, new_path, extra, recursive, ignored, debug); + if (!err.empty()) { + return err; + } + } + else if (debug) + { + std::cout << "ignored path: " << new_path << std::endl; } } } else { Standards::Language lang = Standards::Language::None; - if (Path::acceptFile(new_path, extra, &lang) && !ignored.match(new_path)) { - if (stat(new_path.c_str(), &file_stat) == -1) { - const int err = errno; - return "could not stat file '" + new_path + "' (errno: " + std::to_string(err) + ")"; + if (Path::acceptFile(new_path, extra, &lang)) { + if (!ignored.match(new_path)) + { + if (stat(new_path.c_str(), &file_stat) == -1) { + const int err = errno; + return "could not stat file '" + new_path + "' (errno: " + std::to_string(err) + ")"; + } + files.emplace_back(new_path, lang, file_stat.st_size); + } + else if (debug) + { + std::cout << "ignored path: " << new_path << std::endl; } - files.emplace_back(new_path, lang, file_stat.st_size); } } } @@ -245,7 +273,7 @@ static std::string addFiles2(std::list &files, return ""; } -std::string FileLister::addFiles(std::list &files, const std::string &path, const std::set &extra, bool recursive, const PathMatch& ignored) +std::string FileLister::addFiles(std::list &files, const std::string &path, const std::set &extra, bool recursive, const PathMatch& ignored, bool debug) { if (path.empty()) return "no path specified"; @@ -256,7 +284,7 @@ std::string FileLister::addFiles(std::list &files, const std::s std::list filesSorted; - std::string err = addFiles2(filesSorted, corrected_path, extra, recursive, ignored); + std::string err = addFiles2(filesSorted, corrected_path, extra, recursive, ignored, debug); // files need to be sorted as the filesystems dosn't provide a stable order filesSorted.sort([](const FileWithDetails& a, const FileWithDetails& b) { @@ -269,7 +297,7 @@ std::string FileLister::addFiles(std::list &files, const std::s #endif -std::string FileLister::recursiveAddFiles(std::list &files, const std::string &path, const std::set &extra, const PathMatch& ignored) +std::string FileLister::recursiveAddFiles(std::list &files, const std::string &path, const std::set &extra, const PathMatch& ignored, bool debug) { - return addFiles(files, path, extra, true, ignored); + return addFiles(files, path, extra, true, ignored, debug); } diff --git a/cli/filelister.h b/cli/filelister.h index 6cdd99c7e43..95d47fae021 100644 --- a/cli/filelister.h +++ b/cli/filelister.h @@ -41,9 +41,10 @@ class FileLister { * @param path root path * @param extra Extra file extensions * @param ignored ignored paths + * @param debug log if path was ignored * @return On success, an empty string is returned. On error, a error message is returned. */ - static std::string recursiveAddFiles(std::list &files, const std::string &path, const std::set &extra, const PathMatch& ignored); + static std::string recursiveAddFiles(std::list &files, const std::string &path, const std::set &extra, const PathMatch& ignored, bool debug = false); /** * @brief (Recursively) add source files to a map. @@ -55,9 +56,10 @@ class FileLister { * @param extra Extra file extensions * @param recursive Enable recursion * @param ignored ignored paths + * @param debug log when a path was ignored * @return On success, an empty string is returned. On error, a error message is returned. */ - static std::string addFiles(std::list &files, const std::string &path, const std::set &extra, bool recursive, const PathMatch& ignored); + static std::string addFiles(std::list &files, const std::string &path, const std::set &extra, bool recursive, const PathMatch& ignored, bool debug = false); }; /// @} diff --git a/lib/importproject.cpp b/lib/importproject.cpp index 2d30b80f633..f9b4a2d15cd 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -42,7 +42,7 @@ #include "json.h" // TODO: align the exclusion logic with PathMatch -void ImportProject::ignorePaths(const std::vector &ipaths) +void ImportProject::ignorePaths(const std::vector &ipaths, bool debug) { for (auto it = fileSettings.cbegin(); it != fileSettings.cend();) { bool ignore = false; @@ -63,8 +63,11 @@ void ImportProject::ignorePaths(const std::vector &ipaths) } } } - if (ignore) + if (ignore) { + if (debug) + std::cout << "ignored path: " << it->filename() << std::endl; it = fileSettings.erase(it); + } else ++it; } diff --git a/lib/importproject.h b/lib/importproject.h index 243c2aff3a2..8a3705b3e2a 100644 --- a/lib/importproject.h +++ b/lib/importproject.h @@ -93,7 +93,7 @@ class CPPCHECKLIB WARN_UNUSED ImportProject { std::string platform; } guiProject; - void ignorePaths(const std::vector &ipaths); + void ignorePaths(const std::vector &ipaths, bool debug = false); void ignoreOtherConfigs(const std::string &cfg); Type import(const std::string &filename, Settings *settings=nullptr, Suppressions *supprs=nullptr); diff --git a/lib/settings.h b/lib/settings.h index 6286029bd62..49e4f1e6a3e 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -184,6 +184,9 @@ class CPPCHECKLIB WARN_UNUSED Settings { /** @brief Is --debug-clang-output given? */ bool debugClangOutput{}; + /** @brief Is --debug-ignore given? */ + bool debugignore{}; + /** @brief Internal: Is --debug-lookup or --debug-lookup=all given? */ bool debuglookup{}; diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index ec2b5cbcd9b..86c42787020 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -440,6 +440,7 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(debugClangOutput); TEST_CASE(debugXmlMultiple); TEST_CASE(debugNormalXmlMultiple); + TEST_CASE(debugIgnore); TEST_CASE(ignorepaths1); TEST_CASE(ignorepaths2); @@ -2974,6 +2975,13 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS("cppcheck: error: printing debug output in XML format does not support multiple input files.\n", logger->str()); } + void debugIgnore() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--debug-ignore", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS(true, settings->debugignore); + } + void ignorepaths1() { REDIRECT; const char * const argv[] = {"cppcheck", "-isrc", "file.cpp"}; From a9cd5ca3cd633f02bb7cfe1162e9de014398d17d Mon Sep 17 00:00:00 2001 From: firewave Date: Wed, 24 Jul 2024 10:51:50 +0200 Subject: [PATCH 05/10] TestCmdlineParser: added more ignore tests --- test/testcmdlineparser.cpp | 74 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index 86c42787020..c6ff476e589 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -449,6 +449,11 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(ignorefilepaths1); TEST_CASE(ignorefilepaths2); TEST_CASE(ignorefilepaths3); + TEST_CASE(ignorefilepaths4); + TEST_CASE(ignorefilepaths5); + TEST_CASE(ignorefilepaths6); + TEST_CASE(ignorefilepaths7); + TEST_CASE(ignorefilepaths8); TEST_CASE(nonexistentpath); @@ -2988,6 +2993,8 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); ASSERT_EQUALS("src", parser->getIgnoredPaths()[0]); + ASSERT_EQUALS(1, parser->getPathNames().size()); + ASSERT_EQUALS("file.cpp", parser->getPathNames()[0]); } void ignorepaths2() { @@ -2996,6 +3003,8 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); ASSERT_EQUALS("src", parser->getIgnoredPaths()[0]); + ASSERT_EQUALS(1, parser->getPathNames().size()); + ASSERT_EQUALS("file.cpp", parser->getPathNames()[0]); } void ignorepaths3() { @@ -3005,6 +3014,8 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS(2, parser->getIgnoredPaths().size()); ASSERT_EQUALS("src", parser->getIgnoredPaths()[0]); ASSERT_EQUALS("module", parser->getIgnoredPaths()[1]); + ASSERT_EQUALS(1, parser->getPathNames().size()); + ASSERT_EQUALS("file.cpp", parser->getPathNames()[0]); } void ignorepaths4() { @@ -3014,6 +3025,8 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS(2, parser->getIgnoredPaths().size()); ASSERT_EQUALS("src", parser->getIgnoredPaths()[0]); ASSERT_EQUALS("module", parser->getIgnoredPaths()[1]); + ASSERT_EQUALS(1, parser->getPathNames().size()); + ASSERT_EQUALS("file.cpp", parser->getPathNames()[0]); } void ignorefilepaths1() { @@ -3022,6 +3035,8 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); ASSERT_EQUALS("foo.cpp", parser->getIgnoredPaths()[0]); + ASSERT_EQUALS(1, parser->getPathNames().size()); + ASSERT_EQUALS("file.cpp", parser->getPathNames()[0]); } void ignorefilepaths2() { @@ -3030,6 +3045,8 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); ASSERT_EQUALS("src/foo.cpp", parser->getIgnoredPaths()[0]); + ASSERT_EQUALS(1, parser->getPathNames().size()); + ASSERT_EQUALS("file.cpp", parser->getPathNames()[0]); } void ignorefilepaths3() { @@ -3038,6 +3055,63 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); ASSERT_EQUALS("foo.cpp", parser->getIgnoredPaths()[0]); + ASSERT_EQUALS(1, parser->getPathNames().size()); + ASSERT_EQUALS("file.cpp", parser->getPathNames()[0]); + } + + void ignorefilepaths4() { + REDIRECT; + const char * const argv[] = {"cppcheck", "-ifoo.cpp", "file.cpp"}; + ASSERT(!fillSettingsFromArgs(argv)); + ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); + ASSERT_EQUALS("foo.cpp", parser->getIgnoredPaths()[0]); + ASSERT_EQUALS(1, parser->getPathNames().size()); + ASSERT_EQUALS("file.cpp", parser->getPathNames()[0]); + TODO_ASSERT_EQUALS("cppcheck: error: could not find or open any of the paths given.\n", "cppcheck: error: could not find or open any of the paths given.\ncppcheck: Maybe all paths were ignored?\n", logger->str()); + } + + void ignorefilepaths5() { + REDIRECT; + const char * const argv[] = {"cppcheck", "-ifile.cpp", "file.cpp"}; + ASSERT(!fillSettingsFromArgs(argv)); + ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); + ASSERT_EQUALS("file.cpp", parser->getIgnoredPaths()[0]); + ASSERT_EQUALS(1, parser->getPathNames().size()); + ASSERT_EQUALS("file.cpp", parser->getPathNames()[0]); + ASSERT_EQUALS("cppcheck: error: could not find or open any of the paths given.\ncppcheck: Maybe all paths were ignored?\n", logger->str()); + } + + void ignorefilepaths6() { + REDIRECT; + const char * const argv[] = {"cppcheck", "-isrc/file.cpp", "src/file.cpp"}; + ASSERT(!fillSettingsFromArgs(argv)); + ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); + ASSERT_EQUALS("src/file.cpp", parser->getIgnoredPaths()[0]); + ASSERT_EQUALS(1, parser->getPathNames().size()); + ASSERT_EQUALS("src/file.cpp", parser->getPathNames()[0]); + ASSERT_EQUALS("cppcheck: error: could not find or open any of the paths given.\ncppcheck: Maybe all paths were ignored?\n", logger->str()); + } + + void ignorefilepaths7() { + REDIRECT; + const char * const argv[] = {"cppcheck", "-isrc\\file.cpp", "src/file.cpp"}; + ASSERT(!fillSettingsFromArgs(argv)); + ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); + ASSERT_EQUALS("src/file.cpp", parser->getIgnoredPaths()[0]); + ASSERT_EQUALS(1, parser->getPathNames().size()); + ASSERT_EQUALS("src/file.cpp", parser->getPathNames()[0]); + ASSERT_EQUALS("cppcheck: error: could not find or open any of the paths given.\ncppcheck: Maybe all paths were ignored?\n", logger->str()); + } + + void ignorefilepaths8() { + REDIRECT; + const char * const argv[] = {"cppcheck", "-isrc/file.cpp", "src\\file.cpp"}; + ASSERT(!fillSettingsFromArgs(argv)); + ASSERT_EQUALS(1, parser->getIgnoredPaths().size()); + ASSERT_EQUALS("src/file.cpp", parser->getIgnoredPaths()[0]); + ASSERT_EQUALS(1, parser->getPathNames().size()); + ASSERT_EQUALS("src/file.cpp", parser->getPathNames()[0]); + ASSERT_EQUALS("cppcheck: error: could not find or open any of the paths given.\ncppcheck: Maybe all paths were ignored?\n", logger->str()); } void nonexistentpath() { From a98743a5985e52c19ded3930624cff3602ea78cb Mon Sep 17 00:00:00 2001 From: firewave Date: Sat, 15 Feb 2025 07:53:21 +0100 Subject: [PATCH 06/10] TestPath: added `Path::fromNativeSeparators()` tests --- test/testpath.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/testpath.cpp b/test/testpath.cpp index 1c022117a0d..4a43cf3e53c 100644 --- a/test/testpath.cpp +++ b/test/testpath.cpp @@ -55,6 +55,7 @@ class TestPath : public TestFixture { TEST_CASE(simplifyPath); TEST_CASE(getAbsolutePath); TEST_CASE(exists); + TEST_CASE(fromNativeSeparators); } void removeQuotationMarks() const { @@ -577,6 +578,20 @@ class TestPath : public TestFixture { ASSERT_EQUALS(false, Path::exists("testpath.txt", &b)); ASSERT_EQUALS(false, b); } + + void fromNativeSeparators() const { + ASSERT_EQUALS("lib/file.c", Path::fromNativeSeparators("lib/file.c")); + ASSERT_EQUALS("lib//file.c", Path::fromNativeSeparators("lib//file.c")); + ASSERT_EQUALS("/lib/file.c", Path::fromNativeSeparators("/lib/file.c")); + ASSERT_EQUALS("//lib/file.c", Path::fromNativeSeparators("//lib/file.c")); + ASSERT_EQUALS("./lib/file.c", Path::fromNativeSeparators("./lib/file.c")); + + ASSERT_EQUALS("lib/file.c", Path::fromNativeSeparators("lib\\file.c")); + ASSERT_EQUALS("lib//file.c", Path::fromNativeSeparators("lib\\\\file.c")); + ASSERT_EQUALS("/lib/file.c", Path::fromNativeSeparators("\\lib\\file.c")); + ASSERT_EQUALS("//lib/file.c", Path::fromNativeSeparators("\\\\lib\\file.c")); + ASSERT_EQUALS("./lib/file.c", Path::fromNativeSeparators(".\\lib\\file.c")); + } }; REGISTER_TEST(TestPath) From 15ba23c639a992250affa1c3ac9df00cf49bbd21 Mon Sep 17 00:00:00 2001 From: firewave Date: Sat, 15 Feb 2025 07:54:06 +0100 Subject: [PATCH 07/10] pathmath.h: clarified how matching directories work --- lib/pathmatch.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/pathmatch.h b/lib/pathmatch.h index 4ee7eea6c15..f0ace4fbc94 100644 --- a/lib/pathmatch.h +++ b/lib/pathmatch.h @@ -35,6 +35,9 @@ class CPPCHECKLIB PathMatch { /** * The constructor. + * + * If a path is a directory it needs to end with a file separator. + * * @param paths List of masks. * @param caseSensitive Match the case of the characters when * matching paths? @@ -43,6 +46,9 @@ class CPPCHECKLIB PathMatch { /** * @brief Match path against list of masks. + * + * If you want to match a directory the given path needs to end with a path separator. + * * @param path Path to match. * @return true if any of the masks match the path, false otherwise. */ From 5bf98485e6cf8cbe6852adb671eaf105a181edc2 Mon Sep 17 00:00:00 2001 From: firewave Date: Sat, 15 Feb 2025 08:30:52 +0100 Subject: [PATCH 08/10] TestFileLister: test excluding directories --- test/testfilelister.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/testfilelister.cpp b/test/testfilelister.cpp index f49b049df0c..80601d61050 100644 --- a/test/testfilelister.cpp +++ b/test/testfilelister.cpp @@ -40,6 +40,7 @@ class TestFileLister : public TestFixture { TEST_CASE(recursiveAddFilesEmptyPath); TEST_CASE(excludeFile1); TEST_CASE(excludeFile2); + TEST_CASE(excludeDir); TEST_CASE(addFiles); } @@ -136,6 +137,21 @@ class TestFileLister : public TestFixture { ASSERT_EQUALS(basedir + "lib/token.cpp", files.begin()->path()); } + void excludeDir() const { + const std::string basedir = findBaseDir() + "."; + + std::list files; + std::vector ignored{"lib/"}; // needs to end with slash so it matches directories - added by CmdLineParser + PathMatch matcher(ignored); + std::string err = FileLister::recursiveAddFiles(files, basedir, {}, matcher); + ASSERT_EQUALS("", err); + ASSERT(!files.empty()); + const auto it = std::find_if(files.cbegin(), files.cend(), [](const FileWithDetails& f){ + return f.spath().find("/lib/") != std::string::npos; + }); + ASSERT(it == files.cend()); + } + void addFiles() const { const std::string adddir = findBaseDir() + "."; From d39f00d4f5d5c7690a5de144b4809330b60a895e Mon Sep 17 00:00:00 2001 From: firewave Date: Sat, 15 Feb 2025 14:20:03 +0100 Subject: [PATCH 09/10] FileLister: ignore directories as a whole instead of its contents individually --- cli/filelister.cpp | 8 ++++++-- test/cli/other_test.py | 27 ++++++++++++++++++++++++++- test/cli/testutils.py | 4 ++-- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/cli/filelister.cpp b/cli/filelister.cpp index 684ed10c328..676d0448a51 100644 --- a/cli/filelister.cpp +++ b/cli/filelister.cpp @@ -128,7 +128,9 @@ static std::string addFiles2(std::list&files, const std::string } else { // Directory if (recursive) { - if (!ignored.match(fname)) { + // append a slash if it is a directory since that is what we are doing for mIgnoredPaths directory entries. + // otherwise we would ignore all its contents individually instead as a whole. + if (!ignored.match(fname + '/')) { std::list filesSorted; std::string err = addFiles2(filesSorted, fname, extra, recursive, ignored); @@ -240,7 +242,9 @@ static std::string addFiles2(std::list &files, #endif if (path_is_directory) { if (recursive) { - if (!ignored.match(new_path)) { + // append a slash if it is a directory since that is what we are doing for mIgnoredPaths directory entries. + // otherwise we would ignore all its contents individually instead as a whole. + if (!ignored.match(new_path + '/')) { std::string err = addFiles2(files, new_path, extra, recursive, ignored, debug); if (!err.empty()) { return err; diff --git a/test/cli/other_test.py b/test/cli/other_test.py index 58313336f29..e0a431a4430 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -3140,4 +3140,29 @@ def test_debug_valueflow_xml(tmp_path): # #13606 assert 'floatvalue' in value_elem[1].attrib assert value_elem[1].attrib['floatvalue'] == '1e-07' assert 'floatvalue' in value_elem[2].attrib - assert value_elem[2].attrib['floatvalue'] == '1e-07' \ No newline at end of file + assert value_elem[2].attrib['floatvalue'] == '1e-07' + + +def test_dir_ignore(tmp_path): + test_file = tmp_path / 'test.cpp' + with open(test_file, 'wt'): + pass + + lib_dir = tmp_path / 'lib' + os.mkdir(lib_dir) + lib_test_file = lib_dir / 'test.cpp' + with open(lib_test_file, 'wt'): + pass + + args = [ + '-ilib', + '--debug-ignore', + str(tmp_path) + ] + # make sure the whole directory is being ignored instead of each of its contents individually + out_lines = [ + 'ignored path: {}'.format(lib_dir), + 'Checking {} ...'.format(test_file) + ] + + assert_cppcheck(args, ec_exp=0, err_exp=[], out_exp=out_lines, cwd=str(tmp_path)) \ No newline at end of file diff --git a/test/cli/testutils.py b/test/cli/testutils.py index 00b9483d08e..f352af49f15 100644 --- a/test/cli/testutils.py +++ b/test/cli/testutils.py @@ -236,8 +236,8 @@ def cppcheck(*args, **kwargs): return return_code, stdout, stderr -def assert_cppcheck(args, ec_exp=None, out_exp=None, err_exp=None, env=None): - exitcode, stdout, stderr = cppcheck(args, env) +def assert_cppcheck(args, ec_exp=None, out_exp=None, err_exp=None, env=None, cwd=None): + exitcode, stdout, stderr = cppcheck(args, env=env, cwd=cwd) if ec_exp is not None: assert exitcode == ec_exp, stdout if out_exp is not None: From a7476af8f853f3081bf39d0e023ef7d4284433ec Mon Sep 17 00:00:00 2001 From: firewave Date: Mon, 17 Feb 2025 00:33:04 +0100 Subject: [PATCH 10/10] fixed #13641 - FileLister: do not report an error on Windows when the given path does not exist --- cli/filelister.cpp | 5 +++-- test/testfilelister.cpp | 5 ----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/cli/filelister.cpp b/cli/filelister.cpp index 676d0448a51..30392ef4b22 100644 --- a/cli/filelister.cpp +++ b/cli/filelister.cpp @@ -86,8 +86,9 @@ static std::string addFiles2(std::list&files, const std::string HANDLE hFind = FindFirstFileA(searchPattern.c_str(), &ffd); if (INVALID_HANDLE_VALUE == hFind) { const DWORD err = GetLastError(); - if (err == ERROR_FILE_NOT_FOUND) { - // no files matched + if (err == ERROR_FILE_NOT_FOUND || // the pattern did not match anything + err == ERROR_PATH_NOT_FOUND) // the given search path does not exist + { return ""; } return "finding files failed. Search pattern: '" + searchPattern + "'. (error: " + std::to_string(err) + ")"; diff --git a/test/testfilelister.cpp b/test/testfilelister.cpp index 80601d61050..fefafededd9 100644 --- a/test/testfilelister.cpp +++ b/test/testfilelister.cpp @@ -181,12 +181,7 @@ class TestFileLister : public TestFixture { { const std::string addfile = Path::join(Path::join(adddir, "lib2"), "token.cpp"); // does not exist const std::string err = FileLister::addFiles(files, addfile, {}, true,PathMatch({})); -#ifdef _WIN32 - // TODO: get rid of this error - caused by missing intermediate folder - ASSERT_EQUALS("finding files failed. Search pattern: '" + dirprefix_nat + "lib2\\token.cpp'. (error: 3)", err); -#else ASSERT_EQUALS("", err); -#endif } { const std::string addfile = Path::join(Path::join(adddir, "lib"), "matchcompiler.h");