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