mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #1957 from elmart/clint-pep8
Merge PR #1957 'Make clint.py pep8-compliant'
This commit is contained in:
commit
0854c21af3
384
clint.py
384
clint.py
@ -204,7 +204,7 @@ _ERROR_CATEGORIES = [
|
|||||||
'whitespace/semicolon',
|
'whitespace/semicolon',
|
||||||
'whitespace/tab',
|
'whitespace/tab',
|
||||||
'whitespace/todo'
|
'whitespace/todo'
|
||||||
]
|
]
|
||||||
|
|
||||||
# The default state of the category filter. This is overrided by the --filter=
|
# The default state of the category filter. This is overrided by the --filter=
|
||||||
# flag. By default all errors are on, so only add here categories that should be
|
# flag. By default all errors are on, so only add here categories that should be
|
||||||
@ -233,7 +233,7 @@ _ALT_TOKEN_REPLACEMENT = {
|
|||||||
'xor_eq': '^=',
|
'xor_eq': '^=',
|
||||||
'not': '!',
|
'not': '!',
|
||||||
'not_eq': '!='
|
'not_eq': '!='
|
||||||
}
|
}
|
||||||
|
|
||||||
# Compile regular expression that matches all the above keywords. The "[ =()]"
|
# Compile regular expression that matches all the above keywords. The "[ =()]"
|
||||||
# bit is meant to avoid matching these keywords outside of boolean expressions.
|
# bit is meant to avoid matching these keywords outside of boolean expressions.
|
||||||
@ -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):
|
||||||
@ -1220,7 +1242,7 @@ threading_list = (
|
|||||||
('localtime_r(', 'os_localtime_r('),
|
('localtime_r(', 'os_localtime_r('),
|
||||||
('strtok_r(', 'os_strtok_r('),
|
('strtok_r(', 'os_strtok_r('),
|
||||||
('ttyname_r(', 'os_ttyname_r('),
|
('ttyname_r(', 'os_ttyname_r('),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def CheckPosixThreading(filename, clean_lines, linenum, error):
|
def CheckPosixThreading(filename, clean_lines, linenum, 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,35 +1894,37 @@ 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
|
||||||
search_position = linenum-2
|
# afterwards.
|
||||||
|
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])):
|
||||||
search_position -= 1
|
search_position -= 1
|
||||||
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,15 +1954,16 @@ 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:
|
||||||
if (not Match(r'^\s*{ //', line) and
|
if (not Match(r'^\s*{ //', line) and
|
||||||
((commentpos >= 1 and
|
((commentpos >= 1 and
|
||||||
line[commentpos-1] not in string.whitespace) or
|
line[commentpos - 1] not in string.whitespace) or
|
||||||
(commentpos >= 2 and
|
(commentpos >= 2 and
|
||||||
line[commentpos-2] not in string.whitespace))):
|
line[commentpos - 2] not in string.whitespace))):
|
||||||
error(filename, linenum, 'whitespace/comments', 2,
|
error(filename, linenum, 'whitespace/comments', 2,
|
||||||
'At least two spaces is best between code and comments')
|
'At least two spaces is best between code and comments')
|
||||||
# There should always be a space between the // and the comment
|
# There should always be a space between the // and the comment
|
||||||
@ -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.
|
||||||
|
|
||||||
@ -2580,11 +2629,12 @@ def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
|
|||||||
applicable to #include lines in CheckLanguage must be put here.
|
applicable to #include lines in CheckLanguage must be put here.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
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
|
||||||
error: The function to call with any errors found.
|
inserted.
|
||||||
|
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).
|
||||||
@ -2694,14 +2747,15 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
|
|||||||
uint32 inappropriately), but we do the best we can.
|
uint32 inappropriately), but we do the best we can.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
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.
|
||||||
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
|
||||||
error: The function to call with any errors found.
|
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
|
# If the line is empty or consists of entirely a comment, no need to
|
||||||
# check it.
|
# check it.
|
||||||
@ -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,26 +2885,31 @@ 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=[]):
|
||||||
"""Processes a single line in the file.
|
"""Processes a single line in the file.
|
||||||
|
|
||||||
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
|
||||||
arguments: filename, clean_lines, line, error
|
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
|
raw_lines = clean_lines.raw_lines
|
||||||
ParseNolintSuppressions(filename, raw_lines[line], line, error)
|
ParseNolintSuppressions(filename, raw_lines[line], line, error)
|
||||||
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user