Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(264)

Unified Diff: cpplint/cpplint.py

Issue 1697023: Update cpplint.py to #150:... (Closed) Base URL: http://google-styleguide.googlecode.com/svn/trunk/
Patch Set: Created 10 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | cpplint/cpplint_unittest.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: cpplint/cpplint.py
===================================================================
--- cpplint/cpplint.py (revision 43)
+++ cpplint/cpplint.py (working copy)
@@ -102,8 +102,9 @@
certain of the problem, and 1 meaning it could be a legitimate construct.
This will miss some errors, and is not a substitute for a code review.
- To prevent specific lines from being linted, add a '// NOLINT' comment to the
- end of the line.
+ To suppress false-positive errors of a certain category, add a
+ 'NOLINT(category)' comment to the line. NOLINT or NOLINT(*)
+ suppresses errors of all categories on that line.
The files passed in will be linted; at least one file must be provided.
Linted extensions are .cc, .cpp, and .h. Other file types will be ignored.
@@ -145,64 +146,65 @@
# If you add a new error message with a new category, add it to the list
# here! cpplint_unittest.py should tell you if you forget to do this.
# \ used for clearer layout -- pylint: disable-msg=C6013
-_ERROR_CATEGORIES = '''\
- build/class
- build/deprecated
- build/endif_comment
- build/forward_decl
- build/header_guard
- build/include
- build/include_alpha
- build/include_order
- build/include_what_you_use
- build/namespaces
- build/printf_format
- build/storage_class
- legal/copyright
- readability/braces
- readability/casting
- readability/check
- readability/constructors
- readability/fn_size
- readability/function
- readability/multiline_comment
- readability/multiline_string
- readability/streams
- readability/todo
- readability/utf8
- runtime/arrays
- runtime/casting
- runtime/explicit
- runtime/int
- runtime/init
- runtime/invalid_increment
- runtime/member_string_references
- runtime/memset
- runtime/operator
- runtime/printf
- runtime/printf_format
- runtime/references
- runtime/rtti
- runtime/sizeof
- runtime/string
- runtime/threadsafe_fn
- runtime/virtual
- whitespace/blank_line
- whitespace/braces
- whitespace/comma
- whitespace/comments
- whitespace/end_of_line
- whitespace/ending_newline
- whitespace/indent
- whitespace/labels
- whitespace/line_length
- whitespace/newline
- whitespace/operators
- whitespace/parens
- whitespace/semicolon
- whitespace/tab
- whitespace/todo
-'''
+_ERROR_CATEGORIES = [
+ 'build/class',
+ 'build/deprecated',
+ 'build/endif_comment',
+ 'build/forward_decl',
+ 'build/header_guard',
+ 'build/include',
+ 'build/include_alpha',
+ 'build/include_order',
+ 'build/include_what_you_use',
+ 'build/namespaces',
+ 'build/printf_format',
+ 'build/storage_class',
+ 'legal/copyright',
+ 'readability/braces',
+ 'readability/casting',
+ 'readability/check',
+ 'readability/constructors',
+ 'readability/fn_size',
+ 'readability/function',
+ 'readability/multiline_comment',
+ 'readability/multiline_string',
+ 'readability/nolint',
+ 'readability/streams',
+ 'readability/todo',
+ 'readability/utf8',
+ 'runtime/arrays',
+ 'runtime/casting',
+ 'runtime/explicit',
+ 'runtime/int',
+ 'runtime/init',
+ 'runtime/invalid_increment',
+ 'runtime/member_string_references',
+ 'runtime/memset',
+ 'runtime/operator',
+ 'runtime/printf',
+ 'runtime/printf_format',
+ 'runtime/references',
+ 'runtime/rtti',
+ 'runtime/sizeof',
+ 'runtime/string',
+ 'runtime/threadsafe_fn',
+ 'runtime/virtual',
+ 'whitespace/blank_line',
+ 'whitespace/braces',
+ 'whitespace/comma',
+ 'whitespace/comments',
+ 'whitespace/end_of_line',
+ 'whitespace/ending_newline',
+ 'whitespace/indent',
+ 'whitespace/labels',
+ 'whitespace/line_length',
+ 'whitespace/newline',
+ 'whitespace/operators',
+ 'whitespace/parens',
+ 'whitespace/semicolon',
+ 'whitespace/tab',
+ 'whitespace/todo'
+ ]
# The default state of the category filter. This is overrided by the --filter=
# flag. By default all errors are on, so only add here categories that should be
@@ -218,8 +220,8 @@
_STL_HEADERS = frozenset([
'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception',
'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set',
- 'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'pair.h',
- 'pthread_alloc', 'queue', 'set', 'set.h', 'sstream', 'stack',
+ 'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'new',
+ 'pair.h', 'pthread_alloc', 'queue', 'set', 'set.h', 'sstream', 'stack',
'stl_alloc.h', 'stl_relops.h', 'type_traits.h',
'utility', 'vector', 'vector.h',
])
@@ -287,7 +289,62 @@
_regexp_compile_cache = {}
+# Finds occurrences of NOLINT or NOLINT(...).
+_RE_SUPPRESSION = re.compile(r'\bNOLINT\b(\([^)]*\))?')
+# {str, set(int)}: a map from error categories to sets of linenumbers
+# on which those errors are expected and should be suppressed.
+_error_suppressions = {}
+
+def ParseNolintSuppressions(filename, raw_line, linenum, error):
+ """Updates the global list of error-suppressions.
+
+ Parses any NOLINT comments on the current line, updating the global
+ error_suppressions store. Reports an error if the NOLINT comment
+ was malformed.
+
+ Args:
+ filename: str, the name of the input file.
+ raw_line: str, the line of input text, with comments.
+ linenum: int, the number of the current line.
+ error: function, an error handler.
+ """
+ # FIXME(adonovan): "NOLINT(" is misparsed as NOLINT(*).
+ m = _RE_SUPPRESSION.search(raw_line)
+ if m:
+ category = m.group(1)
+ if category in (None, '(*)'): # => "suppress all"
+ _error_suppressions.setdefault(None, set()).add(linenum)
+ else:
+ if category.startswith('(') and category.endswith(')'):
+ category = category[1:-1]
+ if category in _ERROR_CATEGORIES:
+ _error_suppressions.setdefault(category, set()).add(linenum)
+ else:
+ error(filename, linenum, 'readability/nolint', 5,
+ 'Unknown NOLINT error category: %s' % category)
+
+
+def ResetNolintSuppressions():
+ "Resets the set of NOLINT suppressions to empty."
+ _error_suppressions.clear()
+
+
+def IsErrorSuppressedByNolint(category, linenum):
+ """Returns true if the specified error category is suppressed on this line.
+
+ Consults the global error_suppressions map populated by
+ ParseNolintSuppressions/ResetNolintSuppressions.
+
+ 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 a NOLINT comment.
+ """
+ return (linenum in _error_suppressions.get(category, set()) or
+ linenum in _error_suppressions.get(None, set()))
+
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
@@ -701,10 +758,15 @@
return self.Extension()[1:] in ('c', 'cc', 'cpp', 'cxx')
-def _ShouldPrintError(category, confidence):
- """Returns true iff confidence >= verbose, and category passes filter."""
- # There are two ways we might decide not to print an error message:
+def _ShouldPrintError(category, confidence, linenum):
+ """Returns true iff confidence >= verbose, category passes
+ filter and is not NOLINT-suppressed."""
+
+ # There are three ways we might decide not to print an error message:
+ # a "NOLINT(category)" comment appears in the source,
# the verbosity level isn't high enough, or the filters filter it out.
+ if IsErrorSuppressedByNolint(category, linenum):
+ return False
if confidence < _cpplint_state.verbose_level:
return False
@@ -731,6 +793,10 @@
that is, how certain we are this is a legitimate style regression, and
not a misidentification or a use that's sometimes justified.
+ False positives can be suppressed by the use of
+ "cpplint(category)" comments on the offending line. These are
+ parsed into _error_suppressions.
+
Args:
filename: The name of the file containing the error.
linenum: The number of the line containing the error.
@@ -742,9 +808,7 @@
and 1 meaning that it could be a legitimate construct.
message: The error message.
"""
- # There are two ways we might decide not to print an error message:
- # the verbosity level isn't high enough, or the filters filter it out.
- if _ShouldPrintError(category, confidence):
+ if _ShouldPrintError(category, confidence, linenum):
_cpplint_state.IncrementErrorCount(category)
if _cpplint_state.output_format == 'vs7':
sys.stderr.write('%s(%s): %s [%s] [%d]\n' % (
@@ -962,6 +1026,10 @@
"""
+ # Restores original filename in case that cpplint is invoked from Emacs's
+ # flymake.
+ filename = re.sub(r'_flymake\.h$', '.h', filename)
+
fileinfo = FileInfo(filename)
return re.sub(r'[-./\s]', '_', fileinfo.RepositoryName()).upper() + '_'
@@ -1008,20 +1076,23 @@
# The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__
# for backward compatibility.
- if ifndef != cppvar and not Search(r'\bNOLINT\b', lines[ifndef_linenum]):
+ if ifndef != cppvar:
error_level = 0
if ifndef != cppvar + '_':
error_level = 5
+ ParseNolintSuppressions(filename, lines[ifndef_linenum], ifndef_linenum,
+ error)
error(filename, ifndef_linenum, 'build/header_guard', error_level,
'#ifndef header guard has wrong style, please use: %s' % cppvar)
- if (endif != ('#endif // %s' % cppvar) and
- not Search(r'\bNOLINT\b', lines[endif_linenum])):
+ if endif != ('#endif // %s' % cppvar):
error_level = 0
if endif != ('#endif // %s' % (cppvar + '_')):
error_level = 5
+ ParseNolintSuppressions(filename, lines[endif_linenum], endif_linenum,
+ error)
error(filename, endif_linenum, 'build/header_guard', error_level,
'#endif line should be "#endif // %s"' % cppvar)
@@ -1519,8 +1590,7 @@
error(filename, linenum, 'readability/fn_size', 5,
'Lint failed to find start of function body.')
elif Match(r'^\}\s*$', line): # function end
- if not Search(r'\bNOLINT\b', raw_line):
- function_state.Check(error, filename, linenum)
+ function_state.Check(error, filename, linenum)
function_state.End()
elif not Match(r'^\s*$', line):
function_state.Count() # Count non-blank/non-comment lines.
@@ -2027,9 +2097,11 @@
line):
error(filename, linenum, 'whitespace/labels', 4,
'Labels should always be indented at least one space. '
- 'If this is a member-initializer list in a constructor, '
- 'the colon should be on the line after the definition header.')
+ 'If this is a member-initializer list in a constructor or '
+ 'the base class list in a class definition, the colon should '
+ 'be on the following line.')
+
# Check if the line is a header guard.
is_header_guard = False
if file_extension == 'h':
@@ -2401,7 +2473,8 @@
# When snprintf is used, the second argument shouldn't be a literal.
match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line)
- if match:
+ if match and match.group(2) != '0':
+ # If 2nd arg is zero, snprintf is used to calculate size.
error(filename, linenum, 'runtime/printf', 3,
'If you can, use sizeof(%s) instead of %s as the 2nd arg '
'to snprintf.' % (match.group(1), match.group(2)))
@@ -2750,8 +2823,13 @@
continue
# String is special -- it is a non-templatized type in STL.
- if _RE_PATTERN_STRING.search(line):
- required['<string>'] = (linenum, 'string')
+ m = _RE_PATTERN_STRING.search(line)
+ if m:
+ # Don't warn about strings in non-STL namespaces:
+ # (We check only the first match per line; good enough.)
+ prefix = line[:m.start()]
+ if prefix.endswith('std::') or not prefix.endswith('::'):
+ required['<string>'] = (linenum, 'string')
for pattern, template, header in _re_pattern_algorithm_header:
if pattern.search(line):
@@ -2783,9 +2861,7 @@
# found.
# e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h'
# instead of 'foo_flymake.h'
- emacs_flymake_suffix = '_flymake.cc'
- if abs_filename.endswith(emacs_flymake_suffix):
- abs_filename = abs_filename[:-len(emacs_flymake_suffix)] + '.cc'
+ abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename)
# include_state is modified during iteration, so we iterate over a copy of
# the keys.
@@ -2836,9 +2912,8 @@
"""
raw_lines = clean_lines.raw_lines
+ ParseNolintSuppressions(filename, raw_lines[line], line, error)
CheckForFunctionLengths(filename, clean_lines, line, function_state, error)
- if Search(r'\bNOLINT\b', raw_lines[line]): # ignore nolint lines
- return
CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
CheckStyle(filename, clean_lines, line, file_extension, error)
CheckLanguage(filename, clean_lines, line, file_extension, include_state,
@@ -2866,6 +2941,8 @@
function_state = _FunctionState()
class_state = _ClassState()
+ ResetNolintSuppressions()
+
CheckForCopyright(filename, lines, error)
if file_extension == 'h':
@@ -2886,7 +2963,6 @@
CheckForNewlineAtEOF(filename, lines, error)
-
def ProcessFile(filename, vlevel):
"""Does google-lint on a single file.
@@ -2968,7 +3044,7 @@
These are the categories used to filter messages via --filter.
"""
- sys.stderr.write(_ERROR_CATEGORIES)
+ sys.stderr.write(''.join(' %s\n' % cat for cat in _ERROR_CATEGORIES))
sys.exit(0)
« no previous file with comments | « no previous file | cpplint/cpplint_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698