aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xclint.py112
1 files changed, 110 insertions, 2 deletions
diff --git a/clint.py b/clint.py
index 097b54f1c1..0eaab6e3f6 100755
--- a/clint.py
+++ b/clint.py
@@ -56,12 +56,15 @@ import sre_compile
import string
import sys
import unicodedata
+import json
+import collections # for defaultdict
_USAGE = """
Syntax: clint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
[--counting=total|toplevel|detailed] [--root=subdir]
- [--linelength=digits]
+ [--linelength=digits] [--record-errors=file]
+ [--suppress-errors=file]
<file> [file] ...
The style guidelines this tries to follow are those in
@@ -156,6 +159,13 @@ Syntax: clint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
Examples:
--extensions=hpp,cpp
+
+ record-errors=file
+ Record errors to the given location. This file may later be used for error
+ suppression using suppress-errors flag.
+
+ suppress-errors=file
+ Errors listed in the given file will not be reported.
"""
# We categorize each error message we print. Here are the categories.
@@ -270,6 +280,10 @@ _RE_SUPPRESSION = re.compile(r'\bNOLINT\b(\([^)]*\))?')
# on which those errors are expected and should be suppressed.
_error_suppressions = {}
+# {(str, int)}: a set of error categories and line numbers which are expected to
+# be suppressed
+_error_suppressions_2 = set()
+
# The allowed line length of files.
# This is set by --linelength flag.
_line_length = 80
@@ -309,11 +323,30 @@ def ParseNolintSuppressions(filename, raw_line, linenum, error):
'Unknown NOLINT error category: %s' % category)
+def ParseKnownErrorSuppressions(filename, raw_lines, linenum):
+ """Updates the global list of error-suppressions from suppress-file.
+
+ Args:
+ filename: str, the name of the input file.
+ raw_lines: list, all file lines
+ linenum: int, the number of the current line.
+ """
+ key = tuple(raw_lines[linenum - 1 if linenum else 0:linenum + 2])
+ if key in _cpplint_state.suppressed_errors[filename]:
+ for category in _cpplint_state.suppressed_errors[filename][key]:
+ _error_suppressions_2.add((category, linenum))
+
+
def ResetNolintSuppressions():
"Resets the set of NOLINT suppressions to empty."
_error_suppressions.clear()
+def ResetKnownErrorSuppressions():
+ "Resets the set of suppress-errors=file suppressions to empty."
+ _error_suppressions_2.clear()
+
+
def IsErrorSuppressedByNolint(category, linenum):
"""Returns true if the specified error category is suppressed on this line.
@@ -330,6 +363,19 @@ def IsErrorSuppressedByNolint(category, linenum):
linenum in _error_suppressions.get(None, set()))
+def IsErrorInSuppressedErrorsList(category, linenum):
+ """Returns true if the specified error is suppressed by suppress-errors=file
+
+ Args:
+ category: str, the category of the error.
+ linenum: int, the current line number.
+ Returns:
+ bool, True iff the error should be suppressed due to presense in
+ suppressions file.
+ """
+ return (category, linenum) in _error_suppressions_2
+
+
def Match(pattern, s):
"""Matches the string with the pattern, caching the compiled regexp."""
# The regexp compilation caching is inlined in both Match and Search for
@@ -454,6 +500,10 @@ class _CppLintState(object):
# "vs7" - format that Microsoft Visual Studio 7 can parse
self.output_format = 'emacs'
+ self.record_errors_file = None
+ self.suppressed_errors = collections.defaultdict(
+ lambda: collections.defaultdict(set))
+
def SetOutputFormat(self, output_format):
"""Sets the output format for errors."""
self.output_format = output_format
@@ -517,6 +567,25 @@ class _CppLintState(object):
(category, count))
sys.stderr.write('Total errors found: %d\n' % self.error_count)
+ def SuppressErrorsFrom(self, fname):
+ """Open file and read a list of suppressed errors from it"""
+ if fname is None:
+ return
+ try:
+ with open(fname) as fp:
+ for line in fp:
+ fname, lines, category = json.loads(line)
+ lines = tuple(lines)
+ self.suppressed_errors[fname][lines].add(category)
+ except IOError:
+ pass
+
+ def RecordErrorsTo(self, fname):
+ """Open file with suppressed errors for writing"""
+ if fname is None:
+ return
+ self.record_errors_file = open(fname, 'w')
+
_cpplint_state = _CppLintState()
@@ -545,6 +614,16 @@ def _SetCountingStyle(level):
_cpplint_state.SetCountingStyle(level)
+def _SuppressErrorsFrom(fname):
+ """Sets the file containing suppressed errors."""
+ _cpplint_state.SuppressErrorsFrom(fname)
+
+
+def _RecordErrorsTo(fname):
+ """Sets the file containing suppressed errors to write to."""
+ _cpplint_state.RecordErrorsTo(fname)
+
+
def _Filters():
"""Returns the module's list of output filters, as a list."""
return _cpplint_state.filters
@@ -687,6 +766,8 @@ def _ShouldPrintError(category, confidence, linenum):
# the verbosity level isn't high enough, or the filters filter it out.
if IsErrorSuppressedByNolint(category, linenum):
return False
+ if IsErrorInSuppressedErrorsList(category, linenum):
+ return False
if confidence < _cpplint_state.verbose_level:
return False
@@ -2986,6 +3067,23 @@ def ProcessFileData(filename, file_extension, lines, error,
nesting_state = _NestingState()
ResetNolintSuppressions()
+ ResetKnownErrorSuppressions()
+
+ for line in range(1, len(lines)):
+ ParseKnownErrorSuppressions(filename, lines, line)
+
+ if _cpplint_state.record_errors_file:
+ raw_lines = lines[:]
+
+ def RecordedError(filename, linenum, category, confidence, message):
+ if not IsErrorSuppressedByNolint(category, linenum):
+ key = raw_lines[linenum - 1 if linenum else 0:linenum + 2]
+ err = [filename, key, category]
+ json.dump(err, _cpplint_state.record_errors_file)
+ _cpplint_state.record_errors_file.write('\n')
+ Error(filename, linenum, category, confidence, message)
+
+ error = RecordedError
if file_extension == 'h':
CheckForHeaderGuard(filename, lines, error)
@@ -3113,7 +3211,9 @@ def ParseArguments(args):
'filter=',
'root=',
'linelength=',
- 'extensions='])
+ 'extensions=',
+ 'record-errors=',
+ 'suppress-errors='])
except getopt.GetoptError:
PrintUsage('Invalid arguments.')
@@ -3121,6 +3221,8 @@ def ParseArguments(args):
output_format = _OutputFormat()
filters = ''
counting_style = ''
+ record_errors_file = None
+ suppress_errors_file = None
for (opt, val) in opts:
if opt == '--help':
@@ -3153,6 +3255,10 @@ def ParseArguments(args):
_valid_extensions = set(val.split(','))
except ValueError:
PrintUsage('Extensions must be comma separated list.')
+ elif opt == '--record-errors':
+ record_errors_file = val
+ elif opt == '--suppress-errors':
+ suppress_errors_file = val
if not filenames:
PrintUsage('No files were specified.')
@@ -3161,6 +3267,8 @@ def ParseArguments(args):
_SetVerboseLevel(verbosity)
_SetFilters(filters)
_SetCountingStyle(counting_style)
+ _SuppressErrorsFrom(suppress_errors_file)
+ _RecordErrorsTo(record_errors_file)
return filenames