Skip to content
Merged
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
1 change: 1 addition & 0 deletions cli/cmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
path = Path::fromNativeSeparators(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, '/'))
Expand Down
43 changes: 24 additions & 19 deletions lib/pathmatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,55 +24,60 @@
#include <cstddef>
#include <utility>

PathMatch::PathMatch(std::vector<std::string> excludedPaths, bool caseSensitive)
: mExcludedPaths(std::move(excludedPaths)), mCaseSensitive(caseSensitive)
PathMatch::PathMatch(std::vector<std::string> paths, bool caseSensitive)
: mPaths(std::move(paths)), mCaseSensitive(caseSensitive)
{
if (!mCaseSensitive)
for (std::string& excludedPath : mExcludedPaths)
strTolower(excludedPath);
mWorkingDirectory.push_back(Path::getCurrentPath());
for (std::string& p : mPaths)
{
p = Path::fromNativeSeparators(p);
if (!mCaseSensitive)
strTolower(p);
}
// TODO: also make lowercase?
mWorkingDirectory.push_back(Path::fromNativeSeparators(Path::getCurrentPath()));
}

bool PathMatch::match(const std::string &path) const
{
if (path.empty())
return false;

// TODO: align the exclusion logic with ImportProject::ignorePaths()
for (std::vector<std::string>::const_iterator i = mExcludedPaths.cbegin(); i != mExcludedPaths.cend(); ++i) {
const std::string excludedPath((!Path::isAbsolute(path) && Path::isAbsolute(*i)) ? Path::getRelativePath(*i, mWorkingDirectory) : *i);
std::string findpath = Path::fromNativeSeparators(path);
if (!mCaseSensitive)
strTolower(findpath);

std::string findpath = Path::fromNativeSeparators(path);
if (!mCaseSensitive)
strTolower(findpath);
const bool is_absolute = Path::isAbsolute(path);

// TODO: align the match logic with ImportProject::ignorePaths()
for (std::vector<std::string>::const_iterator i = mPaths.cbegin(); i != mPaths.cend(); ++i) {
const std::string pathToMatch((!is_absolute && Path::isAbsolute(*i)) ? Path::getRelativePath(*i, mWorkingDirectory) : *i);

// Filtering directory name
if (endsWith(excludedPath,'/')) {
if (endsWith(pathToMatch,'/')) {
if (!endsWith(findpath,'/'))
findpath = removeFilename(findpath);

if (excludedPath.length() > findpath.length())
if (pathToMatch.length() > findpath.length())
continue;
// Match relative paths starting with mask
// -isrc matches src/foo.cpp
if (findpath.compare(0, excludedPath.size(), excludedPath) == 0)
if (findpath.compare(0, pathToMatch.size(), pathToMatch) == 0)
return true;
// Match only full directory name in middle or end of the path
// -isrc matches myproject/src/ but does not match
// myproject/srcfiles/ or myproject/mysrc/
if (findpath.find("/" + excludedPath) != std::string::npos)
if (findpath.find("/" + pathToMatch) != std::string::npos)
return true;
}
// Filtering filename
else {
if (excludedPath.length() > findpath.length())
if (pathToMatch.length() > findpath.length())
continue;
// Check if path ends with mask
// -ifoo.cpp matches (./)foo.c, src/foo.cpp and proj/src/foo.cpp
// -isrc/file.cpp matches src/foo.cpp and proj/src/foo.cpp
if (findpath.compare(findpath.size() - excludedPath.size(), findpath.size(), excludedPath) == 0)
if (findpath.compare(findpath.size() - pathToMatch.size(), findpath.size(), pathToMatch) == 0)
return true;

}
}
return false;
Expand Down
6 changes: 3 additions & 3 deletions lib/pathmatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ class CPPCHECKLIB PathMatch {

/**
* The constructor.
* @param excludedPaths List of masks.
* @param paths List of masks.
* @param caseSensitive Match the case of the characters when
* matching paths?
*/
explicit PathMatch(std::vector<std::string> excludedPaths, bool caseSensitive = true);
explicit PathMatch(std::vector<std::string> paths, bool caseSensitive = true);

/**
* @brief Match path against list of masks.
Expand All @@ -58,7 +58,7 @@ class CPPCHECKLIB PathMatch {
static std::string removeFilename(const std::string &path);

private:
std::vector<std::string> mExcludedPaths;
std::vector<std::string> mPaths;
bool mCaseSensitive;
std::vector<std::string> mWorkingDirectory;
};
Expand Down
280 changes: 280 additions & 0 deletions test/cli/other_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1762,3 +1762,283 @@ def test_checkers_report(tmpdir):
assert exitcode == 0, stdout
assert 'Active checkers:' in stderr
assert '--checkers-report' not in stderr


def test_ignore(tmpdir):
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?'
]

args = [
'-itest.cpp',
test_file
]

exitcode, stdout, _ = cppcheck(args, cwd=tmpdir)
assert exitcode == 1, stdout
assert stdout.splitlines() == lines_exp

# make sure it also matches when specified after the file
args = [
test_file,
'-itest.cpp'
]

exitcode, stdout, _ = cppcheck(args, cwd=tmpdir)
assert exitcode == 1, stdout
assert stdout.splitlines() == lines_exp

args = [
'-isrc/test.cpp',
test_file
]

exitcode, stdout, _ = cppcheck(args, cwd=tmpdir)
assert exitcode == 1, stdout
assert stdout.splitlines() == lines_exp

args = [
'-isrc\\test.cpp',
test_file
]

exitcode, stdout, _ = cppcheck(args, cwd=tmpdir)
assert exitcode == 1, stdout
assert stdout.splitlines() == lines_exp

args = [
'-isrc/',
test_file
]

exitcode, stdout, _ = cppcheck(args, cwd=tmpdir)
assert exitcode == 1, stdout
assert stdout.splitlines() == lines_exp

args = [
'-isrc\\',
test_file
]

exitcode, stdout, _ = cppcheck(args, cwd=tmpdir)
assert exitcode == 1, stdout
assert stdout.splitlines() == lines_exp

args = [
'-i{}'.format(test_file),
test_file
]

exitcode, stdout, _ = cppcheck(args, cwd=tmpdir)
assert exitcode == 1, stdout
assert stdout.splitlines() == lines_exp


def __write_gui_project(tmpdir, test_file, ignore):
project_file = os.path.join(tmpdir, 'test.cppcheck')
with open(project_file, 'wt') as f:
f.write(
"""<?xml version="1.0" encoding="UTF-8"?>
<project>
<paths>
<dir name="{}"/>
</paths>
<ignore>
<path name="{}"/>
</ignore>
</project>""".format(test_file, ignore))

return project_file


def test_ignore_project(tmpdir):
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?'
]

project_file = __write_gui_project(tmpdir, test_file, 'test.cpp')
args = [
'--project={}'.format(project_file)
]

exitcode, stdout, _ = cppcheck(args, cwd=tmpdir)
assert exitcode == 1, stdout
assert stdout.splitlines() == lines_exp

# make sure -i works when specified before project
project_file = __write_gui_project(tmpdir, test_file, 'test2.cpp')
args = [
'-itest.cpp',
'--project={}'.format(project_file)
]

exitcode, stdout, _ = cppcheck(args, cwd=tmpdir)
assert exitcode == 1, stdout
assert stdout.splitlines() == lines_exp

# make sure -i works when specified after project
project_file = __write_gui_project(tmpdir, test_file, 'test2.cpp')
args = [
'--project={}'.format(project_file),
'-itest.cpp'
]

exitcode, stdout, _ = cppcheck(args, cwd=tmpdir)
assert exitcode == 1, stdout
assert stdout.splitlines() == lines_exp

project_file = __write_gui_project(tmpdir, test_file, 'src/test.cpp')
args = [
'--project={}'.format(project_file)
]

exitcode, stdout, _ = cppcheck(args, cwd=tmpdir)
assert exitcode == 1, stdout
assert stdout.splitlines() == lines_exp

project_file = __write_gui_project(tmpdir, test_file, 'src\\test.cpp')
args = [
'--project={}'.format(project_file)
]

exitcode, stdout, _ = cppcheck(args, cwd=tmpdir)
assert exitcode == 1, stdout
assert stdout.splitlines() == lines_exp

project_file = __write_gui_project(tmpdir, test_file, 'src/')
args = [
'--project={}'.format(project_file)
]

exitcode, stdout, _ = cppcheck(args, cwd=tmpdir)
assert exitcode == 1, stdout
assert stdout.splitlines() == lines_exp

project_file = __write_gui_project(tmpdir, test_file, 'src\\')
args = [
'--project={}'.format(project_file)
]

exitcode, stdout, _ = cppcheck(args, cwd=tmpdir)
assert exitcode == 1, stdout
assert stdout.splitlines() == lines_exp

project_file = __write_gui_project(tmpdir, test_file, test_file)
args = [
'--project={}'.format(project_file)
]

exitcode, stdout, _ = cppcheck(args, cwd=tmpdir)
assert exitcode == 1, stdout
assert stdout.splitlines() == lines_exp


def __write_compdb(tmpdir, test_file):
compile_commands = os.path.join(tmpdir, 'compile_commands.json')
j = [
{
'directory': os.path.dirname(test_file),
'file': test_file,
'command': 'gcc -c {}'.format(test_file)
}
]
with open(compile_commands, 'wt') as f:
f.write(json.dumps(j))
return compile_commands


# TODO: -i appears to be ignored
@pytest.mark.xfail(strict=True)
def test_ignore_project_2(tmpdir):
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?'
]

project_file = __write_compdb(tmpdir, test_file)
args = [
'-itest.cpp',
'--project={}'.format(project_file)
]

exitcode, stdout, _ = cppcheck(args, cwd=tmpdir)
assert exitcode == 1, stdout
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

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

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

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

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

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
Loading