aboutsummaryrefslogtreecommitdiff
path: root/src/clint.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/clint.py')
-rwxr-xr-xsrc/clint.py313
1 files changed, 5 insertions, 308 deletions
diff --git a/src/clint.py b/src/clint.py
index b0992fcd63..944946bd16 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -49,7 +49,6 @@ import re
import sre_compile
import string
import sys
-import unicodedata
import json
import collections # for defaultdict
@@ -173,12 +172,9 @@ _ERROR_CATEGORIES = [
'build/deprecated',
'build/endif_comment',
'build/header_guard',
- 'build/include',
'build/include_alpha',
'build/printf_format',
'build/storage_class',
- 'build/useless_fattr',
- 'readability/alt_tokens',
'readability/bool',
'readability/braces',
'readability/multiline_comment',
@@ -189,7 +185,6 @@ _ERROR_CATEGORIES = [
'readability/increment',
'runtime/arrays',
'runtime/int',
- 'runtime/invalid_increment',
'runtime/memset',
'runtime/printf',
'runtime/printf_format',
@@ -197,20 +192,13 @@ _ERROR_CATEGORIES = [
'runtime/deprecated',
'syntax/parenthesis',
'whitespace/alignment',
- 'whitespace/blank_line',
'whitespace/braces',
'whitespace/comments',
- 'whitespace/empty_conditional_body',
- 'whitespace/empty_loop_body',
- 'whitespace/end_of_line',
- 'whitespace/ending_newline',
'whitespace/indent',
'whitespace/newline',
'whitespace/operators',
'whitespace/parens',
- 'whitespace/tab',
'whitespace/todo',
- 'whitespace/line_continuation',
'whitespace/cast',
]
@@ -220,11 +208,6 @@ _ERROR_CATEGORIES = [
# All entries here should start with a '-' or '+', as in the --filter= flag.
_DEFAULT_FILTERS = ['-build/include_alpha']
-# These constants define types of headers for use with
-# _IncludeState.CheckNextIncludeOrder().
-_C_SYS_HEADER = 1
-_OTHER_HEADER = 5
-
# These constants define the current inline assembly state
_NO_ASM = 0 # Outside of inline assembly block
_INSIDE_ASM = 1 # Inside inline assembly block
@@ -356,96 +339,6 @@ def Search(pattern, s):
return _regexp_compile_cache[pattern].search(s)
-class _IncludeState(dict): # lgtm [py/missing-equals]
-
- """Tracks line numbers for includes, and the order in which includes appear.
-
- As a dict, an _IncludeState object serves as a mapping between include
- filename and line number on which that file was included.
-
- Call CheckNextIncludeOrder() once for each header in the file, passing
- in the type constants defined above.
-
- """
- # self._section will move monotonically through this set. If it ever
- # needs to move backwards, CheckNextIncludeOrder will raise an error.
- _INITIAL_SECTION = 0
- _C_SECTION = 2
- _OTHER_H_SECTION = 4
-
- _TYPE_NAMES = {
- _C_SYS_HEADER: 'C system header',
- _OTHER_HEADER: 'other header',
- }
- _SECTION_NAMES = {
- _INITIAL_SECTION: "... nothing. (This can't be an error.)",
- _C_SECTION: 'C system header',
- _OTHER_H_SECTION: 'other header',
- }
-
- def __init__(self):
- dict.__init__(self)
- self.ResetSection()
-
- def ResetSection(self):
- # The name of the current section.
- self._section = self._INITIAL_SECTION
- # The path of last found header.
- self._last_header = ''
-
- def SetLastHeader(self, header_path):
- self._last_header = header_path
-
- def CanonicalizeAlphabeticalOrder(self, header_path):
- """Returns a path canonicalized for alphabetical comparison.
-
- - replaces "-" with "_" so they both cmp the same.
- - lowercase everything, just in case.
-
- Args:
- header_path: Path to be canonicalized.
-
- Returns:
- Canonicalized path.
- """
- return header_path.replace('-', '_').lower()
-
- def CheckNextIncludeOrder(self, header_type):
- """Returns a non-empty error message if the next header is out of order.
-
- This function also updates the internal state to be ready to check
- the next include.
-
- Args:
- header_type: One of the _XXX_HEADER constants defined above.
-
- Returns:
- The empty string if the header is in the right order, or an
- error message describing what's wrong.
-
- """
- error_message = ('Found %s after %s' %
- (self._TYPE_NAMES[header_type],
- self._SECTION_NAMES[self._section]))
-
- last_section = self._section
-
- if header_type == _C_SYS_HEADER:
- if self._section <= self._C_SECTION:
- self._section = self._C_SECTION
- else:
- self._last_header = ''
- return error_message
- else:
- assert header_type == _OTHER_HEADER
- self._section = self._OTHER_H_SECTION
-
- if last_section != self._section:
- self._last_header = ''
-
- return ''
-
-
class _CppLintState:
"""Maintains module-wide state.."""
@@ -932,7 +825,6 @@ BRACES = {
'(': ')',
'{': '}',
'[': ']',
- # '<': '>', C++-specific pair removed
}
@@ -1253,24 +1145,6 @@ def CheckForBadCharacters(filename, lines, error):
5, 'Line contains NUL byte.')
-def CheckForNewlineAtEOF(filename, lines, error):
- """Logs an error if there is no newline char at the end of the file.
-
- Args:
- filename: The name of the current file.
- lines: An array of strings, each representing a line of the file.
- error: The function to call with any errors found.
- """
-
- # The array lines() was created by adding two newlines to the
- # original file (go figure), then splitting on \n.
- # To verify that the file ends in \n, we just have to make sure the
- # last-but-two element of lines() exists and is empty.
- if len(lines) < 3 or lines[-2]:
- error(filename, len(lines) - 2, 'whitespace/ending_newline', 5,
- 'Could not find a newline character at the end of the file.')
-
-
def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error):
"""Logs an error if we see /* ... */ or "..." that extend past one line.
@@ -2156,7 +2030,6 @@ def CheckSpacing(filename, clean_lines, linenum, error):
# for the case where the previous line is indented 6 spaces, which
# may happen when the initializers of a constructor do not fit into
# a 80 column line.
- exception = False
if Match(r' {6}\w', prev_line): # Initializer list?
# We are looking for the opening column of initializer list,
# which should be indented 4 spaces to cause 6 space indentation
@@ -2165,39 +2038,6 @@ def CheckSpacing(filename, clean_lines, linenum, error):
while (search_position >= 0
and Match(r' {6}\w', elided[search_position])):
search_position -= 1
- exception = (search_position >= 0
- and elided[search_position][:5] == ' :')
- else:
- # Search for the function arguments or an initializer list. We
- # use a simple heuristic here: If the line is indented 4 spaces;
- # and we have a closing paren, without the opening paren,
- # followed by an opening brace or colon (for initializer lists)
- # we assume that it is the last line of a function header. If
- # we have a colon indented 4 spaces, it is an initializer list.
- exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',
- prev_line)
- or Match(r' {4}:', prev_line))
-
- if not exception:
- error(filename, linenum, 'whitespace/blank_line', 2,
- 'Redundant blank line at the start of a code block '
- 'should be deleted.')
- # Ignore blank lines at the end of a block in a long if-else
- # chain, like this:
- # if (condition1) {
- # // Something followed by a blank line
- #
- # } else if (condition2) {
- # // Something else
- # }
- if linenum + 1 < clean_lines.NumLines():
- next_line = raw[linenum + 1]
- if (next_line
- and Match(r'\s*}', next_line)
- and next_line.find('} else ') == -1):
- error(filename, linenum, 'whitespace/blank_line', 3,
- 'Redundant blank line at the end of a code block '
- 'should be deleted.')
# Next, we complain if there's a comment too near the text
commentpos = line.find('//')
@@ -2334,12 +2174,6 @@ def CheckSpacing(filename, clean_lines, linenum, error):
error(filename, linenum, 'whitespace/operators', 4,
'Extra space for operator %s' % match.group(1))
- # A pet peeve of mine: no spaces after an if, while, switch, or for
- match = Search(r' (if\(|for\(|while\(|switch\()', line)
- if match:
- error(filename, linenum, 'whitespace/parens', 5,
- 'Missing space before ( in %s' % match.group(1))
-
# For if/for/while/switch, the left and right parens should be
# consistent about how many spaces are inside the parens, and
# there should either be zero or one spaces inside the parens.
@@ -2407,9 +2241,6 @@ def CheckSpacing(filename, clean_lines, linenum, error):
for offset in range(endlinenum + 1,
min(endlinenum + 3, clean_lines.NumLines() - 1)):
trailing_text += clean_lines.elided[offset]
- if not Match(r'^[\s}]*[{.;,)<\]]', trailing_text):
- error(filename, linenum, 'whitespace/braces', 5,
- 'Missing space before {')
# Make sure '} else {' has spaces.
if Search(r'}else', line):
@@ -2429,18 +2260,6 @@ def CheckSpacing(filename, clean_lines, linenum, error):
error(filename, linenum, 'whitespace/braces', 5,
'Missing space before }')
- if Search(r'\S {2,}\\$', line):
- error(filename, linenum, 'whitespace/line_continuation', 5,
- 'Too many spaces before \\, line continuation character must be '
- 'preceded by exactly one space. For “blank lines” '
- 'it is preferred to use the same amount of spaces as preceding '
- 'indent')
-
- if Match(r'^ +#', line):
- error(filename, linenum, 'whitespace/indent', 5,
- 'Must not indent preprocessor directives, use 1-space indent '
- 'after the hash')
-
cast_line = re.sub(r'^# *define +\w+\([^)]*\)', '', line)
match = Search(r'(?<!\bkvec_t)'
r'(?<!\bkvec_withinit_t)'
@@ -2717,65 +2536,6 @@ def CheckBraces(filename, clean_lines, linenum, error):
"You don't need a ; after a }")
-def CheckEmptyBlockBody(filename, clean_lines, linenum, error):
- """Look for empty loop/conditional body with only a single semicolon.
-
- Args:
- filename: The name of the current file.
- clean_lines: A CleansedLines instance containing the file.
- linenum: The number of the line to check.
- error: The function to call with any errors found.
- """
-
- # Search for loop keywords at the beginning of the line. Because only
- # whitespaces are allowed before the keywords, this will also ignore most
- # do-while-loops, since those lines should start with closing brace.
- #
- # We also check "if" blocks here, since an empty conditional block
- # is likely an error.
- line = clean_lines.elided[linenum]
- matched = Match(r'\s*(for|while|if)\s*\(', line)
- if matched:
- # Find the end of the conditional expression
- (end_line, end_linenum, end_pos) = CloseExpression(
- clean_lines, linenum, line.find('('))
-
- # Output warning if what follows the condition expression is a
- # semicolon. No warning for all other cases, including whitespace or
- # newline, since we have a separate check for semicolons preceded by
- # whitespace.
- if end_pos >= 0 and Match(r';', end_line[end_pos:]):
- if matched.group(1) == 'if':
- error(filename, end_linenum,
- 'whitespace/empty_conditional_body', 5,
- 'Empty conditional bodies should use {}')
- else:
- error(filename, end_linenum, 'whitespace/empty_loop_body', 5,
- 'Empty loop bodies should use {} or continue')
-
-
-def GetLineWidth(line):
- """Determines the width of the line in column positions.
-
- Args:
- line: A string, which may be a Unicode string.
-
- Returns:
- The width of the line in column positions, accounting for Unicode
- combining characters and wide characters.
- """
- if isinstance(line, str):
- width = 0
- for uc in unicodedata.normalize('NFC', line):
- if unicodedata.east_asian_width(uc) in ('W', 'F'):
- width += 2
- elif not unicodedata.combining(uc):
- width += 1
- return width
- else:
- return len(line)
-
-
def CheckStyle(filename, clean_lines, linenum, error):
"""Checks rules from the 'C++ style rules' section of cppguide.html.
@@ -2796,10 +2556,6 @@ def CheckStyle(filename, clean_lines, linenum, error):
raw_lines = clean_lines.lines_without_raw_strings
line = raw_lines[linenum]
- if line.find('\t') != -1:
- error(filename, linenum, 'whitespace/tab', 1,
- 'Tab found; better to use spaces')
-
# One or three blank spaces at the beginning of the line is weird; it's
# hard to reconcile that with 2-space indents.
# NOTE: here are the conditions rob pike used for his tests. Mine aren't
@@ -2815,18 +2571,9 @@ def CheckStyle(filename, clean_lines, linenum, error):
# if(prevodd && match(prevprev, " +for \\(")) complain = 0;
initial_spaces = 0
cleansed_line = clean_lines.elided[linenum]
+
while initial_spaces < len(line) and line[initial_spaces] == ' ':
initial_spaces += 1
- if line and line[-1].isspace():
- error(filename, linenum, 'whitespace/end_of_line', 4,
- 'Line ends in whitespace. Consider deleting these extra spaces.')
- # There are certain situations we allow one space, notably for section
- # labels
- elif ((initial_spaces == 1 or initial_spaces == 3) and
- not Match(r'\s*\w+\s*:\s*$', cleansed_line)):
- error(filename, linenum, 'whitespace/indent', 3,
- 'Weird number of spaces at line-start. '
- 'Are you using a 2-space indent?')
if (cleansed_line.count(';') > 1 and
# for loops are allowed two ;'s (and may run over two lines).
@@ -2842,45 +2589,12 @@ def CheckStyle(filename, clean_lines, linenum, error):
# Some more style checks
CheckBraces(filename, clean_lines, linenum, error)
- CheckEmptyBlockBody(filename, clean_lines, linenum, error)
CheckSpacing(filename, clean_lines, linenum, error)
_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$')
-def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
- """Check rules that are applicable to #include lines.
-
- Strings on #include lines are NOT removed from elided line, to make
- certain tasks easier. However, to prevent false positives, checks
- applicable to #include lines in CheckLanguage must be put here.
-
- Args:
- filename : The name of the current file.
- clean_lines : A CleansedLines instance containing the file.
- linenum : The number of the line to check.
- include_state : An _IncludeState instance in which the headers are
- inserted.
- error : The function to call with any errors found.
- """
-
- line = clean_lines.lines[linenum]
-
- # we shouldn't include a file more than once. actually, there are a
- # handful of instances where doing so is okay, but in general it's
- # not.
- match = _RE_PATTERN_INCLUDE.search(line)
- if match:
- include = match.group(2)
- is_system = (match.group(1) == '<')
- if include in include_state:
- if is_system or not include.endswith('.c.h'):
- error(filename, linenum, 'build/include', 4,
- '"%s" already included at %s:%s' %
- (include, filename, include_state[include]))
-
-
def _GetTextInside(text, start_pattern):
r"""Retrieves all the text between matching open and close parentheses.
@@ -2938,7 +2652,7 @@ def _GetTextInside(text, start_pattern):
return text[start_position:position - 1]
-def CheckLanguage(filename, clean_lines, linenum, include_state, error):
+def CheckLanguage(filename, clean_lines, linenum, error):
"""Checks rules from the 'C++ language rules' section of cppguide.html.
Some of these rules are hard to test (function overloading, using
@@ -2948,8 +2662,6 @@ def CheckLanguage(filename, clean_lines, linenum, include_state, error):
filename : The name of the current file.
clean_lines : A CleansedLines instance containing the file.
linenum : The number of the line to check.
- include_state : An _IncludeState instance in which the headers are
- inserted.
error : The function to call with any errors found.
"""
# If the line is empty or consists of entirely a comment, no need to
@@ -2958,16 +2670,6 @@ def CheckLanguage(filename, clean_lines, linenum, include_state, error):
if not line:
return
- match = _RE_PATTERN_INCLUDE.search(line)
- if match:
- CheckIncludeLine(filename, clean_lines, linenum, include_state, error)
- return
-
- # Reset include state across preprocessor directives. This is meant
- # to silence warnings for conditional includes.
- if Match(r'^\s*#\s*(?:ifdef|elif|else|endif)\b', line):
- include_state.ResetSection()
-
# TODO(unknown): figure out if they're using default arguments in fn proto.
# Check if people are using the verboten C basic types.
@@ -3125,7 +2827,7 @@ def CheckLanguage(filename, clean_lines, linenum, include_state, error):
def ProcessLine(filename, clean_lines, line,
- include_state, function_state, nesting_state, error,
+ function_state, nesting_state, error,
extra_check_functions=[]):
"""Processes a single line in the file.
@@ -3134,8 +2836,6 @@ def ProcessLine(filename, clean_lines, line,
clean_lines : An array of strings, each representing a line of
the file, with comments stripped.
line : Number of line being processed.
- include_state : An _IncludeState instance in which the headers are
- inserted.
function_state : A _FunctionState instance which counts function
lines, etc.
nesting_state : A _NestingState instance which maintains
@@ -3158,7 +2858,7 @@ def ProcessLine(filename, clean_lines, line,
CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
CheckForOldStyleComments(filename, init_lines[line], line, error)
CheckStyle(filename, clean_lines, line, error)
- CheckLanguage(filename, clean_lines, line, include_state, error)
+ CheckLanguage(filename, clean_lines, line, error)
CheckForNonStandardConstructs(filename, clean_lines, line, error)
CheckPosixThreading(filename, clean_lines, line, error)
CheckMemoryFunctions(filename, clean_lines, line, error)
@@ -3185,7 +2885,6 @@ def ProcessFileData(filename, file_extension, lines, error,
lines = (['// marker so line numbers and indices both start at 1'] + lines +
['// marker so line numbers end in a known way'])
- include_state = _IncludeState()
function_state = _FunctionState()
nesting_state = _NestingState()
@@ -3216,15 +2915,13 @@ def ProcessFileData(filename, file_extension, lines, error,
clean_lines = CleansedLines(lines, init_lines)
for line in range(clean_lines.NumLines()):
ProcessLine(filename, clean_lines, line,
- include_state, function_state, nesting_state, error,
+ function_state, nesting_state, error,
extra_check_functions)
# We check here rather than inside ProcessLine so that we see raw
# lines rather than "cleaned" lines.
CheckForBadCharacters(filename, lines, error)
- CheckForNewlineAtEOF(filename, lines, error)
-
def ProcessFile(filename, vlevel, extra_check_functions=[]):
"""Does neovim-lint on a single file.