aboutsummaryrefslogtreecommitdiff
path: root/src/clint.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/clint.py')
-rwxr-xr-xsrc/clint.py167
1 files changed, 127 insertions, 40 deletions
diff --git a/src/clint.py b/src/clint.py
index efc5f18378..34af5d15fd 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -49,6 +49,7 @@ from __future__ import unicode_literals
import codecs
import copy
+import fileinput
import getopt
import math # for log
import os
@@ -65,7 +66,7 @@ _USAGE = """
Syntax: clint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
[--counting=total|toplevel|detailed] [--root=subdir]
[--linelength=digits] [--record-errors=file]
- [--suppress-errors=file]
+ [--suppress-errors=file] [--stdin-filename=filename]
<file> [file] ...
The style guidelines this tries to follow are those in
@@ -167,6 +168,9 @@ Syntax: clint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
suppress-errors=file
Errors listed in the given file will not be reported.
+
+ stdin-filename=filename
+ Use specified filename when reading from stdin (file "-").
"""
# We categorize each error message we print. Here are the categories.
@@ -182,6 +186,7 @@ _ERROR_CATEGORIES = [
'build/include_order',
'build/printf_format',
'build/storage_class',
+ 'build/useless_fattr',
'readability/alt_tokens',
'readability/bool',
'readability/braces',
@@ -200,6 +205,7 @@ _ERROR_CATEGORIES = [
'runtime/printf',
'runtime/printf_format',
'runtime/threadsafe_fn',
+ 'runtime/deprecated',
'syntax/parenthesis',
'whitespace/alignment',
'whitespace/blank_line',
@@ -569,9 +575,10 @@ class _CppLintState(object):
def PrintErrorCounts(self):
"""Print a summary of errors by category, and the total."""
for category, count in self.errors_by_category.items():
- sys.stderr.write('Category \'%s\' errors found: %d\n' %
+ sys.stdout.write('Category \'%s\' errors found: %d\n' %
(category, count))
- sys.stderr.write('Total errors found: %d\n' % self.error_count)
+ if self.error_count:
+ sys.stdout.write('Total errors found: %d\n' % self.error_count)
def SuppressErrorsFrom(self, fname):
"""Open file and read a list of suppressed errors from it"""
@@ -818,13 +825,13 @@ def Error(filename, linenum, category, confidence, message):
if _ShouldPrintError(category, confidence, linenum):
_cpplint_state.IncrementErrorCount(category)
if _cpplint_state.output_format == 'vs7':
- sys.stderr.write('%s(%s): %s [%s] [%d]\n' % (
+ sys.stdout.write('%s(%s): %s [%s] [%d]\n' % (
filename, linenum, message, category, confidence))
elif _cpplint_state.output_format == 'eclipse':
- sys.stderr.write('%s:%s: warning: %s [%s] [%d]\n' % (
+ sys.stdout.write('%s:%s: warning: %s [%s] [%d]\n' % (
filename, linenum, message, category, confidence))
else:
- sys.stderr.write('%s:%s: %s [%s] [%d]\n' % (
+ sys.stdout.write('%s:%s: %s [%s] [%d]\n' % (
filename, linenum, message, category, confidence))
@@ -1224,6 +1231,10 @@ def CheckForHeaderGuard(filename, lines, error):
lines: An array of strings, each representing a line of the file.
error: The function to call with any errors found.
"""
+ if filename.endswith('.c.h') or FileInfo(filename).RelativePath() in set((
+ 'func_attr.h',
+ )):
+ return
cppvar = GetHeaderGuardCPPVariable(filename)
@@ -2117,8 +2128,10 @@ def CheckExpressionAlignment(filename, clean_lines, linenum, error, startpos=0):
+ (level_starts[depth][2] == '{')):
if depth not in ignore_error_levels:
error(filename, linenum, 'whitespace/alignment', 2,
- 'Inner expression should be aligned '
- 'as opening brace + 1 (+ 2 in case of {)')
+ ('Inner expression should be aligned '
+ 'as opening brace + 1 (+ 2 in case of {{). '
+ 'Relevant opening is on line {0!r}').format(
+ level_starts[depth][3]))
prev_line_start = pos
elif brace == 'e':
pass
@@ -2135,7 +2148,8 @@ def CheckExpressionAlignment(filename, clean_lines, linenum, error, startpos=0):
ignore_error_levels.add(depth)
line_ended_with_opening = (
pos == len(line) - 2 * (line.endswith(' \\')) - 1)
- level_starts[depth] = (pos, line_ended_with_opening, brace)
+ level_starts[depth] = (pos, line_ended_with_opening, brace,
+ linenum)
if line_ended_with_opening:
depth_line_starts[depth] = (prev_line_start, brace)
else:
@@ -2268,11 +2282,14 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
# //!< Header comment
# or they begin with multiple slashes followed by a space:
# //////// Header comment
+ # or they are Vim {{{ fold markers
match = (Search(r'[=/-]{4,}\s*$', line[commentend:]) or
Search(r'^/$', line[commentend:]) or
Search(r'^!< ', line[commentend:]) or
Search(r'^/< ', line[commentend:]) or
- Search(r'^/+ ', line[commentend:]))
+ Search(r'^/+ ', line[commentend:]) or
+ Search(r'^(?:\{{3}|\}{3})\d*(?: |$)',
+ line[commentend:]))
if not match:
error(filename, linenum, 'whitespace/comments', 4,
'Should have a space between // and comment')
@@ -2516,6 +2533,13 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
cast_line = re.sub(r'^# *define +\w+\([^)]*\)', '', line)
match = Search(r'(?<!\bkvec_t)'
+ r'(?<!\bkvec_withinit_t)'
+ r'(?<!\bklist_t)'
+ r'(?<!\bkliter_t)'
+ r'(?<!\bkhash_t)'
+ r'(?<!\bkbtree_t)'
+ r'(?<!\bkbitr_t)'
+ r'(?<!\bPMap)'
r'\((?:const )?(?:struct )?[a-zA-Z_]\w*(?: *\*(?:const)?)*\)'
r' +'
r'-?(?:\*+|&)?(?:\w+|\+\+|--|\()', cast_line)
@@ -2560,22 +2584,51 @@ def CheckBraces(filename, clean_lines, linenum, error):
line = clean_lines.elided[linenum] # get rid of comments and strings
- if not (filename.endswith('.c') or filename.endswith('.h')):
- if Match(r'\s*{\s*$', line):
- # We allow an open brace to start a line in the case where someone
- # is using braces in a block to explicitly create a new scope, which
- # is commonly used to control the lifetime of stack-allocated
- # variables. Braces are also used for brace initializers inside
- # function calls. We don't detect this perfectly: we just don't
- # complain if the last non-whitespace character on the previous
- # non-blank line is ',', ';', ':', '(', '{', or '}', or if the
- # previous line starts a preprocessor block.
- prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
- if (not Search(r'[,;:}{(]\s*$', prevline) and
- not Match(r'\s*#', prevline)):
- error(filename, linenum, 'whitespace/braces', 4,
- '{ should almost always be at the end'
- ' of the previous line')
+ if Match(r'\s+{\s*$', line):
+ # We allow an open brace to start a line in the case where someone
+ # is using braces in a block to explicitly create a new scope, which
+ # is commonly used to control the lifetime of stack-allocated
+ # variables. Braces are also used for brace initializers inside
+ # function calls. We don't detect this perfectly: we just don't
+ # complain if the last non-whitespace character on the previous
+ # non-blank line is ',', ';', ':', '(', '{', or '}', or if the
+ # previous line starts a preprocessor block.
+ prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
+ if (not Search(r'[,;:}{(]\s*$', prevline) and
+ not Match(r'\s*#', prevline)):
+ error(filename, linenum, 'whitespace/braces', 4,
+ '{ should almost always be at the end'
+ ' of the previous line')
+
+ # Brace must appear after function signature, but on the *next* line
+ if Match(r'^(?:\w+(?: ?\*+)? )+\w+\(', line):
+ pos = line.find('(')
+ (endline, end_linenum, endpos) = CloseExpression(
+ clean_lines, linenum, pos)
+ if endline.endswith('{'):
+ error(filename, end_linenum, 'readability/braces', 5,
+ 'Brace starting function body must be placed on its own line')
+ else:
+ func_start_linenum = end_linenum + 1
+ while not clean_lines.lines[func_start_linenum] == '{':
+ attrline = Match(r'^((?!# *define).*?)(?:FUNC_ATTR|FUNC_API|REAL_FATTR)_\w+(?:\(\d+(, \d+)*\))?',
+ clean_lines.lines[func_start_linenum])
+ if attrline:
+ if len(attrline.group(1)) != 2:
+ error(filename, func_start_linenum,
+ 'whitespace/indent', 5,
+ 'Function attribute line should have 2-space '
+ 'indent')
+
+ func_start_linenum += 1
+ else:
+ func_start = clean_lines.lines[func_start_linenum]
+ if not func_start.startswith('enum ') and func_start.endswith('{'):
+ error(filename, func_start_linenum,
+ 'readability/braces', 5,
+ 'Brace starting function body must be placed '
+ 'after the function signature')
+ break
# An else clause should be on the same line as the preceding closing brace.
# If there is no preceding closing brace, there should be one.
@@ -3001,9 +3054,10 @@ def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
include = match.group(2)
is_system = (match.group(1) == '<')
if include in include_state:
- error(filename, linenum, 'build/include', 4,
- '"%s" already included at %s:%s' %
- (include, filename, include_state[include]))
+ 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]))
else:
include_state[include] = linenum
@@ -3140,11 +3194,28 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
# Check if some verboten C functions are being used.
if Search(r'\bsprintf\b', line):
error(filename, linenum, 'runtime/printf', 5,
- 'Never use sprintf. Use snprintf instead.')
- match = Search(r'\b(strcpy|strcat)\b', line)
+ 'Use snprintf instead of sprintf.')
+ match = Search(r'\b(strncpy|STRNCPY)\b', line)
+ if match:
+ error(filename, linenum, 'runtime/printf', 4,
+ 'Use xstrlcpy or snprintf instead of %s (unless this is from Vim)'
+ % match.group(1))
+ match = Search(r'\b(strcpy)\b', line)
+ if match:
+ error(filename, linenum, 'runtime/printf', 4,
+ 'Use xstrlcpy or snprintf instead of %s' % match.group(1))
+ match = Search(r'\b(STRNCAT|strncat|strcat|vim_strcat)\b', line)
if match:
error(filename, linenum, 'runtime/printf', 4,
- 'Almost always, snprintf is better than %s' % match.group(1))
+ 'Use xstrlcat or snprintf instead of %s' % match.group(1))
+ if not Search(r'eval/typval\.[ch]$', filename):
+ match = Search(r'(?:\.|->)'
+ r'(?:lv_(?:first|last|refcount|len|watch|idx(?:_item)?'
+ r'|copylist|lock)'
+ r'|li_(?:next|prev|tv))\b', line)
+ if match:
+ error(filename, linenum, 'runtime/deprecated', 4,
+ 'Accessing list_T internals directly is prohibited')
# Check for suspicious usage of "if" like
# } if (a == b) {
@@ -3232,6 +3303,13 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
error(filename, linenum, 'readability/bool', 4,
'Use %s instead of %s.' % (token.lower(), token))
+ # Detect MAYBE
+ match = Search(r'\b(MAYBE)\b', line)
+ if match:
+ token = match.group(1)
+ error(filename, linenum, 'readability/bool', 4,
+ 'Use kNONE from TriState instead of %s.' % token)
+
# Detect preincrement/predecrement
match = Match(r'^\s*(?:\+\+|--)', line)
if match:
@@ -3382,10 +3460,12 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]):
# is processed.
if filename == '-':
- lines = codecs.StreamReaderWriter(sys.stdin,
- codecs.getreader('utf8'),
- codecs.getwriter('utf8'),
- 'replace').read().split('\n')
+ 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
else:
lines = codecs.open(
filename, 'r', 'utf8', 'replace').read().split('\n')
@@ -3408,8 +3488,9 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]):
# When reading from stdin, the extension is unknown, so no cpplint tests
# should rely on the extension.
if filename != '-' and file_extension not in _valid_extensions:
- sys.stderr.write('Ignoring %s; not a valid file name '
- '(%s)\n' % (filename, ', '.join(_valid_extensions)))
+ sys.stderr.write('Ignoring {}; only linting {} files\n'.format(
+ filename,
+ ', '.join('.{}'.format(ext) for ext in _valid_extensions)))
else:
ProcessFileData(filename, file_extension, lines, Error,
extra_check_functions)
@@ -3465,7 +3546,9 @@ def ParseArguments(args):
'linelength=',
'extensions=',
'record-errors=',
- 'suppress-errors='])
+ 'suppress-errors=',
+ 'stdin-filename=',
+ ])
except getopt.GetoptError:
PrintUsage('Invalid arguments.')
@@ -3475,6 +3558,7 @@ def ParseArguments(args):
counting_style = ''
record_errors_file = None
suppress_errors_file = None
+ stdin_filename = None
for (opt, val) in opts:
if opt == '--help':
@@ -3511,6 +3595,8 @@ def ParseArguments(args):
record_errors_file = val
elif opt == '--suppress-errors':
suppress_errors_file = val
+ elif opt == '--stdin-filename':
+ stdin_filename = val
if not filenames:
PrintUsage('No files were specified.')
@@ -3521,6 +3607,7 @@ def ParseArguments(args):
_SetCountingStyle(counting_style)
_SuppressErrorsFrom(suppress_errors_file)
_RecordErrorsTo(record_errors_file)
+ _cpplint_state.stdin_filename = stdin_filename
return filenames
@@ -3539,7 +3626,7 @@ def main():
if __name__ == '__main__':
main()
-# vim: ts=4 sts=4 sw=4
+# vim: ts=4 sts=4 sw=4 foldmarker=▶,▲
# Ignore "too complex" warnings when using pymode.
# pylama:ignore=C901