summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Trott <rtrott@gmail.com>2020-10-09 04:33:19 -0700
committerMyles Borins <mylesborins@github.com>2020-10-14 16:21:24 -0400
commita19b320a3159d9eee1153d93e506be5f2a86363e (patch)
treec123eb3032c28752bd0dc6aec18db8805bbc5142
parent64ebbddb5f88fc238034edacde9696624348e4fb (diff)
downloadnode-new-a19b320a3159d9eee1153d93e506be5f2a86363e.tar.gz
tools: bump cpplint.py to 1.4.6
Refs: https://github.com/cpplint/cpplint/releases/tag/1.4.6 PR-URL: https://github.com/nodejs/node/pull/35569 Reviewed-By: Richard Lau <rlau@redhat.com> Reviewed-By: Daijiro Wachi <daijiro.wachi@gmail.com> Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
-rwxr-xr-xtools/cpplint.py265
1 files changed, 106 insertions, 159 deletions
diff --git a/tools/cpplint.py b/tools/cpplint.py
index 4ea91c0dc0..dd6095265d 100755
--- a/tools/cpplint.py
+++ b/tools/cpplint.py
@@ -59,7 +59,7 @@ import xml.etree.ElementTree
# if empty, use defaults
_valid_extensions = set([])
-__VERSION__ = '1.4.4'
+__VERSION__ = '1.4.6'
try:
xrange # Python 2
@@ -280,7 +280,6 @@ _ERROR_CATEGORIES = [
'build/include',
'build/include_subdir',
'build/include_alpha',
- 'build/include_inline',
'build/include_order',
'build/include_what_you_use',
'build/namespaces_literals',
@@ -295,13 +294,11 @@ _ERROR_CATEGORIES = [
'readability/constructors',
'readability/fn_size',
'readability/inheritance',
- 'readability/pointer_notation',
'readability/multiline_comment',
'readability/multiline_string',
'readability/namespace',
'readability/nolint',
'readability/nul',
- 'readability/null_usage',
'readability/strings',
'readability/todo',
'readability/utf8',
@@ -321,7 +318,6 @@ _ERROR_CATEGORIES = [
'runtime/string',
'runtime/threadsafe_fn',
'runtime/vlog',
- 'runtime/v8_persistent',
'whitespace/blank_line',
'whitespace/braces',
'whitespace/comma',
@@ -626,14 +622,6 @@ _SEARCH_C_FILE = re.compile(r'\b(?:LINT_C_FILE|'
# Match string that indicates we're working on a Linux Kernel file.
_SEARCH_KERNEL_FILE = re.compile(r'\b(?:LINT_KERNEL_FILE)')
-_NULL_TOKEN_PATTERN = re.compile(r'\bNULL\b')
-
-_V8_PERSISTENT_PATTERN = re.compile(r'\bv8::Persistent\b')
-
-_RIGHT_LEANING_POINTER_PATTERN = re.compile(r'[^=|(,\s><);&?:}]'
- r'(?<!(sizeof|return))'
- r'\s\*[a-zA-Z_][0-9a-zA-Z_]*')
-
_regexp_compile_cache = {}
# {str, set(int)}: a map from error categories to sets of linenumbers
@@ -653,7 +641,7 @@ _repository = None
# Files to exclude from linting. This is set by the --exclude flag.
_excludes = None
-# Whether to suppress PrintInfo messages
+# Whether to supress PrintInfo messages
_quiet = False
# The allowed line length of files.
@@ -690,7 +678,7 @@ def unicode_escape_decode(x):
# Treat all headers starting with 'h' equally: .h, .hpp, .hxx etc.
# This is set by --headers flag.
-_hpp_headers = set(['h', 'hh', 'hpp', 'hxx', 'h++', 'cuh'])
+_hpp_headers = set([])
# {str, bool}: a map from error categories to booleans which indicate if the
# category should be suppressed for every line.
@@ -699,30 +687,39 @@ _global_error_suppressions = {}
def ProcessHppHeadersOption(val):
global _hpp_headers
try:
- _hpp_headers = set(val.split(','))
- # Automatically append to extensions list so it does not have to be set 2 times
- _valid_extensions.update(_hpp_headers)
+ _hpp_headers = {ext.strip() for ext in val.split(',')}
except ValueError:
PrintUsage('Header extensions must be comma separated list.')
def IsHeaderExtension(file_extension):
- return file_extension in _hpp_headers
+ return file_extension in GetHeaderExtensions()
def GetHeaderExtensions():
- return _hpp_headers or ['h']
+ if _hpp_headers:
+ return _hpp_headers
+ if _valid_extensions:
+ return {h for h in _valid_extensions if 'h' in h}
+ return set(['h', 'hh', 'hpp', 'hxx', 'h++', 'cuh'])
# The allowed extensions for file names
# This is set by --extensions flag
def GetAllExtensions():
- if not _valid_extensions:
- return GetHeaderExtensions().union(set(['c', 'cc', 'cpp', 'cxx', 'c++', 'cu']))
- return _valid_extensions
+ return GetHeaderExtensions().union(_valid_extensions or set(
+ ['c', 'cc', 'cpp', 'cxx', 'c++', 'cu']))
+
+def ProcessExtensionsOption(val):
+ global _valid_extensions
+ try:
+ extensions = [ext.strip() for ext in val.split(',')]
+ _valid_extensions = set(extensions)
+ except ValueError:
+ PrintUsage('Extensions should be a comma-separated list of values;'
+ 'for example: extensions=hpp,cpp\n'
+ 'This could not be parsed: "%s"' % (val,))
def GetNonHeaderExtensions():
return GetAllExtensions().difference(GetHeaderExtensions())
-
-
def ParseNolintSuppressions(filename, raw_line, linenum, error):
"""Updates the global list of line error-suppressions.
@@ -853,9 +850,9 @@ class _IncludeState(object):
# needs to move backwards, CheckNextIncludeOrder will raise an error.
_INITIAL_SECTION = 0
_MY_H_SECTION = 1
- _OTHER_H_SECTION = 2
- _C_SECTION = 3
- _CPP_SECTION = 4
+ _C_SECTION = 2
+ _CPP_SECTION = 3
+ _OTHER_H_SECTION = 4
_TYPE_NAMES = {
_C_SYS_HEADER: 'C system header',
@@ -867,9 +864,9 @@ class _IncludeState(object):
_SECTION_NAMES = {
_INITIAL_SECTION: "... nothing. (This can't be an error.)",
_MY_H_SECTION: 'a header this file implements',
- _OTHER_H_SECTION: 'other header',
_C_SECTION: 'C system header',
_CPP_SECTION: 'C++ system header',
+ _OTHER_H_SECTION: 'other header',
}
def __init__(self):
@@ -1129,9 +1126,9 @@ class _CppLintState(object):
num_failures = len(self._junit_failures)
testsuite = xml.etree.ElementTree.Element('testsuite')
- testsuite.attrib['name'] = 'cpplint'
testsuite.attrib['errors'] = str(num_errors)
testsuite.attrib['failures'] = str(num_failures)
+ testsuite.attrib['name'] = 'cpplint'
if num_errors == 0 and num_failures == 0:
testsuite.attrib['tests'] = str(1)
@@ -1325,7 +1322,7 @@ class FileInfo(object):
If we have a real absolute path name here we can try to do something smart:
detecting the root of the checkout and truncating /path/to/checkout from
the name so that we get header guards that don't include things like
- "C:\Documents and Settings\..." or "/home/username/..." in them and thus
+ "C:\\Documents and Settings\\..." or "/home/username/..." in them and thus
people on different computers who have checked the source out to different
locations won't see bogus errors.
"""
@@ -2265,21 +2262,6 @@ def CheckForBadCharacters(filename, lines, error):
error(filename, linenum, 'readability/nul', 5, 'Line contains NUL byte.')
-def CheckInlineHeader(filename, include_state, error):
- """Logs an error if both a header and its inline variant are included."""
-
- all_headers = dict(item for sublist in include_state.include_list
- for item in sublist)
- bad_headers = set('%s.h' % name[:-6] for name in all_headers.keys()
- if name.endswith('-inl.h'))
- bad_headers &= set(all_headers.keys())
-
- for name in bad_headers:
- err = '%s includes both %s and %s-inl.h' % (filename, name, name)
- linenum = all_headers[name]
- error(filename, linenum, 'build/include_inline', 5, err)
-
-
def CheckForNewlineAtEOF(filename, lines, error):
"""Logs an error if there is no newline char at the end of the file.
@@ -3171,7 +3153,8 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum,
Search(r'\bstd\s*::\s*initializer_list\b', constructor_args[0]))
copy_constructor = bool(
onearg_constructor and
- Match(r'(const\s+)?%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&'
+ Match(r'((const\s+(volatile\s+)?)?|(volatile\s+(const\s+)?))?'
+ r'%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&'
% re.escape(base_classname), constructor_args[0].strip()))
if (not is_marked_explicit and
@@ -3302,7 +3285,7 @@ def CheckForFunctionLengths(filename, clean_lines, linenum,
"""Reports for long function bodies.
For an overview why this is done, see:
- https://google.github.io/styleguide/cppguide.html#Write_Short_Functions
+ https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions
Uses a simplistic algorithm assuming other style guidelines
(especially spacing) are followed.
@@ -3343,7 +3326,7 @@ def CheckForFunctionLengths(filename, clean_lines, linenum,
if Search(r'(;|})', start_line): # Declarations and trivial functions
body_found = True
break # ... ignore
- elif Search(r'{', start_line):
+ if Search(r'{', start_line):
body_found = True
function = Search(r'((\w|:)*)\(', line).group(1)
if Match(r'TEST', function): # Handle TEST... macros
@@ -3537,8 +3520,8 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
line = clean_lines.elided[linenum]
# You shouldn't have spaces before your brackets, except maybe after
- # 'delete []' or 'return []() {};'
- if Search(r'\w\s+\[', line) and not Search(r'(?:delete|return)\s+\[', line):
+ # 'delete []', 'return []() {};', or 'auto [abc, ...] = ...;'.
+ if Search(r'\w\s+\[', line) and not Search(r'(?:auto&?|delete|return)\s+\[', line):
error(filename, linenum, 'whitespace/braces', 5,
'Extra space before [')
@@ -4056,11 +4039,11 @@ def CheckBraces(filename, clean_lines, linenum, error):
# its line, and the line after that should have an indent level equal to or
# lower than the if. We also check for ambiguous if/else nesting without
# braces.
- if_else_match = Search(r'\b(if\s*\(|else\b)', line)
+ if_else_match = Search(r'\b(if\s*(|constexpr)\s*\(|else\b)', line)
if if_else_match and not Match(r'\s*#', line):
if_indent = GetIndentLevel(line)
endline, endlinenum, endpos = line, linenum, if_else_match.end()
- if_match = Search(r'\bif\s*\(', line)
+ if_match = Search(r'\bif\s*(|constexpr)\s*\(', line)
if if_match:
# This could be a multiline if condition, so find the end first.
pos = if_match.end() - 1
@@ -4528,71 +4511,6 @@ def CheckAltTokens(filename, clean_lines, linenum, error):
'Use operator %s instead of %s' % (
_ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1)))
-def CheckNullTokens(filename, clean_lines, linenum, error):
- """Check NULL usage.
-
- 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]
-
- # Avoid preprocessor lines
- if Match(r'^\s*#', line):
- return
-
- if line.find('/*') >= 0 or line.find('*/') >= 0:
- return
-
- for match in _NULL_TOKEN_PATTERN.finditer(line):
- error(filename, linenum, 'readability/null_usage', 2,
- 'Use nullptr instead of NULL')
-
-def CheckV8PersistentTokens(filename, clean_lines, linenum, error):
- """Check v8::Persistent usage.
-
- 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]
-
- # Avoid preprocessor lines
- if Match(r'^\s*#', line):
- return
-
- if line.find('/*') >= 0 or line.find('*/') >= 0:
- return
-
- for match in _V8_PERSISTENT_PATTERN.finditer(line):
- error(filename, linenum, 'runtime/v8_persistent', 2,
- 'Use v8::Global instead of v8::Persistent')
-
-def CheckLeftLeaningPointer(filename, clean_lines, linenum, error):
- """Check for left-leaning pointer placement.
-
- 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]
-
- # Avoid preprocessor lines
- if Match(r'^\s*#', line):
- return
-
- if '/*' in line or '*/' in line:
- return
-
- for match in _RIGHT_LEANING_POINTER_PATTERN.finditer(line):
- error(filename, linenum, 'readability/pointer_notation', 2,
- 'Use left leaning pointer instead of right leaning')
def GetLineWidth(line):
"""Determines the width of the line in column positions.
@@ -4747,9 +4665,6 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
CheckSpacingForFunctionCall(filename, clean_lines, linenum, error)
CheckCheck(filename, clean_lines, linenum, error)
CheckAltTokens(filename, clean_lines, linenum, error)
- CheckNullTokens(filename, clean_lines, linenum, error)
- CheckV8PersistentTokens(filename, clean_lines, linenum, error)
- CheckLeftLeaningPointer(filename, clean_lines, linenum, error)
classinfo = nesting_state.InnermostClass()
if classinfo:
CheckSectionSpacing(filename, clean_lines, classinfo, linenum, error)
@@ -4910,14 +4825,27 @@ def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
'Do not include .' + extension + ' files from other packages')
return
- if not _THIRD_PARTY_HEADERS_PATTERN.match(include):
+ # We DO want to include a 3rd party looking header if it matches the
+ # filename. Otherwise we get an erroneous error "...should include its
+ # header" error later.
+ third_src_header = False
+ for ext in GetHeaderExtensions():
+ basefilename = filename[0:len(filename) - len(fileinfo.Extension())]
+ headerfile = basefilename + '.' + ext
+ headername = FileInfo(headerfile).RepositoryName()
+ if headername in include or include in headername:
+ third_src_header = True
+ break
+
+ if third_src_header or not _THIRD_PARTY_HEADERS_PATTERN.match(include):
include_state.include_list[-1].append((include, linenum))
# We want to ensure that headers appear in the right order:
- # 1) for foo.cc, foo.h
- # 2) other project headers
- # 3) c system files
- # 4) cpp system files
+ # 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
@@ -5180,7 +5108,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
and line[-1] != '\\'):
error(filename, linenum, 'build/namespaces', 4,
'Do not use unnamed namespaces in header files. See '
- 'https://google.github.io/styleguide/cppguide.html#Namespaces'
+ 'https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'
' for more information.')
@@ -5708,11 +5636,11 @@ _HEADERS_CONTAINING_TEMPLATES = (
)),
('<limits>', ('numeric_limits',)),
('<list>', ('list',)),
- ('<map>', ('map', 'multimap',)),
+ ('<map>', ('multimap',)),
('<memory>', ('allocator', 'make_shared', 'make_unique', 'shared_ptr',
'unique_ptr', 'weak_ptr')),
('<queue>', ('queue', 'priority_queue',)),
- ('<set>', ('set', 'multiset',)),
+ ('<set>', ('multiset',)),
('<stack>', ('stack',)),
('<string>', ('char_traits', 'basic_string',)),
('<tuple>', ('tuple',)),
@@ -5746,6 +5674,16 @@ for _header, _templates in _HEADERS_MAYBE_TEMPLATES:
(re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'),
_template,
_header))
+# Match set<type>, but not foo->set<type>, foo.set<type>
+_re_pattern_headers_maybe_templates.append(
+ (re.compile(r'[^>.]\bset\s*\<'),
+ 'set<>',
+ '<set>'))
+# Match 'map<type> var' and 'std::map<type>(...)', but not 'map<type>(...)''
+_re_pattern_headers_maybe_templates.append(
+ (re.compile(r'(std\b::\bmap\s*\<)|(^(std\b::\b)map\b\(\s*\<)'),
+ 'map<>',
+ '<map>'))
# Other scripts may reach in and modify this pattern.
_re_pattern_templates = []
@@ -5828,18 +5766,19 @@ def UpdateIncludeState(filename, include_dict, io=codecs):
"""
headerfile = None
try:
- headerfile = io.open(filename, 'r', 'utf8', 'replace')
+ with io.open(filename, 'r', 'utf8', 'replace') as headerfile:
+ linenum = 0
+ for line in headerfile:
+ linenum += 1
+ clean_line = CleanseComments(line)
+ match = _RE_PATTERN_INCLUDE.search(clean_line)
+ if match:
+ include = match.group(2)
+ include_dict.setdefault(include, linenum)
+ return True
except IOError:
return False
- linenum = 0
- for line in headerfile:
- linenum += 1
- clean_line = CleanseComments(line)
- match = _RE_PATTERN_INCLUDE.search(clean_line)
- if match:
- include = match.group(2)
- include_dict.setdefault(include, linenum)
- return True
+
def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
@@ -6291,8 +6230,6 @@ def ProcessFileData(filename, file_extension, lines, error,
CheckForNewlineAtEOF(filename, lines, error)
- CheckInlineHeader(filename, include_state, error)
-
def ProcessConfigOverrides(filename):
""" Loads the configuration files and processes the config overrides.
@@ -6311,7 +6248,7 @@ def ProcessConfigOverrides(filename):
if not base_name:
break # Reached the root directory.
- cfg_file = os.path.join(abs_path, ".cpplint")
+ cfg_file = os.path.join(abs_path, "CPPLINT.cfg")
abs_filename = abs_path
if not os.path.isfile(cfg_file):
continue
@@ -6355,14 +6292,7 @@ def ProcessConfigOverrides(filename):
except ValueError:
_cpplint_state.PrintError('Line length must be numeric.')
elif name == 'extensions':
- global _valid_extensions
- try:
- extensions = [ext.strip() for ext in val.split(',')]
- _valid_extensions = set(extensions)
- except ValueError:
- sys.stderr.write('Extensions should be a comma-separated list of values;'
- 'for example: extensions=hpp,cpp\n'
- 'This could not be parsed: "%s"' % (val,))
+ ProcessExtensionsOption(val)
elif name == 'root':
global _root
# root directories are specified relative to CPPLINT.cfg dir.
@@ -6425,7 +6355,8 @@ def ProcessFile(filename, vlevel, extra_check_functions=None):
codecs.getwriter('utf8'),
'replace').read().split('\n')
else:
- lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n')
+ with codecs.open(filename, 'r', 'utf8', 'replace') as target_file:
+ lines = target_file.read().split('\n')
# Remove trailing '\r'.
# The -1 accounts for the extra trailing blank line we get from split()
@@ -6585,11 +6516,7 @@ def ParseArguments(args):
_excludes = set()
_excludes.update(glob.glob(val))
elif opt == '--extensions':
- global _valid_extensions
- try:
- _valid_extensions = set(val.split(','))
- except ValueError:
- PrintUsage('Extensions must be comma seperated list.')
+ ProcessExtensionsOption(val)
elif opt == '--headers':
ProcessHppHeadersOption(val)
elif opt == '--recursive':
@@ -6641,15 +6568,35 @@ def _ExpandDirectories(filenames):
for filename in expanded:
if os.path.splitext(filename)[1][1:] in GetAllExtensions():
filtered.append(filename)
-
return filtered
-def _FilterExcludedFiles(filenames):
+def _FilterExcludedFiles(fnames):
"""Filters out files listed in the --exclude command line switch. File paths
in the switch are evaluated relative to the current working directory
"""
exclude_paths = [os.path.abspath(f) for f in _excludes]
- return [f for f in filenames if os.path.abspath(f) not in exclude_paths]
+ # because globbing does not work recursively, exclude all subpath of all excluded entries
+ return [f for f in fnames
+ if not any(e for e in exclude_paths
+ if _IsParentOrSame(e, os.path.abspath(f)))]
+
+def _IsParentOrSame(parent, child):
+ """Return true if child is subdirectory of parent.
+ Assumes both paths are absolute and don't contain symlinks.
+ """
+ parent = os.path.normpath(parent)
+ child = os.path.normpath(child)
+ if parent == child:
+ return True
+
+ prefix = os.path.commonprefix([parent, child])
+ if prefix != parent:
+ return False
+ # Note: os.path.commonprefix operates on character basis, so
+ # take extra care of situations like '/foo/ba' and '/foo/bar/baz'
+ child_suffix = child[len(prefix):]
+ child_suffix = child_suffix.lstrip(os.sep)
+ return child == os.path.join(prefix, child_suffix)
def main():
filenames = ParseArguments(sys.argv[1:])