Add suppressions to the XML dump (#1166)

* Added parsing suppressions from dump xml.

* Added code to dump suppressions to an xml file

* Added declaration for dump function

* Suppressions will now be written to the xml file when a dump is requested

* Fixed syntax error

* Removed excess whitespace

* Fixed indentation to be consistent

* Fixed indentation to be consistent

* Fixed indentation to be consistent

* Added missing include for ErrorLogger::toXml

* Fixed suggestions from pull request #1166

Switched to using ranged for loop to iterate through suppressions.
Made the line number attribute optional, rather than 0 if not specified.  This means when Python deserialises it it will be None, which is more pythonic.

* Implemented checking suppressions in reportError

This modification expects suppressions and a function to be called to write a line of output to be passed in.  The function checks if any of the suppressions match the warning (with the new Suppression.isMatch function) and if so returns None.  This change maintains the old behaviour of returning the warning text, but adds the possibility of returning None if the warning was suppressed.

* Fixed code quality warnings

* Removed more extraneous whitespace
This commit is contained in:
rebnridgway 2018-04-24 21:19:24 +01:00 committed by Daniel Marjamäki
parent 485d3e0229
commit 995b496ddf
4 changed files with 78 additions and 4 deletions

View File

@ -8,6 +8,7 @@ License: No restrictions, use this as you need.
import xml.etree.ElementTree as ET
import argparse
from fnmatch import fnmatch
class Directive:
@ -450,12 +451,43 @@ class ValueFlow:
for value in element:
self.values.append(ValueFlow.Value(value))
class Suppression:
"""
Suppression class
This class contains a suppression entry to suppress a warning.
Attributes
errorId The id string of the error to suppress, can be a wildcard
fileName The name of the file to suppress warnings for, can include wildcards
lineNumber The number of the line to suppress warnings from, can be 0 to represent any line
symbolName The name of the symbol to match warnings for, can include wildcards
"""
errorId = None
fileName = None
lineNumber = None
symbolName = None
def __init__(self, element):
self.errorId = element.get('errorId')
self.fileName = element.get('fileName')
self.lineNumber = element.get('lineNumber')
self.symbolName = element.get('symbolName')
def isMatch(file, line, message, errorId):
if (fnmatch(file, self.fileName)
and (self.lineNumber is None or line == self.lineNumber)
and fnmatch(message, '*'+self.symbolName+'*')
and fnmatch(errorId, self.errorId)):
return true
else:
return false
class Configuration:
"""
Configuration class
This class contains the directives, tokens, scopes, functions,
variables and value flows for one configuration.
variables, value flows, and suppressions for one configuration.
Attributes:
name Name of the configuration, "" for default
@ -465,6 +497,7 @@ class Configuration:
functions List of Function items
variables List of Variable items
valueflow List of ValueFlow values
suppressions List of warning suppressions
"""
name = ''
@ -474,6 +507,7 @@ class Configuration:
functions = []
variables = []
valueflow = []
suppressions = []
def __init__(self, confignode):
self.name = confignode.get('cfg')
@ -483,6 +517,7 @@ class Configuration:
self.functions = []
self.variables = []
self.valueflow = []
self.suppressions = []
arguments = []
for element in confignode:
@ -518,6 +553,9 @@ class Configuration:
if element.tag == 'valueflow':
for values in element:
self.valueflow.append(ValueFlow(values))
if element.tag == "suppressions":
for suppression in element:
self.suppressions.append(Suppression(suppression))
IdMap = {None: None, '0': None, '00000000': None, '0000000000000000': None}
for token in self.tokenlist:
@ -711,7 +749,7 @@ def ArgumentParser():
return parser
def reportError(template, callstack=(), severity='', message='', id=''):
def reportError(template, callstack=(), severity='', message='', errorId='', suppressions=None, outputFunc=None):
"""
Format an error message according to the template.
@ -732,6 +770,13 @@ def reportError(template, callstack=(), severity='', message='', id=''):
stack = ' -> '.join('[' + f + ':' + str(l) + ']' for (f, l) in callstack)
file = callstack[-1][0]
line = str(callstack[-1][1])
if suppressions is not None and any(suppression.isMatch(file, line, message, errorId) for suppression in suppressions):
return None
outputLine = template.format(callstack=stack, file=file, line=line,
severity=severity, message=message, id=errorId)
if outputFunc is not None:
outputFunc(outputLine)
# format message
return template.format(callstack=stack, file=file, line=line,
severity=severity, message=message, id=id)
return outputLine

View File

@ -225,6 +225,9 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
// Parse comments and then remove them
preprocessor.inlineSuppressions(tokens1);
if (_settings.dump && fdump.is_open()) {
_settings.nomsg.dump(fdump);
}
tokens1.removeComments();
preprocessor.removeComments();

View File

@ -18,6 +18,7 @@
#include "suppressions.h"
#include "errorlogger.h"
#include "mathlib.h"
#include "path.h"
@ -29,6 +30,8 @@
#include <sstream>
#include <utility>
class ErrorLogger;
static bool isValidGlobPattern(const std::string &pattern)
{
for (std::string::const_iterator i = pattern.begin(); i != pattern.end(); ++i) {
@ -274,6 +277,23 @@ bool Suppressions::isSuppressed(const Suppressions::ErrorMessage &errmsg)
return false;
}
void Suppressions::dump(std::ostream & out)
{
out << " <suppressions>" << std::endl;
for (const Suppression &suppression : _suppressions) {
out << " <suppression";
out << " errorId=\"" << ErrorLogger::toxml(suppression.errorId) << '"';
if (!suppression.fileName.empty())
out << " fileName=\"" << ErrorLogger::toxml(suppression.fileName) << '"';
if (suppression.lineNumber > 0)
out << " lineNumber=\"" << suppression.lineNumber << '"';
if (!suppression.symbolName.empty())
out << " symbolName=\"" << ErrorLogger::toxml(suppression.symbolName) << '\"';
out << " />" << std::endl;
}
out << " </suppressions>" << std::endl;
}
std::list<Suppressions::Suppression> Suppressions::getUnmatchedLocalSuppressions(const std::string &file, const bool unusedFunctionChecking) const
{
std::list<Suppression> result;

View File

@ -135,6 +135,12 @@ public:
*/
bool isSuppressed(const ErrorMessage &errmsg);
/**
* @brief Create an xml dump of suppressions
* @param out stream to write XML to
*/
void dump(std::ostream &out);
/**
* @brief Returns list of unmatched local (per-file) suppressions.
* @return list of unmatched suppressions