Skip to content

Fix #12821 (GUI: exclude folders in imported project) #7645

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ $(libcppdir)/forwardanalyzer.o: lib/forwardanalyzer.cpp lib/addoninfo.h lib/anal
$(libcppdir)/fwdanalysis.o: lib/fwdanalysis.cpp lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vfvalue.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/fwdanalysis.cpp

$(libcppdir)/importproject.o: lib/importproject.cpp externals/picojson/picojson.h externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h
$(libcppdir)/importproject.o: lib/importproject.cpp externals/picojson/picojson.h externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/importproject.cpp

$(libcppdir)/infer.o: lib/infer.cpp lib/calculate.h lib/config.h lib/errortypes.h lib/infer.h lib/mathlib.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueptr.h lib/vfvalue.h
Expand All @@ -606,7 +606,7 @@ $(libcppdir)/path.o: lib/path.cpp externals/simplecpp/simplecpp.h lib/config.h l
$(libcppdir)/pathanalysis.o: lib/pathanalysis.cpp lib/astutils.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/pathanalysis.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vfvalue.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/pathanalysis.cpp

$(libcppdir)/pathmatch.o: lib/pathmatch.cpp lib/config.h lib/path.h lib/pathmatch.h lib/standards.h lib/utils.h
$(libcppdir)/pathmatch.o: lib/pathmatch.cpp lib/config.h lib/path.h lib/pathmatch.h lib/standards.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/pathmatch.cpp

$(libcppdir)/platform.o: lib/platform.cpp externals/tinyxml2/tinyxml2.h lib/config.h lib/mathlib.h lib/path.h lib/platform.h lib/standards.h lib/xml.h
Expand All @@ -630,7 +630,7 @@ $(libcppdir)/standards.o: lib/standards.cpp externals/simplecpp/simplecpp.h lib/
$(libcppdir)/summaries.o: lib/summaries.cpp lib/addoninfo.h lib/analyzerinfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/summaries.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/summaries.cpp

$(libcppdir)/suppressions.o: lib/suppressions.cpp externals/tinyxml2/tinyxml2.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/mathlib.h lib/path.h lib/platform.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h
$(libcppdir)/suppressions.o: lib/suppressions.cpp externals/tinyxml2/tinyxml2.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/suppressions.cpp

$(libcppdir)/templatesimplifier.o: lib/templatesimplifier.cpp lib/addoninfo.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
Expand Down Expand Up @@ -816,7 +816,7 @@ test/testother.o: test/testother.cpp lib/addoninfo.h lib/check.h lib/checkers.h
test/testpath.o: test/testpath.cpp lib/addoninfo.h lib/check.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/testpath.cpp

test/testpathmatch.o: test/testpathmatch.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/pathmatch.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h
test/testpathmatch.o: test/testpathmatch.cpp lib/addoninfo.h lib/check.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/pathmatch.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testpathmatch.cpp

test/testplatform.o: test/testplatform.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.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/utils.h lib/xml.h test/fixture.h
Expand Down
38 changes: 5 additions & 33 deletions cli/cmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,9 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[])
std::list<FileSettings> fileSettings;
if (!mSettings.fileFilters.empty()) {
// filter only for the selected filenames from all project files
PathMatch filtermatcher(mSettings.fileFilters, Path::getCurrentPath());
std::copy_if(fileSettingsRef.cbegin(), fileSettingsRef.cend(), std::back_inserter(fileSettings), [&](const FileSettings &fs) {
return matchglobs(mSettings.fileFilters, fs.filename());
return filtermatcher.match(fs.filename());
});
if (fileSettings.empty()) {
mLogger.printError("could not find any files matching the filter.");
Expand Down Expand Up @@ -242,16 +243,9 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[])

if (!pathnamesRef.empty()) {
std::list<FileWithDetails> filesResolved;
// TODO: this needs to be inlined into PathMatch as it depends on the underlying filesystem
#if defined(_WIN32)
// For Windows we want case-insensitive path matching
const bool caseSensitive = false;
#else
const bool caseSensitive = true;
#endif
// Execute recursiveAddFiles() to each given file parameter
// TODO: verbose log which files were ignored?
const PathMatch matcher(ignored, caseSensitive);
const 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()) {
Expand Down Expand Up @@ -1619,24 +1613,6 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
return Result::Fail;
}

for (auto& path : mIgnoredPaths)
{
path = Path::removeQuotationMarks(std::move(path));
path = Path::simplifyPath(std::move(path));

bool isdir = false;
if (!Path::exists(path, &isdir) && mSettings.debugignore) {
// FIXME: this is misleading because we match from the end of the path so it does not require to exist
//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;

Expand Down Expand Up @@ -2160,13 +2136,9 @@ bool CmdLineParser::loadCppcheckCfg()
std::list<FileWithDetails> CmdLineParser::filterFiles(const std::vector<std::string>& fileFilters,
const std::list<FileWithDetails>& filesResolved) {
std::list<FileWithDetails> files;
#ifdef _WIN32
constexpr bool caseInsensitive = true;
#else
constexpr bool caseInsensitive = false;
#endif
PathMatch filtermatcher(fileFilters, Path::getCurrentPath());
std::copy_if(filesResolved.cbegin(), filesResolved.cend(), std::inserter(files, files.end()), [&](const FileWithDetails& entry) {
return matchglobs(fileFilters, entry.path(), caseInsensitive) || matchglobs(fileFilters, entry.spath(), caseInsensitive);
return filtermatcher.match(entry.path()) || filtermatcher.match(entry.spath());
});
return files;
}
6 changes: 1 addition & 5 deletions gui/filelist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,7 @@ static std::vector<std::string> toStdStringList(const QStringList &stringList)

QStringList FileList::applyExcludeList() const
{
#ifdef _WIN32
const PathMatch pathMatch(toStdStringList(mExcludedPaths), true);
#else
const PathMatch pathMatch(toStdStringList(mExcludedPaths), false);
#endif
const PathMatch pathMatch(toStdStringList(mExcludedPaths), QDir::currentPath().toStdString());

QStringList paths;
for (const QFileInfo& item : mFileList) {
Expand Down
52 changes: 25 additions & 27 deletions lib/importproject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "importproject.h"

#include "path.h"
#include "pathmatch.h"
#include "settings.h"
#include "standards.h"
#include "suppressions.h"
Expand All @@ -42,30 +43,11 @@

#include "json.h"

// TODO: align the exclusion logic with PathMatch
// TODO: PathMatch lacks glob support
void ImportProject::ignorePaths(const std::vector<std::string> &ipaths, bool debug)
{
PathMatch matcher(ipaths, Path::getCurrentPath());
for (auto it = fileSettings.cbegin(); it != fileSettings.cend();) {
bool ignore = false;
for (std::string i : ipaths) {
if (it->filename().size() > i.size() && it->filename().compare(0,i.size(),i)==0) {
ignore = true;
break;
}
if (isValidGlobPattern(i) && matchglob(i, it->filename())) {
ignore = true;
break;
}
if (!Path::isAbsolute(i)) {
i = mPath + i;
if (it->filename().size() > i.size() && it->filename().compare(0,i.size(),i)==0) {
ignore = true;
break;
}
}
}
if (ignore) {
if (matcher.match(it->filename())) {
if (debug)
std::cout << "ignored path: " << it->filename() << std::endl;
it = fileSettings.erase(it);
Expand Down Expand Up @@ -858,8 +840,9 @@ bool ImportProject::importVcxproj(const std::string &filename, const tinyxml2::X
}

// Project files
PathMatch filtermatcher(fileFilters, Path::getCurrentPath());
for (const std::string &cfilename : compileList) {
if (!fileFilters.empty() && !matchglobs(fileFilters, cfilename))
if (!fileFilters.empty() && !filtermatcher.match(cfilename))
continue;

for (const ProjectConfiguration &p : projectConfigurationList) {
Expand Down Expand Up @@ -937,6 +920,8 @@ ImportProject::SharedItemsProject ImportProject::importVcxitems(const std::strin
SharedItemsProject result;
result.pathToProjectFile = filename;

PathMatch filtermatcher(fileFilters, Path::getCurrentPath());

tinyxml2::XMLDocument doc;
const tinyxml2::XMLError error = doc.LoadFile(filename.c_str());
if (error != tinyxml2::XML_SUCCESS) {
Expand All @@ -957,8 +942,8 @@ ImportProject::SharedItemsProject ImportProject::importVcxitems(const std::strin
std::string file(include);
findAndReplace(file, "$(MSBuildThisFileDirectory)", "./");

// Don't include file if it matches the filter
if (!fileFilters.empty() && !matchglobs(fileFilters, file))
// Skip file if it doesn't match the filter
if (!fileFilters.empty() && !filtermatcher.match(file))
continue;

result.sourceFiles.emplace_back(file);
Expand Down Expand Up @@ -1269,7 +1254,20 @@ static std::list<std::string> readXmlStringList(const tinyxml2::XMLElement *node
continue;
const char *attr = attribute ? child->Attribute(attribute) : child->GetText();
if (attr)
ret.push_back(joinRelativePath(path, attr));
ret.emplace_back(joinRelativePath(path, attr));
}
return ret;
}

static std::list<std::string> readXmlPathMatchList(const tinyxml2::XMLElement *node, const std::string &path, const char name[], const char attribute[])
{
std::list<std::string> ret;
for (const tinyxml2::XMLElement *child = node->FirstChildElement(); child; child = child->NextSiblingElement()) {
if (strcmp(child->Name(), name) != 0)
continue;
const char *attr = attribute ? child->Attribute(attribute) : child->GetText();
if (attr)
ret.emplace_back(PathMatch::joinRelativePattern(path, attr));
}
return ret;
}
Expand Down Expand Up @@ -1339,13 +1337,13 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings &setti
else if (strcmp(name, CppcheckXml::PathsElementName) == 0)
paths = readXmlStringList(node, path, CppcheckXml::PathName, CppcheckXml::PathNameAttrib);
else if (strcmp(name, CppcheckXml::ExcludeElementName) == 0)
guiProject.excludedPaths = readXmlStringList(node, "", CppcheckXml::ExcludePathName, CppcheckXml::ExcludePathNameAttrib); // TODO: append instead of overwrite
guiProject.excludedPaths = readXmlPathMatchList(node, path, CppcheckXml::ExcludePathName, CppcheckXml::ExcludePathNameAttrib); // TODO: append instead of overwrite
else if (strcmp(name, CppcheckXml::FunctionContracts) == 0)
;
else if (strcmp(name, CppcheckXml::VariableContractsElementName) == 0)
;
else if (strcmp(name, CppcheckXml::IgnoreElementName) == 0)
guiProject.excludedPaths = readXmlStringList(node, "", CppcheckXml::IgnorePathName, CppcheckXml::IgnorePathNameAttrib); // TODO: append instead of overwrite
guiProject.excludedPaths = readXmlPathMatchList(node, path, CppcheckXml::IgnorePathName, CppcheckXml::IgnorePathNameAttrib); // TODO: append instead of overwrite
else if (strcmp(name, CppcheckXml::LibrariesElementName) == 0)
guiProject.libraries = readXmlStringList(node, "", CppcheckXml::LibraryElementName, nullptr); // TODO: append instead of overwrite
else if (strcmp(name, CppcheckXml::SuppressionsElementName) == 0) {
Expand Down
14 changes: 10 additions & 4 deletions lib/path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,18 +173,24 @@ std::string Path::getCurrentExecutablePath(const char* fallback)
return success ? std::string(buf) : std::string(fallback);
}

bool Path::isAbsolute(const std::string& path)
static bool issep(char c)
{
const std::string& nativePath = toNativeSeparators(path);
return c == '/' || c == '\\';
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm techically in linux, backslash is not a path separator. you can create a directory or file with backslash in the name.

}

bool Path::isAbsolute(const std::string& path)
{
#ifdef _WIN32
if (path.length() < 2)
return false;

if (issep(path[0]) && issep(path[1]))
return true;

// On Windows, 'C:\foo\bar' is an absolute path, while 'C:foo\bar' is not
return startsWith(nativePath, "\\\\") || (std::isalpha(nativePath[0]) != 0 && nativePath.compare(1, 2, ":\\") == 0);
return std::isalpha(path[0]) && path[1] == ':' && issep(path[2]);
#else
return !nativePath.empty() && nativePath[0] == '/';
return !path.empty() && issep(path[0]);
#endif
}

Expand Down
Loading