diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 842d597b0a4..2e808ab13b2 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -247,7 +247,7 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[]) std::list filesResolved; // Execute recursiveAddFiles() to each given file parameter // TODO: verbose log which files were ignored? - const PathMatch matcher(ignored, Path::getCurrentPath()); + PathMatch matcher(ignored, Path::getCurrentPath()); for (const std::string &pathname : pathnamesRef) { const std::string err = FileLister::recursiveAddFiles(filesResolved, Path::toNativeSeparators(pathname), mSettings.library.markupExtensions(), matcher, mSettings.debugignore); if (!err.empty()) { @@ -264,6 +264,12 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[]) return false; } + const auto& unmatched = matcher.unmatched(); + if (!unmatched.empty()) { + mLogger.printError("unused ignore/exclude path '" + unmatched.front() + "' to hide warnings in certain files use suppressions instead."); + return false; + } + std::list files; if (!mSettings.fileFilters.empty()) { files = filterFiles(mSettings.fileFilters, filesResolved); @@ -1723,12 +1729,16 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a mPathNames = project.guiProject.pathNames; if (!project.fileSettings.empty()) { - project.ignorePaths(mIgnoredPaths, mSettings.debugignore); + const auto& unmatched = 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? return Result::Fail; } + if (!unmatched.empty()) { + mLogger.printError("unused ignore/exclude path '" + unmatched.front() + "' to hide warnings in certain files use suppressions instead."); + return Result::Fail; + } mFileSettings = project.fileSettings; } diff --git a/cli/filelister.cpp b/cli/filelister.cpp index 9b95689679c..8e2ac784dc6 100644 --- a/cli/filelister.cpp +++ b/cli/filelister.cpp @@ -201,7 +201,7 @@ static std::string addFiles2(std::list &files, const std::string &path, const std::set &extra, bool recursive, - const PathMatch& ignored, + PathMatch& ignored, bool debug) { if (ignored.match(path)) @@ -280,7 +280,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, bool debug) +std::string FileLister::addFiles(std::list &files, const std::string &path, const std::set &extra, bool recursive, PathMatch& ignored, bool debug) { if (path.empty()) return "no path specified"; @@ -304,7 +304,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, bool debug) +std::string FileLister::recursiveAddFiles(std::list &files, const std::string &path, const std::set &extra, PathMatch& ignored, bool debug) { return addFiles(files, path, extra, true, ignored, debug); } diff --git a/cli/filelister.h b/cli/filelister.h index 12b8ddeed7e..e49ecb76179 100644 --- a/cli/filelister.h +++ b/cli/filelister.h @@ -44,7 +44,7 @@ class FileLister { * @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, bool debug = false); + static std::string recursiveAddFiles(std::list &files, const std::string &path, const std::set &extra, PathMatch& ignored, bool debug = false); /** * @brief (Recursively) add source files to a map. @@ -59,7 +59,7 @@ class FileLister { * @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, bool debug = false); + static std::string addFiles(std::list &files, const std::string &path, const std::set &extra, bool recursive, PathMatch& ignored, bool debug = false); }; /// @} diff --git a/gui/filelist.cpp b/gui/filelist.cpp index cdfa6676a4e..bdb009ed743 100644 --- a/gui/filelist.cpp +++ b/gui/filelist.cpp @@ -100,7 +100,14 @@ QStringList FileList::getFileList() const } return names; } - return applyExcludeList(); + QStringList unmatched; + return applyExcludeList(unmatched); +} + +QStringList FileList::getUnmatchedExcludes() const { + QStringList unmatched; + (void)applyExcludeList(unmatched); + return unmatched; } void FileList::addExcludeList(const QStringList &paths) @@ -117,9 +124,9 @@ static std::vector toStdStringList(const QStringList &stringList) return ret; } -QStringList FileList::applyExcludeList() const +QStringList FileList::applyExcludeList(QStringList& unmatched) const { - const PathMatch pathMatch(toStdStringList(mExcludedPaths), QDir::currentPath().toStdString()); + PathMatch pathMatch(toStdStringList(mExcludedPaths), QDir::currentPath().toStdString()); QStringList paths; for (const QFileInfo& item : mFileList) { @@ -129,5 +136,10 @@ QStringList FileList::applyExcludeList() const if (!pathMatch.match(canonical.toStdString())) paths << canonical; } + + for (const std::string& excludePath: pathMatch.unmatched()) { + unmatched << QString::fromStdString(excludePath); + } + return paths; } diff --git a/gui/filelist.h b/gui/filelist.h index 59f1284998d..b83a3b2e3fe 100644 --- a/gui/filelist.h +++ b/gui/filelist.h @@ -24,6 +24,8 @@ #include #include +class PathMatch; + /** * @brief A class for listing files and directories to check. * This class creates a list of files to check. If directory name is given then @@ -64,6 +66,12 @@ class FileList { */ QStringList getFileList() const; + /** + * @brief Return list of unmatched excludes + * @return list of unmatched excludes + */ + QStringList getUnmatchedExcludes() const; + /** * @brief Add list of paths to exclusion list. * @param paths Paths to exclude. @@ -89,9 +97,10 @@ class FileList { * This method takes the list of paths and applies the exclude lists to * it. And then returns the list of paths that did not match the * exclude filters. + * @param unmatched output of unmatched exclude paths * @return Filtered list of paths. */ - QStringList applyExcludeList() const; + QStringList applyExcludeList(QStringList& unmatched) const; private: QFileInfoList mFileList; diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 3ed37eb7b25..fff2d7fe3aa 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -683,6 +683,17 @@ void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLib, c return; } + const QStringList& unmatchedExcludePaths = pathList.getUnmatchedExcludes(); + if (!unmatchedExcludePaths.isEmpty()) { + QMessageBox msg(QMessageBox::Warning, + "Cppcheck", + tr("Unused exclude paths:\n%1\nto hide warnings in certain files use suppressions instead").arg(unmatchedExcludePaths.join("\n")), + QMessageBox::Ok, + this); + msg.exec(); + return; + } + std::list fdetails = enrichFilesForAnalysis(fileNames, checkSettings); // TODO: lock UI here? diff --git a/gui/test/filelist/testfilelist.cpp b/gui/test/filelist/testfilelist.cpp index 003c43c1ba0..7b720f82163 100644 --- a/gui/test/filelist/testfilelist.cpp +++ b/gui/test/filelist/testfilelist.cpp @@ -184,4 +184,39 @@ void TestFileList::filterFiles5() const QVERIFY(!files.contains(base + "/dir1/dir11/foo11.cpp")); } +void TestFileList::unmatchedExcludes1() const +{ + FileList list; + QStringList filters; + filters << "foo1.cpp" << "foo3.cc"; + list.addExcludeList(filters); + list.addDirectory(QString(SRCDIR) + "/../data/files"); + QVERIFY(list.getUnmatchedExcludes().isEmpty()); +} + +void TestFileList::unmatchedExcludes2() const +{ + FileList list; + QStringList filters; + filters << "foo1.cpp" << "bar.cpp" << "dir3/"; + list.addExcludeList(filters); + list.addDirectory(QString(SRCDIR) + "/../data/files", true); + const QStringList unmatched = list.getUnmatchedExcludes(); + QCOMPARE(unmatched.size(), 2); + QCOMPARE(unmatched[0], QString("bar.cpp")); + QCOMPARE(unmatched[1], QString("dir3/")); + // unmatched excludes does not affect the file list + QCOMPARE(list.getFileList().size(), 9); +} + +void TestFileList::unmatchedExcludes3() const +{ + FileList list; + QStringList filters; + filters << "dir1/"; + list.addExcludeList(filters); + list.addDirectory(QString(SRCDIR) + "/../data/files", true); + QVERIFY(list.getUnmatchedExcludes().isEmpty()); +} + QTEST_MAIN(TestFileList) diff --git a/gui/test/filelist/testfilelist.h b/gui/test/filelist/testfilelist.h index f8d9e3a5b7b..0520cef1aa9 100644 --- a/gui/test/filelist/testfilelist.h +++ b/gui/test/filelist/testfilelist.h @@ -33,4 +33,7 @@ private slots: void filterFiles3() const; void filterFiles4() const; void filterFiles5() const; + void unmatchedExcludes1() const; + void unmatchedExcludes2() const; + void unmatchedExcludes3() const; }; diff --git a/lib/importproject.cpp b/lib/importproject.cpp index 61ef7a2d38a..67ac89a0d77 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -191,7 +191,7 @@ void ImportProject::parseArgs(FileSettings &fs, const std::vector & fsSetDefines(fs, std::move(defs)); } -void ImportProject::ignorePaths(const std::vector &ipaths, bool debug) +std::vector ImportProject::ignorePaths(const std::vector &ipaths, bool debug) { PathMatch matcher(ipaths, Path::getCurrentPath()); for (auto it = fileSettings.cbegin(); it != fileSettings.cend();) { @@ -203,6 +203,7 @@ void ImportProject::ignorePaths(const std::vector &ipaths, bool deb else ++it; } + return matcher.unmatched(); } void ImportProject::ignoreOtherConfigs(const std::string &cfg) diff --git a/lib/importproject.h b/lib/importproject.h index b8bbbed3fa3..4b2dc79ec1b 100644 --- a/lib/importproject.h +++ b/lib/importproject.h @@ -102,7 +102,7 @@ class CPPCHECKLIB WARN_UNUSED ImportProject { std::string platform; } guiProject; - void ignorePaths(const std::vector &ipaths, bool debug = false); + std::vector 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/pathmatch.cpp b/lib/pathmatch.cpp index 87420828f17..c5d053d4877 100644 --- a/lib/pathmatch.cpp +++ b/lib/pathmatch.cpp @@ -31,10 +31,13 @@ PathMatch::PathMatch(std::vector patterns, std::string basepath, Sy mPatterns(std::move(patterns)), mBasepath(std::move(basepath)), mSyntax(syntax) {} -bool PathMatch::match(const std::string &path, Filemode mode) const +bool PathMatch::match(const std::string &path, Filemode mode) { return std::any_of(mPatterns.cbegin(), mPatterns.cend(), [&] (const std::string &pattern) { - return match(pattern, path, mBasepath, mode, mSyntax); + const bool res = match(pattern, path, mBasepath, mode, mSyntax); + if (res) + mMatchedPatterns.insert(pattern); + return res; }); } @@ -149,3 +152,12 @@ bool PathMatch::match(const std::string &pattern, const std::string &path, const return false; } } + +std::vector PathMatch::unmatched() const { + std::vector ret; + for (const std::string& s: mPatterns) { + if (mMatchedPatterns.count(s) == 0) + ret.push_back(s); + } + return ret; +} diff --git a/lib/pathmatch.h b/lib/pathmatch.h index 72fc89b7faa..c8caae679f3 100644 --- a/lib/pathmatch.h +++ b/lib/pathmatch.h @@ -117,7 +117,7 @@ class CPPCHECKLIB PathMatch { * @param mode The file mode of the file named by the path. * @return true if any of the masks match the path, false otherwise. */ - bool match(const std::string &path, Filemode mode = Filemode::regular) const; + bool match(const std::string &path, Filemode mode = Filemode::regular); /** * @brief Match path against a single pattern. @@ -169,12 +169,15 @@ class CPPCHECKLIB PathMatch { return pattern; } + std::vector unmatched() const; + protected: class PathIterator; private: /* List of patterns */ std::vector mPatterns; + std::set mMatchedPatterns; /* Base path to with patterns and paths are relative */ std::string mBasepath; /* The syntax to use */ diff --git a/test/helpers.cpp b/test/helpers.cpp index 06ad0c4c298..7c26feae6c1 100644 --- a/test/helpers.cpp +++ b/test/helpers.cpp @@ -84,7 +84,8 @@ ScopedFile::~ScopedFile() { // TODO: simplify the function call // hack to be able to delete *.plist output files std::list files; - const std::string res = FileLister::addFiles(files, mPath, {".plist"}, false, PathMatch()); + PathMatch ignored; + const std::string res = FileLister::addFiles(files, mPath, {".plist"}, false, ignored); if (!res.empty()) { std::cout << "ScopedFile(" << mPath + ") - generating file list failed (" << res << ")" << std::endl; } diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index 6f963e07212..28c106d4d72 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -519,6 +519,11 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(ignorefilepaths7); TEST_CASE(ignorefilepaths8); TEST_CASE(ignorefilepaths9); + TEST_CASE(ignoreUnused1); + TEST_CASE(ignoreUnused2); + TEST_CASE(ignoreUsed); + TEST_CASE(ignoreUnusedProject); + TEST_CASE(ignoreUsedProject); TEST_CASE(nonexistentpath); @@ -3649,6 +3654,56 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS("cppcheck: error: could not find or open any of the paths given.\ncppcheck: Maybe all paths were ignored?\n", logger->str()); } + void ignoreUnused1() { + REDIRECT; + ScopedFile file("file.cpp", ""); + const char * const argv[] = {"cppcheck", "-ifoo.cpp", "file.cpp"}; + ASSERT(!fillSettingsFromArgs(argv)); + ASSERT_EQUALS("cppcheck: error: unused ignore/exclude path 'foo.cpp' to hide warnings in certain files use suppressions instead.\n", logger->str()); + } + + void ignoreUnused2() { + REDIRECT; + ScopedFile file1("file1.cpp", ""); + ScopedFile file2("file2.cpp", ""); + const char * const argv[] = {"cppcheck", "-ifile1.cpp", "-ifoo.cpp", "file1.cpp", "file2.cpp"}; + ASSERT(!fillSettingsFromArgs(argv)); + ASSERT_EQUALS("cppcheck: error: unused ignore/exclude path 'foo.cpp' to hide warnings in certain files use suppressions instead.\n", logger->str()); + } + + void ignoreUsed() { + REDIRECT; + ScopedFile file1("file1.cpp", ""); + ScopedFile file2("file2.cpp", ""); + const char * const argv[] = {"cppcheck", "-ifile1.cpp", "file1.cpp", "file2.cpp"}; + ASSERT(fillSettingsFromArgs(argv)); + ASSERT_EQUALS("", logger->str()); + ASSERT_EQUALS(1, parser->getFiles().size()); + ASSERT_EQUALS("file2.cpp", parser->getFiles().cbegin()->path()); + } + + void ignoreUnusedProject() { + REDIRECT; + ScopedFile file("compile_commands.json", + R"([{"directory": "/tmp", "command": "gcc -c file1.c", "file": "file1.c"}, + {"directory": "/tmp", "command": "gcc -c file2.c", "file": "file2.c"}])"); + const char * const argv[] = {"cppcheck", "--project=compile_commands.json", "-ifile1.c", "-ifoo.c"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parseFromArgs(argv)); + ASSERT_EQUALS("cppcheck: error: unused ignore/exclude path 'foo.c' to hide warnings in certain files use suppressions instead.\n", logger->str()); + } + + void ignoreUsedProject() { + REDIRECT; + ScopedFile file("compile_commands.json", + R"([{"directory": "/tmp", "command": "gcc -c file1.c", "file": "file1.c"}, + {"directory": "/tmp", "command": "gcc -c file2.c", "file": "file2.c"}])"); + const char * const argv[] = {"cppcheck", "--project=compile_commands.json", "-ifile1.c"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parseFromArgs(argv)); + ASSERT_EQUALS("", logger->str()); + ASSERT_EQUALS(1, parser->getFileSettings().size()); + ASSERT_EQUALS("/tmp/file2.c", parser->getFileSettings().cbegin()->filename()); + } + void nonexistentpath() { REDIRECT; const char * const argv[] = {"cppcheck", "file.cpp"}; diff --git a/test/testfilelister.cpp b/test/testfilelister.cpp index 13057735513..e1c55564743 100644 --- a/test/testfilelister.cpp +++ b/test/testfilelister.cpp @@ -60,7 +60,8 @@ class TestFileLister : public TestFixture { // Recursively add add files.. std::list files; - std::string err = FileLister::recursiveAddFiles(files, adddir, {}, PathMatch()); + PathMatch ignored; + std::string err = FileLister::recursiveAddFiles(files, adddir, {}, ignored); ASSERT_EQUALS("", err); ASSERT(!files.empty()); @@ -106,7 +107,8 @@ class TestFileLister : public TestFixture { void recursiveAddFilesEmptyPath() const { std::list files; - const std::string err = FileLister::recursiveAddFiles(files, "", {}, PathMatch()); + PathMatch ignored; + const std::string err = FileLister::recursiveAddFiles(files, "", {}, ignored); ASSERT_EQUALS("no path specified", err); } @@ -124,7 +126,8 @@ class TestFileLister : public TestFixture { const std::string basedir = findBaseDir(); std::list files; - std::string err = FileLister::recursiveAddFiles(files, basedir + "lib/token.cpp", {}, PathMatch()); + PathMatch ignored; + std::string err = FileLister::recursiveAddFiles(files, basedir + "lib/token.cpp", {}, ignored); ASSERT_EQUALS("", err); ASSERT_EQUALS(1, files.size()); ASSERT_EQUALS(basedir + "lib/token.cpp", files.begin()->path()); @@ -157,27 +160,32 @@ class TestFileLister : public TestFixture { { const std::string addfile = Path::join(Path::join(adddir, "cli"), "main.cpp"); - const std::string err = FileLister::addFiles(files, addfile, {}, true,PathMatch()); + PathMatch ignored; + const std::string err = FileLister::addFiles(files, addfile, {}, true, ignored); ASSERT_EQUALS("", err); } { const std::string addfile = Path::join(Path::join(adddir, "lib"), "token.cpp"); - const std::string err = FileLister::addFiles(files, addfile, {}, true,PathMatch()); + PathMatch ignored; + const std::string err = FileLister::addFiles(files, addfile, {}, true, ignored); ASSERT_EQUALS("", err); } { const std::string addfile = Path::join(Path::join(adddir, "cli"), "token.cpp"); // does not exist - const std::string err = FileLister::addFiles(files, addfile, {}, true,PathMatch()); + PathMatch ignored; + const std::string err = FileLister::addFiles(files, addfile, {}, true, ignored); ASSERT_EQUALS("", err); } { 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()); + PathMatch ignored; + const std::string err = FileLister::addFiles(files, addfile, {}, true, ignored); ASSERT_EQUALS("", err); } { const std::string addfile = Path::join(Path::join(adddir, "lib"), "matchcompiler.h"); - const std::string err = FileLister::addFiles(files, addfile, {}, true,PathMatch()); + PathMatch ignored; + const std::string err = FileLister::addFiles(files, addfile, {}, true, ignored); ASSERT_EQUALS("", err); } diff --git a/test/testpathmatch.cpp b/test/testpathmatch.cpp index 7e721502a11..8b7a54fa604 100644 --- a/test/testpathmatch.cpp +++ b/test/testpathmatch.cpp @@ -42,10 +42,10 @@ class TestPathMatch : public TestFixture { #else const std::string basepath{"/test"}; #endif - const PathMatch emptyMatcher{{}, basepath}; - const PathMatch srcMatcher{{"src/"}, basepath}; - const PathMatch fooCppMatcher{{"foo.cpp"}, basepath}; - const PathMatch srcFooCppMatcher{{"src/foo.cpp"}, basepath}; + PathMatch emptyMatcher{{}, basepath}; + PathMatch srcMatcher{{"src/"}, basepath}; + PathMatch fooCppMatcher{{"foo.cpp"}, basepath}; + PathMatch srcFooCppMatcher{{"src/foo.cpp"}, basepath}; void run() override { TEST_CASE(emptymaskemptyfile); @@ -85,32 +85,36 @@ class TestPathMatch : public TestFixture { TEST_CASE(globstar1); TEST_CASE(globstar2); TEST_CASE(pathiterator); + TEST_CASE(unmatched1); + TEST_CASE(unmatched2); + TEST_CASE(unmatched3); + TEST_CASE(unmatched4); } // Test empty PathMatch - void emptymaskemptyfile() const { + void emptymaskemptyfile() { ASSERT(!emptyMatcher.match("")); } - void emptymaskpath1() const { + void emptymaskpath1() { ASSERT(!emptyMatcher.match("src/", ifdir)); } - void emptymaskpath2() const { + void emptymaskpath2() { ASSERT(!emptyMatcher.match("../src/", ifdir)); } - void emptymaskpath3() const { + void emptymaskpath3() { ASSERT(!emptyMatcher.match("/home/user/code/src/", ifdir)); ASSERT(!emptyMatcher.match("d:/home/user/code/src/", ifdir)); } // Test PathMatch containing "src/" - void onemaskemptypath() const { + void onemaskemptypath() { ASSERT(!srcMatcher.match("")); } - void onemasksamepath() const { + void onemasksamepath() { ASSERT(srcMatcher.match("src/", ifdir)); ASSERT(!srcMatcher.match("src/", ifreg)); } @@ -127,7 +131,7 @@ class TestPathMatch : public TestFixture { ASSERT(!match.match("srC/", ifreg)); } - void onemasksamepathwithfile() const { + void onemasksamepathwithfile() { ASSERT(srcMatcher.match("src/file.txt")); } @@ -140,36 +144,36 @@ class TestPathMatch : public TestFixture { ASSERT(!match.match(shorterToMatch, ifdir)); } - void onemaskdifferentdir1() const { + void onemaskdifferentdir1() { ASSERT(!srcMatcher.match("srcfiles/file.txt")); } - void onemaskdifferentdir2() const { + void onemaskdifferentdir2() { ASSERT(!srcMatcher.match("proj/srcfiles/file.txt")); } - void onemaskdifferentdir3() const { + void onemaskdifferentdir3() { ASSERT(!srcMatcher.match("proj/mysrc/file.txt")); } - void onemaskdifferentdir4() const { + void onemaskdifferentdir4() { ASSERT(!srcMatcher.match("proj/mysrcfiles/file.txt")); } - void onemasklongerpath1() const { + void onemasklongerpath1() { ASSERT(srcMatcher.match("/tmp/src/", ifdir)); ASSERT(srcMatcher.match("d:/tmp/src/", ifdir)); } - void onemasklongerpath2() const { + void onemasklongerpath2() { ASSERT(srcMatcher.match("src/module/", ifdir)); } - void onemasklongerpath3() const { + void onemasklongerpath3() { ASSERT(srcMatcher.match("project/src/module/", ifdir)); } - void onemaskcwd() const { + void onemaskcwd() { ASSERT(srcMatcher.match("./src", ifdir)); } @@ -197,7 +201,7 @@ class TestPathMatch : public TestFixture { } // Test PathMatch containing "foo.cpp" - void filemask1() const { + void filemask1() { ASSERT(fooCppMatcher.match("foo.cpp")); } @@ -206,32 +210,32 @@ class TestPathMatch : public TestFixture { ASSERT(match.match("fOo.cpp")); } - void filemask2() const { + void filemask2() { ASSERT(fooCppMatcher.match("../foo.cpp")); } - void filemask3() const { + void filemask3() { ASSERT(fooCppMatcher.match("src/foo.cpp")); } - void filemaskcwd() const { + void filemaskcwd() { ASSERT(fooCppMatcher.match("./lib/foo.cpp")); } // Test PathMatch containing "src/foo.cpp" - void filemaskpath1() const { + void filemaskpath1() { ASSERT(srcFooCppMatcher.match("src/foo.cpp")); } - void filemaskpath2() const { + void filemaskpath2() { ASSERT(srcFooCppMatcher.match("proj/src/foo.cpp")); } - void filemaskpath3() const { + void filemaskpath3() { ASSERT(!srcFooCppMatcher.match("foo.cpp")); } - void filemaskpath4() const { + void filemaskpath4() { ASSERT(!srcFooCppMatcher.match("bar/foo.cpp")); } @@ -308,6 +312,45 @@ class TestPathMatch : public TestFixture { /* The server and share should actually be considered part of the root and not be removed */ ASSERT_EQUALS("//", PathIterator("\\\\Server\\Share\\Directory", "../..\\../..", windows).read()); } + + void unmatched1() const { + // nothing has been matched yet => all patterns are unmatched + PathMatch match({"src/", "foo.cpp"}); + ASSERT_EQUALS(2, match.unmatched().size()); + ASSERT_EQUALS("src/", match.unmatched()[0]); + ASSERT_EQUALS("foo.cpp", match.unmatched()[1]); + } + + void unmatched2() const { + PathMatch match({"src/", "foo.cpp"}); + ASSERT(match.match("src/bar.cpp")); + ASSERT_EQUALS(1, match.unmatched().size()); + ASSERT_EQUALS("foo.cpp", match.unmatched()[0]); + ASSERT(match.match("lib/foo.cpp")); + ASSERT_EQUALS(0, match.unmatched().size()); + } + + void unmatched3() const { + // failed matches does not affect the unmatched patterns + PathMatch match({"src/", "foo.cpp"}); + ASSERT(!match.match("lib/bar.cpp")); + ASSERT(!match.match("src/", ifreg)); + ASSERT_EQUALS(2, match.unmatched().size()); + ASSERT(match.match("src/", ifdir)); + ASSERT_EQUALS(1, match.unmatched().size()); + ASSERT_EQUALS("foo.cpp", match.unmatched()[0]); + } + + void unmatched4() const { + // glob patterns + PathMatch match({"test*.cpp", "src/**/foo.c"}); + ASSERT(match.match("src/lib/foo/foo.c")); + ASSERT_EQUALS(1, match.unmatched().size()); + ASSERT_EQUALS("test*.cpp", match.unmatched()[0]); + ASSERT(!match.match("src/foo.c")); + ASSERT(match.match("test1.cpp")); + ASSERT_EQUALS(0, match.unmatched().size()); + } }; REGISTER_TEST(TestPathMatch) diff --git a/tools/dmake/dmake.cpp b/tools/dmake/dmake.cpp index eaf0a727646..f8d5f9d7a17 100644 --- a/tools/dmake/dmake.cpp +++ b/tools/dmake/dmake.cpp @@ -171,7 +171,7 @@ static std::string getCppFiles(std::vector &files, const std::strin std::list filelist; const std::set extra; const std::vector masks; - const PathMatch matcher(masks, Path::getCurrentPath()); + PathMatch matcher(masks, Path::getCurrentPath()); std::string err = FileLister::addFiles(filelist, path, extra, recursive, matcher); if (!err.empty()) return err;