Skip to content

Commit b898e10

Browse files
committed
error when exclude is unused
1 parent 5f9b5cc commit b898e10

19 files changed

Lines changed: 319 additions & 84 deletions

‎cli/cmdlineparser.cpp‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[])
247247
std::list<FileWithDetails> filesResolved;
248248
// Execute recursiveAddFiles() to each given file parameter
249249
// TODO: verbose log which files were ignored?
250-
const PathMatch matcher(ignored, Path::getCurrentPath());
250+
PathMatch matcher(ignored, Path::getCurrentPath());
251251
for (const std::string &pathname : pathnamesRef) {
252252
const std::string err = FileLister::recursiveAddFiles(filesResolved, Path::toNativeSeparators(pathname), mSettings.library.markupExtensions(), matcher, mSettings.debugignore);
253253
if (!err.empty()) {
@@ -264,6 +264,12 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[])
264264
return false;
265265
}
266266

267+
const auto& unmatched = matcher.unmatched();
268+
if (!unmatched.empty()) {
269+
mLogger.printError("unused ignore/exclude path '" + unmatched.front() + "'. To hide warnings in certain files use suppressions instead.");
270+
return false;
271+
}
272+
267273
std::list<FileWithDetails> files;
268274
if (!mSettings.fileFilters.empty()) {
269275
files = filterFiles(mSettings.fileFilters, filesResolved);
@@ -1723,12 +1729,16 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
17231729
mPathNames = project.guiProject.pathNames;
17241730

17251731
if (!project.fileSettings.empty()) {
1726-
project.ignorePaths(mIgnoredPaths, mSettings.debugignore);
1732+
const auto& unmatched = project.ignorePaths(mIgnoredPaths, mSettings.debugignore);
17271733
if (project.fileSettings.empty()) {
17281734
mLogger.printError("no C or C++ source files found.");
17291735
mLogger.printMessage("all paths were ignored"); // TODO: log this differently?
17301736
return Result::Fail;
17311737
}
1738+
if (!unmatched.empty()) {
1739+
mLogger.printError("unused ignore/exclude path '" + unmatched.front() + "'. To hide warnings in certain files use suppressions instead.");
1740+
return Result::Fail;
1741+
}
17321742
mFileSettings = project.fileSettings;
17331743
}
17341744

‎cli/filelister.cpp‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
// When compiling Unicode targets WinAPI automatically uses *W Unicode versions
4747
// of called functions. Thus, we explicitly call *A versions of the functions.
4848

49-
static std::string addFiles2(std::list<FileWithDetails>&files, const std::string &path, const std::set<std::string> &extra, bool recursive, const PathMatch& ignored, bool debug = false)
49+
static std::string addFiles2(std::list<FileWithDetails>&files, const std::string &path, const std::set<std::string> &extra, bool recursive, PathMatch& ignored, bool debug = false)
5050
{
5151
const std::string cleanedPath = Path::toNativeSeparators(path);
5252

@@ -163,7 +163,7 @@ static std::string addFiles2(std::list<FileWithDetails>&files, const std::string
163163
return "";
164164
}
165165

166-
std::string FileLister::addFiles(std::list<FileWithDetails> &files, const std::string &path, const std::set<std::string> &extra, bool recursive, const PathMatch& ignored, bool debug)
166+
std::string FileLister::addFiles(std::list<FileWithDetails> &files, const std::string &path, const std::set<std::string> &extra, bool recursive, PathMatch& ignored, bool debug)
167167
{
168168
if (path.empty())
169169
return "no path specified";
@@ -205,7 +205,7 @@ static std::string addFiles2(std::list<FileWithDetails> &files,
205205
const std::string &path,
206206
const std::set<std::string> &extra,
207207
bool recursive,
208-
const PathMatch& ignored,
208+
PathMatch& ignored,
209209
bool debug)
210210
{
211211
if (ignored.match(path))
@@ -284,7 +284,7 @@ static std::string addFiles2(std::list<FileWithDetails> &files,
284284
return "";
285285
}
286286

287-
std::string FileLister::addFiles(std::list<FileWithDetails> &files, const std::string &path, const std::set<std::string> &extra, bool recursive, const PathMatch& ignored, bool debug)
287+
std::string FileLister::addFiles(std::list<FileWithDetails> &files, const std::string &path, const std::set<std::string> &extra, bool recursive, PathMatch& ignored, bool debug)
288288
{
289289
if (path.empty())
290290
return "no path specified";
@@ -312,7 +312,7 @@ std::string FileLister::addFiles(std::list<FileWithDetails> &files, const std::s
312312

313313
#endif
314314

315-
std::string FileLister::recursiveAddFiles(std::list<FileWithDetails> &files, const std::string &path, const std::set<std::string> &extra, const PathMatch& ignored, bool debug)
315+
std::string FileLister::recursiveAddFiles(std::list<FileWithDetails> &files, const std::string &path, const std::set<std::string> &extra, PathMatch& ignored, bool debug)
316316
{
317317
return addFiles(files, path, extra, true, ignored, debug);
318318
}

‎cli/filelister.h‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class FileLister {
4444
* @param debug log if path was ignored
4545
* @return On success, an empty string is returned. On error, a error message is returned.
4646
*/
47-
static std::string recursiveAddFiles(std::list<FileWithDetails> &files, const std::string &path, const std::set<std::string> &extra, const PathMatch& ignored, bool debug = false);
47+
static std::string recursiveAddFiles(std::list<FileWithDetails> &files, const std::string &path, const std::set<std::string> &extra, PathMatch& ignored, bool debug = false);
4848

4949
/**
5050
* @brief (Recursively) add source files to a map.
@@ -59,7 +59,7 @@ class FileLister {
5959
* @param debug log when a path was ignored
6060
* @return On success, an empty string is returned. On error, a error message is returned.
6161
*/
62-
static std::string addFiles(std::list<FileWithDetails> &files, const std::string &path, const std::set<std::string> &extra, bool recursive, const PathMatch& ignored, bool debug = false);
62+
static std::string addFiles(std::list<FileWithDetails> &files, const std::string &path, const std::set<std::string> &extra, bool recursive, PathMatch& ignored, bool debug = false);
6363
};
6464

6565
/// @}

‎gui/filelist.cpp‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,9 @@ void FileList::addPathList(const QStringList &paths)
9090
}
9191
}
9292

93-
QStringList FileList::getFileList() const
93+
QStringList FileList::getFileList()
9494
{
95+
mUnmatchedExcludes.clear();
9596
if (mExcludedPaths.empty()) {
9697
QStringList names;
9798
for (const QFileInfo& item : mFileList) {
@@ -103,6 +104,11 @@ QStringList FileList::getFileList() const
103104
return applyExcludeList();
104105
}
105106

107+
const QStringList& FileList::getUnmatchedExcludes() &
108+
{
109+
return mUnmatchedExcludes;
110+
}
111+
106112
void FileList::addExcludeList(const QStringList &paths)
107113
{
108114
mExcludedPaths = paths;
@@ -117,9 +123,9 @@ static std::vector<std::string> toStdStringList(const QStringList &stringList)
117123
return ret;
118124
}
119125

120-
QStringList FileList::applyExcludeList() const
126+
QStringList FileList::applyExcludeList()
121127
{
122-
const PathMatch pathMatch(toStdStringList(mExcludedPaths), QDir::currentPath().toStdString());
128+
PathMatch pathMatch(toStdStringList(mExcludedPaths), QDir::currentPath().toStdString());
123129

124130
QStringList paths;
125131
for (const QFileInfo& item : mFileList) {
@@ -129,5 +135,10 @@ QStringList FileList::applyExcludeList() const
129135
if (!pathMatch.match(canonical.toStdString()))
130136
paths << canonical;
131137
}
138+
139+
for (const std::string& excludePath: pathMatch.unmatched()) {
140+
mUnmatchedExcludes << QString::fromStdString(excludePath);
141+
}
142+
132143
return paths;
133144
}

‎gui/filelist.h‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,13 @@ class FileList {
6262
* @brief Return list of filenames (to check).
6363
* @return list of filenames to check.
6464
*/
65-
QStringList getFileList() const;
65+
QStringList getFileList();
66+
67+
/**
68+
* @brief Return list of exclude paths that did not match any file in the last getFileList() call
69+
* @return list of unmatched excludes
70+
*/
71+
const QStringList& getUnmatchedExcludes() &;
6672

6773
/**
6874
* @brief Add list of paths to exclusion list.
@@ -88,14 +94,16 @@ class FileList {
8894
* @brief Get filtered list of paths.
8995
* This method takes the list of paths and applies the exclude lists to
9096
* it. And then returns the list of paths that did not match the
91-
* exclude filters.
97+
* exclude filters. The exclude paths that did not match any file
98+
* are stored in mUnmatchedExcludes.
9299
* @return Filtered list of paths.
93100
*/
94-
QStringList applyExcludeList() const;
101+
QStringList applyExcludeList();
95102

96103
private:
97104
QFileInfoList mFileList;
98105
QStringList mExcludedPaths;
106+
QStringList mUnmatchedExcludes;
99107
};
100108

101109
#endif // FILELIST_H

‎gui/mainwindow.cpp‎

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLib, const bo
647647
mUI->mResults->setCheckSettings(checkSettings);
648648
}
649649

650-
void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLib, const bool checkConfig)
650+
void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLib, const bool checkConfig, const bool checkUnusedExcludes)
651651
{
652652
if (files.isEmpty())
653653
return;
@@ -683,6 +683,17 @@ void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLib, c
683683
return;
684684
}
685685

686+
const QStringList unmatchedExcludePaths = checkUnusedExcludes ? pathList.getUnmatchedExcludes() : QStringList();
687+
if (!unmatchedExcludePaths.isEmpty()) {
688+
QMessageBox msg(QMessageBox::Warning,
689+
"Cppcheck",
690+
tr("Unused exclude paths:\n%1\nto hide warnings in certain files use suppressions instead").arg(unmatchedExcludePaths.join("\n")),
691+
QMessageBox::Ok,
692+
this);
693+
msg.exec();
694+
return;
695+
}
696+
686697
std::list<FileWithDetails> fdetails = enrichFilesForAnalysis(fileNames, checkSettings);
687698

688699
// TODO: lock UI here?
@@ -1981,7 +1992,9 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const QStringLis
19811992
if (paths.isEmpty()) {
19821993
paths << mCurrentDirectory;
19831994
}
1984-
doAnalyzeFiles(paths, checkLib, checkConfig);
1995+
// the exclude paths can only be validated when the whole project is analyzed
1996+
const bool checkUnusedExcludes = recheckFiles.isEmpty();
1997+
doAnalyzeFiles(paths, checkLib, checkConfig, checkUnusedExcludes);
19851998
}
19861999

19872000
void MainWindow::newProjectFile()

‎gui/mainwindow.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,9 @@ private slots:
317317
* @param files List of files and/or directories to analyze
318318
* @param checkLib Flag to indicate if library should be checked
319319
* @param checkConfig Flag to indicate if the configuration should be checked.
320+
* @param checkUnusedExcludes Flag to indicate if unused exclude paths should be reported.
320321
*/
321-
void doAnalyzeFiles(const QStringList &files, bool checkLib = false, bool checkConfig = false);
322+
void doAnalyzeFiles(const QStringList &files, bool checkLib = false, bool checkConfig = false, bool checkUnusedExcludes = false);
322323

323324
/**
324325
* @brief Get our default cppcheck settings and read project file.

‎gui/test/filelist/testfilelist.cpp‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,4 +184,41 @@ void TestFileList::filterFiles5() const
184184
QVERIFY(!files.contains(base + "/dir1/dir11/foo11.cpp"));
185185
}
186186

187+
void TestFileList::unmatchedExcludes1() const
188+
{
189+
FileList list;
190+
QStringList filters;
191+
filters << "foo1.cpp" << "foo3.cc";
192+
list.addExcludeList(filters);
193+
list.addDirectory(QString(SRCDIR) + "/../data/files");
194+
QVERIFY(!list.getFileList().isEmpty());
195+
QVERIFY(list.getUnmatchedExcludes().isEmpty());
196+
}
197+
198+
void TestFileList::unmatchedExcludes2() const
199+
{
200+
FileList list;
201+
QStringList filters;
202+
filters << "foo1.cpp" << "bar.cpp" << "dir3/";
203+
list.addExcludeList(filters);
204+
list.addDirectory(QString(SRCDIR) + "/../data/files", true);
205+
// unmatched excludes does not affect the file list
206+
QCOMPARE(list.getFileList().size(), 9);
207+
const QStringList unmatched = list.getUnmatchedExcludes();
208+
QCOMPARE(unmatched.size(), 2);
209+
QCOMPARE(unmatched[0], QString("bar.cpp"));
210+
QCOMPARE(unmatched[1], QString("dir3/"));
211+
}
212+
213+
void TestFileList::unmatchedExcludes3() const
214+
{
215+
FileList list;
216+
QStringList filters;
217+
filters << "dir1/";
218+
list.addExcludeList(filters);
219+
list.addDirectory(QString(SRCDIR) + "/../data/files", true);
220+
QVERIFY(!list.getFileList().isEmpty());
221+
QVERIFY(list.getUnmatchedExcludes().isEmpty());
222+
}
223+
187224
QTEST_MAIN(TestFileList)

‎gui/test/filelist/testfilelist.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,7 @@ private slots:
3333
void filterFiles3() const;
3434
void filterFiles4() const;
3535
void filterFiles5() const;
36+
void unmatchedExcludes1() const;
37+
void unmatchedExcludes2() const;
38+
void unmatchedExcludes3() const;
3639
};

‎lib/importproject.cpp‎

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ void ImportProject::parseArgs(FileSettings &fs, const std::vector<std::string> &
235235
fsSetDefines(fs, std::move(defs));
236236
}
237237

238-
void ImportProject::ignorePaths(const std::vector<std::string> &ipaths, bool debug)
238+
std::vector<std::string> ImportProject::ignorePaths(const std::vector<std::string> &ipaths, bool debug)
239239
{
240240
PathMatch matcher(ipaths, Path::getCurrentPath());
241241
for (auto it = fileSettings.cbegin(); it != fileSettings.cend();) {
@@ -247,6 +247,7 @@ void ImportProject::ignorePaths(const std::vector<std::string> &ipaths, bool deb
247247
else
248248
++it;
249249
}
250+
return matcher.unmatched();
250251
}
251252

252253
void ImportProject::ignoreOtherConfigs(const std::string &cfg)
@@ -1759,27 +1760,24 @@ ImportProject::Type ImportProject::import(const std::string &filename, Settings
17591760
if (!mPath.empty() && !endsWith(mPath,'/'))
17601761
mPath += '/';
17611762

1762-
const std::vector<std::string> fileFilters =
1763-
settings ? settings->fileFilters : std::vector<std::string>();
1764-
17651763
if (endsWith(filename, ".json")) {
17661764
if (processCompileCommands(fin)) {
17671765
setRelativePaths(filename);
17681766
return ImportProject::Type::COMPILE_DB;
17691767
}
17701768
} else if (endsWith(filename, ".sln")) {
1771-
if (importSln(fin, filename, fileFilters)) {
1769+
if (importSln(fin, filename)) {
17721770
setRelativePaths(filename);
17731771
return ImportProject::Type::VS_SLN;
17741772
}
17751773
} else if (endsWith(filename, ".slnx")) {
1776-
if (importSlnx(filename, fileFilters)) {
1774+
if (importSlnx(filename)) {
17771775
setRelativePaths(filename);
17781776
return ImportProject::Type::VS_SLNX;
17791777
}
17801778
} else if (endsWith(filename, ".vcxproj")) {
17811779
PropertiesMap mVariables;
1782-
if (importVcxproj(toAbsolute(filename), mVariables, fileFilters)) {
1780+
if (importVcxproj(toAbsolute(filename), mVariables)) {
17831781
setRelativePaths(filename);
17841782
return ImportProject::Type::VS_VCXPROJ;
17851783
}
@@ -1907,7 +1905,7 @@ void ImportProject::setSolution(const std::string &filename, PropertiesMap &prop
19071905
properties["SolutionName"] = fileStem(properties["SolutionFileName"]);
19081906
}
19091907

1910-
bool ImportProject::importSln(std::istream &istr, const std::string &filename, const std::vector<std::string> &fileFilters)
1908+
bool ImportProject::importSln(std::istream &istr, const std::string &filename)
19111909
{
19121910
std::string line;
19131911

@@ -2000,7 +1998,7 @@ bool ImportProject::importSln(std::istream &istr, const std::string &filename, c
20001998

20011999
for (const std::string &vcxproj : vcxprojs) {
20022000
PropertiesMap mVariables = solutionVariables;
2003-
if (!importVcxproj(vcxproj, mVariables, fileFilters)) {
2001+
if (!importVcxproj(vcxproj, mVariables)) {
20042002
errors.emplace_back("failed to load '" + vcxproj + "' from Visual Studio solution");
20052003
return false;
20062004
}
@@ -2009,7 +2007,7 @@ bool ImportProject::importSln(std::istream &istr, const std::string &filename, c
20092007
return true;
20102008
}
20112009

2012-
bool ImportProject::importSlnx(const std::string& filename, const std::vector<std::string>& fileFilters)
2010+
bool ImportProject::importSlnx(const std::string& filename)
20132011
{
20142012
debugs.clear();
20152013

@@ -2054,7 +2052,7 @@ bool ImportProject::importSlnx(const std::string& filename, const std::vector<st
20542052
vcxproj = Path::fromNativeSeparators(std::move(vcxproj));
20552053

20562054
PropertiesMap mVariables = solutionVariables;
2057-
if (!importVcxproj(vcxproj, mVariables, fileFilters)) {
2055+
if (!importVcxproj(vcxproj, mVariables)) {
20582056
errors.emplace_back("failed to load '" + vcxproj + "' from Visual Studio solution");
20592057
return false;
20602058
}
@@ -4583,8 +4581,7 @@ ImportProject::ImportResult ImportProject::processImport(const std::string &file
45834581
}
45844582

45854583
bool ImportProject::importVcxproj(const std::string &filename,
4586-
PropertiesMap &properties,
4587-
const std::vector<std::string> &fileFilters)
4584+
PropertiesMap &properties)
45884585
{
45894586
tinyxml2::XMLDocument doc;
45904587
const tinyxml2::XMLError error = doc.LoadFile(filename.c_str());
@@ -4908,11 +4905,7 @@ bool ImportProject::importVcxproj(const std::string &filename,
49084905
// we can only set it globally but in this context it needs to be treated per file
49094906

49104907
// Project files
4911-
PathMatch filtermatcher(fileFilters, Path::getCurrentPath());
49124908
for (const ItemGroupClCompile &compile : compileList) {
4913-
if (!fileFilters.empty() && !filtermatcher.match(compile.filename))
4914-
continue;
4915-
49164909
const std::string &excl = compile.get("ExcludedFromBuild");
49174910
if (!excl.empty() && caseInsensitiveStringCompare(excl, "true") == 0)
49184911
continue;

0 commit comments

Comments
 (0)