Merge pull request #1957 from elmart/clint-pep8

Merge PR #1957 'Make clint.py pep8-compliant'
This commit is contained in:
Eliseo Martínez 2015-02-08 21:41:41 +01:00
commit 0854c21af3

346
clint.py
View File

@ -278,6 +278,7 @@ _line_length = 80
# This is set by --extensions flag.
_valid_extensions = set(['c', 'h'])
def ParseNolintSuppressions(filename, raw_line, linenum, error):
"""Updates the global list of error-suppressions.
@ -301,7 +302,8 @@ def ParseNolintSuppressions(filename, raw_line, linenum, error):
if category.startswith('(') and category.endswith(')'):
category = category[1:-1]
if category in _ERROR_CATEGORIES:
_error_suppressions.setdefault(category, set()).add(linenum)
_error_suppressions.setdefault(
category, set()).add(linenum)
else:
error(filename, linenum, 'readability/nolint', 5,
'Unknown NOLINT error category: %s' % category)
@ -327,6 +329,7 @@ def IsErrorSuppressedByNolint(category, linenum):
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
@ -345,6 +348,7 @@ def Search(pattern, s):
class _IncludeState(dict):
"""Tracks line numbers for includes, and the order in which includes appear.
As a dict, an _IncludeState object serves as a mapping between include
@ -434,6 +438,7 @@ class _IncludeState(dict):
class _CppLintState(object):
"""Maintains module-wide state.."""
def __init__(self):
@ -470,12 +475,14 @@ class _CppLintState(object):
error message.
Args:
filters: A string of comma-separated filters (eg "+whitespace/indent").
filters: A string of comma-separated filters.
E.g. "+whitespace/indent".
Each filter should start with + or -; else we die.
Raises:
ValueError: The comma-separated filters did not all start with '+' or '-'.
E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter"
ValueError: The comma-separated filters did not all start with
'+' or '-'.
E.g. "-,+whitespace,-whitespace/indent,whitespace/bad"
"""
# Default filters always have less priority than the flag ones.
self.filters = _DEFAULT_FILTERS[:]
@ -485,8 +492,8 @@ class _CppLintState(object):
self.filters.append(clean_filt)
for filt in self.filters:
if not (filt.startswith('+') or filt.startswith('-')):
raise ValueError('Every filter in --filters must start with + or -'
' (%s does not)' % filt)
raise ValueError('Every filter in --filters must start with '
'+ or - (%s does not)' % filt)
def ResetErrorCounts(self):
"""Sets the module's error statistic back to zero."""
@ -557,6 +564,7 @@ def _SetFilters(filters):
class _FunctionState(object):
"""Tracks current function name and the number of lines in its body."""
_NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc.
@ -597,7 +605,8 @@ class _FunctionState(object):
trigger = base_trigger * 2**_VerboseLevel()
if self.lines_in_function > trigger:
error_level = int(math.log(self.lines_in_function / base_trigger, 2))
error_level = int(
math.log(self.lines_in_function / base_trigger, 2))
# 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ...
if error_level > 5:
error_level = 5
@ -613,6 +622,7 @@ class _FunctionState(object):
class FileInfo:
"""Provides utility functions for filenames.
FileInfo provides easy access to the components of a file's path
@ -661,7 +671,7 @@ class FileInfo:
return (project,) + os.path.splitext(rest)
def BaseName(self):
"""File base name - text after the final slash, before the final period."""
"""File base name - text after the final slash, before final period."""
return self.Split()[1]
def Extension(self):
@ -670,7 +680,7 @@ class FileInfo:
def _ShouldPrintError(category, confidence, linenum):
"""If confidence >= verbose, category passes filter and is not suppressed."""
"""If confidence >= verbose, category passes filter and isn't suppressed."""
# There are three ways we might decide not to print an error message:
# a "NOLINT(category)" comment appears in the source,
@ -807,8 +817,8 @@ def RemoveMultiLineComments(filename, lines, error):
return
lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin)
if lineix_end >= len(lines):
error(filename, lineix_begin + 1, 'readability/multiline_comment', 5,
'Could not find end of multi-line comment')
error(filename, lineix_begin + 1, 'readability/multiline_comment',
5, 'Could not find end of multi-line comment')
return
RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1)
lineix = lineix_end + 1
@ -831,6 +841,7 @@ def CleanseComments(line):
class CleansedLines(object):
"""Holds 3 copies of all lines with different preprocessing applied to them.
1) elided member contains lines without strings and comments,
@ -848,7 +859,8 @@ class CleansedLines(object):
for linenum in range(len(self.lines_without_raw_strings)):
self.lines.append(CleanseComments(
self.lines_without_raw_strings[linenum]))
elided = self._CollapseStrings(self.lines_without_raw_strings[linenum])
elided = self._CollapseStrings(
self.lines_without_raw_strings[linenum])
self.elided.append(CleanseComments(elided))
def NumLines(self):
@ -868,9 +880,9 @@ class CleansedLines(object):
The line with collapsed strings.
"""
if not _RE_PATTERN_INCLUDE.match(elided):
# Remove escaped characters first to make quote/single quote collapsing
# basic. Things that look like escaped characters shouldn't occur
# outside of strings and chars.
# Remove escaped characters first to make quote/single quote
# collapsing basic. Things that look like escaped characters
# shouldn't occur outside of strings and chars.
elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided)
elided = _RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES.sub("''", elided)
elided = _RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES.sub('""', elided)
@ -923,10 +935,14 @@ def CloseExpression(clean_lines, linenum, pos):
startchar = line[pos]
if startchar not in '({[<':
return (line, clean_lines.NumLines(), -1)
if startchar == '(': endchar = ')'
if startchar == '[': endchar = ']'
if startchar == '{': endchar = '}'
if startchar == '<': endchar = '>'
if startchar == '(':
endchar = ')'
if startchar == '[':
endchar = ']'
if startchar == '{':
endchar = '}'
if startchar == '<':
endchar = '>'
# Check first line
(end_pos, num_open) = FindEndOfExpressionInLine(
@ -995,10 +1011,14 @@ def ReverseCloseExpression(clean_lines, linenum, pos):
endchar = line[pos]
if endchar not in ')}]>':
return (line, 0, -1)
if endchar == ')': startchar = '('
if endchar == ']': startchar = '['
if endchar == '}': startchar = '{'
if endchar == '>': startchar = '<'
if endchar == ')':
startchar = '('
if endchar == ']':
startchar = '['
if endchar == '}':
startchar = '{'
if endchar == '>':
startchar = '<'
# Check last line
(start_pos, num_open) = FindStartOfExpressionInLine(
@ -1101,8 +1121,8 @@ def CheckForHeaderGuard(filename, lines, error):
if define != ifndef:
error(filename, 0, 'build/header_guard', 5,
'#ifndef and #define don\'t match, suggested CPP variable is: %s' %
cppvar)
'#ifndef and #define don\'t match, suggested CPP variable is: %s'
% cppvar)
return
if endif != ('#endif // %s' % cppvar):
@ -1136,9 +1156,11 @@ def CheckForBadCharacters(filename, lines, error):
for linenum, line in enumerate(lines):
if u'\ufffd' in line:
error(filename, linenum, 'readability/utf8', 5,
'Line contains invalid UTF-8 (or Unicode replacement character).')
'Line contains invalid UTF-8'
' (or Unicode replacement character).')
if '\0' in line:
error(filename, linenum, 'readability/nul', 5, 'Line contains NUL byte.')
error(filename, linenum, 'readability/nul',
5, 'Line contains NUL byte.')
def CheckForNewlineAtEOF(filename, lines, error):
@ -1241,7 +1263,8 @@ def CheckPosixThreading(filename, clean_lines, linenum, error):
line = clean_lines.elided[linenum]
for single_thread_function, multithread_safe_function in threading_list:
ix = line.find(single_thread_function)
# Comparisons made explicit for clarity -- pylint: disable=g-explicit-bool-comparison
# Comparisons made explicit for clarity -- pylint:
# disable=g-explicit-bool-comparison
if ix >= 0 and (ix == 0 or (not line[ix - 1].isalnum() and
line[ix - 1] not in ('_', '.', '>'))):
error(filename, linenum, 'runtime/threadsafe_fn', 2,
@ -1258,6 +1281,7 @@ _RE_PATTERN_INVALID_INCREMENT = re.compile(
class _BlockInfo(object):
"""Stores information about a generic block of code."""
def __init__(self, seen_open_brace):
@ -1267,6 +1291,7 @@ class _BlockInfo(object):
class _PreprocessorInfo(object):
"""Stores checkpoints of nesting stacks when #if/#else is seen."""
def __init__(self, stack_before_if):
@ -1281,6 +1306,7 @@ class _PreprocessorInfo(object):
class _NestingState(object):
"""Holds states related to parsing braces."""
def __init__(self):
@ -1325,7 +1351,8 @@ class _NestingState(object):
"""
if Match(r'^\s*#\s*(if|ifdef|ifndef)\b', line):
# Beginning of #if block, save the nesting stack here. The saved
# stack will allow us to restore the parsing state in the #else case.
# stack will allow us to restore the parsing state in the #else
# case.
self.pp_stack.append(_PreprocessorInfo(copy.deepcopy(self.stack)))
elif Match(r'^\s*#\s*(else|elif)\b', line):
# Beginning of #else block
@ -1335,7 +1362,8 @@ class _NestingState(object):
# whole nesting stack up to this point. This is what we
# keep after the #endif.
self.pp_stack[-1].seen_else = True
self.pp_stack[-1].stack_before_else = copy.deepcopy(self.stack)
self.pp_stack[-1].stack_before_else = copy.deepcopy(
self.stack)
# Restore the stack to how it was before the #if
self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if)
@ -1387,8 +1415,8 @@ class _NestingState(object):
# Enter assembly block
inner_block.inline_asm = _INSIDE_ASM
else:
# Not entering assembly block. If previous line was _END_ASM,
# we will now shift to _NO_ASM state.
# Not entering assembly block. If previous line was
# _END_ASM, we will now shift to _NO_ASM state.
inner_block.inline_asm = _NO_ASM
elif (inner_block.inline_asm == _INSIDE_ASM and
inner_block.open_parentheses == 0):
@ -1446,8 +1474,8 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum,
- invalid inner-style forward declaration.
- >? and <? operators, and their >?= and <?= cousins.
Additionally, check for constructor/destructor style violations and reference
members, as it is very convenient to do so while checking for
Additionally, check for constructor/destructor style violations and
reference members, as it is very convenient to do so while checking for
gcc-2 compliance.
Args:
@ -1501,7 +1529,8 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum,
if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?',
line):
error(filename, linenum, 'build/deprecated', 3,
'>? and <? (max and min) operators are non-standard and deprecated.')
'>? and <? (max and min) operators are'
' non-standard and deprecated.')
def CheckSpacingForFunctionCall(filename, line, linenum, error):
@ -1525,7 +1554,8 @@ def CheckSpacingForFunctionCall(filename, line, linenum, error):
r'\bswitch\s*\((.*)\)\s*{'):
match = Search(pattern, line)
if match:
fncall = match.group(1) # look inside the parens for function calls
# look inside the parens for function calls
fncall = match.group(1)
break
# Except in if/for/while/switch, there should never be space
@ -1547,7 +1577,8 @@ def CheckSpacingForFunctionCall(filename, line, linenum, error):
not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and
# Ignore pointers/references to arrays.
not Search(r' \([^)]+\)\[[^\]]+\]', fncall)):
if Search(r'\w\s*\(\s(?!\s*\\$)', fncall): # a ( used for a fn call
# a ( used for a fn call
if Search(r'\w\s*\(\s(?!\s*\\$)', fncall):
error(filename, linenum, 'whitespace/parens', 4,
'Extra space after ( in function call')
elif Search(r'\(\s+(?!(\s*\\)|\()', fncall):
@ -1629,7 +1660,8 @@ def CheckForFunctionLengths(filename, clean_lines, linenum,
for start_linenum in range(linenum, clean_lines.NumLines()):
start_line = lines[start_linenum]
joined_line += ' ' + start_line.lstrip()
if Search(r'(;|})', start_line): # Declarations and trivial functions
# Declarations and trivial functions
if Search(r'(;|})', start_line):
body_found = True
break # ... ignore
elif Search(r'{', start_line):
@ -1644,7 +1676,8 @@ def CheckForFunctionLengths(filename, clean_lines, linenum,
function_state.Begin(function)
break
if not body_found:
# No body for the function (or evidence of a non-function) was found.
# No body for the function (or evidence of a non-function) was
# found.
error(filename, linenum, 'readability/fn_size', 5,
'Lint failed to find start of function body.')
elif Match(r'^\}\s*$', line): # function end
@ -1687,7 +1720,8 @@ def CheckComment(comment, filename, linenum, error):
'"// TODO(my_username): Stuff."')
middle_whitespace = match.group(4)
# Comparisons made explicit for correctness -- pylint: disable=g-explicit-bool-comparison
# Comparisons made explicit for correctness -- pylint:
# disable=g-explicit-bool-comparison
if middle_whitespace != ' ' and middle_whitespace != '':
error(filename, linenum, 'whitespace/todo', 2,
'TODO(my_username): should be followed by a space')
@ -1731,10 +1765,10 @@ def FindNextMatchingAngleBracket(clean_lines, linenum, init_suffix):
# Found matching angle bracket
return True
elif operator == ',':
# Got a comma after a bracket, this is most likely a template
# argument. We have not seen a closing angle bracket yet, but
# it's probably a few lines later if we look for it, so just
# return early here.
# Got a comma after a bracket, this is most likely a
# template argument. We have not seen a closing angle
# bracket yet, but it's probably a few lines later if we
# look for it, so just return early here.
return True
else:
# Got some other operator.
@ -1746,7 +1780,8 @@ def FindNextMatchingAngleBracket(clean_lines, linenum, init_suffix):
nesting_stack.append(operator)
elif operator in (')', ']'):
# We don't bother checking for matching () or []. If we got
# something like (] or [), it would have been a syntax error.
# something like (] or [), it would have been a syntax
# error.
nesting_stack.pop()
else:
@ -1838,8 +1873,8 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
"""
# Don't use "elided" lines here, otherwise we can't check commented lines.
# Don't want to use "raw" either, because we don't want to check inside C++11
# raw strings,
# Don't want to use "raw" either, because we don't want to check inside
# C++11 raw strings,
raw = clean_lines.lines_without_raw_strings
line = raw[linenum]
@ -1859,22 +1894,24 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
elided = clean_lines.elided
prev_line = elided[linenum - 1]
prevbrace = prev_line.rfind('{')
# TODO(unknown): Don't complain if line before blank line, and line after,
# both start with alnums and are indented the same amount.
# This ignores whitespace at the start of a namespace block
# because those are not usually indented.
# TODO(unknown): Don't complain if line before blank line, and line
# after,both start with alnums and are indented the same
# amount. This ignores whitespace at the start of a
# namespace block because those are not usually indented.
if prevbrace != -1 and prev_line[prevbrace:].find('}') == -1:
# OK, we have a blank line at the start of a code block. Before we
# complain, we check if it is an exception to the rule: The previous
# non-empty line has the parameters of a function header that are indented
# 4 spaces (because they did not fit in a 80 column line when placed on
# the same line as the function name). We also check for the case where
# the previous line is indented 6 spaces, which may happen when the
# initializers of a constructor do not fit into a 80 column line.
# non-empty line has the parameters of a function header that are
# indented 4 spaces (because they did not fit in a 80 column line
# when placed on the same line as the function name). We also check
# for the case where the previous line is indented 6 spaces, which
# may happen when the initializers of a constructor do not fit into
# a 80 column line.
exception = False
if Match(r' {6}\w', prev_line): # Initializer list?
# We are looking for the opening column of initializer list, which
# should be indented 4 spaces to cause 6 space indentation afterwards.
# We are looking for the opening column of initializer list,
# which should be indented 4 spaces to cause 6 space indentation
# afterwards.
search_position = linenum - 2
while (search_position >= 0
and Match(r' {6}\w', elided[search_position])):
@ -1882,12 +1919,12 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
exception = (search_position >= 0
and elided[search_position][:5] == ' :')
else:
# Search for the function arguments or an initializer list. We use a
# simple heuristic here: If the line is indented 4 spaces; and we have a
# closing paren, without the opening paren, followed by an opening brace
# or colon (for initializer lists) we assume that it is the last line of
# a function header. If we have a colon indented 4 spaces, it is an
# initializer list.
# Search for the function arguments or an initializer list. We
# use a simple heuristic here: If the line is indented 4 spaces;
# and we have a closing paren, without the opening paren,
# followed by an opening brace or colon (for initializer lists)
# we assume that it is the last line of a function header. If
# we have a colon indented 4 spaces, it is an initializer list.
exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',
prev_line)
or Match(r' {4}:', prev_line))
@ -1917,7 +1954,8 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
commentpos = line.find('//')
if commentpos != -1:
# Check if the // may be in quotes. If so, ignore it
# Comparisons made explicit for clarity -- pylint: disable=g-explicit-bool-comparison
# Comparisons made explicit for clarity -- pylint:
# disable=g-explicit-bool-comparison
if (line.count('"', 0, commentpos) -
line.count('\\"', 0, commentpos)) % 2 == 0: # not in quotes
# Allow one space for new scopes, two spaces otherwise:
@ -1994,8 +2032,8 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
# technically should should flag if at least one side is missing a
# space. This is done to avoid some false positives with shifts.
match = Search(r'[^\s<]<([^\s=<].*)', reduced_line)
if (match and
not FindNextMatchingAngleBracket(clean_lines, linenum, match.group(1))):
if (match and not FindNextMatchingAngleBracket(clean_lines, linenum,
match.group(1))):
error(filename, linenum, 'whitespace/operators', 3,
'Missing spaces around <')
@ -2058,7 +2096,8 @@ 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)
# 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
@ -2146,8 +2185,8 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
'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.')
'Line contains only semicolon. If this should be an empty'
' statement, use {} instead.')
elif (Search(r'\s+;\s*$', line) and
not Search(r'\bfor\b', line)):
error(filename, linenum, 'whitespace/semicolon', 5,
@ -2192,18 +2231,20 @@ def CheckBraces(filename, clean_lines, linenum, error):
if not (filename.endswith('.c') or filename.endswith('.h')):
if Match(r'\s*{\s*$', line):
# We allow an open brace to start a line in the case where someone is using
# braces in a block to explicitly create a new scope, which is commonly used
# to control the lifetime of stack-allocated variables. Braces are also
# used for brace initializers inside function calls. We don't detect this
# perfectly: we just don't complain if the last non-whitespace character on
# the previous non-blank line is ',', ';', ':', '(', '{', or '}', or if the
# We allow an open brace to start a line in the case where someone
# is using braces in a block to explicitly create a new scope, which
# is commonly used to control the lifetime of stack-allocated
# variables. Braces are also used for brace initializers inside
# function calls. We don't detect this perfectly: we just don't
# complain if the last non-whitespace character on the previous
# non-blank line is ',', ';', ':', '(', '{', or '}', or if the
# previous line starts a preprocessor block.
prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
if (not Search(r'[,;:}{(]\s*$', prevline) and
not Match(r'\s*#', prevline)):
error(filename, linenum, 'whitespace/braces', 4,
'{ should almost always be at the end of the previous line')
'{ should almost always be at the end'
' of the previous line')
# An else clause should be on the same line as the preceding closing brace.
if Match(r'\s*else\s*', line):
@ -2220,13 +2261,17 @@ def CheckBraces(filename, clean_lines, linenum, error):
pos = line.find('else if')
pos = line.find('(', pos)
if pos > 0:
(endline, _, endpos) = CloseExpression(clean_lines, linenum, pos)
if endline[endpos:].find('{') == -1: # must be brace after if
(endline, _, endpos) = CloseExpression(
clean_lines, linenum, pos)
# must be brace after if
if endline[endpos:].find('{') == -1:
error(filename, linenum, 'readability/braces', 5,
'If an else has a brace on one side, it should have it on both')
'If an else has a brace on one side,'
' it should have it on both')
else: # common case: else not followed by a multi-line if
error(filename, linenum, 'readability/braces', 5,
'If an else has a brace on one side, it should have it on both')
'If an else has a brace on one side,'
' it should have it on both')
# Likewise, an else should never have the else clause on the same line
if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line):
@ -2326,7 +2371,8 @@ def CheckBraces(filename, clean_lines, linenum, error):
# Try matching cases 2-3.
match = Match(r'^(.*(?:else|\)\s*const)\s*)\{', line)
if not match:
# Try matching cases 4-6. These are always matched on separate lines.
# Try matching cases 4-6. These are always matched on separate
# lines.
#
# Note that we can't simply concatenate the previous line to the
# current line and do a single match, otherwise we may output
@ -2377,12 +2423,14 @@ def CheckEmptyBlockBody(filename, clean_lines, linenum, error):
(end_line, end_linenum, end_pos) = CloseExpression(
clean_lines, linenum, line.find('('))
# Output warning if what follows the condition expression is a semicolon.
# No warning for all other cases, including whitespace or newline, since we
# have a separate check for semicolons preceded by whitespace.
# Output warning if what follows the condition expression is a
# semicolon. No warning for all other cases, including whitespace or
# newline, since we have a separate check for semicolons preceded by
# whitespace.
if end_pos >= 0 and Match(r';', end_line[end_pos:]):
if matched.group(1) == 'if':
error(filename, end_linenum, 'whitespace/empty_conditional_body', 5,
error(filename, end_linenum,
'whitespace/empty_conditional_body', 5,
'Empty conditional bodies should use {}')
else:
error(filename, end_linenum, 'whitespace/empty_loop_body', 5,
@ -2462,8 +2510,8 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
"""
# Don't use "elided" lines here, otherwise we can't check commented lines.
# Don't want to use "raw" either, because we don't want to check inside C++11
# raw strings,
# Don't want to use "raw" either, because we don't want to check inside
# C++11 raw strings,
raw_lines = clean_lines.lines_without_raw_strings
line = raw_lines[linenum]
@ -2474,7 +2522,8 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
# One or three blank spaces at the beginning of the line is weird; it's
# hard to reconcile that with 2-space indents.
# NOTE: here are the conditions rob pike used for his tests. Mine aren't
# as sophisticated, but it may be worth becoming so: RLENGTH==initial_spaces
# as sophisticated, but it may be worth becoming so:
# RLENGTH==initial_spaces
# if(RLENGTH > 20) complain = 0;
# if(match($0, " +(error|private|public|protected):")) complain = 0;
# if(match(prev, "&& *$")) complain = 0;
@ -2490,7 +2539,8 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
if line and line[-1].isspace():
error(filename, linenum, 'whitespace/end_of_line', 4,
'Line ends in whitespace. Consider deleting these extra spaces.')
# There are certain situations we allow one space, notably for section labels
# There are certain situations we allow one space, notably for section
# labels
elif ((initial_spaces == 1 or initial_spaces == 3) and
not Match(r'\s*\w+\s*:\s*$', cleansed_line)):
error(filename, linenum, 'whitespace/indent', 3,
@ -2505,8 +2555,8 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
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.
# #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.
@ -2571,7 +2621,6 @@ def _ClassifyInclude(fileinfo, include, is_system):
return _OTHER_HEADER
def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
"""Check rules that are applicable to #include lines.
@ -2583,7 +2632,8 @@ def CheckIncludeLine(filename, clean_lines, linenum, include_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.
include_state: An _IncludeState instance in which the headers are inserted.
include_state : An _IncludeState instance in which the headers are
inserted.
error : The function to call with any errors found.
"""
fileinfo = FileInfo(filename)
@ -2625,21 +2675,24 @@ def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
_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)
'%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):
r"""Retrieves all the text between matching open and close parentheses.
Given a string of lines and a regular expression string, retrieve all the text
following the expression and between opening punctuation symbols like
Given a string of lines and a regular expression string, retrieve all the
text following the expression and between opening punctuation symbols like
(, [, or {, and the matching close-punctuation symbol. This properly nested
occurrences of the punctuations, so for the text like
printf(a(), b(c()));
a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'.
start_pattern must match string having an open punctuation symbol at the end.
start_pattern must match string having an open punctuation symbol at the
end.
Args:
text: The lines to extract text. Its comments and strings must be elided.
@ -2648,7 +2701,7 @@ def _GetTextInside(text, start_pattern):
the text.
Returns:
The extracted text.
None if either the opening string or ending punctuation could not be found.
None if either the opening string or ending punctuation couldn't be found.
"""
# TODO(sugawarayu): Audit cpplint.py to see what places could be profitably
# rewritten to use _GetTextInside (and use inferior regexp matching today).
@ -2698,9 +2751,10 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
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.
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
@ -2725,7 +2779,8 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
match = Search(r'\b(short|long(?! +double)|long long)\b', line)
if match:
error(filename, linenum, 'runtime/int', 4,
'Use int16_t/int64_t/etc, rather than the C type %s' % match.group(1))
'Use int16_t/int64_t/etc, rather than the C type %s'
% match.group(1))
# When snprintf is used, the second argument shouldn't be a literal.
match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line)
@ -2789,20 +2844,29 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
skip_next = False
continue
if Search(r'sizeof\(.+\)', tok): continue
if Search(r'arraysize\(\w+\)', tok): continue
if Search(r'sizeof\(.+\)', tok):
continue
if Search(r'arraysize\(\w+\)', tok):
continue
tok = tok.lstrip('(')
tok = tok.rstrip(')')
if not tok: continue
if Match(r'\d+', tok): continue
if Match(r'0[xX][0-9a-fA-F]+', tok): continue
if Match(r'k[A-Z0-9]\w*', tok): continue
if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue
if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue
# A catch all for tricky sizeof cases, including 'sizeof expression',
# 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)'
# requires skipping the next token because we split on ' ' and '*'.
if not tok:
continue
if Match(r'\d+', tok):
continue
if Match(r'0[xX][0-9a-fA-F]+', tok):
continue
if Match(r'k[A-Z0-9]\w*', tok):
continue
if Match(r'(.+::)?k[A-Z0-9]\w*', tok):
continue
if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok):
continue
# A catch all for tricky sizeof cases, including
# 'sizeof expression', 'sizeof(*type)', 'sizeof(const type)',
# 'sizeof(struct StructName)' requires skipping the next token
# because we split on ' ' and '*'.
if tok.startswith('sizeof'):
skip_next = True
continue
@ -2810,8 +2874,9 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
break
if not is_const:
error(filename, linenum, 'runtime/arrays', 1,
'Do not use variable-length arrays. Use an appropriately named '
"('k' followed by CamelCase) compile-time constant for the size.")
"Do not use variable-length arrays. Use an appropriately"
" named ('k' followed by CamelCase) compile-time constant for"
" the size.")
# Detect TRUE and FALSE.
match = Search(r'\b(TRUE|FALSE)\b', line)
@ -2820,6 +2885,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
error(filename, linenum, 'readability/bool', 4,
'Use %s instead of %s.' % (token.lower(), token))
def ProcessLine(filename, file_extension, clean_lines, line,
include_state, function_state, nesting_state, error,
extra_check_functions=[]):
@ -2828,17 +2894,21 @@ def ProcessLine(filename, file_extension, clean_lines, line,
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.
clean_lines : An array of strings, each representing a line of
the file, with comments stripped.
line : Number of line being processed.
include_state: An _IncludeState instance in which the headers are inserted.
function_state: A _FunctionState instance which counts function lines, etc.
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
extra_check_functions: An array of additional check functions that will be
run on each source line. Each function takes 4
include_state : An _IncludeState instance in which the headers are
inserted.
function_state : A _FunctionState instance which counts function
lines, etc.
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
extra_check_functions : An array of additional check functions that will
be run on each source line. Each function takes 4
arguments : filename, clean_lines, line, error
"""
raw_lines = clean_lines.raw_lines
@ -2848,7 +2918,8 @@ def ProcessLine(filename, file_extension, clean_lines, line,
return
CheckForFunctionLengths(filename, clean_lines, line, function_state, error)
CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
CheckStyle(filename, clean_lines, line, file_extension, nesting_state, 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,
@ -2857,6 +2928,7 @@ def ProcessLine(filename, file_extension, clean_lines, line,
for check_fn in extra_check_functions:
check_fn(filename, clean_lines, line, error)
def ProcessFileData(filename, file_extension, lines, error,
extra_check_functions=[]):
"""Performs lint checks and reports any errors to the given error function.
@ -2897,6 +2969,7 @@ def ProcessFileData(filename, file_extension, lines, error,
CheckForNewlineAtEOF(filename, lines, error)
def ProcessFile(filename, vlevel, extra_check_functions=[]):
"""Does neovim-lint on a single file.
@ -2930,7 +3003,8 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]):
codecs.getwriter('utf8'),
'replace').read().split('\n')
else:
lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n')
lines = codecs.open(
filename, 'r', 'utf8', 'replace').read().split('\n')
carriage_return_found = False
# Remove trailing '\r'.
@ -2999,7 +3073,9 @@ def ParseArguments(args):
The list of filenames to lint.
"""
try:
(opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=',
(opts, filenames) = getopt.getopt(args, '', ['help',
'output=',
'verbose=',
'counting=',
'filter=',
'root=',
@ -3018,7 +3094,8 @@ def ParseArguments(args):
PrintUsage(None)
elif opt == '--output':
if val not in ('emacs', 'vs7', 'eclipse'):
PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.')
PrintUsage('The only allowed output formats are emacs,'
' vs7 and eclipse.')
output_format = val
elif opt == '--verbose':
verbosity = int(val)
@ -3028,7 +3105,8 @@ def ParseArguments(args):
PrintCategories()
elif opt == '--counting':
if val not in ('total', 'toplevel', 'detailed'):
PrintUsage('Valid counting options are total, toplevel, and detailed')
PrintUsage(
'Valid counting options are total, toplevel, and detailed')
counting_style = val
elif opt == '--linelength':
global _line_length
@ -3067,3 +3145,7 @@ def main():
if __name__ == '__main__':
main()
# Ignore "too complex" warnings when using pymode.
# pylama:ignore=C901