Skip to content

Commit 26acdb1

Browse files
dmcppcheckclaude
andcommitted
Avoid false "unused ignore/exclude path" errors
Do not apply --file-filter when importing Visual Studio projects; the filtering is done later for all inputs. Filtering during import removed files before ignore paths were matched, depending on argument order. PathMatch::match() now records all matching patterns, and a pattern that is covered by a matched pattern (e.g. a file inside an excluded directory) is not reported as unmatched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent f790e2a commit 26acdb1

5 files changed

Lines changed: 50 additions & 37 deletions

File tree

‎lib/importproject.cpp‎

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -324,28 +324,25 @@ ImportProject::Type ImportProject::import(const std::string &filename, Settings
324324
if (!mPath.empty() && !endsWith(mPath,'/'))
325325
mPath += '/';
326326

327-
const std::vector<std::string> fileFilters =
328-
settings ? settings->fileFilters : std::vector<std::string>();
329-
330327
if (endsWith(filename, ".json")) {
331328
if (importCompileCommands(fin)) {
332329
setRelativePaths(filename);
333330
return ImportProject::Type::COMPILE_DB;
334331
}
335332
} else if (endsWith(filename, ".sln")) {
336-
if (importSln(fin, mPath, fileFilters)) {
333+
if (importSln(fin, mPath)) {
337334
setRelativePaths(filename);
338335
return ImportProject::Type::VS_SLN;
339336
}
340337
} else if (endsWith(filename, ".slnx")) {
341-
if (importSlnx(filename, fileFilters)) {
338+
if (importSlnx(filename)) {
342339
setRelativePaths(filename);
343340
return ImportProject::Type::VS_SLNX;
344341
}
345342
} else if (endsWith(filename, ".vcxproj")) {
346343
std::map<std::string, std::string, cppcheck::stricmp> variables;
347344
std::vector<SharedItemsProject> sharedItemsProjects;
348-
if (importVcxproj(filename, variables, "", fileFilters, sharedItemsProjects)) {
345+
if (importVcxproj(filename, variables, "", sharedItemsProjects)) {
349346
setRelativePaths(filename);
350347
return ImportProject::Type::VS_VCXPROJ;
351348
}
@@ -464,7 +461,7 @@ bool ImportProject::importCompileCommands(std::istream &istr)
464461
return true;
465462
}
466463

467-
bool ImportProject::importSln(std::istream &istr, const std::string &path, const std::vector<std::string> &fileFilters)
464+
bool ImportProject::importSln(std::istream &istr, const std::string &path)
468465
{
469466
std::string line;
470467

@@ -500,7 +497,7 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
500497
if (!Path::isAbsolute(vcxproj))
501498
vcxproj = path + vcxproj;
502499
vcxproj = Path::fromNativeSeparators(std::move(vcxproj));
503-
if (!importVcxproj(vcxproj, variables, "", fileFilters, sharedItemsProjects)) {
500+
if (!importVcxproj(vcxproj, variables, "", sharedItemsProjects)) {
504501
errors.emplace_back("failed to load '" + vcxproj + "' from Visual Studio solution");
505502
return false;
506503
}
@@ -515,7 +512,7 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
515512
return true;
516513
}
517514

518-
bool ImportProject::importSlnx(const std::string& filename, const std::vector<std::string>& fileFilters)
515+
bool ImportProject::importSlnx(const std::string& filename)
519516
{
520517
tinyxml2::XMLDocument doc;
521518
const tinyxml2::XMLError error = doc.LoadFile(filename.c_str());
@@ -556,7 +553,7 @@ bool ImportProject::importSlnx(const std::string& filename, const std::vector<st
556553
vcxproj = variables["SolutionDir"] + vcxproj;
557554

558555
vcxproj = Path::fromNativeSeparators(std::move(vcxproj));
559-
if (!importVcxproj(vcxproj, variables, "", fileFilters, sharedItemsProjects)) {
556+
if (!importVcxproj(vcxproj, variables, "", sharedItemsProjects)) {
560557
errors.emplace_back("failed to load '" + vcxproj + "' from Visual Studio solution");
561558
return false;
562559
}
@@ -939,7 +936,6 @@ static void loadVisualStudioProperties(const std::string &props, std::map<std::s
939936
bool ImportProject::importVcxproj(const std::string &filename,
940937
std::map<std::string, std::string, cppcheck::stricmp> &variables,
941938
const std::string &additionalIncludeDirectories,
942-
const std::vector<std::string> &fileFilters,
943939
std::vector<SharedItemsProject> &cache)
944940
{
945941
tinyxml2::XMLDocument doc;
@@ -948,10 +944,10 @@ bool ImportProject::importVcxproj(const std::string &filename,
948944
errors.emplace_back(std::string("Visual Studio project file is not a valid XML - ") + tinyxml2::XMLDocument::ErrorIDToName(error));
949945
return false;
950946
}
951-
return importVcxproj(filename, doc, variables, additionalIncludeDirectories, fileFilters, cache);
947+
return importVcxproj(filename, doc, variables, additionalIncludeDirectories, cache);
952948
}
953949

954-
bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::XMLDocument &doc, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters, std::vector<SharedItemsProject> &cache)
950+
bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::XMLDocument &doc, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, std::vector<SharedItemsProject> &cache)
955951
{
956952
variables["ProjectDir"] = Path::simplifyPath(Path::getPathFromFilename(filename));
957953

@@ -1030,7 +1026,7 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X
10301026
return false;
10311027
}
10321028

1033-
SharedItemsProject toAdd = importVcxitems(pathToSharedItemsFile, fileFilters, cache);
1029+
SharedItemsProject toAdd = importVcxitems(pathToSharedItemsFile, cache);
10341030
if (!toAdd.successful) {
10351031
errors.emplace_back("Could not load shared items project \"" + pathToSharedItemsFile + "\" from original path \"" + std::string(projectAttribute) + "\".");
10361032
return false;
@@ -1059,11 +1055,7 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X
10591055
}
10601056

10611057
// Project files
1062-
PathMatch filtermatcher(fileFilters, Path::getCurrentPath());
10631058
for (const ItemGroupClCompile& compile : compileList) {
1064-
if (!fileFilters.empty() && !filtermatcher.match(compile.mFilename))
1065-
continue;
1066-
10671059
for (const ProjectConfiguration &p : projectConfigurationList) {
10681060

10691061
if (!guiProject.checkVsConfigs.empty()) {
@@ -1130,7 +1122,7 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X
11301122
return true;
11311123
}
11321124

1133-
ImportProject::SharedItemsProject ImportProject::importVcxitems(const std::string& filename, const std::vector<std::string>& fileFilters, std::vector<SharedItemsProject> &cache)
1125+
ImportProject::SharedItemsProject ImportProject::importVcxitems(const std::string& filename, std::vector<SharedItemsProject> &cache)
11341126
{
11351127
auto isInCacheCheck = [filename](const ImportProject::SharedItemsProject& e) -> bool {
11361128
return filename == e.pathToProjectFile;
@@ -1143,8 +1135,6 @@ ImportProject::SharedItemsProject ImportProject::importVcxitems(const std::strin
11431135
SharedItemsProject result;
11441136
result.pathToProjectFile = filename;
11451137

1146-
PathMatch filtermatcher(fileFilters, Path::getCurrentPath());
1147-
11481138
tinyxml2::XMLDocument doc;
11491139
const tinyxml2::XMLError error = doc.LoadFile(filename.c_str());
11501140
if (error != tinyxml2::XML_SUCCESS) {
@@ -1165,10 +1155,6 @@ ImportProject::SharedItemsProject ImportProject::importVcxitems(const std::strin
11651155
std::string file(include);
11661156
findAndReplace(file, "$(MSBuildThisFileDirectory)", "./");
11671157

1168-
// Skip file if it doesn't match the filter
1169-
if (!fileFilters.empty() && !filtermatcher.match(file))
1170-
continue;
1171-
11721158
result.sourceFiles.emplace_back(file);
11731159
} else {
11741160
errors.emplace_back("Could not find shared items source file");

‎lib/importproject.h‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,15 +119,15 @@ class CPPCHECKLIB WARN_UNUSED ImportProject {
119119
std::vector<std::string> sourceFiles;
120120
};
121121

122-
bool importVcxproj(const std::string &filename, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters, std::vector<SharedItemsProject> &cache);
123-
bool importVcxproj(const std::string &filename, const tinyxml2::XMLDocument &doc, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters, std::vector<SharedItemsProject> &cache);
122+
bool importVcxproj(const std::string &filename, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, std::vector<SharedItemsProject> &cache);
123+
bool importVcxproj(const std::string &filename, const tinyxml2::XMLDocument &doc, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, std::vector<SharedItemsProject> &cache);
124124

125125
private:
126126
static void parseArgs(FileSettings &fs, const std::vector<std::string> &args);
127127

128-
bool importSln(std::istream &istr, const std::string &path, const std::vector<std::string> &fileFilters);
129-
bool importSlnx(const std::string& filename, const std::vector<std::string>& fileFilters);
130-
SharedItemsProject importVcxitems(const std::string &filename, const std::vector<std::string> &fileFilters, std::vector<SharedItemsProject> &cache);
128+
bool importSln(std::istream &istr, const std::string &path);
129+
bool importSlnx(const std::string& filename);
130+
SharedItemsProject importVcxitems(const std::string &filename, std::vector<SharedItemsProject> &cache);
131131
bool importBcb6Prj(const std::string &projectFilename);
132132

133133
std::string mPath;

‎lib/pathmatch.cpp‎

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,15 @@ PathMatch::PathMatch(std::vector<std::string> patterns, std::string basepath, Sy
3434

3535
bool PathMatch::match(const std::string &path, Filemode mode)
3636
{
37-
return std::any_of(mPatterns.cbegin(), mPatterns.cend(), [&] (const std::string &pattern) {
38-
const bool res = match(pattern, path, mBasepath, mode, mSyntax);
39-
if (res)
37+
// check all patterns so every matching pattern is recorded
38+
bool ret = false;
39+
for (const std::string &pattern : mPatterns) {
40+
if (match(pattern, path, mBasepath, mode, mSyntax)) {
4041
mMatchedPatterns.insert(pattern);
41-
return res;
42-
});
42+
ret = true;
43+
}
44+
}
45+
return ret;
4346
}
4447

4548
bool PathMatch::match(const std::string &pattern, const std::string &path, const std::string &basepath, Filemode mode, Syntax syntax)
@@ -157,7 +160,14 @@ bool PathMatch::match(const std::string &pattern, const std::string &path, const
157160
std::vector<std::string> PathMatch::unmatched() const {
158161
std::vector<std::string> ret;
159162
std::copy_if(mPatterns.cbegin(), mPatterns.cend(), std::back_inserter(ret), [this](const std::string& s) {
160-
return mMatchedPatterns.count(s) == 0;
163+
if (mMatchedPatterns.count(s) != 0)
164+
return false;
165+
// paths inside a matched directory are not traversed, so a pattern that is
166+
// covered by a matched pattern is considered used
167+
const Filemode mode = !s.empty() && PathIterator::issep(s.back(), mSyntax) ? Filemode::directory : Filemode::regular;
168+
return std::none_of(mMatchedPatterns.cbegin(), mMatchedPatterns.cend(), [&](const std::string& matched) {
169+
return match(matched, s, mBasepath, mode, mSyntax);
170+
});
161171
});
162172
return ret;
163173
}

‎test/testimportproject.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,7 @@ class TestImportProject : public TestFixture {
637637
TestImporter project;
638638
std::map<std::string, std::string, cppcheck::stricmp> variables;
639639
std::vector<TestImporter::SharedItemsProject> cache;
640-
ASSERT_EQUALS(project.importVcxproj("test.vcxproj", doc, variables, {}, {}, cache), true);
640+
ASSERT_EQUALS(project.importVcxproj("test.vcxproj", doc, variables, {}, cache), true);
641641
ASSERT_EQUALS(project.fileSettings.size(), 2);
642642
ASSERT(project.fileSettings.front().defines.find(";UNICODE=1;") != std::string::npos);
643643
ASSERT(project.fileSettings.front().defines.find(";_UNICODE=1") != std::string::npos);

‎test/testpathmatch.cpp‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ class TestPathMatch : public TestFixture {
8989
TEST_CASE(unmatched2);
9090
TEST_CASE(unmatched3);
9191
TEST_CASE(unmatched4);
92+
TEST_CASE(unmatched5);
93+
TEST_CASE(unmatched6);
9294
}
9395

9496
// Test empty PathMatch
@@ -351,6 +353,21 @@ class TestPathMatch : public TestFixture {
351353
ASSERT(match.match("test1.cpp"));
352354
ASSERT_EQUALS(0, match.unmatched().size());
353355
}
356+
357+
void unmatched5() const {
358+
// all matching patterns are recorded
359+
PathMatch match({"src/", "src/foo.cpp"});
360+
ASSERT(match.match("src/foo.cpp"));
361+
ASSERT_EQUALS(0, match.unmatched().size());
362+
}
363+
364+
void unmatched6() const {
365+
// a pattern inside a matched directory is considered used
366+
PathMatch match({"src/", "src/foo.cpp", "src/lib/", "lib/foo.cpp"});
367+
ASSERT(match.match("src/", ifdir));
368+
ASSERT_EQUALS(1, match.unmatched().size());
369+
ASSERT_EQUALS("lib/foo.cpp", match.unmatched()[0]);
370+
}
354371
};
355372

356373
REGISTER_TEST(TestPathMatch)

0 commit comments

Comments
 (0)