aboutsummaryrefslogtreecommitdiff
path: root/src/clint.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/clint.py')
-rwxr-xr-xsrc/clint.py198
1 files changed, 25 insertions, 173 deletions
diff --git a/src/clint.py b/src/clint.py
index befb10c9c7..b0992fcd63 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -175,7 +175,6 @@ _ERROR_CATEGORIES = [
'build/header_guard',
'build/include',
'build/include_alpha',
- 'build/include_order',
'build/printf_format',
'build/storage_class',
'build/useless_fattr',
@@ -200,18 +199,15 @@ _ERROR_CATEGORIES = [
'whitespace/alignment',
'whitespace/blank_line',
'whitespace/braces',
- 'whitespace/comma',
'whitespace/comments',
'whitespace/empty_conditional_body',
'whitespace/empty_loop_body',
'whitespace/end_of_line',
'whitespace/ending_newline',
'whitespace/indent',
- 'whitespace/line_length',
'whitespace/newline',
'whitespace/operators',
'whitespace/parens',
- 'whitespace/semicolon',
'whitespace/tab',
'whitespace/todo',
'whitespace/line_continuation',
@@ -265,7 +261,7 @@ _valid_extensions = {'c', 'h'}
_RE_COMMENTLINE = re.compile(r'^\s*//')
-def ParseNolintSuppressions(filename, raw_line, linenum, error):
+def ParseNolintSuppressions(raw_line, linenum):
"""Updates the global list of error-suppressions.
Parses any NOLINT comments on the current line, updating the global
@@ -273,10 +269,8 @@ def ParseNolintSuppressions(filename, raw_line, linenum, error):
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(*).
matched = _RE_SUPPRESSION.search(raw_line)
@@ -463,6 +457,7 @@ class _CppLintState:
self.filters = _DEFAULT_FILTERS[:]
self.counting = 'total' # In what way are we counting errors?
self.errors_by_category = {} # string to int dict storing error counts
+ self.stdin_filename = ''
# output format:
# "emacs" - format that emacs can parse (default)
@@ -658,7 +653,8 @@ class FileInfo:
def FullName(self):
"""Make Windows paths like Unix."""
- return os.path.abspath(self._filename).replace('\\', '/')
+ abspath = str(os.path.abspath(self._filename))
+ return abspath.replace('\\', '/')
def RelativePath(self):
"""FullName with <prefix>/src/nvim/ chopped off."""
@@ -1100,6 +1096,7 @@ def ReverseCloseExpression(clean_lines, linenum, pos):
"""
line = clean_lines.elided[linenum]
endchar = line[pos]
+ startchar = None
if endchar not in ')}]>':
return (line, 0, -1)
if endchar == ')':
@@ -1209,8 +1206,7 @@ def CheckForHeaderGuard(filename, lines, error):
if ifndef != cppvar + '_':
error_level = 5
- ParseNolintSuppressions(filename, lines[ifndef_linenum], ifndef_linenum,
- error)
+ ParseNolintSuppressions(lines[ifndef_linenum], ifndef_linenum)
error(filename, ifndef_linenum, 'build/header_guard', error_level,
'#ifndef header guard has wrong style, please use: %s' % cppvar)
@@ -1225,8 +1221,7 @@ def CheckForHeaderGuard(filename, lines, error):
if endif != ('#endif // %s' % (cppvar + '_')):
error_level = 5
- ParseNolintSuppressions(filename, lines[endif_linenum], endif_linenum,
- error)
+ ParseNolintSuppressions(lines[endif_linenum], endif_linenum)
error(filename, endif_linenum, 'build/header_guard', error_level,
'#endif line should be "#endif // %s"' % cppvar)
@@ -1452,12 +1447,6 @@ def CheckOSFunctions(filename, clean_lines, linenum, error):
'...) instead of ' + function + '...).')
-# Matches invalid increment: *count++, which moves pointer instead of
-# incrementing a value.
-_RE_PATTERN_INVALID_INCREMENT = re.compile(
- r'^\s*\*\w+(\+\+|--);')
-
-
class _BlockInfo:
"""Stores information about a generic block of code."""
@@ -1564,14 +1553,12 @@ class _NestingState:
# TODO(unknown): unexpected #endif, issue warning?
pass
- def Update(self, filename, clean_lines, linenum, error):
+ def Update(self, clean_lines, linenum):
"""Update nesting state with current line.
Args:
- filename: The name of the current file.
clean_lines: A CleansedLines instance containing the file.
linenum: The number of the line to check.
- error: The function to call with any errors found.
"""
line = clean_lines.elided[linenum]
@@ -1637,8 +1624,7 @@ class _NestingState:
line = matched.group(2)
-def CheckForNonStandardConstructs(filename, clean_lines, linenum,
- nesting_state, error):
+def CheckForNonStandardConstructs(filename, clean_lines, linenum, error):
r"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
Complain about several constructs which gcc-2 accepts, but which are
@@ -1660,8 +1646,6 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum,
filename: The name of the current file.
clean_lines: A CleansedLines instance containing the file.
linenum: The number of the line to check.
- nesting_state: A _NestingState instance which maintains information about
- the current stack of nested blocks being parsed.
error: A callable to which errors are reported, which takes 4 arguments:
filename, line number, error level, and message
"""
@@ -2120,7 +2104,7 @@ def CheckExpressionAlignment(filename, clean_lines, linenum, error, startpos=0):
del level_starts[depth]
-def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
+def CheckSpacing(filename, clean_lines, linenum, error):
"""Checks for the correctness of various spacing issues in the code.
Things we check for: spaces around operators, spaces after
@@ -2134,8 +2118,6 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
filename: The name of the current file.
clean_lines: A CleansedLines instance containing the file.
linenum: The number of the line to check.
- nesting_state: A _NestingState instance which maintains information about
- the current stack of nested blocks being parsed.
error: The function to call with any errors found.
"""
@@ -2378,29 +2360,6 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
'Should have zero or one spaces inside ( and ) in %s' %
match.group(1))
- # You should always have a space after a comma (either as fn arg or
- # operator).
- #
- # This does not apply when the non-space character following the
- # comma is another comma, since the only time when that happens is
- # for empty macro arguments.
- #
- # We run this check in two passes: first pass on elided lines to
- # verify that lines contain missing whitespaces, second pass on raw
- # lines to confirm that those missing whitespaces are not due to
- # elided comments.
- if Search(r',[^,\s]', line) and Search(r',[^,\s]', raw[linenum]):
- error(filename, linenum, 'whitespace/comma', 3,
- 'Missing space after ,')
-
- # You should always have a space after a semicolon
- # except for few corner cases
- # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more
- # space after ;
- if Search(r';[^\s};\\)/]', line):
- error(filename, linenum, 'whitespace/semicolon', 3,
- 'Missing space after ;')
-
# Next we will look for issues with function calls.
CheckSpacingForFunctionCall(filename, line, linenum, error)
@@ -2463,19 +2422,6 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
error(filename, linenum, 'whitespace/braces', 5,
'Extra space before [')
- # You shouldn't have a space before a semicolon at the end of the line.
- if Search(r':\s*;\s*$', line):
- error(filename, linenum, 'whitespace/semicolon', 5,
- 'Semicolon defining empty statement. Use {} instead.')
- elif Search(r'^\s*;\s*$', line):
- error(filename, linenum, 'whitespace/semicolon', 5,
- 'Line contains only semicolon. If this should be an empty'
- ' statement, use {} instead.')
- elif Search(r'\s+;\s*$', line):
- error(filename, linenum, 'whitespace/semicolon', 5,
- 'Extra space before last semicolon. If this should be an empty '
- 'statement, use {} instead.')
-
if Search(r'\{(?!\})\S', line):
error(filename, linenum, 'whitespace/braces', 5,
'Missing space after {')
@@ -2830,8 +2776,7 @@ def GetLineWidth(line):
return len(line)
-def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
- error):
+def CheckStyle(filename, clean_lines, linenum, error):
"""Checks rules from the 'C++ style rules' section of cppguide.html.
Most of these rules are hard to test (naming, comment style), but we
@@ -2842,9 +2787,6 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
filename: The name of the current file.
clean_lines: A CleansedLines instance containing the file.
linenum: The number of the line to check.
- file_extension: The extension (without the dot) of the filename.
- nesting_state: A _NestingState instance which maintains information about
- the current stack of nested blocks being parsed.
error: The function to call with any errors found.
"""
@@ -2886,35 +2828,6 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
'Weird number of spaces at line-start. '
'Are you using a 2-space indent?')
- # Check if the line is a header guard.
- is_header_guard = False
- if file_extension == 'h':
- cppvar = GetHeaderGuardCPPVariable(filename)
- if (line.startswith('#ifndef %s' % cppvar) or
- line.startswith('#define %s' % cppvar) or
- line.startswith('#endif // %s' % cppvar)):
- is_header_guard = True
- # #include lines and header guards can be long, since there's no clean way
- # to split them.
- #
- # URLs can be long too. It's possible to split these, but it makes them
- # harder to cut&paste.
- #
- # The "$Id:...$" comment may also get very long without it being the
- # developers fault.
- if (not line.startswith('#include') and not is_header_guard and
- not Match(r'^\s*//.*http(s?)://\S*$', line) and
- not Match(r'^// \$Id:.*#[0-9]+ \$$', line)):
- line_width = GetLineWidth(line)
- extended_length = int(_line_length * 1.25)
- if line_width > extended_length:
- error(filename, linenum, 'whitespace/line_length', 4,
- 'Lines should very rarely be longer than %i characters' %
- extended_length)
- elif line_width > _line_length:
- error(filename, linenum, 'whitespace/line_length', 2,
- 'Lines should be <= %i characters long' % _line_length)
-
if (cleansed_line.count(';') > 1 and
# for loops are allowed two ;'s (and may run over two lines).
cleansed_line.find('for') == -1 and
@@ -2930,33 +2843,10 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
# Some more style checks
CheckBraces(filename, clean_lines, linenum, error)
CheckEmptyBlockBody(filename, clean_lines, linenum, error)
- CheckSpacing(filename, clean_lines, linenum, nesting_state, error)
+ CheckSpacing(filename, clean_lines, linenum, error)
-_RE_PATTERN_INCLUDE_NEW_STYLE = re.compile(r'#include +"[^/]+\.h"')
_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$')
-# Matches the first component of a filename delimited by -s and _s. That is:
-# _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo'
-# _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo'
-# _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo'
-# _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo'
-_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+')
-
-
-def _ClassifyInclude(fileinfo, include, is_system):
- """Figures out what kind of header 'include' is.
-
- Args:
- fileinfo: The current file cpplint is running over. A FileInfo instance.
- include: The path to a #included file.
- is_system: True if the #include used <> rather than "".
-
- Returns:
- One of the _XXX_HEADER constants.
- """
- if is_system:
- return _C_SYS_HEADER
- return _OTHER_HEADER
def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
@@ -2974,16 +2864,9 @@ def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
inserted.
error : The function to call with any errors found.
"""
- fileinfo = FileInfo(filename)
line = clean_lines.lines[linenum]
- # "include" should use the new style "foo/bar.h" instead of just "bar.h"
- # XXX: neovim doesn't currently use this style
- # if _RE_PATTERN_INCLUDE_NEW_STYLE.search(line):
- # error(filename, linenum, 'build/include', 4,
- # 'Include the directory when naming .h files')
-
# we shouldn't include a file more than once. actually, there are a
# handful of instances where doing so is okay, but in general it's
# not.
@@ -2996,29 +2879,6 @@ def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
error(filename, linenum, 'build/include', 4,
'"%s" already included at %s:%s' %
(include, filename, include_state[include]))
- else:
- include_state[include] = linenum
-
- # We want to ensure that headers appear in the right order:
- # 1) for foo.cc, foo.h (preferred location)
- # 2) c system files
- # 3) cpp system files
- # 4) for foo.cc, foo.h (deprecated location)
- # 5) other google headers
- #
- # We classify each include statement as one of those 5 types
- # using a number of techniques. The include_state object keeps
- # track of the highest type seen, and complains if we see a
- # lower type after that.
- error_message = include_state.CheckNextIncludeOrder(
- _ClassifyInclude(fileinfo, include, is_system))
- if error_message:
- error(filename, linenum, 'build/include_order', 4,
- '%s. Should be: c system, c++ system, other.'
- % error_message)
- canonical_include = include_state.CanonicalizeAlphabeticalOrder(
- include)
- include_state.SetLastHeader(canonical_include)
def _GetTextInside(text, start_pattern):
@@ -3078,8 +2938,7 @@ def _GetTextInside(text, start_pattern):
return text[start_position:position - 1]
-def CheckLanguage(filename, clean_lines, linenum, file_extension,
- include_state, nesting_state, error):
+def CheckLanguage(filename, clean_lines, linenum, include_state, error):
"""Checks rules from the 'C++ language rules' section of cppguide.html.
Some of these rules are hard to test (function overloading, using
@@ -3089,11 +2948,8 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
filename : The name of the current file.
clean_lines : A CleansedLines instance containing the file.
linenum : The number of the line to check.
- file_extension : The extension (without the dot) of the filename.
include_state : An _IncludeState instance in which the headers are
inserted.
- nesting_state : A _NestingState instance which maintains information
- about the current stack of nested blocks being parsed.
error : The function to call with any errors found.
"""
# If the line is empty or consists of entirely a comment, no need to
@@ -3173,8 +3029,9 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
if printf_args:
match = Match(r'([\w.\->()]+)$', printf_args)
if match and match.group(1) != '__VA_ARGS__':
- function_name = re.search(r'\b((?:string)?printf)\s*\(',
- line, re.I).group(1)
+ function_name_groups = re.search(r'\b((?:string)?printf)\s*\(', line, re.I)
+ assert function_name_groups
+ function_name = function_name_groups.group(1)
error(filename, linenum, 'runtime/printf', 4,
'Potential format string bug. Do %s("%%s", %s) instead.'
% (function_name, match.group(1)))
@@ -3267,14 +3124,13 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
'for(;; action)')
-def ProcessLine(filename, file_extension, clean_lines, line,
+def ProcessLine(filename, clean_lines, line,
include_state, function_state, nesting_state, error,
extra_check_functions=[]):
"""Processes a single line in the file.
Args:
filename : Filename of the file that is being processed.
- file_extension : The extension (dot not included) of the file.
clean_lines : An array of strings, each representing a line of
the file, with comments stripped.
line : Number of line being processed.
@@ -3294,19 +3150,16 @@ def ProcessLine(filename, file_extension, clean_lines, line,
"""
raw_lines = clean_lines.raw_lines
init_lines = clean_lines.init_lines
- ParseNolintSuppressions(filename, raw_lines[line], line, error)
- nesting_state.Update(filename, clean_lines, line, error)
+ ParseNolintSuppressions(raw_lines[line], line)
+ nesting_state.Update(clean_lines, line)
if nesting_state.stack and nesting_state.stack[-1].inline_asm != _NO_ASM:
return
CheckForFunctionLengths(filename, clean_lines, line, function_state, error)
CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
CheckForOldStyleComments(filename, init_lines[line], line, error)
- CheckStyle(
- filename, clean_lines, line, file_extension, nesting_state, error)
- CheckLanguage(filename, clean_lines, line, file_extension, include_state,
- nesting_state, error)
- CheckForNonStandardConstructs(filename, clean_lines, line,
- nesting_state, error)
+ CheckStyle(filename, clean_lines, line, error)
+ CheckLanguage(filename, clean_lines, line, include_state, error)
+ CheckForNonStandardConstructs(filename, clean_lines, line, error)
CheckPosixThreading(filename, clean_lines, line, error)
CheckMemoryFunctions(filename, clean_lines, line, error)
CheckOSFunctions(filename, clean_lines, line, error)
@@ -3349,6 +3202,7 @@ def ProcessFileData(filename, file_extension, lines, error,
if not IsErrorSuppressedByNolint(category, linenum):
key = init_lines[linenum - 1 if linenum else 0:linenum + 2]
err = [filename, key, category]
+ assert _cpplint_state.record_errors_file
json.dump(err, _cpplint_state.record_errors_file)
_cpplint_state.record_errors_file.write('\n')
Error(filename, linenum, category, confidence, message)
@@ -3361,7 +3215,7 @@ def ProcessFileData(filename, file_extension, lines, error,
RemoveMultiLineComments(filename, lines, error)
clean_lines = CleansedLines(lines, init_lines)
for line in range(clean_lines.NumLines()):
- ProcessLine(filename, file_extension, clean_lines, line,
+ ProcessLine(filename, clean_lines, line,
include_state, function_state, nesting_state, error,
extra_check_functions)
@@ -3401,8 +3255,6 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]):
if filename == '-':
stdin = sys.stdin.read()
- if sys.version_info < (3, 0):
- stdin = stdin.decode('utf8')
lines = stdin.split('\n')
if _cpplint_state.stdin_filename is not None:
filename = _cpplint_state.stdin_filename
@@ -3498,7 +3350,7 @@ def ParseArguments(args):
counting_style = ''
record_errors_file = None
suppress_errors_file = None
- stdin_filename = None
+ stdin_filename = ''
for (opt, val) in opts:
if opt == '--help':