diff --git a/addons/cppcheckdata.py b/addons/cppcheckdata.py index 9843f20b6..bd46b80cd 100755 --- a/addons/cppcheckdata.py +++ b/addons/cppcheckdata.py @@ -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 diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 33aa78883..50f72df61 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -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(); diff --git a/lib/suppressions.cpp b/lib/suppressions.cpp index b452615eb..b16ca21af 100644 --- a/lib/suppressions.cpp +++ b/lib/suppressions.cpp @@ -18,6 +18,7 @@ #include "suppressions.h" +#include "errorlogger.h" #include "mathlib.h" #include "path.h" @@ -29,6 +30,8 @@ #include #include +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 << " " << std::endl; + for (const Suppression &suppression : _suppressions) { + out << " 0) + out << " lineNumber=\"" << suppression.lineNumber << '"'; + if (!suppression.symbolName.empty()) + out << " symbolName=\"" << ErrorLogger::toxml(suppression.symbolName) << '\"'; + out << " />" << std::endl; + } + out << " " << std::endl; +} + std::list Suppressions::getUnmatchedLocalSuppressions(const std::string &file, const bool unusedFunctionChecking) const { std::list result; diff --git a/lib/suppressions.h b/lib/suppressions.h index fc042c919..ac784fe99 100644 --- a/lib/suppressions.h +++ b/lib/suppressions.h @@ -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