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