mirror of
https://github.com/google/styleguide.git
synced 2024-03-22 13:11:43 +08:00
Update cpplint.py to #242:
- Check indentation of public/protected/private keywords. - Remove RTTI warning. - Silence warning about multiple inheritance from global namespace. - Copy ctors don't need "explicit". - Understand "const char* const&" as a const reference. - Remove runtime/sizeof. - Recognize the "catch" keyword. - List C++11 headers - Allow sscanf() - Allow for one extra level of nesting in template class decls. - False positive for semicolons after single-line nameless unions. R=mark@chromium.org Review URL: https://codereview.appspot.com/15740044
This commit is contained in:
parent
7b24563e08
commit
fd5da63478
387
cpplint/cpplint.py
vendored
387
cpplint/cpplint.py
vendored
|
@ -200,8 +200,6 @@ _ERROR_CATEGORIES = [
|
|||
'runtime/printf',
|
||||
'runtime/printf_format',
|
||||
'runtime/references',
|
||||
'runtime/rtti',
|
||||
'runtime/sizeof',
|
||||
'runtime/string',
|
||||
'runtime/threadsafe_fn',
|
||||
'whitespace/blank_line',
|
||||
|
@ -213,7 +211,6 @@ _ERROR_CATEGORIES = [
|
|||
'whitespace/ending_newline',
|
||||
'whitespace/forcolon',
|
||||
'whitespace/indent',
|
||||
'whitespace/labels',
|
||||
'whitespace/line_length',
|
||||
'whitespace/newline',
|
||||
'whitespace/operators',
|
||||
|
@ -233,36 +230,143 @@ _DEFAULT_FILTERS = ['-build/include_alpha']
|
|||
# decided those were OK, as long as they were in UTF-8 and didn't represent
|
||||
# hard-coded international strings, which belong in a separate i18n file.
|
||||
|
||||
# Headers that we consider STL headers.
|
||||
_STL_HEADERS = frozenset([
|
||||
'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception',
|
||||
'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set',
|
||||
'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'new',
|
||||
'pair.h', 'pthread_alloc', 'queue', 'set', 'set.h', 'sstream', 'stack',
|
||||
'stl_alloc.h', 'stl_relops.h', 'type_traits.h',
|
||||
'utility', 'vector', 'vector.h',
|
||||
])
|
||||
|
||||
|
||||
# Non-STL C++ system headers.
|
||||
# C++ headers
|
||||
_CPP_HEADERS = frozenset([
|
||||
'algo.h', 'builtinbuf.h', 'bvector.h', 'cassert', 'cctype',
|
||||
'cerrno', 'cfloat', 'ciso646', 'climits', 'clocale', 'cmath',
|
||||
'complex', 'complex.h', 'csetjmp', 'csignal', 'cstdarg', 'cstddef',
|
||||
'cstdio', 'cstdlib', 'cstring', 'ctime', 'cwchar', 'cwctype',
|
||||
'defalloc.h', 'deque.h', 'editbuf.h', 'exception', 'fstream',
|
||||
'fstream.h', 'hashtable.h', 'heap.h', 'indstream.h', 'iomanip',
|
||||
'iomanip.h', 'ios', 'iosfwd', 'iostream', 'iostream.h', 'istream',
|
||||
'istream.h', 'iterator.h', 'limits', 'map.h', 'multimap.h', 'multiset.h',
|
||||
'numeric', 'ostream', 'ostream.h', 'parsestream.h', 'pfstream.h',
|
||||
'PlotFile.h', 'procbuf.h', 'pthread_alloc.h', 'rope', 'rope.h',
|
||||
'ropeimpl.h', 'SFile.h', 'slist', 'slist.h', 'stack.h', 'stdexcept',
|
||||
'stdiostream.h', 'streambuf', 'streambuf.h', 'stream.h', 'strfile.h',
|
||||
'string', 'strstream', 'strstream.h', 'tempbuf.h', 'tree.h', 'typeinfo',
|
||||
# Legacy
|
||||
'algobase.h',
|
||||
'algo.h',
|
||||
'alloc.h',
|
||||
'builtinbuf.h',
|
||||
'bvector.h',
|
||||
'complex.h',
|
||||
'defalloc.h',
|
||||
'deque.h',
|
||||
'editbuf.h',
|
||||
'fstream.h',
|
||||
'function.h',
|
||||
'hash_map',
|
||||
'hash_map.h',
|
||||
'hash_set',
|
||||
'hash_set.h',
|
||||
'hashtable.h',
|
||||
'heap.h',
|
||||
'indstream.h',
|
||||
'iomanip.h',
|
||||
'iostream.h',
|
||||
'istream.h',
|
||||
'iterator.h',
|
||||
'list.h',
|
||||
'map.h',
|
||||
'multimap.h',
|
||||
'multiset.h',
|
||||
'ostream.h',
|
||||
'pair.h',
|
||||
'parsestream.h',
|
||||
'pfstream.h',
|
||||
'procbuf.h',
|
||||
'pthread_alloc',
|
||||
'pthread_alloc.h',
|
||||
'rope',
|
||||
'rope.h',
|
||||
'ropeimpl.h',
|
||||
'set.h',
|
||||
'slist',
|
||||
'slist.h',
|
||||
'stack.h',
|
||||
'stdiostream.h',
|
||||
'stl_alloc.h',
|
||||
'stl_relops.h',
|
||||
'streambuf.h',
|
||||
'stream.h',
|
||||
'strfile.h',
|
||||
'strstream.h',
|
||||
'tempbuf.h',
|
||||
'tree.h',
|
||||
'type_traits.h',
|
||||
'vector.h',
|
||||
# 17.6.1.2 C++ library headers
|
||||
'algorithm',
|
||||
'array',
|
||||
'atomic',
|
||||
'bitset',
|
||||
'chrono',
|
||||
'codecvt',
|
||||
'complex',
|
||||
'condition_variable',
|
||||
'deque',
|
||||
'exception',
|
||||
'forward_list',
|
||||
'fstream',
|
||||
'functional',
|
||||
'future',
|
||||
'initializer_list',
|
||||
'iomanip',
|
||||
'ios',
|
||||
'iosfwd',
|
||||
'iostream',
|
||||
'istream',
|
||||
'iterator',
|
||||
'limits',
|
||||
'list',
|
||||
'locale',
|
||||
'map',
|
||||
'memory',
|
||||
'mutex',
|
||||
'new',
|
||||
'numeric',
|
||||
'ostream',
|
||||
'queue',
|
||||
'random',
|
||||
'ratio',
|
||||
'regex',
|
||||
'set',
|
||||
'sstream',
|
||||
'stack',
|
||||
'stdexcept',
|
||||
'streambuf',
|
||||
'string',
|
||||
'strstream',
|
||||
'system_error',
|
||||
'thread',
|
||||
'tuple',
|
||||
'typeindex',
|
||||
'typeinfo',
|
||||
'type_traits',
|
||||
'unordered_map',
|
||||
'unordered_set',
|
||||
'utility',
|
||||
'valarray',
|
||||
'vector',
|
||||
# 17.6.1.2 C++ headers for C library facilities
|
||||
'cassert',
|
||||
'ccomplex',
|
||||
'cctype',
|
||||
'cerrno',
|
||||
'cfenv',
|
||||
'cfloat',
|
||||
'cinttypes',
|
||||
'ciso646',
|
||||
'climits',
|
||||
'clocale',
|
||||
'cmath',
|
||||
'csetjmp',
|
||||
'csignal',
|
||||
'cstdalign',
|
||||
'cstdarg',
|
||||
'cstdbool',
|
||||
'cstddef',
|
||||
'cstdint',
|
||||
'cstdio',
|
||||
'cstdlib',
|
||||
'cstring',
|
||||
'ctgmath',
|
||||
'ctime',
|
||||
'cuchar',
|
||||
'cwchar',
|
||||
'cwctype',
|
||||
])
|
||||
|
||||
|
||||
# Assertion macros. These are defined in base/logging.h and
|
||||
# testing/base/gunit.h. Note that the _M versions need to come first
|
||||
# for substring matching to work.
|
||||
|
@ -416,6 +520,24 @@ def Match(pattern, s):
|
|||
return _regexp_compile_cache[pattern].match(s)
|
||||
|
||||
|
||||
def ReplaceAll(pattern, rep, s):
|
||||
"""Replaces instances of pattern in a string with a replacement.
|
||||
|
||||
The compiled regex is kept in a cache shared by Match and Search.
|
||||
|
||||
Args:
|
||||
pattern: regex pattern
|
||||
rep: replacement text
|
||||
s: search string
|
||||
|
||||
Returns:
|
||||
string with replacements made (or original string if no replacements)
|
||||
"""
|
||||
if pattern not in _regexp_compile_cache:
|
||||
_regexp_compile_cache[pattern] = sre_compile.compile(pattern)
|
||||
return _regexp_compile_cache[pattern].sub(rep, s)
|
||||
|
||||
|
||||
def Search(pattern, s):
|
||||
"""Searches the string for the pattern, caching the compiled regexp."""
|
||||
if not pattern in _regexp_compile_cache:
|
||||
|
@ -464,6 +586,9 @@ class _IncludeState(dict):
|
|||
# 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.
|
||||
|
||||
|
@ -479,19 +604,25 @@ class _IncludeState(dict):
|
|||
"""
|
||||
return header_path.replace('-inl.h', '.h').replace('-', '_').lower()
|
||||
|
||||
def IsInAlphabeticalOrder(self, header_path):
|
||||
def IsInAlphabeticalOrder(self, clean_lines, linenum, header_path):
|
||||
"""Check if a header is in alphabetical order with the previous header.
|
||||
|
||||
Args:
|
||||
header_path: Header to be checked.
|
||||
clean_lines: A CleansedLines instance containing the file.
|
||||
linenum: The number of the line to check.
|
||||
header_path: Canonicalized header to be checked.
|
||||
|
||||
Returns:
|
||||
Returns true if the header is in alphabetical order.
|
||||
"""
|
||||
canonical_header = self.CanonicalizeAlphabeticalOrder(header_path)
|
||||
if self._last_header > canonical_header:
|
||||
# If previous section is different from current section, _last_header will
|
||||
# be reset to empty string, so it's always less than current header.
|
||||
#
|
||||
# If previous line was a blank line, assume that the headers are
|
||||
# intentionally sorted the way they are.
|
||||
if (self._last_header > header_path and
|
||||
not Match(r'^\s*$', clean_lines.elided[linenum - 1])):
|
||||
return False
|
||||
self._last_header = canonical_header
|
||||
return True
|
||||
|
||||
def CheckNextIncludeOrder(self, header_type):
|
||||
|
@ -1401,8 +1532,18 @@ class _ClassInfo(_BlockInfo):
|
|||
self.is_derived = False
|
||||
if class_or_struct == 'struct':
|
||||
self.access = 'public'
|
||||
self.is_struct = True
|
||||
else:
|
||||
self.access = 'private'
|
||||
self.is_struct = False
|
||||
|
||||
# Remember initial indentation level for this class. Using raw_lines here
|
||||
# instead of elided to account for leading comments like http://go/abjhm
|
||||
initial_indent = Match(r'^( *)\S', clean_lines.raw_lines[linenum])
|
||||
if initial_indent:
|
||||
self.class_indent = len(initial_indent.group(1))
|
||||
else:
|
||||
self.class_indent = 0
|
||||
|
||||
# Try to find the end of the class. This will be confused by things like:
|
||||
# class A {
|
||||
|
@ -1423,6 +1564,19 @@ class _ClassInfo(_BlockInfo):
|
|||
if Search('(^|[^:]):($|[^:])', clean_lines.elided[linenum]):
|
||||
self.is_derived = True
|
||||
|
||||
def CheckEnd(self, filename, clean_lines, linenum, error):
|
||||
# Check that closing brace is aligned with beginning of the class.
|
||||
# Only do this if the closing brace is indented by only whitespaces.
|
||||
# This means we will not check single-line class definitions.
|
||||
indent = Match(r'^( *)\}', clean_lines.elided[linenum])
|
||||
if indent and len(indent.group(1)) != self.class_indent:
|
||||
if self.is_struct:
|
||||
parent = 'struct ' + self.name
|
||||
else:
|
||||
parent = 'class ' + self.name
|
||||
error(filename, linenum, 'whitespace/indent', 3,
|
||||
'Closing brace should be aligned with beginning of %s' % parent)
|
||||
|
||||
|
||||
class _NamespaceInfo(_BlockInfo):
|
||||
"""Stores information about a namespace."""
|
||||
|
@ -1661,8 +1815,8 @@ class _NestingState(object):
|
|||
# To avoid these cases, we ignore classes that are followed by '=' or '>'
|
||||
class_decl_match = Match(
|
||||
r'\s*(template\s*<[\w\s<>,:]*>\s*)?'
|
||||
'(class|struct)\s+([A-Z_]+\s+)*(\w+(?:::\w+)*)'
|
||||
'(([^=>]|<[^<>]*>)*)$', line)
|
||||
r'(class|struct)\s+([A-Z_]+\s+)*(\w+(?:::\w+)*)'
|
||||
r'(([^=>]|<[^<>]*>|<[^<>]*<[^<>]*>\s*>)*)$', line)
|
||||
if (class_decl_match and
|
||||
(not self.stack or self.stack[-1].open_parentheses == 0)):
|
||||
self.stack.append(_ClassInfo(
|
||||
|
@ -1677,9 +1831,30 @@ class _NestingState(object):
|
|||
|
||||
# Update access control if we are inside a class/struct
|
||||
if self.stack and isinstance(self.stack[-1], _ClassInfo):
|
||||
access_match = Match(r'\s*(public|private|protected)\s*:', line)
|
||||
classinfo = self.stack[-1]
|
||||
access_match = Match(
|
||||
r'^(.*)\b(public|private|protected|signals)(\s+(?:slots\s*)?)?'
|
||||
r':(?:[^:]|$)',
|
||||
line)
|
||||
if access_match:
|
||||
self.stack[-1].access = access_match.group(1)
|
||||
classinfo.access = access_match.group(2)
|
||||
|
||||
# Check that access keywords are indented +1 space. Skip this
|
||||
# check if the keywords are not preceded by whitespaces, examples:
|
||||
# http://go/cfudb + http://go/vxnkk
|
||||
indent = access_match.group(1)
|
||||
if (len(indent) != classinfo.class_indent + 1 and
|
||||
Match(r'^\s*$', indent)):
|
||||
if classinfo.is_struct:
|
||||
parent = 'struct ' + classinfo.name
|
||||
else:
|
||||
parent = 'class ' + classinfo.name
|
||||
slots = ''
|
||||
if access_match.group(3):
|
||||
slots = access_match.group(3)
|
||||
error(filename, linenum, 'whitespace/indent', 3,
|
||||
'%s%s: should be indented +1 space inside %s' % (
|
||||
access_match.group(2), slots, parent))
|
||||
|
||||
# Consume braces or semicolons from what's left of the line
|
||||
while True:
|
||||
|
@ -1848,8 +2023,8 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum,
|
|||
line)
|
||||
if (args and
|
||||
args.group(1) != 'void' and
|
||||
not Match(r'(const\s+)?%s\s*(?:<\w+>\s*)?&' % re.escape(base_classname),
|
||||
args.group(1).strip())):
|
||||
not Match(r'(const\s+)?%s(\s+const)?\s*(?:<\w+>\s*)?&'
|
||||
% re.escape(base_classname), args.group(1).strip())):
|
||||
error(filename, linenum, 'runtime/explicit', 5,
|
||||
'Single-argument constructors should be marked explicit.')
|
||||
|
||||
|
@ -1892,7 +2067,7 @@ def CheckSpacingForFunctionCall(filename, line, linenum, error):
|
|||
# Note that we assume the contents of [] to be short enough that
|
||||
# they'll never need to wrap.
|
||||
if ( # Ignore control structures.
|
||||
not Search(r'\b(if|for|while|switch|return|delete)\b', fncall) and
|
||||
not Search(r'\b(if|for|while|switch|return|delete|catch)\b', fncall) and
|
||||
# Ignore pointers/references to functions.
|
||||
not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and
|
||||
# Ignore pointers/references to arrays.
|
||||
|
@ -2635,7 +2810,7 @@ def CheckBraces(filename, clean_lines, linenum, error):
|
|||
break
|
||||
if (Search(r'{.*}\s*;', line) and
|
||||
line.count('{') == line.count('}') and
|
||||
not Search(r'struct|class|enum|\s*=\s*{', line)):
|
||||
not Search(r'struct|union|class|enum|\s*=\s*{', line)):
|
||||
error(filename, linenum, 'readability/braces', 4,
|
||||
"You don't need a ; after a }")
|
||||
|
||||
|
@ -2833,21 +3008,12 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
|
|||
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 labels
|
||||
# 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?')
|
||||
# Labels should always be indented at least one space.
|
||||
elif not initial_spaces and line[:2] != '//' and Search(r'[^:]:\s*$',
|
||||
line):
|
||||
error(filename, linenum, 'whitespace/labels', 4,
|
||||
'Labels should always be indented at least one space. '
|
||||
'If this is a member-initializer list in a constructor or '
|
||||
'the base class list in a class definition, the colon should '
|
||||
'be on the following line.')
|
||||
|
||||
|
||||
# Check if the line is a header guard.
|
||||
is_header_guard = False
|
||||
|
@ -2980,8 +3146,7 @@ def _ClassifyInclude(fileinfo, include, is_system):
|
|||
"""
|
||||
# This is a list of all standard c++ header files, except
|
||||
# those already checked for above.
|
||||
is_stl_h = include in _STL_HEADERS
|
||||
is_cpp_h = is_stl_h or include in _CPP_HEADERS
|
||||
is_cpp_h = include in _CPP_HEADERS
|
||||
|
||||
if is_system:
|
||||
if is_cpp_h:
|
||||
|
@ -3069,9 +3234,12 @@ def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
|
|||
error(filename, linenum, 'build/include_order', 4,
|
||||
'%s. Should be: %s.h, c system, c++ system, other.' %
|
||||
(error_message, fileinfo.BaseName()))
|
||||
if not include_state.IsInAlphabeticalOrder(include):
|
||||
canonical_include = include_state.CanonicalizeAlphabeticalOrder(include)
|
||||
if not include_state.IsInAlphabeticalOrder(
|
||||
clean_lines, linenum, canonical_include):
|
||||
error(filename, linenum, 'build/include_alpha', 4,
|
||||
'Include "%s" not in alphabetical order' % include)
|
||||
include_state.SetLastHeader(canonical_include)
|
||||
|
||||
# Look for any of the stream classes that are part of standard C++.
|
||||
match = _RE_PATTERN_INCLUDE.match(line)
|
||||
|
@ -3140,8 +3308,24 @@ def _GetTextInside(text, start_pattern):
|
|||
return text[start_position:position - 1]
|
||||
|
||||
|
||||
def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
|
||||
error):
|
||||
# Patterns for matching call-by-reference parameters.
|
||||
_RE_PATTERN_IDENT = r'[_a-zA-Z]\w*' # =~ [[:alpha:]][[:alnum:]]*
|
||||
_RE_PATTERN_TYPE = (
|
||||
r'(?:const\s+)?(?:typename\s+|class\s+|struct\s+|union\s+|enum\s+)?'
|
||||
r'[\w:]*\w(?:\s*<[\w:*, ]*>(?:::\w+)?)?')
|
||||
# A call-by-reference parameter ends with '& identifier'.
|
||||
_RE_PATTERN_REF_PARAM = re.compile(
|
||||
r'(' + _RE_PATTERN_TYPE + r'(?:\s*(?:\bconst\b|[*]))*\s*'
|
||||
r'&\s*' + _RE_PATTERN_IDENT + r')\s*(?:=[^,()]+)?[,)]')
|
||||
# A call-by-const-reference parameter either ends with 'const& identifier'
|
||||
# or looks like 'const type& identifier' when 'type' is atomic.
|
||||
_RE_PATTERN_CONST_REF_PARAM = (
|
||||
r'(?:.*\s*\bconst\s*&\s*' + _RE_PATTERN_IDENT +
|
||||
r'|const\s+' + _RE_PATTERN_TYPE + r'\s*&\s*' + _RE_PATTERN_IDENT + r')')
|
||||
|
||||
|
||||
def CheckLanguage(filename, clean_lines, linenum, file_extension,
|
||||
include_state, nesting_state, error):
|
||||
"""Checks rules from the 'C++ language rules' section of cppguide.html.
|
||||
|
||||
Some of these rules are hard to test (function overloading, using
|
||||
|
@ -3153,6 +3337,8 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
|
|||
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
|
||||
|
@ -3179,30 +3365,56 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
|
|||
|
||||
# TODO(unknown): figure out if they're using default arguments in fn proto.
|
||||
|
||||
# Check for non-const references in functions. This is tricky because &
|
||||
# is also used to take the address of something. We allow <> for templates,
|
||||
# (ignoring whatever is between the braces) and : for classes.
|
||||
# These are complicated re's. They try to capture the following:
|
||||
# paren (for fn-prototype start), typename, &, varname. For the const
|
||||
# version, we're willing for const to be before typename or after
|
||||
# Don't check the implementation on same line.
|
||||
fnline = line.split('{', 1)[0]
|
||||
if (len(re.findall(r'\([^()]*\b(?:[\w:]|<[^()]*>)+(\s?&|&\s?)\w+', fnline)) >
|
||||
len(re.findall(r'\([^()]*\bconst\s+(?:typename\s+)?(?:struct\s+)?'
|
||||
r'(?:[\w:]|<[^()]*>)+(\s?&|&\s?)\w+', fnline)) +
|
||||
len(re.findall(r'\([^()]*\b(?:[\w:]|<[^()]*>)+\s+const(\s?&|&\s?)[\w]+',
|
||||
fnline))):
|
||||
|
||||
# Check for non-const references in function parameters. A single '&' may
|
||||
# found in the following places:
|
||||
# inside expression: binary & for bitwise AND
|
||||
# inside expression: unary & for taking the address of something
|
||||
# inside declarators: reference parameter
|
||||
# We will exclude the first two cases by checking that we are not inside a
|
||||
# function body, including one that was just introduced by a trailing '{'.
|
||||
# TODO(unknown): Doesn't account for preprocessor directives.
|
||||
# TODO(unknown): Doesn't account for 'catch(Exception& e)' [rare].
|
||||
# TODO(unknown): Doesn't account for line breaks within declarators.
|
||||
check_params = False
|
||||
if not nesting_state.stack:
|
||||
check_params = True # top level
|
||||
elif (isinstance(nesting_state.stack[-1], _ClassInfo) or
|
||||
isinstance(nesting_state.stack[-1], _NamespaceInfo)):
|
||||
check_params = True # within class or namespace
|
||||
elif Match(r'.*{\s*$', line):
|
||||
if (len(nesting_state.stack) == 1 or
|
||||
isinstance(nesting_state.stack[-2], _ClassInfo) or
|
||||
isinstance(nesting_state.stack[-2], _NamespaceInfo)):
|
||||
check_params = True # just opened global/class/namespace block
|
||||
# We allow non-const references in a few standard places, like functions
|
||||
# called "swap()" or iostream operators like "<<" or ">>". We also filter
|
||||
# out for loops, which lint otherwise mistakenly thinks are functions.
|
||||
if not Search(
|
||||
r'(for|swap|Swap|operator[<>][<>])\s*\(\s*'
|
||||
r'(?:(?:typename\s*)?[\w:]|<.*>)+\s*&',
|
||||
fnline):
|
||||
# called "swap()" or iostream operators like "<<" or ">>". Do not check
|
||||
# those function parameters.
|
||||
#
|
||||
# We also accept & in static_assert, which looks like a function but
|
||||
# it's actually a declaration expression.
|
||||
whitelisted_functions = (r'(?:[sS]wap(?:<\w:+>)?|'
|
||||
r'operator\s*[<>][<>]|'
|
||||
r'static_assert|COMPILE_ASSERT'
|
||||
r')\s*\(')
|
||||
if Search(whitelisted_functions, line):
|
||||
check_params = False
|
||||
elif not Search(r'\S+\([^)]*$', line):
|
||||
# Don't see a whitelisted function on this line. Actually we
|
||||
# didn't see any function name on this line, so this is likely a
|
||||
# multi-line parameter list. Try a bit harder to catch this case.
|
||||
for i in xrange(2):
|
||||
if (linenum > i and
|
||||
Search(whitelisted_functions, clean_lines.elided[linenum - i - 1])):
|
||||
check_params = False
|
||||
break
|
||||
|
||||
if check_params:
|
||||
decls = ReplaceAll(r'{[^}]*}', ' ', line) # exclude function body
|
||||
for parameter in re.findall(_RE_PATTERN_REF_PARAM, decls):
|
||||
if not Match(_RE_PATTERN_CONST_REF_PARAM, parameter):
|
||||
error(filename, linenum, 'runtime/references', 2,
|
||||
'Is this a non-const reference? '
|
||||
'If so, make const or use a pointer.')
|
||||
'If so, make const or use a pointer: ' + parameter)
|
||||
|
||||
# Check to see if they're using an conversion function cast.
|
||||
# I just try to capture the most common basic types, though there are more.
|
||||
|
@ -3276,13 +3488,6 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
|
|||
'"%schar %s[]".' %
|
||||
(match.group(1), match.group(2)))
|
||||
|
||||
# Check that we're not using RTTI outside of testing code.
|
||||
if Search(r'\bdynamic_cast<', line) and not _IsTestFilename(filename):
|
||||
error(filename, linenum, 'runtime/rtti', 5,
|
||||
'Do not use dynamic_cast<>. If you need to cast within a class '
|
||||
"hierarchy, use static_cast<> to upcast. Google doesn't support "
|
||||
'RTTI.')
|
||||
|
||||
if Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line):
|
||||
error(filename, linenum, 'runtime/init', 4,
|
||||
'You seem to be initializing a member variable with itself.')
|
||||
|
@ -3324,10 +3529,6 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
|
|||
error(filename, linenum, 'runtime/printf', 4,
|
||||
'Almost always, snprintf is better than %s' % match.group(1))
|
||||
|
||||
if Search(r'\bsscanf\b', line):
|
||||
error(filename, linenum, 'runtime/printf', 1,
|
||||
'sscanf can be ok, but is slow and can overflow buffers.')
|
||||
|
||||
# Check if some verboten operator overloading is going on
|
||||
# TODO(unknown): catch out-of-line unary operator&:
|
||||
# class X {};
|
||||
|
@ -3448,8 +3649,6 @@ def CheckCStyleCast(filename, linenum, line, raw_line, cast_type, pattern,
|
|||
error):
|
||||
"""Checks for a C-style cast by looking for the pattern.
|
||||
|
||||
This also handles sizeof(type) warnings, due to similarity of content.
|
||||
|
||||
Args:
|
||||
filename: The name of the current file.
|
||||
linenum: The number of the line to check.
|
||||
|
@ -3468,12 +3667,10 @@ def CheckCStyleCast(filename, linenum, line, raw_line, cast_type, pattern,
|
|||
if not match:
|
||||
return False
|
||||
|
||||
# e.g., sizeof(int)
|
||||
# Exclude lines with sizeof, since sizeof looks like a cast.
|
||||
sizeof_match = Match(r'.*sizeof\s*$', line[0:match.start(1) - 1])
|
||||
if sizeof_match:
|
||||
error(filename, linenum, 'runtime/sizeof', 1,
|
||||
'Using sizeof(type). Use sizeof(varname) instead if possible')
|
||||
return True
|
||||
return False
|
||||
|
||||
# operator++(int) and operator--(int)
|
||||
if (line[0:match.start(1) - 1].endswith(' operator++') or
|
||||
|
@ -3802,7 +3999,7 @@ def ProcessLine(filename, file_extension, clean_lines, line,
|
|||
CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
|
||||
CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error)
|
||||
CheckLanguage(filename, clean_lines, line, file_extension, include_state,
|
||||
error)
|
||||
nesting_state, error)
|
||||
CheckForNonStandardConstructs(filename, clean_lines, line,
|
||||
nesting_state, error)
|
||||
CheckPosixThreading(filename, clean_lines, line, error)
|
||||
|
|
|
@ -147,13 +147,14 @@ class CpplintTestBase(unittest.TestCase):
|
|||
def PerformLanguageRulesCheck(self, file_name, code):
|
||||
error_collector = ErrorCollector(self.assert_)
|
||||
include_state = cpplint._IncludeState()
|
||||
nesting_state = cpplint._NestingState()
|
||||
lines = code.split('\n')
|
||||
cpplint.RemoveMultiLineComments(file_name, lines, error_collector)
|
||||
lines = cpplint.CleansedLines(lines)
|
||||
ext = file_name[file_name.rfind('.') + 1:]
|
||||
for i in xrange(lines.NumLines()):
|
||||
cpplint.CheckLanguage(file_name, lines, i, ext, include_state,
|
||||
error_collector)
|
||||
nesting_state, error_collector)
|
||||
return error_collector.Results()
|
||||
|
||||
def PerformFunctionLengthsCheck(self, code):
|
||||
|
@ -186,12 +187,13 @@ class CpplintTestBase(unittest.TestCase):
|
|||
# First, build up the include state.
|
||||
error_collector = ErrorCollector(self.assert_)
|
||||
include_state = cpplint._IncludeState()
|
||||
nesting_state = cpplint._NestingState()
|
||||
lines = code.split('\n')
|
||||
cpplint.RemoveMultiLineComments(filename, lines, error_collector)
|
||||
lines = cpplint.CleansedLines(lines)
|
||||
for i in xrange(lines.NumLines()):
|
||||
cpplint.CheckLanguage(filename, lines, i, '.h', include_state,
|
||||
error_collector)
|
||||
nesting_state, error_collector)
|
||||
# We could clear the error_collector here, but this should
|
||||
# also be fine, since our IncludeWhatYouUse unittests do not
|
||||
# have language problems.
|
||||
|
@ -410,16 +412,6 @@ class CpplintTest(CpplintTestBase):
|
|||
'Take the address before doing the cast, rather than after'
|
||||
' [runtime/casting] [4]')
|
||||
|
||||
self.TestLint(
|
||||
'int* x = &dynamic_cast<int *>(foo);',
|
||||
['Are you taking an address of a cast? '
|
||||
'This is dangerous: could be a temp var. '
|
||||
'Take the address before doing the cast, rather than after'
|
||||
' [runtime/casting] [4]',
|
||||
'Do not use dynamic_cast<>. If you need to cast within a class '
|
||||
'hierarchy, use static_cast<> to upcast. Google doesn\'t support '
|
||||
'RTTI. [runtime/rtti] [5]'])
|
||||
|
||||
self.TestLint(
|
||||
'int* x = &reinterpret_cast<int *>(foo);',
|
||||
'Are you taking an address of a cast? '
|
||||
|
@ -444,20 +436,6 @@ class CpplintTest(CpplintTestBase):
|
|||
'Foo::Foo(Bar r) : r_(r), l_(r_), ll_(l_) { }',
|
||||
'')
|
||||
|
||||
def testRuntimeRTTI(self):
|
||||
statement = 'int* x = dynamic_cast<int*>(&foo);'
|
||||
error_message = (
|
||||
'Do not use dynamic_cast<>. If you need to cast within a class '
|
||||
'hierarchy, use static_cast<> to upcast. Google doesn\'t support '
|
||||
'RTTI. [runtime/rtti] [5]')
|
||||
# dynamic_cast is disallowed in most files.
|
||||
self.TestLanguageRulesCheck('foo.cc', statement, error_message)
|
||||
self.TestLanguageRulesCheck('foo.h', statement, error_message)
|
||||
# It is explicitly allowed in tests, however.
|
||||
self.TestLanguageRulesCheck('foo_test.cc', statement, '')
|
||||
self.TestLanguageRulesCheck('foo_unittest.cc', statement, '')
|
||||
self.TestLanguageRulesCheck('foo_regtest.cc', statement, '')
|
||||
|
||||
# Test for unnamed arguments in a method.
|
||||
def testCheckForUnnamedParams(self):
|
||||
message = ('All parameters should be named in a function'
|
||||
|
@ -571,17 +549,6 @@ class CpplintTest(CpplintTestBase):
|
|||
'MockCallback<int(float, char)>',
|
||||
'')
|
||||
|
||||
# Test sizeof(type) cases.
|
||||
def testSizeofType(self):
|
||||
self.TestLint(
|
||||
'sizeof(int);',
|
||||
'Using sizeof(type). Use sizeof(varname) instead if possible'
|
||||
' [runtime/sizeof] [1]')
|
||||
self.TestLint(
|
||||
'sizeof(int *);',
|
||||
'Using sizeof(type). Use sizeof(varname) instead if possible'
|
||||
' [runtime/sizeof] [1]')
|
||||
|
||||
# Test false errors that happened with some include file names
|
||||
def testIncludeFilenameFalseError(self):
|
||||
self.TestLint(
|
||||
|
@ -876,14 +843,16 @@ class CpplintTest(CpplintTestBase):
|
|||
def testExplicitSingleArgumentConstructors(self):
|
||||
# missing explicit is bad
|
||||
self.TestMultiLineLint(
|
||||
"""class Foo {
|
||||
"""
|
||||
class Foo {
|
||||
Foo(int f);
|
||||
};""",
|
||||
'Single-argument constructors should be marked explicit.'
|
||||
' [runtime/explicit] [5]')
|
||||
# missing explicit is bad, even with whitespace
|
||||
self.TestMultiLineLint(
|
||||
"""class Foo {
|
||||
"""
|
||||
class Foo {
|
||||
Foo (int f);
|
||||
};""",
|
||||
['Extra space before ( in function call [whitespace/parens] [4]',
|
||||
|
@ -891,93 +860,107 @@ class CpplintTest(CpplintTestBase):
|
|||
' [runtime/explicit] [5]'])
|
||||
# missing explicit, with distracting comment, is still bad
|
||||
self.TestMultiLineLint(
|
||||
"""class Foo {
|
||||
"""
|
||||
class Foo {
|
||||
Foo(int f); // simpler than Foo(blargh, blarg)
|
||||
};""",
|
||||
'Single-argument constructors should be marked explicit.'
|
||||
' [runtime/explicit] [5]')
|
||||
# missing explicit, with qualified classname
|
||||
self.TestMultiLineLint(
|
||||
"""class Qualifier::AnotherOne::Foo {
|
||||
"""
|
||||
class Qualifier::AnotherOne::Foo {
|
||||
Foo(int f);
|
||||
};""",
|
||||
'Single-argument constructors should be marked explicit.'
|
||||
' [runtime/explicit] [5]')
|
||||
# missing explicit for inline constructors is bad as well
|
||||
self.TestMultiLineLint(
|
||||
"""class Foo {
|
||||
"""
|
||||
class Foo {
|
||||
inline Foo(int f);
|
||||
};""",
|
||||
'Single-argument constructors should be marked explicit.'
|
||||
' [runtime/explicit] [5]')
|
||||
# structs are caught as well.
|
||||
self.TestMultiLineLint(
|
||||
"""struct Foo {
|
||||
"""
|
||||
struct Foo {
|
||||
Foo(int f);
|
||||
};""",
|
||||
'Single-argument constructors should be marked explicit.'
|
||||
' [runtime/explicit] [5]')
|
||||
# Templatized classes are caught as well.
|
||||
self.TestMultiLineLint(
|
||||
"""template<typename T> class Foo {
|
||||
"""
|
||||
template<typename T> class Foo {
|
||||
Foo(int f);
|
||||
};""",
|
||||
'Single-argument constructors should be marked explicit.'
|
||||
' [runtime/explicit] [5]')
|
||||
# inline case for templatized classes.
|
||||
self.TestMultiLineLint(
|
||||
"""template<typename T> class Foo {
|
||||
"""
|
||||
template<typename T> class Foo {
|
||||
inline Foo(int f);
|
||||
};""",
|
||||
'Single-argument constructors should be marked explicit.'
|
||||
' [runtime/explicit] [5]')
|
||||
# proper style is okay
|
||||
self.TestMultiLineLint(
|
||||
"""class Foo {
|
||||
"""
|
||||
class Foo {
|
||||
explicit Foo(int f);
|
||||
};""",
|
||||
'')
|
||||
# two argument constructor is okay
|
||||
self.TestMultiLineLint(
|
||||
"""class Foo {
|
||||
"""
|
||||
class Foo {
|
||||
Foo(int f, int b);
|
||||
};""",
|
||||
'')
|
||||
# two argument constructor, across two lines, is okay
|
||||
self.TestMultiLineLint(
|
||||
"""class Foo {
|
||||
"""
|
||||
class Foo {
|
||||
Foo(int f,
|
||||
int b);
|
||||
};""",
|
||||
'')
|
||||
# non-constructor (but similar name), is okay
|
||||
self.TestMultiLineLint(
|
||||
"""class Foo {
|
||||
"""
|
||||
class Foo {
|
||||
aFoo(int f);
|
||||
};""",
|
||||
'')
|
||||
# constructor with void argument is okay
|
||||
self.TestMultiLineLint(
|
||||
"""class Foo {
|
||||
"""
|
||||
class Foo {
|
||||
Foo(void);
|
||||
};""",
|
||||
'')
|
||||
# single argument method is okay
|
||||
self.TestMultiLineLint(
|
||||
"""class Foo {
|
||||
"""
|
||||
class Foo {
|
||||
Bar(int b);
|
||||
};""",
|
||||
'')
|
||||
# comments should be ignored
|
||||
self.TestMultiLineLint(
|
||||
"""class Foo {
|
||||
"""
|
||||
class Foo {
|
||||
// Foo(int f);
|
||||
};""",
|
||||
'')
|
||||
# single argument function following class definition is okay
|
||||
# (okay, it's not actually valid, but we don't want a false positive)
|
||||
self.TestMultiLineLint(
|
||||
"""class Foo {
|
||||
"""
|
||||
class Foo {
|
||||
Foo(int f, int b);
|
||||
};
|
||||
Foo(int f);""",
|
||||
|
@ -988,18 +971,27 @@ class CpplintTest(CpplintTestBase):
|
|||
'')
|
||||
# single argument copy constructor is okay.
|
||||
self.TestMultiLineLint(
|
||||
"""class Foo {
|
||||
"""
|
||||
class Foo {
|
||||
Foo(const Foo&);
|
||||
};""",
|
||||
'')
|
||||
self.TestMultiLineLint(
|
||||
"""class Foo {
|
||||
"""
|
||||
class Foo {
|
||||
Foo(Foo const&);
|
||||
};""",
|
||||
'')
|
||||
self.TestMultiLineLint(
|
||||
"""
|
||||
class Foo {
|
||||
Foo(Foo&);
|
||||
};""",
|
||||
'')
|
||||
# templatized copy constructor is okay.
|
||||
self.TestMultiLineLint(
|
||||
"""template<typename T> class Foo {
|
||||
"""
|
||||
template<typename T> class Foo {
|
||||
Foo(const Foo<T>&);
|
||||
};""",
|
||||
'')
|
||||
|
@ -1267,7 +1259,8 @@ class CpplintTest(CpplintTestBase):
|
|||
'DISALLOW_COPY_AND_ASSIGN',
|
||||
'DISALLOW_IMPLICIT_CONSTRUCTORS'):
|
||||
self.TestMultiLineLint(
|
||||
"""class A {'
|
||||
"""
|
||||
class A {'
|
||||
public:
|
||||
%s(A);
|
||||
};""" % macro_name,
|
||||
|
@ -1275,14 +1268,16 @@ class CpplintTest(CpplintTestBase):
|
|||
' [readability/constructors] [3]')
|
||||
|
||||
self.TestMultiLineLint(
|
||||
"""struct B {'
|
||||
"""
|
||||
struct B {'
|
||||
%s(B);
|
||||
};""" % macro_name,
|
||||
('%s must be in the private: section' % macro_name) +
|
||||
' [readability/constructors] [3]')
|
||||
|
||||
self.TestMultiLineLint(
|
||||
"""class Outer1 {'
|
||||
"""
|
||||
class Outer1 {'
|
||||
private:
|
||||
struct Inner1 {
|
||||
%s(Inner1);
|
||||
|
@ -1293,7 +1288,8 @@ class CpplintTest(CpplintTestBase):
|
|||
' [readability/constructors] [3]')
|
||||
|
||||
self.TestMultiLineLint(
|
||||
"""class Outer2 {'
|
||||
"""
|
||||
class Outer2 {'
|
||||
private:
|
||||
class Inner2 {
|
||||
%s(Inner2);
|
||||
|
@ -1305,7 +1301,8 @@ class CpplintTest(CpplintTestBase):
|
|||
# correctly. Use different macros for inner and outer classes so
|
||||
# that we can tell the error messages apart.
|
||||
self.TestMultiLineLint(
|
||||
"""class Outer3 {
|
||||
"""
|
||||
class Outer3 {
|
||||
struct Inner3 {
|
||||
DISALLOW_EVIL_CONSTRUCTORS(Inner3);
|
||||
};
|
||||
|
@ -1314,7 +1311,8 @@ class CpplintTest(CpplintTestBase):
|
|||
('DISALLOW_EVIL_CONSTRUCTORS must be in the private: section'
|
||||
' [readability/constructors] [3]'))
|
||||
self.TestMultiLineLint(
|
||||
"""struct Outer4 {
|
||||
"""
|
||||
struct Outer4 {
|
||||
class Inner4 {
|
||||
DISALLOW_EVIL_CONSTRUCTORS(Inner4);
|
||||
};
|
||||
|
@ -1527,12 +1525,16 @@ class CpplintTest(CpplintTestBase):
|
|||
def testNonConstReference(self):
|
||||
# Passing a non-const reference as function parameter is forbidden.
|
||||
operand_error_message = ('Is this a non-const reference? '
|
||||
'If so, make const or use a pointer.'
|
||||
'If so, make const or use a pointer: %s'
|
||||
' [runtime/references] [2]')
|
||||
# Warn of use of a non-const reference in operators and functions
|
||||
self.TestLint('bool operator>(Foo& s, Foo& f);', operand_error_message)
|
||||
self.TestLint('bool operator+(Foo& s, Foo& f);', operand_error_message)
|
||||
self.TestLint('int len(Foo& s);', operand_error_message)
|
||||
self.TestLint('bool operator>(Foo& s, Foo& f);',
|
||||
[operand_error_message % 'Foo& s',
|
||||
operand_error_message % 'Foo& f'])
|
||||
self.TestLint('bool operator+(Foo& s, Foo& f);',
|
||||
[operand_error_message % 'Foo& s',
|
||||
operand_error_message % 'Foo& f'])
|
||||
self.TestLint('int len(Foo& s);', operand_error_message % 'Foo& s')
|
||||
# Allow use of non-const references in a few specific cases
|
||||
self.TestLint('stream& operator>>(stream& s, Foo& f);', '')
|
||||
self.TestLint('stream& operator<<(stream& s, Foo& f);', '')
|
||||
|
@ -1543,6 +1545,28 @@ class CpplintTest(CpplintTestBase):
|
|||
self.TestLint('void foo(const struct tm& tm);', '')
|
||||
# Passing a const reference to a typename is OK.
|
||||
self.TestLint('void foo(const typename tm& tm);', '')
|
||||
# Const reference to a pointer type is OK.
|
||||
self.TestLint('void foo(const Bar* const& p) {', '')
|
||||
self.TestLint('void foo(Bar const* const& p) {', '')
|
||||
self.TestLint('void foo(Bar* const& p) {', '')
|
||||
# Const reference to a templated type is OK.
|
||||
self.TestLint('void foo(const std::vector<std::string>& v);', '')
|
||||
# Non-const reference to a pointer type is not OK.
|
||||
self.TestLint('void foo(Bar*& p);',
|
||||
operand_error_message % 'Bar*& p')
|
||||
self.TestLint('void foo(const Bar*& p);',
|
||||
operand_error_message % 'const Bar*& p')
|
||||
self.TestLint('void foo(Bar const*& p);',
|
||||
operand_error_message % 'Bar const*& p')
|
||||
self.TestLint('void foo(struct Bar*& p);',
|
||||
operand_error_message % 'struct Bar*& p')
|
||||
self.TestLint('void foo(const struct Bar*& p);',
|
||||
operand_error_message % 'const struct Bar*& p')
|
||||
self.TestLint('void foo(struct Bar const*& p);',
|
||||
operand_error_message % 'struct Bar const*& p')
|
||||
# Non-const reference to a templated type is not OK.
|
||||
self.TestLint('void foo(std::vector<int>& p);',
|
||||
operand_error_message % 'std::vector<int>& p')
|
||||
# Returning an address of something is not prohibited.
|
||||
self.TestLint('return &something;', '')
|
||||
self.TestLint('if (condition) {return &something; }', '')
|
||||
|
@ -1556,6 +1580,34 @@ class CpplintTest(CpplintTestBase):
|
|||
self.TestLint('for (const string& s : c)', '')
|
||||
self.TestLint('for (auto& r : c)', '')
|
||||
self.TestLint('for (typename Type& a : b)', '')
|
||||
# We don't get confused by some other uses of '&'.
|
||||
self.TestLint('T& operator=(const T& t);', '')
|
||||
self.TestLint('int g() { return (a & b); }', '')
|
||||
self.TestLint('T& r = (T&)*(vp());', '')
|
||||
self.TestLint('T& r = v', '')
|
||||
self.TestLint('static_assert((kBits & kMask) == 0, "text");', '')
|
||||
self.TestLint('COMPILE_ASSERT((kBits & kMask) == 0, text);', '')
|
||||
|
||||
# Another potential false positive. This one needs full parser
|
||||
# state to reproduce as opposed to just TestLint.
|
||||
error_collector = ErrorCollector(self.assert_)
|
||||
cpplint.ProcessFileData(
|
||||
'foo.cc', 'cc',
|
||||
['// Copyright 2008 Your Company. All Rights Reserved.',
|
||||
'void swap(int &x,',
|
||||
' int &y) {',
|
||||
'}',
|
||||
'void swap(',
|
||||
' sparsegroup<T, GROUP_SIZE, Alloc> &x,',
|
||||
' sparsegroup<T, GROUP_SIZE, Alloc> &y) {',
|
||||
'}',
|
||||
'ostream& operator<<(',
|
||||
' ostream& out',
|
||||
' const dense_hash_set<Value, Hash, Equals, Alloc>& seq) {',
|
||||
'}',
|
||||
''],
|
||||
error_collector)
|
||||
self.assertEquals('', error_collector.Results())
|
||||
|
||||
def testBraceAtBeginOfLine(self):
|
||||
self.TestLint('{',
|
||||
|
@ -1628,6 +1680,7 @@ class CpplintTest(CpplintTestBase):
|
|||
self.TestLint('((a+b))', '')
|
||||
self.TestLint('foo (foo)', 'Extra space before ( in function call'
|
||||
' [whitespace/parens] [4]')
|
||||
self.TestLint('} catch (const Foo& ex) {', '')
|
||||
self.TestLint('typedef foo (*foo)(foo)', '')
|
||||
self.TestLint('typedef foo (*foo12bar_)(foo)', '')
|
||||
self.TestLint('typedef foo (Foo::*bar)(foo)', '')
|
||||
|
@ -1652,6 +1705,15 @@ class CpplintTest(CpplintTestBase):
|
|||
self.TestLint('for {', '')
|
||||
self.TestLint('EXPECT_DEBUG_DEATH({', '')
|
||||
|
||||
def testSemiColonAfterBraces(self):
|
||||
self.TestLint('if (cond) {};',
|
||||
'You don\'t need a ; after a } [readability/braces] [4]')
|
||||
self.TestLint('class X {};', '')
|
||||
self.TestLint('struct X {};', '')
|
||||
self.TestLint('union {} x;', '')
|
||||
self.TestLint('union {};', '')
|
||||
self.TestLint('union {};', '')
|
||||
|
||||
def testSpacingAroundElse(self):
|
||||
self.TestLint('}else {', 'Missing space before else'
|
||||
' [whitespace/braces] [5]')
|
||||
|
@ -2211,24 +2273,76 @@ class CpplintTest(CpplintTestBase):
|
|||
self.TestLint(' char* one_space_indent = "public:";',
|
||||
'Weird number of spaces at line-start. '
|
||||
'Are you using a 2-space indent? [whitespace/indent] [3]')
|
||||
self.TestLint(' public:', '')
|
||||
self.TestLint(' public:', '')
|
||||
self.TestLint(' public:', '')
|
||||
|
||||
def testLabel(self):
|
||||
self.TestLint('public:',
|
||||
'Labels should always be indented at least one space. '
|
||||
'If this is a member-initializer list in a constructor or '
|
||||
'the base class list in a class definition, the colon should '
|
||||
'be on the following line. [whitespace/labels] [4]')
|
||||
self.TestLint(' public:', '')
|
||||
self.TestLint(' public:', '')
|
||||
self.TestLint(' public:', '')
|
||||
self.TestLint(' public:', '')
|
||||
self.TestLint(' public:', '')
|
||||
|
||||
def testNotALabel(self):
|
||||
self.TestLint('MyVeryLongNamespace::MyVeryLongClassName::', '')
|
||||
def testSectionIndent(self):
|
||||
self.TestMultiLineLint(
|
||||
"""
|
||||
class A {
|
||||
public: // no warning
|
||||
private: // warning here
|
||||
};""",
|
||||
'private: should be indented +1 space inside class A'
|
||||
' [whitespace/indent] [3]')
|
||||
self.TestMultiLineLint(
|
||||
"""
|
||||
class B {
|
||||
public: // no warning
|
||||
template<> struct C {
|
||||
public: // warning here
|
||||
protected: // no warning
|
||||
};
|
||||
};""",
|
||||
'public: should be indented +1 space inside struct C'
|
||||
' [whitespace/indent] [3]')
|
||||
self.TestMultiLineLint(
|
||||
"""
|
||||
struct D {
|
||||
};""",
|
||||
'Closing brace should be aligned with beginning of struct D'
|
||||
' [whitespace/indent] [3]')
|
||||
self.TestMultiLineLint(
|
||||
"""
|
||||
template<typename E> class F {
|
||||
};""",
|
||||
'Closing brace should be aligned with beginning of class F'
|
||||
' [whitespace/indent] [3]')
|
||||
self.TestMultiLineLint(
|
||||
"""
|
||||
class G {
|
||||
Q_OBJECT
|
||||
public slots:
|
||||
signals:
|
||||
};""",
|
||||
['public slots: should be indented +1 space inside class G'
|
||||
' [whitespace/indent] [3]',
|
||||
'signals: should be indented +1 space inside class G'
|
||||
' [whitespace/indent] [3]'])
|
||||
self.TestMultiLineLint(
|
||||
"""
|
||||
class H {
|
||||
/* comments */ class I {
|
||||
public: // no warning
|
||||
private: // warning here
|
||||
};
|
||||
};""",
|
||||
'private: should be indented +1 space inside class I'
|
||||
' [whitespace/indent] [3]')
|
||||
self.TestMultiLineLint(
|
||||
"""
|
||||
class J
|
||||
: public ::K {
|
||||
public: // no warning
|
||||
protected: // warning here
|
||||
};""",
|
||||
'protected: should be indented +1 space inside class J'
|
||||
' [whitespace/indent] [3]')
|
||||
self.TestMultiLineLint(
|
||||
"""
|
||||
class L
|
||||
: public M,
|
||||
public ::N {
|
||||
};""",
|
||||
'')
|
||||
|
||||
def testTab(self):
|
||||
self.TestLint('\tint a;',
|
||||
|
@ -2368,7 +2482,8 @@ class CpplintTest(CpplintTestBase):
|
|||
};""",
|
||||
'')
|
||||
self.TestMultiLineLint(
|
||||
"""class Foo
|
||||
"""
|
||||
class Foo
|
||||
#ifdef DERIVE_FROM_GOO
|
||||
: public Goo {
|
||||
#else
|
||||
|
@ -2966,7 +3081,13 @@ class OrderOfIncludesTest(CpplintTestBase):
|
|||
|
||||
def testRegression(self):
|
||||
def Format(includes):
|
||||
return ''.join(['#include %s\n' % include for include in includes])
|
||||
include_list = []
|
||||
for header_path in includes:
|
||||
if header_path:
|
||||
include_list.append('#include %s\n' % header_path)
|
||||
else:
|
||||
include_list.append('\n')
|
||||
return ''.join(include_list)
|
||||
|
||||
# Test singleton cases first.
|
||||
self.TestLanguageRulesCheck('foo/foo.cc', Format(['"foo/foo.h"']), '')
|
||||
|
@ -2998,6 +3119,17 @@ class OrderOfIncludesTest(CpplintTestBase):
|
|||
Format(['"foo/bar-inl.h"',
|
||||
'"foo/foo-inl.h"']),
|
||||
'')
|
||||
self.TestLanguageRulesCheck(
|
||||
'foo/foo.cc',
|
||||
Format(['"foo/e.h"',
|
||||
'"foo/b.h"', # warning here (e>b)
|
||||
'"foo/c.h"',
|
||||
'"foo/d.h"',
|
||||
'"foo/a.h"']), # warning here (d>a)
|
||||
['Include "foo/b.h" not in alphabetical order'
|
||||
' [build/include_alpha] [4]',
|
||||
'Include "foo/a.h" not in alphabetical order'
|
||||
' [build/include_alpha] [4]'])
|
||||
# -inl.h headers are no longer special.
|
||||
self.TestLanguageRulesCheck('foo/foo.cc',
|
||||
Format(['"foo/foo-inl.h"', '<string>']),
|
||||
|
@ -3030,6 +3162,21 @@ class OrderOfIncludesTest(CpplintTestBase):
|
|||
'"base/google.h"',
|
||||
'"base/google-inl.h"']),
|
||||
'')
|
||||
# Allow project includes to be separated by blank lines
|
||||
self.TestLanguageRulesCheck('a/a.cc',
|
||||
Format(['"a/a.h"',
|
||||
'<string>',
|
||||
'"base/google.h"',
|
||||
'',
|
||||
'"a/b.h"']),
|
||||
'')
|
||||
self.TestLanguageRulesCheck('a/a.cc',
|
||||
Format(['"a/a.h"',
|
||||
'<string>',
|
||||
'"base/google.h"',
|
||||
'"a/b.h"']),
|
||||
'Include "a/b.h" not in alphabetical '
|
||||
'order [build/include_alpha] [4]')
|
||||
|
||||
|
||||
class CheckForFunctionLengthsTest(CpplintTestBase):
|
||||
|
@ -3386,6 +3533,7 @@ class NestnigStateTest(unittest.TestCase):
|
|||
self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo))
|
||||
self.assertEquals(self.nesting_state.stack[0].name, 'A')
|
||||
self.assertFalse(self.nesting_state.stack[0].is_derived)
|
||||
self.assertEquals(self.nesting_state.stack[0].class_indent, 0)
|
||||
|
||||
self.UpdateWithLines(['};',
|
||||
'struct B : public A {'])
|
||||
|
@ -3414,6 +3562,7 @@ class NestnigStateTest(unittest.TestCase):
|
|||
self.assertTrue(isinstance(self.nesting_state.stack[1], cpplint._ClassInfo))
|
||||
self.assertEquals(self.nesting_state.stack[1].name, 'E')
|
||||
self.assertFalse(self.nesting_state.stack[1].is_derived)
|
||||
self.assertEquals(self.nesting_state.stack[1].class_indent, 2)
|
||||
self.assertEquals(self.nesting_state.InnermostClass().name, 'E')
|
||||
|
||||
self.UpdateWithLines(['}', '}'])
|
||||
|
@ -3553,6 +3702,18 @@ class NestnigStateTest(unittest.TestCase):
|
|||
self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo))
|
||||
self.assertEquals(self.nesting_state.stack[0].name, 'D')
|
||||
|
||||
def testTemplateInnerClass(self):
|
||||
self.UpdateWithLines(['class A {',
|
||||
' public:'])
|
||||
self.assertEquals(len(self.nesting_state.stack), 1)
|
||||
self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo))
|
||||
|
||||
self.UpdateWithLines([' template <class B>',
|
||||
' class C<alloc<B> >',
|
||||
' : public A {'])
|
||||
self.assertEquals(len(self.nesting_state.stack), 2)
|
||||
self.assertTrue(isinstance(self.nesting_state.stack[1], cpplint._ClassInfo))
|
||||
|
||||
def testArguments(self):
|
||||
self.UpdateWithLines(['class A {'])
|
||||
self.assertEquals(len(self.nesting_state.stack), 1)
|
||||
|
|
Loading…
Reference in New Issue
Block a user