support wildcard characters * and ? in suppression list
This commit is contained in:
parent
a9f2879889
commit
7a219b1fb8
|
@ -116,9 +116,81 @@ std::string Settings::Suppressions::parseFile(std::istream &istr)
|
|||
return "";
|
||||
}
|
||||
|
||||
bool Settings::Suppressions::FileMatcher::match(const std::string &pattern, const std::string &name)
|
||||
{
|
||||
const char *p = pattern.c_str();
|
||||
const char *n = name.c_str();
|
||||
std::list<std::pair<const char *, const char *> > backtrack;
|
||||
|
||||
for (;;) {
|
||||
bool matching = true;
|
||||
while (*p != '\0' && matching) {
|
||||
switch (*p) {
|
||||
case '*':
|
||||
// Step forward until we match the next character after *
|
||||
while (*n != '\0' && *n != p[1]) {
|
||||
n++;
|
||||
}
|
||||
if (*n != '\0') {
|
||||
// If this isn't the last possibility, save it for later
|
||||
backtrack.push_back(std::make_pair(p, n));
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
// Any character matches unless we're at the end of the name
|
||||
if (*n != '\0') {
|
||||
n++;
|
||||
} else {
|
||||
matching = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Non-wildcard characters match literally
|
||||
if (*n == *p) {
|
||||
n++;
|
||||
} else {
|
||||
matching = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
// If we haven't failed matching and we've reached the end of the name, then success
|
||||
if (matching && *n == '\0') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If there are no other paths to tray, then fail
|
||||
if (backtrack.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Restore pointers from backtrack stack
|
||||
p = backtrack.back().first;
|
||||
n = backtrack.back().second;
|
||||
backtrack.pop_back();
|
||||
|
||||
// Advance name pointer by one because the current position didn't work
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Settings::Suppressions::FileMatcher::addFile(const std::string &name, unsigned int line)
|
||||
{
|
||||
_files[name].insert(line);
|
||||
if (name.find_first_of("*?") != std::string::npos) {
|
||||
for (std::string::const_iterator i = name.begin(); i != name.end(); ++i) {
|
||||
if (*i == '*') {
|
||||
std::string::const_iterator j = i + 1;
|
||||
if (j != name.end() && (*j == '*' || *j == '?')) {
|
||||
return "Failed to add suppression. Syntax error in glob.";
|
||||
}
|
||||
}
|
||||
}
|
||||
_globs[name].insert(line);
|
||||
} else {
|
||||
_files[name].insert(line);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
@ -128,14 +200,26 @@ bool Settings::Suppressions::FileMatcher::isSuppressed(const std::string &file,
|
|||
if (_files.find("") != _files.end())
|
||||
return true;
|
||||
|
||||
if (_files.find(file) == _files.end())
|
||||
std::set<unsigned int> lineset;
|
||||
|
||||
std::map<std::string, std::set<unsigned int> >::const_iterator f = _files.find(file);
|
||||
if (f != _files.end()) {
|
||||
lineset.insert(f->second.begin(), f->second.end());
|
||||
}
|
||||
for (std::map<std::string, std::set<unsigned int> >::iterator g = _globs.begin(); g != _globs.end(); ++g) {
|
||||
if (match(g->first, file)) {
|
||||
lineset.insert(g->second.begin(), g->second.end());
|
||||
}
|
||||
}
|
||||
|
||||
if (lineset.empty())
|
||||
return false;
|
||||
|
||||
// Check should all errors in this file be filtered out
|
||||
if (std::find(_files[file].begin(), _files[file].end(), 0U) != _files[file].end())
|
||||
if (lineset.find(0U) != lineset.end())
|
||||
return true;
|
||||
|
||||
if (std::find(_files[file].begin(), _files[file].end(), line) == _files[file].end())
|
||||
if (lineset.find(line) == lineset.end())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
|
|
@ -307,7 +307,8 @@ Directory name is matched to all parts of the path.</para>
|
|||
<term><option>--suppressions-list=<file></option></term>
|
||||
<listitem>
|
||||
<para>Suppress warnings listed in the file. Filename and line are optional. The format of the single line in file is: [error id]:[filename]:[line].
|
||||
You can use --template or --xml to see the error id.</para>
|
||||
You can use --template or --xml to see the error id.
|
||||
The filename may contain the wildcard characters * or ?.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
|
|
|
@ -385,6 +385,10 @@ gui/test.cpp,16,error,mismatchAllocDealloc,Mismatching allocation and deallocati
|
|||
line flag. Copy and paste the <literal>id</literal> string from the XML
|
||||
output.</para>
|
||||
|
||||
<para>The <literal>filename</literal> may include the wildcard characters
|
||||
* or ?, which match any sequence of characters or any single character
|
||||
respectively.</para>
|
||||
|
||||
<para>Here is an example:</para>
|
||||
|
||||
<programlisting>memleak:file1.cpp
|
||||
|
|
|
@ -67,11 +67,37 @@ private:
|
|||
|
||||
void suppressionsGlob()
|
||||
{
|
||||
Settings::Suppressions suppressions;
|
||||
std::istringstream s("error:x*.cpp\n");
|
||||
ASSERT_EQUALS("", suppressions.parseFile(s));
|
||||
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "xyz.cpp", 1));
|
||||
ASSERT_EQUALS(false, suppressions.isSuppressed("errorid", "abc.cpp", 1));
|
||||
// Check for syntax errors in glob
|
||||
{
|
||||
Settings::Suppressions suppressions;
|
||||
std::istringstream s("errorid:**.cpp\n");
|
||||
ASSERT_EQUALS("Failed to add suppression. Syntax error in glob.", suppressions.parseFile(s));
|
||||
}
|
||||
|
||||
// Check that globbing works
|
||||
{
|
||||
Settings::Suppressions suppressions;
|
||||
std::istringstream s("errorid:x*.cpp\nerrorid:y?.cpp\nerrorid:test.c*");
|
||||
ASSERT_EQUALS("", suppressions.parseFile(s));
|
||||
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "xyz.cpp", 1));
|
||||
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "xyz.cpp.cpp", 1));
|
||||
ASSERT_EQUALS(false, suppressions.isSuppressed("errorid", "abc.cpp", 1));
|
||||
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "ya.cpp", 1));
|
||||
ASSERT_EQUALS(false, suppressions.isSuppressed("errorid", "y.cpp", 1));
|
||||
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "test.c", 1));
|
||||
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "test.cpp", 1));
|
||||
}
|
||||
|
||||
// Check that both a filename match and a glob match apply
|
||||
{
|
||||
Settings::Suppressions suppressions;
|
||||
std::istringstream s("errorid:x*.cpp\nerrorid:xyz.cpp:1\nerrorid:a*.cpp:1\nerrorid:abc.cpp:2");
|
||||
ASSERT_EQUALS("", suppressions.parseFile(s));
|
||||
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "xyz.cpp", 1));
|
||||
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "xyz.cpp", 2));
|
||||
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "abc.cpp", 1));
|
||||
ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "abc.cpp", 2));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue