mirror of
https://github.com/google/styleguide.git
synced 2024-03-22 13:11:43 +08:00
Update to #179:
- Suggest "const_cast" when encountering "(char*)". - Warn on template arguments to make_pair(). - Require <utility> if pair<> is seen now that <map> doesn't include it. - Warn on lack of "explicit" keyword on single argument inline constructors. - Better check for hanging ')' when closing function calls. - Don't warn on: 'int v[1][3] = {{1, 2, 3}};' - Allow function calls as the first argument to printf(). Review URL: http://codereview.appspot.com/4974066
This commit is contained in:
parent
efeacdf0fa
commit
8a95ecca27
293
cpplint/cpplint.py
vendored
293
cpplint/cpplint.py
vendored
|
@ -150,6 +150,7 @@ _ERROR_CATEGORIES = [
|
||||||
'build/class',
|
'build/class',
|
||||||
'build/deprecated',
|
'build/deprecated',
|
||||||
'build/endif_comment',
|
'build/endif_comment',
|
||||||
|
'build/explicit_make_pair',
|
||||||
'build/forward_decl',
|
'build/forward_decl',
|
||||||
'build/header_guard',
|
'build/header_guard',
|
||||||
'build/include',
|
'build/include',
|
||||||
|
@ -214,7 +215,7 @@ _DEFAULT_FILTERS = [ '-build/include_alpha' ]
|
||||||
|
|
||||||
# We used to check for high-bit characters, but after much discussion we
|
# We used to check for high-bit characters, but after much discussion we
|
||||||
# decided those were OK, as long as they were in UTF-8 and didn't represent
|
# decided those were OK, as long as they were in UTF-8 and didn't represent
|
||||||
# hard-coded international strings, which belong in a seperate i18n file.
|
# hard-coded international strings, which belong in a separate i18n file.
|
||||||
|
|
||||||
# Headers that we consider STL headers.
|
# Headers that we consider STL headers.
|
||||||
_STL_HEADERS = frozenset([
|
_STL_HEADERS = frozenset([
|
||||||
|
@ -310,9 +311,9 @@ def ParseNolintSuppressions(filename, raw_line, linenum, error):
|
||||||
error: function, an error handler.
|
error: function, an error handler.
|
||||||
"""
|
"""
|
||||||
# FIXME(adonovan): "NOLINT(" is misparsed as NOLINT(*).
|
# FIXME(adonovan): "NOLINT(" is misparsed as NOLINT(*).
|
||||||
m = _RE_SUPPRESSION.search(raw_line)
|
matched = _RE_SUPPRESSION.search(raw_line)
|
||||||
if m:
|
if matched:
|
||||||
category = m.group(1)
|
category = matched.group(1)
|
||||||
if category in (None, '(*)'): # => "suppress all"
|
if category in (None, '(*)'): # => "suppress all"
|
||||||
_error_suppressions.setdefault(None, set()).add(linenum)
|
_error_suppressions.setdefault(None, set()).add(linenum)
|
||||||
else:
|
else:
|
||||||
|
@ -404,7 +405,7 @@ class _IncludeState(dict):
|
||||||
self._last_header = ''
|
self._last_header = ''
|
||||||
|
|
||||||
def CanonicalizeAlphabeticalOrder(self, header_path):
|
def CanonicalizeAlphabeticalOrder(self, header_path):
|
||||||
"""Returns a path canonicalized for alphabetical comparisson.
|
"""Returns a path canonicalized for alphabetical comparison.
|
||||||
|
|
||||||
- replaces "-" with "_" so they both cmp the same.
|
- replaces "-" with "_" so they both cmp the same.
|
||||||
- removes '-inl' since we don't require them to be after the main header.
|
- removes '-inl' since we don't require them to be after the main header.
|
||||||
|
@ -662,7 +663,7 @@ class _FunctionState(object):
|
||||||
self.current_function, self.lines_in_function, trigger))
|
self.current_function, self.lines_in_function, trigger))
|
||||||
|
|
||||||
def End(self):
|
def End(self):
|
||||||
"""Stop analizing function body."""
|
"""Stop analyzing function body."""
|
||||||
self.in_a_function = False
|
self.in_a_function = False
|
||||||
|
|
||||||
|
|
||||||
|
@ -760,8 +761,7 @@ class FileInfo:
|
||||||
|
|
||||||
|
|
||||||
def _ShouldPrintError(category, confidence, linenum):
|
def _ShouldPrintError(category, confidence, linenum):
|
||||||
"""Returns true iff confidence >= verbose, category passes
|
"""If confidence >= verbose, category passes filter and is not suppressed."""
|
||||||
filter and is not NOLINT-suppressed."""
|
|
||||||
|
|
||||||
# There are three ways we might decide not to print an error message:
|
# There are three ways we might decide not to print an error message:
|
||||||
# a "NOLINT(category)" comment appears in the source,
|
# a "NOLINT(category)" comment appears in the source,
|
||||||
|
@ -966,7 +966,7 @@ class CleansedLines(object):
|
||||||
def CloseExpression(clean_lines, linenum, pos):
|
def CloseExpression(clean_lines, linenum, pos):
|
||||||
"""If input points to ( or { or [, finds the position that closes it.
|
"""If input points to ( or { or [, finds the position that closes it.
|
||||||
|
|
||||||
If lines[linenum][pos] points to a '(' or '{' or '[', finds the the
|
If lines[linenum][pos] points to a '(' or '{' or '[', finds the
|
||||||
linenum/pos that correspond to the closing of the expression.
|
linenum/pos that correspond to the closing of the expression.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -1248,7 +1248,7 @@ def CheckInvalidIncrement(filename, clean_lines, linenum, error):
|
||||||
class _ClassInfo(object):
|
class _ClassInfo(object):
|
||||||
"""Stores information about a class."""
|
"""Stores information about a class."""
|
||||||
|
|
||||||
def __init__(self, name, linenum):
|
def __init__(self, name, clean_lines, linenum):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.linenum = linenum
|
self.linenum = linenum
|
||||||
self.seen_open_brace = False
|
self.seen_open_brace = False
|
||||||
|
@ -1257,6 +1257,20 @@ class _ClassInfo(object):
|
||||||
self.has_virtual_destructor = False
|
self.has_virtual_destructor = False
|
||||||
self.brace_depth = 0
|
self.brace_depth = 0
|
||||||
|
|
||||||
|
# Try to find the end of the class. This will be confused by things like:
|
||||||
|
# class A {
|
||||||
|
# } *x = { ...
|
||||||
|
#
|
||||||
|
# But it's still good enough for CheckSectionSpacing.
|
||||||
|
self.last_line = 0
|
||||||
|
depth = 0
|
||||||
|
for i in range(linenum, clean_lines.NumLines()):
|
||||||
|
line = clean_lines.lines[i]
|
||||||
|
depth += line.count('{') - line.count('}')
|
||||||
|
if not depth:
|
||||||
|
self.last_line = i
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
class _ClassState(object):
|
class _ClassState(object):
|
||||||
"""Holds the current state of the parse relating to class declarations.
|
"""Holds the current state of the parse relating to class declarations.
|
||||||
|
@ -1383,9 +1397,11 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum,
|
||||||
# class LOCKABLE API Object {
|
# class LOCKABLE API Object {
|
||||||
# };
|
# };
|
||||||
class_decl_match = Match(
|
class_decl_match = Match(
|
||||||
r'\s*(template\s*<[\w\s<>,:]*>\s*)?(class|struct)\s+([A-Z_]+\s+)*(\w+(::\w+)*)', line)
|
r'\s*(template\s*<[\w\s<>,:]*>\s*)?'
|
||||||
|
'(class|struct)\s+([A-Z_]+\s+)*(\w+(::\w+)*)', line)
|
||||||
if class_decl_match:
|
if class_decl_match:
|
||||||
classinfo_stack.append(_ClassInfo(class_decl_match.group(4), linenum))
|
classinfo_stack.append(_ClassInfo(
|
||||||
|
class_decl_match.group(4), clean_lines, linenum))
|
||||||
|
|
||||||
# Everything else in this function uses the top of the stack if it's
|
# Everything else in this function uses the top of the stack if it's
|
||||||
# not empty.
|
# not empty.
|
||||||
|
@ -1415,12 +1431,12 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum,
|
||||||
|
|
||||||
# Look for single-argument constructors that aren't marked explicit.
|
# Look for single-argument constructors that aren't marked explicit.
|
||||||
# Technically a valid construct, but against style.
|
# Technically a valid construct, but against style.
|
||||||
args = Match(r'(?<!explicit)\s+%s\s*\(([^,()]+)\)'
|
args = Match(r'\s+(?:inline\s+)?%s\s*\(([^,()]+)\)'
|
||||||
% re.escape(base_classname),
|
% re.escape(base_classname),
|
||||||
line)
|
line)
|
||||||
if (args and
|
if (args and
|
||||||
args.group(1) != 'void' and
|
args.group(1) != 'void' and
|
||||||
not Match(r'(const\s+)?%s\s*&' % re.escape(base_classname),
|
not Match(r'(const\s+)?%s\s*(?:<\w+>\s*)?&' % re.escape(base_classname),
|
||||||
args.group(1).strip())):
|
args.group(1).strip())):
|
||||||
error(filename, linenum, 'runtime/explicit', 5,
|
error(filename, linenum, 'runtime/explicit', 5,
|
||||||
'Single-argument constructors should be marked explicit.')
|
'Single-argument constructors should be marked explicit.')
|
||||||
|
@ -1511,6 +1527,12 @@ def CheckSpacingForFunctionCall(filename, line, linenum, error):
|
||||||
# If the ) is followed only by a newline or a { + newline, assume it's
|
# If the ) is followed only by a newline or a { + newline, assume it's
|
||||||
# part of a control statement (if/while/etc), and don't complain
|
# part of a control statement (if/while/etc), and don't complain
|
||||||
if Search(r'[^)]\s+\)\s*[^{\s]', fncall):
|
if Search(r'[^)]\s+\)\s*[^{\s]', fncall):
|
||||||
|
# If the closing parenthesis is preceded by only whitespaces,
|
||||||
|
# try to give a more descriptive error message.
|
||||||
|
if Search(r'^\s+\)', fncall):
|
||||||
|
error(filename, linenum, 'whitespace/parens', 2,
|
||||||
|
'Closing ) should be moved to the previous line')
|
||||||
|
else:
|
||||||
error(filename, linenum, 'whitespace/parens', 2,
|
error(filename, linenum, 'whitespace/parens', 2,
|
||||||
'Extra space before )')
|
'Extra space before )')
|
||||||
|
|
||||||
|
@ -1543,7 +1565,7 @@ def CheckForFunctionLengths(filename, clean_lines, linenum,
|
||||||
Trivial bodies are unchecked, so constructors with huge initializer lists
|
Trivial bodies are unchecked, so constructors with huge initializer lists
|
||||||
may be missed.
|
may be missed.
|
||||||
Blank/comment lines are not counted so as to avoid encouraging the removal
|
Blank/comment lines are not counted so as to avoid encouraging the removal
|
||||||
of vertical space and commments just to get through a lint check.
|
of vertical space and comments just to get through a lint check.
|
||||||
NOLINT *on the last line of a function* disables this check.
|
NOLINT *on the last line of a function* disables this check.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -1639,8 +1661,8 @@ def CheckSpacing(filename, clean_lines, linenum, error):
|
||||||
Things we check for: spaces around operators, spaces after
|
Things we check for: spaces around operators, spaces after
|
||||||
if/for/while/switch, no spaces around parens in function calls, two
|
if/for/while/switch, no spaces around parens in function calls, two
|
||||||
spaces between code and comment, don't start a block with a blank
|
spaces between code and comment, don't start a block with a blank
|
||||||
line, don't end a function with a blank line, don't have too many
|
line, don't end a function with a blank line, don't add a blank line
|
||||||
blank lines in a row.
|
after public/protected/private, don't have too many blank lines in a row.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
filename: The name of the current file.
|
filename: The name of the current file.
|
||||||
|
@ -1667,7 +1689,7 @@ def CheckSpacing(filename, clean_lines, linenum, error):
|
||||||
and prev_line[:prevbrace].find('namespace') == -1):
|
and prev_line[:prevbrace].find('namespace') == -1):
|
||||||
# OK, we have a blank line at the start of a code block. Before we
|
# OK, we have a blank line at the start of a code block. Before we
|
||||||
# complain, we check if it is an exception to the rule: The previous
|
# complain, we check if it is an exception to the rule: The previous
|
||||||
# non-empty line has the paramters of a function header that are indented
|
# non-empty line has the parameters of a function header that are indented
|
||||||
# 4 spaces (because they did not fit in a 80 column line when placed on
|
# 4 spaces (because they did not fit in a 80 column line when placed on
|
||||||
# the same line as the function name). We also check for the case where
|
# the same line as the function name). We also check for the case where
|
||||||
# the previous line is indented 6 spaces, which may happen when the
|
# the previous line is indented 6 spaces, which may happen when the
|
||||||
|
@ -1718,6 +1740,11 @@ def CheckSpacing(filename, clean_lines, linenum, error):
|
||||||
error(filename, linenum, 'whitespace/blank_line', 3,
|
error(filename, linenum, 'whitespace/blank_line', 3,
|
||||||
'Blank line at the end of a code block. Is this needed?')
|
'Blank line at the end of a code block. Is this needed?')
|
||||||
|
|
||||||
|
matched = Match(r'\s*(public|protected|private):', prev_line)
|
||||||
|
if matched:
|
||||||
|
error(filename, linenum, 'whitespace/blank_line', 3,
|
||||||
|
'Do not leave a blank line after "%s:"' % matched.group(1))
|
||||||
|
|
||||||
# Next, we complain if there's a comment too near the text
|
# Next, we complain if there's a comment too near the text
|
||||||
commentpos = line.find('//')
|
commentpos = line.find('//')
|
||||||
if commentpos != -1:
|
if commentpos != -1:
|
||||||
|
@ -1838,10 +1865,11 @@ def CheckSpacing(filename, clean_lines, linenum, error):
|
||||||
# Next we will look for issues with function calls.
|
# Next we will look for issues with function calls.
|
||||||
CheckSpacingForFunctionCall(filename, line, linenum, error)
|
CheckSpacingForFunctionCall(filename, line, linenum, error)
|
||||||
|
|
||||||
# Except after an opening paren, you should have spaces before your braces.
|
# Except after an opening paren, or after another opening brace (in case of
|
||||||
# And since you should never have braces at the beginning of a line, this is
|
# an initializer list, for instance), you should have spaces before your
|
||||||
# an easy test.
|
# braces. And since you should never have braces at the beginning of a line,
|
||||||
if Search(r'[^ (]{', line):
|
# this is an easy test.
|
||||||
|
if Search(r'[^ ({]{', line):
|
||||||
error(filename, linenum, 'whitespace/braces', 5,
|
error(filename, linenum, 'whitespace/braces', 5,
|
||||||
'Missing space before {')
|
'Missing space before {')
|
||||||
|
|
||||||
|
@ -1873,6 +1901,58 @@ def CheckSpacing(filename, clean_lines, linenum, error):
|
||||||
'statement, use { } instead.')
|
'statement, use { } instead.')
|
||||||
|
|
||||||
|
|
||||||
|
def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error):
|
||||||
|
"""Checks for additional blank line issues related to sections.
|
||||||
|
|
||||||
|
Currently the only thing checked here is blank line before protected/private.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
filename: The name of the current file.
|
||||||
|
clean_lines: A CleansedLines instance containing the file.
|
||||||
|
class_info: A _ClassInfo objects.
|
||||||
|
linenum: The number of the line to check.
|
||||||
|
error: The function to call with any errors found.
|
||||||
|
"""
|
||||||
|
# Skip checks if the class is small, where small means 25 lines or less.
|
||||||
|
# 25 lines seems like a good cutoff since that's the usual height of
|
||||||
|
# terminals, and any class that can't fit in one screen can't really
|
||||||
|
# be considered "small".
|
||||||
|
#
|
||||||
|
# Also skip checks if we are on the first line. This accounts for
|
||||||
|
# classes that look like
|
||||||
|
# class Foo { public: ... };
|
||||||
|
#
|
||||||
|
# If we didn't find the end of the class, last_line would be zero,
|
||||||
|
# and the check will be skipped by the first condition.
|
||||||
|
if (class_info.last_line - class_info.linenum <= 24 or
|
||||||
|
linenum <= class_info.linenum):
|
||||||
|
return
|
||||||
|
|
||||||
|
matched = Match(r'\s*(public|protected|private):', clean_lines.lines[linenum])
|
||||||
|
if matched:
|
||||||
|
# Issue warning if the line before public/protected/private was
|
||||||
|
# not a blank line, but don't do this if the previous line contains
|
||||||
|
# "class" or "struct". This can happen two ways:
|
||||||
|
# - We are at the beginning of the class.
|
||||||
|
# - We are forward-declaring an inner class that is semantically
|
||||||
|
# private, but needed to be public for implementation reasons.
|
||||||
|
prev_line = clean_lines.lines[linenum - 1]
|
||||||
|
if (not IsBlankLine(prev_line) and
|
||||||
|
not Search(r'\b(class|struct)\b', prev_line)):
|
||||||
|
# Try a bit harder to find the beginning of the class. This is to
|
||||||
|
# account for multi-line base-specifier lists, e.g.:
|
||||||
|
# class Derived
|
||||||
|
# : public Base {
|
||||||
|
end_class_head = class_info.linenum
|
||||||
|
for i in range(class_info.linenum, linenum):
|
||||||
|
if Search(r'\{\s*$', clean_lines.lines[i]):
|
||||||
|
end_class_head = i
|
||||||
|
break
|
||||||
|
if end_class_head < linenum - 1:
|
||||||
|
error(filename, linenum, 'whitespace/blank_line', 3,
|
||||||
|
'"%s:" should be preceded by a blank line' % matched.group(1))
|
||||||
|
|
||||||
|
|
||||||
def GetPreviousNonBlankLine(clean_lines, linenum):
|
def GetPreviousNonBlankLine(clean_lines, linenum):
|
||||||
"""Return the most recent non-blank line and its line number.
|
"""Return the most recent non-blank line and its line number.
|
||||||
|
|
||||||
|
@ -2050,17 +2130,18 @@ def GetLineWidth(line):
|
||||||
"""
|
"""
|
||||||
if isinstance(line, unicode):
|
if isinstance(line, unicode):
|
||||||
width = 0
|
width = 0
|
||||||
for c in unicodedata.normalize('NFC', line):
|
for uc in unicodedata.normalize('NFC', line):
|
||||||
if unicodedata.east_asian_width(c) in ('W', 'F'):
|
if unicodedata.east_asian_width(uc) in ('W', 'F'):
|
||||||
width += 2
|
width += 2
|
||||||
elif not unicodedata.combining(c):
|
elif not unicodedata.combining(uc):
|
||||||
width += 1
|
width += 1
|
||||||
return width
|
return width
|
||||||
else:
|
else:
|
||||||
return len(line)
|
return len(line)
|
||||||
|
|
||||||
|
|
||||||
def CheckStyle(filename, clean_lines, linenum, file_extension, error):
|
def CheckStyle(filename, clean_lines, linenum, file_extension, class_state,
|
||||||
|
error):
|
||||||
"""Checks rules from the 'C++ style rules' section of cppguide.html.
|
"""Checks rules from the 'C++ style rules' section of cppguide.html.
|
||||||
|
|
||||||
Most of these rules are hard to test (naming, comment style), but we
|
Most of these rules are hard to test (naming, comment style), but we
|
||||||
|
@ -2160,6 +2241,9 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, error):
|
||||||
CheckBraces(filename, clean_lines, linenum, error)
|
CheckBraces(filename, clean_lines, linenum, error)
|
||||||
CheckSpacing(filename, clean_lines, linenum, error)
|
CheckSpacing(filename, clean_lines, linenum, error)
|
||||||
CheckCheck(filename, clean_lines, linenum, error)
|
CheckCheck(filename, clean_lines, linenum, error)
|
||||||
|
if class_state and class_state.classinfo_stack:
|
||||||
|
CheckSectionSpacing(filename, clean_lines,
|
||||||
|
class_state.classinfo_stack[-1], linenum, error)
|
||||||
|
|
||||||
|
|
||||||
_RE_PATTERN_INCLUDE_NEW_STYLE = re.compile(r'#include +"[^/]+\.h"')
|
_RE_PATTERN_INCLUDE_NEW_STYLE = re.compile(r'#include +"[^/]+\.h"')
|
||||||
|
@ -2345,6 +2429,63 @@ def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
|
||||||
error(filename, linenum, 'readability/streams', 3,
|
error(filename, linenum, 'readability/streams', 3,
|
||||||
'Streams are highly discouraged.')
|
'Streams are highly discouraged.')
|
||||||
|
|
||||||
|
|
||||||
|
def _GetTextInside(text, start_pattern):
|
||||||
|
"""Retrieves all the text between matching open and close parentheses.
|
||||||
|
|
||||||
|
Given a string of lines and a regular expression string, retrieve all the text
|
||||||
|
following the expression and between opening punctuation symbols like
|
||||||
|
(, [, or {, and the matching close-punctuation symbol. This properly nested
|
||||||
|
occurrences of the punctuations, so for the text like
|
||||||
|
printf(a(), b(c()));
|
||||||
|
a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'.
|
||||||
|
start_pattern must match string having an open punctuation symbol at the end.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: The lines to extract text. Its comments and strings must be elided.
|
||||||
|
It can be single line and can span multiple lines.
|
||||||
|
start_pattern: The regexp string indicating where to start extracting
|
||||||
|
the text.
|
||||||
|
Returns:
|
||||||
|
The extracted text.
|
||||||
|
None if either the opening string or ending punctuation could not be found.
|
||||||
|
"""
|
||||||
|
# TODO(sugawarayu): Audit cpplint.py to see what places could be profitably
|
||||||
|
# rewritten to use _GetTextInside (and use inferior regexp matching today).
|
||||||
|
|
||||||
|
# Give opening punctuations to get the matching close-punctuations.
|
||||||
|
matching_punctuation = {'(': ')', '{': '}', '[': ']'}
|
||||||
|
closing_punctuation = set(matching_punctuation.itervalues())
|
||||||
|
|
||||||
|
# Find the position to start extracting text.
|
||||||
|
match = re.search(start_pattern, text, re.M)
|
||||||
|
if not match: # start_pattern not found in text.
|
||||||
|
return None
|
||||||
|
start_position = match.end(0)
|
||||||
|
|
||||||
|
assert start_position > 0, (
|
||||||
|
'start_pattern must ends with an opening punctuation.')
|
||||||
|
assert text[start_position - 1] in matching_punctuation, (
|
||||||
|
'start_pattern must ends with an opening punctuation.')
|
||||||
|
# Stack of closing punctuations we expect to have in text after position.
|
||||||
|
punctuation_stack = [matching_punctuation[text[start_position - 1]]]
|
||||||
|
position = start_position
|
||||||
|
while punctuation_stack and position < len(text):
|
||||||
|
if text[position] == punctuation_stack[-1]:
|
||||||
|
punctuation_stack.pop()
|
||||||
|
elif text[position] in closing_punctuation:
|
||||||
|
# A closing punctuation without matching opening punctuations.
|
||||||
|
return None
|
||||||
|
elif text[position] in matching_punctuation:
|
||||||
|
punctuation_stack.append(matching_punctuation[text[position]])
|
||||||
|
position += 1
|
||||||
|
if punctuation_stack:
|
||||||
|
# Opening punctuations left without matching close-punctuations.
|
||||||
|
return None
|
||||||
|
# punctuations match.
|
||||||
|
return text[start_position:position - 1]
|
||||||
|
|
||||||
|
|
||||||
def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
|
def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
|
||||||
error):
|
error):
|
||||||
"""Checks rules from the 'C++ language rules' section of cppguide.html.
|
"""Checks rules from the 'C++ language rules' section of cppguide.html.
|
||||||
|
@ -2390,7 +2531,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
|
||||||
# These are complicated re's. They try to capture the following:
|
# These are complicated re's. They try to capture the following:
|
||||||
# paren (for fn-prototype start), typename, &, varname. For the const
|
# paren (for fn-prototype start), typename, &, varname. For the const
|
||||||
# version, we're willing for const to be before typename or after
|
# version, we're willing for const to be before typename or after
|
||||||
# Don't check the implemention on same line.
|
# Don't check the implementation on same line.
|
||||||
fnline = line.split('{', 1)[0]
|
fnline = line.split('{', 1)[0]
|
||||||
if (len(re.findall(r'\([^()]*\b(?:[\w:]|<[^()]*>)+(\s?&|&\s?)\w+', fnline)) >
|
if (len(re.findall(r'\([^()]*\b(?:[\w:]|<[^()]*>)+(\s?&|&\s?)\w+', fnline)) >
|
||||||
len(re.findall(r'\([^()]*\bconst\s+(?:typename\s+)?(?:struct\s+)?'
|
len(re.findall(r'\([^()]*\bconst\s+(?:typename\s+)?(?:struct\s+)?'
|
||||||
|
@ -2430,9 +2571,17 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
|
||||||
|
|
||||||
CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
|
CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
|
||||||
'static_cast',
|
'static_cast',
|
||||||
r'\((int|float|double|bool|char|u?int(16|32|64))\)',
|
r'\((int|float|double|bool|char|u?int(16|32|64))\)', error)
|
||||||
error)
|
|
||||||
# This doesn't catch all cases. Consider (const char * const)"hello".
|
# This doesn't catch all cases. Consider (const char * const)"hello".
|
||||||
|
#
|
||||||
|
# (char *) "foo" should always be a const_cast (reinterpret_cast won't
|
||||||
|
# compile).
|
||||||
|
if CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
|
||||||
|
'const_cast', r'\((char\s?\*+\s?)\)\s*"', error):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# Check pointer casts for other than string constants
|
||||||
CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
|
CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
|
||||||
'reinterpret_cast', r'\((\w+\s?\*+\s?)\)', error)
|
'reinterpret_cast', r'\((\w+\s?\*+\s?)\)', error)
|
||||||
|
|
||||||
|
@ -2533,11 +2682,19 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
|
||||||
# Check for potential format string bugs like printf(foo).
|
# Check for potential format string bugs like printf(foo).
|
||||||
# We constrain the pattern not to pick things like DocidForPrintf(foo).
|
# We constrain the pattern not to pick things like DocidForPrintf(foo).
|
||||||
# Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str())
|
# Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str())
|
||||||
match = re.search(r'\b((?:string)?printf)\s*\(([\w.\->()]+)\)', line, re.I)
|
# TODO(sugawarayu): Catch the following case. Need to change the calling
|
||||||
|
# convention of the whole function to process multiple line to handle it.
|
||||||
|
# printf(
|
||||||
|
# boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line);
|
||||||
|
printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(')
|
||||||
|
if printf_args:
|
||||||
|
match = Match(r'([\w.\->()]+)$', printf_args)
|
||||||
if match:
|
if match:
|
||||||
|
function_name = re.search(r'\b((?:string)?printf)\s*\(',
|
||||||
|
line, re.I).group(1)
|
||||||
error(filename, linenum, 'runtime/printf', 4,
|
error(filename, linenum, 'runtime/printf', 4,
|
||||||
'Potential format string bug. Do %s("%%s", %s) instead.'
|
'Potential format string bug. Do %s("%%s", %s) instead.'
|
||||||
% (match.group(1), match.group(2)))
|
% (function_name, match.group(1)))
|
||||||
|
|
||||||
# Check for potential memset bugs like memset(buf, sizeof(buf), 0).
|
# Check for potential memset bugs like memset(buf, sizeof(buf), 0).
|
||||||
match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line)
|
match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line)
|
||||||
|
@ -2579,7 +2736,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
|
||||||
if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue
|
if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue
|
||||||
# A catch all for tricky sizeof cases, including 'sizeof expression',
|
# A catch all for tricky sizeof cases, including 'sizeof expression',
|
||||||
# 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)'
|
# 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)'
|
||||||
# requires skipping the next token becasue we split on ' ' and '*'.
|
# requires skipping the next token because we split on ' ' and '*'.
|
||||||
if tok.startswith('sizeof'):
|
if tok.startswith('sizeof'):
|
||||||
skip_next = True
|
skip_next = True
|
||||||
continue
|
continue
|
||||||
|
@ -2600,7 +2757,13 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
|
||||||
line)
|
line)
|
||||||
if match and linenum + 1 < clean_lines.NumLines():
|
if match and linenum + 1 < clean_lines.NumLines():
|
||||||
next_line = clean_lines.elided[linenum + 1]
|
next_line = clean_lines.elided[linenum + 1]
|
||||||
if not Search(r'^\s*};', next_line):
|
# We allow some, but not all, declarations of variables to be present
|
||||||
|
# in the statement that defines the class. The [\w\*,\s]* fragment of
|
||||||
|
# the regular expression below allows users to declare instances of
|
||||||
|
# the class or pointers to instances, but not less common types such
|
||||||
|
# as function pointers or arrays. It's a tradeoff between allowing
|
||||||
|
# reasonable code and avoiding trying to parse more C++ using regexps.
|
||||||
|
if not Search(r'^\s*}[\w\*,\s]*;', next_line):
|
||||||
error(filename, linenum, 'readability/constructors', 3,
|
error(filename, linenum, 'readability/constructors', 3,
|
||||||
match.group(1) + ' should be the last thing in the class')
|
match.group(1) + ' should be the last thing in the class')
|
||||||
|
|
||||||
|
@ -2628,20 +2791,24 @@ def CheckCStyleCast(filename, linenum, line, raw_line, cast_type, pattern,
|
||||||
line: The line of code to check.
|
line: The line of code to check.
|
||||||
raw_line: The raw line of code to check, with comments.
|
raw_line: The raw line of code to check, with comments.
|
||||||
cast_type: The string for the C++ cast to recommend. This is either
|
cast_type: The string for the C++ cast to recommend. This is either
|
||||||
reinterpret_cast or static_cast, depending.
|
reinterpret_cast, static_cast, or const_cast, depending.
|
||||||
pattern: The regular expression used to find C-style casts.
|
pattern: The regular expression used to find C-style casts.
|
||||||
error: The function to call with any errors found.
|
error: The function to call with any errors found.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if an error was emitted.
|
||||||
|
False otherwise.
|
||||||
"""
|
"""
|
||||||
match = Search(pattern, line)
|
match = Search(pattern, line)
|
||||||
if not match:
|
if not match:
|
||||||
return
|
return False
|
||||||
|
|
||||||
# e.g., sizeof(int)
|
# e.g., sizeof(int)
|
||||||
sizeof_match = Match(r'.*sizeof\s*$', line[0:match.start(1) - 1])
|
sizeof_match = Match(r'.*sizeof\s*$', line[0:match.start(1) - 1])
|
||||||
if sizeof_match:
|
if sizeof_match:
|
||||||
error(filename, linenum, 'runtime/sizeof', 1,
|
error(filename, linenum, 'runtime/sizeof', 1,
|
||||||
'Using sizeof(type). Use sizeof(varname) instead if possible')
|
'Using sizeof(type). Use sizeof(varname) instead if possible')
|
||||||
return
|
return True
|
||||||
|
|
||||||
remainder = line[match.end(0):]
|
remainder = line[match.end(0):]
|
||||||
|
|
||||||
|
@ -2665,13 +2832,15 @@ def CheckCStyleCast(filename, linenum, line, raw_line, cast_type, pattern,
|
||||||
'/*' not in raw_line)):
|
'/*' not in raw_line)):
|
||||||
error(filename, linenum, 'readability/function', 3,
|
error(filename, linenum, 'readability/function', 3,
|
||||||
'All parameters should be named in a function')
|
'All parameters should be named in a function')
|
||||||
return
|
return True
|
||||||
|
|
||||||
# At this point, all that should be left is actual casts.
|
# At this point, all that should be left is actual casts.
|
||||||
error(filename, linenum, 'readability/casting', 4,
|
error(filename, linenum, 'readability/casting', 4,
|
||||||
'Using C-style cast. Use %s<%s>(...) instead' %
|
'Using C-style cast. Use %s<%s>(...) instead' %
|
||||||
(cast_type, match.group(1)))
|
(cast_type, match.group(1)))
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
_HEADERS_CONTAINING_TEMPLATES = (
|
_HEADERS_CONTAINING_TEMPLATES = (
|
||||||
('<deque>', ('deque',)),
|
('<deque>', ('deque',)),
|
||||||
|
@ -2710,11 +2879,6 @@ _HEADERS_CONTAINING_TEMPLATES = (
|
||||||
('<slist>', ('slist',)),
|
('<slist>', ('slist',)),
|
||||||
)
|
)
|
||||||
|
|
||||||
_HEADERS_ACCEPTED_BUT_NOT_PROMOTED = {
|
|
||||||
# We can trust with reasonable confidence that map gives us pair<>, too.
|
|
||||||
'pair<>': ('map', 'multimap', 'hash_map', 'hash_multimap')
|
|
||||||
}
|
|
||||||
|
|
||||||
_RE_PATTERN_STRING = re.compile(r'\bstring\b')
|
_RE_PATTERN_STRING = re.compile(r'\bstring\b')
|
||||||
|
|
||||||
_re_pattern_algorithm_header = []
|
_re_pattern_algorithm_header = []
|
||||||
|
@ -2847,11 +3011,11 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# String is special -- it is a non-templatized type in STL.
|
# String is special -- it is a non-templatized type in STL.
|
||||||
m = _RE_PATTERN_STRING.search(line)
|
matched = _RE_PATTERN_STRING.search(line)
|
||||||
if m:
|
if matched:
|
||||||
# Don't warn about strings in non-STL namespaces:
|
# Don't warn about strings in non-STL namespaces:
|
||||||
# (We check only the first match per line; good enough.)
|
# (We check only the first match per line; good enough.)
|
||||||
prefix = line[:m.start()]
|
prefix = line[:matched.start()]
|
||||||
if prefix.endswith('std::') or not prefix.endswith('::'):
|
if prefix.endswith('std::') or not prefix.endswith('::'):
|
||||||
required['<string>'] = (linenum, 'string')
|
required['<string>'] = (linenum, 'string')
|
||||||
|
|
||||||
|
@ -2889,7 +3053,8 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
|
||||||
|
|
||||||
# include_state is modified during iteration, so we iterate over a copy of
|
# include_state is modified during iteration, so we iterate over a copy of
|
||||||
# the keys.
|
# the keys.
|
||||||
for header in include_state.keys(): #NOLINT
|
header_keys = include_state.keys()
|
||||||
|
for header in header_keys:
|
||||||
(same_module, common_path) = FilesBelongToSameModule(abs_filename, header)
|
(same_module, common_path) = FilesBelongToSameModule(abs_filename, header)
|
||||||
fullpath = common_path + header
|
fullpath = common_path + header
|
||||||
if same_module and UpdateIncludeState(fullpath, include_state, io):
|
if same_module and UpdateIncludeState(fullpath, include_state, io):
|
||||||
|
@ -2906,16 +3071,37 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
|
||||||
# All the lines have been processed, report the errors found.
|
# All the lines have been processed, report the errors found.
|
||||||
for required_header_unstripped in required:
|
for required_header_unstripped in required:
|
||||||
template = required[required_header_unstripped][1]
|
template = required[required_header_unstripped][1]
|
||||||
if template in _HEADERS_ACCEPTED_BUT_NOT_PROMOTED:
|
|
||||||
headers = _HEADERS_ACCEPTED_BUT_NOT_PROMOTED[template]
|
|
||||||
if [True for header in headers if header in include_state]:
|
|
||||||
continue
|
|
||||||
if required_header_unstripped.strip('<>"') not in include_state:
|
if required_header_unstripped.strip('<>"') not in include_state:
|
||||||
error(filename, required[required_header_unstripped][0],
|
error(filename, required[required_header_unstripped][0],
|
||||||
'build/include_what_you_use', 4,
|
'build/include_what_you_use', 4,
|
||||||
'Add #include ' + required_header_unstripped + ' for ' + template)
|
'Add #include ' + required_header_unstripped + ' for ' + template)
|
||||||
|
|
||||||
|
|
||||||
|
_RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<')
|
||||||
|
|
||||||
|
|
||||||
|
def CheckMakePairUsesDeduction(filename, clean_lines, linenum, error):
|
||||||
|
"""Check that make_pair's template arguments are deduced.
|
||||||
|
|
||||||
|
G++ 4.6 in C++0x mode fails badly if make_pair's template arguments are
|
||||||
|
specified explicitly, and such use isn't intended in any case.
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
raw = clean_lines.raw_lines
|
||||||
|
line = raw[linenum]
|
||||||
|
match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line)
|
||||||
|
if match:
|
||||||
|
error(filename, linenum, 'build/explicit_make_pair',
|
||||||
|
4, # 4 = high confidence
|
||||||
|
'Omit template arguments from make_pair OR use pair directly OR'
|
||||||
|
' if appropriate, construct a pair directly')
|
||||||
|
|
||||||
|
|
||||||
def ProcessLine(filename, file_extension,
|
def ProcessLine(filename, file_extension,
|
||||||
clean_lines, line, include_state, function_state,
|
clean_lines, line, include_state, function_state,
|
||||||
class_state, error, extra_check_functions=[]):
|
class_state, error, extra_check_functions=[]):
|
||||||
|
@ -2941,13 +3127,14 @@ def ProcessLine(filename, file_extension,
|
||||||
ParseNolintSuppressions(filename, raw_lines[line], line, error)
|
ParseNolintSuppressions(filename, raw_lines[line], line, error)
|
||||||
CheckForFunctionLengths(filename, clean_lines, line, function_state, error)
|
CheckForFunctionLengths(filename, clean_lines, line, function_state, error)
|
||||||
CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
|
CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
|
||||||
CheckStyle(filename, clean_lines, line, file_extension, error)
|
CheckStyle(filename, clean_lines, line, file_extension, class_state, error)
|
||||||
CheckLanguage(filename, clean_lines, line, file_extension, include_state,
|
CheckLanguage(filename, clean_lines, line, file_extension, include_state,
|
||||||
error)
|
error)
|
||||||
CheckForNonStandardConstructs(filename, clean_lines, line,
|
CheckForNonStandardConstructs(filename, clean_lines, line,
|
||||||
class_state, error)
|
class_state, error)
|
||||||
CheckPosixThreading(filename, clean_lines, line, error)
|
CheckPosixThreading(filename, clean_lines, line, error)
|
||||||
CheckInvalidIncrement(filename, clean_lines, line, error)
|
CheckInvalidIncrement(filename, clean_lines, line, error)
|
||||||
|
CheckMakePairUsesDeduction(filename, clean_lines, line, error)
|
||||||
for check_fn in extra_check_functions:
|
for check_fn in extra_check_functions:
|
||||||
check_fn(filename, clean_lines, line, error)
|
check_fn(filename, clean_lines, line, error)
|
||||||
|
|
||||||
|
@ -2959,7 +3146,7 @@ def ProcessFileData(filename, file_extension, lines, error,
|
||||||
filename: Filename of the file that is being processed.
|
filename: Filename of the file that is being processed.
|
||||||
file_extension: The extension (dot not included) of the file.
|
file_extension: The extension (dot not included) of the file.
|
||||||
lines: An array of strings, each representing a line of the file, with the
|
lines: An array of strings, each representing a line of the file, with the
|
||||||
last element being empty if the file is termined with a newline.
|
last element being empty if the file is terminated with a newline.
|
||||||
error: A callable to which errors are reported, which takes 4 arguments:
|
error: A callable to which errors are reported, which takes 4 arguments:
|
||||||
filename, line number, error level, and message
|
filename, line number, error level, and message
|
||||||
extra_check_functions: An array of additional check functions that will be
|
extra_check_functions: An array of additional check functions that will be
|
||||||
|
@ -3055,7 +3242,7 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]):
|
||||||
ProcessFileData(filename, file_extension, lines, Error,
|
ProcessFileData(filename, file_extension, lines, Error,
|
||||||
extra_check_functions)
|
extra_check_functions)
|
||||||
if carriage_return_found and os.linesep != '\r\n':
|
if carriage_return_found and os.linesep != '\r\n':
|
||||||
# Use 0 for linenum since outputing only one error for potentially
|
# Use 0 for linenum since outputting only one error for potentially
|
||||||
# several lines.
|
# several lines.
|
||||||
Error(filename, 0, 'whitespace/newline', 1,
|
Error(filename, 0, 'whitespace/newline', 1,
|
||||||
'One or more unexpected \\r (^M) found;'
|
'One or more unexpected \\r (^M) found;'
|
||||||
|
|
|
@ -134,7 +134,8 @@ class CpplintTestBase(unittest.TestCase):
|
||||||
lines = cpplint.CleansedLines(lines)
|
lines = cpplint.CleansedLines(lines)
|
||||||
class_state = cpplint._ClassState()
|
class_state = cpplint._ClassState()
|
||||||
for i in xrange(lines.NumLines()):
|
for i in xrange(lines.NumLines()):
|
||||||
cpplint.CheckStyle('foo.h', lines, i, 'h', error_collector)
|
cpplint.CheckStyle('foo.h', lines, i, 'h', class_state,
|
||||||
|
error_collector)
|
||||||
cpplint.CheckForNonStandardConstructs('foo.h', lines, i, class_state,
|
cpplint.CheckForNonStandardConstructs('foo.h', lines, i, class_state,
|
||||||
error_collector)
|
error_collector)
|
||||||
class_state.CheckFinished('foo.h', error_collector)
|
class_state.CheckFinished('foo.h', error_collector)
|
||||||
|
@ -243,6 +244,29 @@ class CpplintTest(CpplintTestBase):
|
||||||
self.assertEquals(10, cpplint.GetLineWidth(u'x' * 10))
|
self.assertEquals(10, cpplint.GetLineWidth(u'x' * 10))
|
||||||
self.assertEquals(16, cpplint.GetLineWidth(u'都|道|府|県|支庁'))
|
self.assertEquals(16, cpplint.GetLineWidth(u'都|道|府|県|支庁'))
|
||||||
|
|
||||||
|
def testGetTextInside(self):
|
||||||
|
self.assertEquals('', cpplint._GetTextInside('fun()', r'fun\('))
|
||||||
|
self.assertEquals('x, y', cpplint._GetTextInside('f(x, y)', r'f\('))
|
||||||
|
self.assertEquals('a(), b(c())', cpplint._GetTextInside(
|
||||||
|
'printf(a(), b(c()))', r'printf\('))
|
||||||
|
self.assertEquals('x, y{}', cpplint._GetTextInside('f[x, y{}]', r'f\['))
|
||||||
|
self.assertEquals(None, cpplint._GetTextInside('f[a, b(}]', r'f\['))
|
||||||
|
self.assertEquals(None, cpplint._GetTextInside('f[x, y]', r'f\('))
|
||||||
|
self.assertEquals('y, h(z, (a + b))', cpplint._GetTextInside(
|
||||||
|
'f(x, g(y, h(z, (a + b))))', r'g\('))
|
||||||
|
self.assertEquals('f(f(x))', cpplint._GetTextInside('f(f(f(x)))', r'f\('))
|
||||||
|
# Supports multiple lines.
|
||||||
|
self.assertEquals('\n return loop(x);\n',
|
||||||
|
cpplint._GetTextInside(
|
||||||
|
'int loop(int x) {\n return loop(x);\n}\n', r'\{'))
|
||||||
|
# '^' matches the beggining of each line.
|
||||||
|
self.assertEquals('x, y',
|
||||||
|
cpplint._GetTextInside(
|
||||||
|
'#include "inl.h" // skip #define\n'
|
||||||
|
'#define A2(x, y) a_inl_(x, y, __LINE__)\n'
|
||||||
|
'#define A(x) a_inl_(x, "", __LINE__)\n',
|
||||||
|
r'^\s*#define\s*\w+\('))
|
||||||
|
|
||||||
def testFindNextMultiLineCommentStart(self):
|
def testFindNextMultiLineCommentStart(self):
|
||||||
self.assertEquals(1, cpplint.FindNextMultiLineCommentStart([''], 0))
|
self.assertEquals(1, cpplint.FindNextMultiLineCommentStart([''], 0))
|
||||||
|
|
||||||
|
@ -467,6 +491,19 @@ class CpplintTest(CpplintTestBase):
|
||||||
'Using deprecated casting style. '
|
'Using deprecated casting style. '
|
||||||
'Use static_cast<int>(...) instead'
|
'Use static_cast<int>(...) instead'
|
||||||
' [readability/casting] [4]')
|
' [readability/casting] [4]')
|
||||||
|
|
||||||
|
self.TestLint(
|
||||||
|
'(char *) "foo"',
|
||||||
|
'Using C-style cast. '
|
||||||
|
'Use const_cast<char *>(...) instead'
|
||||||
|
' [readability/casting] [4]')
|
||||||
|
|
||||||
|
self.TestLint(
|
||||||
|
'(int*)foo',
|
||||||
|
'Using C-style cast. '
|
||||||
|
'Use reinterpret_cast<int*>(...) instead'
|
||||||
|
' [readability/casting] [4]')
|
||||||
|
|
||||||
# Checks for false positives...
|
# Checks for false positives...
|
||||||
self.TestLint(
|
self.TestLint(
|
||||||
'int a = int(); // Constructor, o.k.',
|
'int a = int(); // Constructor, o.k.',
|
||||||
|
@ -554,74 +591,77 @@ class CpplintTest(CpplintTestBase):
|
||||||
|
|
||||||
def testIncludeWhatYouUse(self):
|
def testIncludeWhatYouUse(self):
|
||||||
self.TestIncludeWhatYouUse(
|
self.TestIncludeWhatYouUse(
|
||||||
'''#include <vector>
|
"""#include <vector>
|
||||||
std::vector<int> foo;
|
std::vector<int> foo;
|
||||||
''',
|
""",
|
||||||
'')
|
'')
|
||||||
self.TestIncludeWhatYouUse(
|
self.TestIncludeWhatYouUse(
|
||||||
'''#include <map>
|
"""#include <map>
|
||||||
std::pair<int,int> foo;
|
std::pair<int,int> foo;
|
||||||
''',
|
""",
|
||||||
'')
|
|
||||||
self.TestIncludeWhatYouUse(
|
|
||||||
'''#include <multimap>
|
|
||||||
std::pair<int,int> foo;
|
|
||||||
''',
|
|
||||||
'')
|
|
||||||
self.TestIncludeWhatYouUse(
|
|
||||||
'''#include <hash_map>
|
|
||||||
std::pair<int,int> foo;
|
|
||||||
''',
|
|
||||||
'')
|
|
||||||
self.TestIncludeWhatYouUse(
|
|
||||||
'''#include <utility>
|
|
||||||
std::pair<int,int> foo;
|
|
||||||
''',
|
|
||||||
'')
|
|
||||||
self.TestIncludeWhatYouUse(
|
|
||||||
'''#include <vector>
|
|
||||||
DECLARE_string(foobar);
|
|
||||||
''',
|
|
||||||
'')
|
|
||||||
self.TestIncludeWhatYouUse(
|
|
||||||
'''#include <vector>
|
|
||||||
DEFINE_string(foobar, "", "");
|
|
||||||
''',
|
|
||||||
'')
|
|
||||||
self.TestIncludeWhatYouUse(
|
|
||||||
'''#include <vector>
|
|
||||||
std::pair<int,int> foo;
|
|
||||||
''',
|
|
||||||
'Add #include <utility> for pair<>'
|
'Add #include <utility> for pair<>'
|
||||||
' [build/include_what_you_use] [4]')
|
' [build/include_what_you_use] [4]')
|
||||||
self.TestIncludeWhatYouUse(
|
self.TestIncludeWhatYouUse(
|
||||||
'''#include "base/foobar.h"
|
"""#include <multimap>
|
||||||
|
std::pair<int,int> foo;
|
||||||
|
""",
|
||||||
|
'Add #include <utility> for pair<>'
|
||||||
|
' [build/include_what_you_use] [4]')
|
||||||
|
self.TestIncludeWhatYouUse(
|
||||||
|
"""#include <hash_map>
|
||||||
|
std::pair<int,int> foo;
|
||||||
|
""",
|
||||||
|
'Add #include <utility> for pair<>'
|
||||||
|
' [build/include_what_you_use] [4]')
|
||||||
|
self.TestIncludeWhatYouUse(
|
||||||
|
"""#include <utility>
|
||||||
|
std::pair<int,int> foo;
|
||||||
|
""",
|
||||||
|
'')
|
||||||
|
self.TestIncludeWhatYouUse(
|
||||||
|
"""#include <vector>
|
||||||
|
DECLARE_string(foobar);
|
||||||
|
""",
|
||||||
|
'')
|
||||||
|
self.TestIncludeWhatYouUse(
|
||||||
|
"""#include <vector>
|
||||||
|
DEFINE_string(foobar, "", "");
|
||||||
|
""",
|
||||||
|
'')
|
||||||
|
self.TestIncludeWhatYouUse(
|
||||||
|
"""#include <vector>
|
||||||
|
std::pair<int,int> foo;
|
||||||
|
""",
|
||||||
|
'Add #include <utility> for pair<>'
|
||||||
|
' [build/include_what_you_use] [4]')
|
||||||
|
self.TestIncludeWhatYouUse(
|
||||||
|
"""#include "base/foobar.h"
|
||||||
std::vector<int> foo;
|
std::vector<int> foo;
|
||||||
''',
|
""",
|
||||||
'Add #include <vector> for vector<>'
|
'Add #include <vector> for vector<>'
|
||||||
' [build/include_what_you_use] [4]')
|
' [build/include_what_you_use] [4]')
|
||||||
self.TestIncludeWhatYouUse(
|
self.TestIncludeWhatYouUse(
|
||||||
'''#include <vector>
|
"""#include <vector>
|
||||||
std::set<int> foo;
|
std::set<int> foo;
|
||||||
''',
|
""",
|
||||||
'Add #include <set> for set<>'
|
'Add #include <set> for set<>'
|
||||||
' [build/include_what_you_use] [4]')
|
' [build/include_what_you_use] [4]')
|
||||||
self.TestIncludeWhatYouUse(
|
self.TestIncludeWhatYouUse(
|
||||||
'''#include "base/foobar.h"
|
"""#include "base/foobar.h"
|
||||||
hash_map<int, int> foobar;
|
hash_map<int, int> foobar;
|
||||||
''',
|
""",
|
||||||
'Add #include <hash_map> for hash_map<>'
|
'Add #include <hash_map> for hash_map<>'
|
||||||
' [build/include_what_you_use] [4]')
|
' [build/include_what_you_use] [4]')
|
||||||
self.TestIncludeWhatYouUse(
|
self.TestIncludeWhatYouUse(
|
||||||
'''#include "base/foobar.h"
|
"""#include "base/foobar.h"
|
||||||
bool foobar = std::less<int>(0,1);
|
bool foobar = std::less<int>(0,1);
|
||||||
''',
|
""",
|
||||||
'Add #include <functional> for less<>'
|
'Add #include <functional> for less<>'
|
||||||
' [build/include_what_you_use] [4]')
|
' [build/include_what_you_use] [4]')
|
||||||
self.TestIncludeWhatYouUse(
|
self.TestIncludeWhatYouUse(
|
||||||
'''#include "base/foobar.h"
|
"""#include "base/foobar.h"
|
||||||
bool foobar = min<int>(0,1);
|
bool foobar = min<int>(0,1);
|
||||||
''',
|
""",
|
||||||
'Add #include <algorithm> for min [build/include_what_you_use] [4]')
|
'Add #include <algorithm> for min [build/include_what_you_use] [4]')
|
||||||
self.TestIncludeWhatYouUse(
|
self.TestIncludeWhatYouUse(
|
||||||
'void a(const string &foobar);',
|
'void a(const string &foobar);',
|
||||||
|
@ -633,55 +673,55 @@ class CpplintTest(CpplintTestBase):
|
||||||
'void a(const my::string &foobar);',
|
'void a(const my::string &foobar);',
|
||||||
'') # Avoid false positives on strings in other namespaces.
|
'') # Avoid false positives on strings in other namespaces.
|
||||||
self.TestIncludeWhatYouUse(
|
self.TestIncludeWhatYouUse(
|
||||||
'''#include "base/foobar.h"
|
"""#include "base/foobar.h"
|
||||||
bool foobar = swap(0,1);
|
bool foobar = swap(0,1);
|
||||||
''',
|
""",
|
||||||
'Add #include <algorithm> for swap [build/include_what_you_use] [4]')
|
'Add #include <algorithm> for swap [build/include_what_you_use] [4]')
|
||||||
self.TestIncludeWhatYouUse(
|
self.TestIncludeWhatYouUse(
|
||||||
'''#include "base/foobar.h"
|
"""#include "base/foobar.h"
|
||||||
bool foobar = transform(a.begin(), a.end(), b.start(), Foo);
|
bool foobar = transform(a.begin(), a.end(), b.start(), Foo);
|
||||||
''',
|
""",
|
||||||
'Add #include <algorithm> for transform '
|
'Add #include <algorithm> for transform '
|
||||||
'[build/include_what_you_use] [4]')
|
'[build/include_what_you_use] [4]')
|
||||||
self.TestIncludeWhatYouUse(
|
self.TestIncludeWhatYouUse(
|
||||||
'''#include "base/foobar.h"
|
"""#include "base/foobar.h"
|
||||||
bool foobar = min_element(a.begin(), a.end());
|
bool foobar = min_element(a.begin(), a.end());
|
||||||
''',
|
""",
|
||||||
'Add #include <algorithm> for min_element '
|
'Add #include <algorithm> for min_element '
|
||||||
'[build/include_what_you_use] [4]')
|
'[build/include_what_you_use] [4]')
|
||||||
self.TestIncludeWhatYouUse(
|
self.TestIncludeWhatYouUse(
|
||||||
'''foo->swap(0,1);
|
"""foo->swap(0,1);
|
||||||
foo.swap(0,1);
|
foo.swap(0,1);
|
||||||
''',
|
""",
|
||||||
'')
|
'')
|
||||||
self.TestIncludeWhatYouUse(
|
self.TestIncludeWhatYouUse(
|
||||||
'''#include <string>
|
"""#include <string>
|
||||||
void a(const std::multimap<int,string> &foobar);
|
void a(const std::multimap<int,string> &foobar);
|
||||||
''',
|
""",
|
||||||
'Add #include <map> for multimap<>'
|
'Add #include <map> for multimap<>'
|
||||||
' [build/include_what_you_use] [4]')
|
' [build/include_what_you_use] [4]')
|
||||||
self.TestIncludeWhatYouUse(
|
self.TestIncludeWhatYouUse(
|
||||||
'''#include <queue>
|
"""#include <queue>
|
||||||
void a(const std::priority_queue<int> &foobar);
|
void a(const std::priority_queue<int> &foobar);
|
||||||
''',
|
""",
|
||||||
'')
|
'')
|
||||||
self.TestIncludeWhatYouUse(
|
self.TestIncludeWhatYouUse(
|
||||||
'''#include <assert.h>
|
"""#include <assert.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
#include "base/port.h"
|
#include "base/port.h"
|
||||||
vector<string> hajoa;''', '')
|
vector<string> hajoa;""", '')
|
||||||
self.TestIncludeWhatYouUse(
|
self.TestIncludeWhatYouUse(
|
||||||
'''#include <string>
|
"""#include <string>
|
||||||
int i = numeric_limits<int>::max()
|
int i = numeric_limits<int>::max()
|
||||||
''',
|
""",
|
||||||
'Add #include <limits> for numeric_limits<>'
|
'Add #include <limits> for numeric_limits<>'
|
||||||
' [build/include_what_you_use] [4]')
|
' [build/include_what_you_use] [4]')
|
||||||
self.TestIncludeWhatYouUse(
|
self.TestIncludeWhatYouUse(
|
||||||
'''#include <limits>
|
"""#include <limits>
|
||||||
int i = numeric_limits<int>::max()
|
int i = numeric_limits<int>::max()
|
||||||
''',
|
""",
|
||||||
'')
|
'')
|
||||||
|
|
||||||
# Test the UpdateIncludeState code path.
|
# Test the UpdateIncludeState code path.
|
||||||
|
@ -694,8 +734,8 @@ class CpplintTest(CpplintTestBase):
|
||||||
|
|
||||||
mock_header_contents = ['#include <set>']
|
mock_header_contents = ['#include <set>']
|
||||||
message = self.PerformIncludeWhatYouUse(
|
message = self.PerformIncludeWhatYouUse(
|
||||||
'''#include "blah/a.h"
|
"""#include "blah/a.h"
|
||||||
std::set<int> foo;''',
|
std::set<int> foo;""",
|
||||||
filename='blah/a.cc',
|
filename='blah/a.cc',
|
||||||
io=MockIo(mock_header_contents))
|
io=MockIo(mock_header_contents))
|
||||||
self.assertEquals(message, '')
|
self.assertEquals(message, '')
|
||||||
|
@ -704,8 +744,8 @@ class CpplintTest(CpplintTestBase):
|
||||||
# a temporary file generated by Emacs's flymake.
|
# a temporary file generated by Emacs's flymake.
|
||||||
mock_header_contents = ['']
|
mock_header_contents = ['']
|
||||||
message = self.PerformIncludeWhatYouUse(
|
message = self.PerformIncludeWhatYouUse(
|
||||||
'''#include "blah/a.h"
|
"""#include "blah/a.h"
|
||||||
std::set<int> foo;''',
|
std::set<int> foo;""",
|
||||||
filename='blah/a_flymake.cc',
|
filename='blah/a_flymake.cc',
|
||||||
io=MockIo(mock_header_contents))
|
io=MockIo(mock_header_contents))
|
||||||
self.assertEquals(message, 'Add #include <set> for set<> '
|
self.assertEquals(message, 'Add #include <set> for set<> '
|
||||||
|
@ -713,16 +753,16 @@ class CpplintTest(CpplintTestBase):
|
||||||
|
|
||||||
# If there's just a cc and the header can't be found then it's ok.
|
# If there's just a cc and the header can't be found then it's ok.
|
||||||
message = self.PerformIncludeWhatYouUse(
|
message = self.PerformIncludeWhatYouUse(
|
||||||
'''#include "blah/a.h"
|
"""#include "blah/a.h"
|
||||||
std::set<int> foo;''',
|
std::set<int> foo;""",
|
||||||
filename='blah/a.cc')
|
filename='blah/a.cc')
|
||||||
self.assertEquals(message, '')
|
self.assertEquals(message, '')
|
||||||
|
|
||||||
# Make sure we find the headers with relative paths.
|
# Make sure we find the headers with relative paths.
|
||||||
mock_header_contents = ['']
|
mock_header_contents = ['']
|
||||||
message = self.PerformIncludeWhatYouUse(
|
message = self.PerformIncludeWhatYouUse(
|
||||||
'''#include "%s/a.h"
|
"""#include "%s/a.h"
|
||||||
std::set<int> foo;''' % os.path.basename(os.getcwd()),
|
std::set<int> foo;""" % os.path.basename(os.getcwd()),
|
||||||
filename='a.cc',
|
filename='a.cc',
|
||||||
io=MockIo(mock_header_contents))
|
io=MockIo(mock_header_contents))
|
||||||
self.assertEquals(message, 'Add #include <set> for set<> '
|
self.assertEquals(message, 'Add #include <set> for set<> '
|
||||||
|
@ -770,22 +810,22 @@ class CpplintTest(CpplintTestBase):
|
||||||
def testMultiLineComments(self):
|
def testMultiLineComments(self):
|
||||||
# missing explicit is bad
|
# missing explicit is bad
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
r'''int a = 0;
|
r"""int a = 0;
|
||||||
/* multi-liner
|
/* multi-liner
|
||||||
class Foo {
|
class Foo {
|
||||||
Foo(int f); // should cause a lint warning in code
|
Foo(int f); // should cause a lint warning in code
|
||||||
}
|
}
|
||||||
*/ ''',
|
*/ """,
|
||||||
'')
|
'')
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
r'''/* int a = 0; multi-liner
|
r"""/* int a = 0; multi-liner
|
||||||
static const int b = 0;''',
|
static const int b = 0;""",
|
||||||
'Could not find end of multi-line comment'
|
'Could not find end of multi-line comment'
|
||||||
' [readability/multiline_comment] [5]')
|
' [readability/multiline_comment] [5]')
|
||||||
self.TestMultiLineLint(r''' /* multi-line comment''',
|
self.TestMultiLineLint(r""" /* multi-line comment""",
|
||||||
'Could not find end of multi-line comment'
|
'Could not find end of multi-line comment'
|
||||||
' [readability/multiline_comment] [5]')
|
' [readability/multiline_comment] [5]')
|
||||||
self.TestMultiLineLint(r''' // /* comment, but not multi-line''', '')
|
self.TestMultiLineLint(r""" // /* comment, but not multi-line""", '')
|
||||||
|
|
||||||
def testMultilineStrings(self):
|
def testMultilineStrings(self):
|
||||||
multiline_string_error_message = (
|
multiline_string_error_message = (
|
||||||
|
@ -809,131 +849,151 @@ class CpplintTest(CpplintTestBase):
|
||||||
def testExplicitSingleArgumentConstructors(self):
|
def testExplicitSingleArgumentConstructors(self):
|
||||||
# missing explicit is bad
|
# missing explicit is bad
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
Foo(int f);
|
Foo(int f);
|
||||||
};''',
|
};""",
|
||||||
'Single-argument constructors should be marked explicit.'
|
'Single-argument constructors should be marked explicit.'
|
||||||
' [runtime/explicit] [5]')
|
' [runtime/explicit] [5]')
|
||||||
# missing explicit is bad, even with whitespace
|
# missing explicit is bad, even with whitespace
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
Foo (int f);
|
Foo (int f);
|
||||||
};''',
|
};""",
|
||||||
['Extra space before ( in function call [whitespace/parens] [4]',
|
['Extra space before ( in function call [whitespace/parens] [4]',
|
||||||
'Single-argument constructors should be marked explicit.'
|
'Single-argument constructors should be marked explicit.'
|
||||||
' [runtime/explicit] [5]'])
|
' [runtime/explicit] [5]'])
|
||||||
# missing explicit, with distracting comment, is still bad
|
# missing explicit, with distracting comment, is still bad
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
Foo(int f); // simpler than Foo(blargh, blarg)
|
Foo(int f); // simpler than Foo(blargh, blarg)
|
||||||
};''',
|
};""",
|
||||||
'Single-argument constructors should be marked explicit.'
|
'Single-argument constructors should be marked explicit.'
|
||||||
' [runtime/explicit] [5]')
|
' [runtime/explicit] [5]')
|
||||||
# missing explicit, with qualified classname
|
# missing explicit, with qualified classname
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Qualifier::AnotherOne::Foo {
|
"""class Qualifier::AnotherOne::Foo {
|
||||||
Foo(int f);
|
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 {
|
||||||
|
inline Foo(int f);
|
||||||
|
};""",
|
||||||
'Single-argument constructors should be marked explicit.'
|
'Single-argument constructors should be marked explicit.'
|
||||||
' [runtime/explicit] [5]')
|
' [runtime/explicit] [5]')
|
||||||
# structs are caught as well.
|
# structs are caught as well.
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''struct Foo {
|
"""struct Foo {
|
||||||
Foo(int f);
|
Foo(int f);
|
||||||
};''',
|
};""",
|
||||||
'Single-argument constructors should be marked explicit.'
|
'Single-argument constructors should be marked explicit.'
|
||||||
' [runtime/explicit] [5]')
|
' [runtime/explicit] [5]')
|
||||||
# Templatized classes are caught as well.
|
# Templatized classes are caught as well.
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''template<typename T> class Foo {
|
"""template<typename T> class Foo {
|
||||||
Foo(int f);
|
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 {
|
||||||
|
inline Foo(int f);
|
||||||
|
};""",
|
||||||
'Single-argument constructors should be marked explicit.'
|
'Single-argument constructors should be marked explicit.'
|
||||||
' [runtime/explicit] [5]')
|
' [runtime/explicit] [5]')
|
||||||
# proper style is okay
|
# proper style is okay
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
explicit Foo(int f);
|
explicit Foo(int f);
|
||||||
};''',
|
};""",
|
||||||
'')
|
'')
|
||||||
# two argument constructor is okay
|
# two argument constructor is okay
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
Foo(int f, int b);
|
Foo(int f, int b);
|
||||||
};''',
|
};""",
|
||||||
'')
|
'')
|
||||||
# two argument constructor, across two lines, is okay
|
# two argument constructor, across two lines, is okay
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
Foo(int f,
|
Foo(int f,
|
||||||
int b);
|
int b);
|
||||||
};''',
|
};""",
|
||||||
'')
|
'')
|
||||||
# non-constructor (but similar name), is okay
|
# non-constructor (but similar name), is okay
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
aFoo(int f);
|
aFoo(int f);
|
||||||
};''',
|
};""",
|
||||||
'')
|
'')
|
||||||
# constructor with void argument is okay
|
# constructor with void argument is okay
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
Foo(void);
|
Foo(void);
|
||||||
};''',
|
};""",
|
||||||
'')
|
'')
|
||||||
# single argument method is okay
|
# single argument method is okay
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
Bar(int b);
|
Bar(int b);
|
||||||
};''',
|
};""",
|
||||||
'')
|
'')
|
||||||
# comments should be ignored
|
# comments should be ignored
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
// Foo(int f);
|
// Foo(int f);
|
||||||
};''',
|
};""",
|
||||||
'')
|
'')
|
||||||
# single argument function following class definition is okay
|
# single argument function following class definition is okay
|
||||||
# (okay, it's not actually valid, but we don't want a false positive)
|
# (okay, it's not actually valid, but we don't want a false positive)
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
Foo(int f, int b);
|
Foo(int f, int b);
|
||||||
};
|
};
|
||||||
Foo(int f);''',
|
Foo(int f);""",
|
||||||
'')
|
'')
|
||||||
# single argument function is okay
|
# single argument function is okay
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''static Foo(int f);''',
|
"""static Foo(int f);""",
|
||||||
'')
|
'')
|
||||||
# single argument copy constructor is okay.
|
# single argument copy constructor is okay.
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
Foo(const Foo&);
|
Foo(const Foo&);
|
||||||
};''',
|
};""",
|
||||||
'')
|
'')
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
Foo(Foo&);
|
Foo(Foo&);
|
||||||
};''',
|
};""",
|
||||||
|
'')
|
||||||
|
# templatized copy constructor is okay.
|
||||||
|
self.TestMultiLineLint(
|
||||||
|
"""template<typename T> class Foo {
|
||||||
|
Foo(const Foo<T>&);
|
||||||
|
};""",
|
||||||
'')
|
'')
|
||||||
|
|
||||||
def testSlashStarCommentOnSingleLine(self):
|
def testSlashStarCommentOnSingleLine(self):
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''/* static */ Foo(int f);''',
|
"""/* static */ Foo(int f);""",
|
||||||
'')
|
'')
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''/*/ static */ Foo(int f);''',
|
"""/*/ static */ Foo(int f);""",
|
||||||
'')
|
'')
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''/*/ static Foo(int f);''',
|
"""/*/ static Foo(int f);""",
|
||||||
'Could not find end of multi-line comment'
|
'Could not find end of multi-line comment'
|
||||||
' [readability/multiline_comment] [5]')
|
' [readability/multiline_comment] [5]')
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
''' /*/ static Foo(int f);''',
|
""" /*/ static Foo(int f);""",
|
||||||
'Could not find end of multi-line comment'
|
'Could not find end of multi-line comment'
|
||||||
' [readability/multiline_comment] [5]')
|
' [readability/multiline_comment] [5]')
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
''' /**/ static Foo(int f);''',
|
""" /**/ static Foo(int f);""",
|
||||||
'')
|
'')
|
||||||
|
|
||||||
# Test suspicious usage of "if" like this:
|
# Test suspicious usage of "if" like this:
|
||||||
|
@ -1017,6 +1077,9 @@ class CpplintTest(CpplintTestBase):
|
||||||
self.TestLint('printf("foo")', '')
|
self.TestLint('printf("foo")', '')
|
||||||
self.TestLint('printf("foo: %s", foo)', '')
|
self.TestLint('printf("foo: %s", foo)', '')
|
||||||
self.TestLint('DocidForPrintf(docid)', '') # Should not trigger.
|
self.TestLint('DocidForPrintf(docid)', '') # Should not trigger.
|
||||||
|
self.TestLint('printf(format, value)', '') # Should not trigger.
|
||||||
|
self.TestLint('printf(format.c_str(), value)', '') # Should not trigger.
|
||||||
|
self.TestLint('printf(format(index).c_str(), value)', '')
|
||||||
self.TestLint(
|
self.TestLint(
|
||||||
'printf(foo)',
|
'printf(foo)',
|
||||||
'Potential format string bug. Do printf("%s", foo) instead.'
|
'Potential format string bug. Do printf("%s", foo) instead.'
|
||||||
|
@ -1121,15 +1184,27 @@ class CpplintTest(CpplintTestBase):
|
||||||
'DISALLOW_IMPLICIT_CONSTRUCTORS'):
|
'DISALLOW_IMPLICIT_CONSTRUCTORS'):
|
||||||
self.TestLanguageRulesCheck(
|
self.TestLanguageRulesCheck(
|
||||||
'some_class.h',
|
'some_class.h',
|
||||||
'''%s(SomeClass);
|
"""%s(SomeClass);
|
||||||
int foo_;
|
int foo_;
|
||||||
};''' % macro_name,
|
};""" % macro_name,
|
||||||
('%s should be the last thing in the class' % macro_name) +
|
('%s should be the last thing in the class' % macro_name) +
|
||||||
' [readability/constructors] [3]')
|
' [readability/constructors] [3]')
|
||||||
self.TestLanguageRulesCheck(
|
self.TestLanguageRulesCheck(
|
||||||
'some_class.h',
|
'some_class.h',
|
||||||
'''%s(SomeClass);
|
"""%s(SomeClass);
|
||||||
};''' % macro_name,
|
};""" % macro_name,
|
||||||
|
'')
|
||||||
|
self.TestLanguageRulesCheck(
|
||||||
|
'some_class.h',
|
||||||
|
"""%s(SomeClass);
|
||||||
|
int foo_;
|
||||||
|
} instance, *pointer_to_instance;""" % macro_name,
|
||||||
|
('%s should be the last thing in the class' % macro_name) +
|
||||||
|
' [readability/constructors] [3]')
|
||||||
|
self.TestLanguageRulesCheck(
|
||||||
|
'some_class.h',
|
||||||
|
"""%s(SomeClass);
|
||||||
|
} instance, *pointer_to_instance;""" % macro_name,
|
||||||
'')
|
'')
|
||||||
|
|
||||||
# Brace usage
|
# Brace usage
|
||||||
|
@ -1138,23 +1213,23 @@ class CpplintTest(CpplintTestBase):
|
||||||
# or initializing an array
|
# or initializing an array
|
||||||
self.TestLint('int a[3] = { 1, 2, 3 };', '')
|
self.TestLint('int a[3] = { 1, 2, 3 };', '')
|
||||||
self.TestLint(
|
self.TestLint(
|
||||||
'''const int foo[] =
|
"""const int foo[] =
|
||||||
{1, 2, 3 };''',
|
{1, 2, 3 };""",
|
||||||
'')
|
'')
|
||||||
# For single line, unmatched '}' with a ';' is ignored (not enough context)
|
# For single line, unmatched '}' with a ';' is ignored (not enough context)
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''int a[3] = { 1,
|
"""int a[3] = { 1,
|
||||||
2,
|
2,
|
||||||
3 };''',
|
3 };""",
|
||||||
'')
|
'')
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''int a[2][3] = { { 1, 2 },
|
"""int a[2][3] = { { 1, 2 },
|
||||||
{ 3, 4 } };''',
|
{ 3, 4 } };""",
|
||||||
'')
|
'')
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''int a[2][3] =
|
"""int a[2][3] =
|
||||||
{ { 1, 2 },
|
{ { 1, 2 },
|
||||||
{ 3, 4 } };''',
|
{ 3, 4 } };""",
|
||||||
'')
|
'')
|
||||||
|
|
||||||
# CHECK/EXPECT_TRUE/EXPECT_FALSE replacements
|
# CHECK/EXPECT_TRUE/EXPECT_FALSE replacements
|
||||||
|
@ -1394,6 +1469,10 @@ class CpplintTest(CpplintTestBase):
|
||||||
self.TestLint('} else {', '')
|
self.TestLint('} else {', '')
|
||||||
self.TestLint('} else if', '')
|
self.TestLint('} else if', '')
|
||||||
|
|
||||||
|
def testSpacingWithInitializerLists(self):
|
||||||
|
self.TestLint('int v[1][3] = {{1, 2, 3}};', '')
|
||||||
|
self.TestLint('int v[1][1] = {{0}};', '')
|
||||||
|
|
||||||
def testSpacingForBinaryOps(self):
|
def testSpacingForBinaryOps(self):
|
||||||
self.TestLint('if (foo<=bar) {', 'Missing spaces around <='
|
self.TestLint('if (foo<=bar) {', 'Missing spaces around <='
|
||||||
' [whitespace/operators] [3]')
|
' [whitespace/operators] [3]')
|
||||||
|
@ -1483,6 +1562,19 @@ class CpplintTest(CpplintTestBase):
|
||||||
' [whitespace/parens] [2]')
|
' [whitespace/parens] [2]')
|
||||||
self.TestLint('TellStory(1 /* wolf */, 3 /* pigs */);',
|
self.TestLint('TellStory(1 /* wolf */, 3 /* pigs */);',
|
||||||
'')
|
'')
|
||||||
|
self.TestMultiLineLint("""TellStory(1, 3
|
||||||
|
);""",
|
||||||
|
'Closing ) should be moved to the previous line'
|
||||||
|
' [whitespace/parens] [2]')
|
||||||
|
self.TestMultiLineLint("""TellStory(Wolves(1),
|
||||||
|
Pigs(3
|
||||||
|
));""",
|
||||||
|
'Closing ) should be moved to the previous line'
|
||||||
|
' [whitespace/parens] [2]')
|
||||||
|
self.TestMultiLineLint("""TellStory(1,
|
||||||
|
3 );""",
|
||||||
|
'Extra space before )'
|
||||||
|
' [whitespace/parens] [2]')
|
||||||
|
|
||||||
def testToDoComments(self):
|
def testToDoComments(self):
|
||||||
start_space = ('Too many spaces before TODO'
|
start_space = ('Too many spaces before TODO'
|
||||||
|
@ -1648,6 +1740,59 @@ class CpplintTest(CpplintTestBase):
|
||||||
'Blank line at the end of a code block. Is this needed?'
|
'Blank line at the end of a code block. Is this needed?'
|
||||||
' [whitespace/blank_line] [3]'))
|
' [whitespace/blank_line] [3]'))
|
||||||
|
|
||||||
|
def testBlankLineBeforeSectionKeyword(self):
|
||||||
|
error_collector = ErrorCollector(self.assert_)
|
||||||
|
cpplint.ProcessFileData('foo.cc', 'cc',
|
||||||
|
['class A {',
|
||||||
|
' public:',
|
||||||
|
' protected:', # warning 1
|
||||||
|
' private:', # warning 2
|
||||||
|
' struct B {',
|
||||||
|
' public:',
|
||||||
|
' private:'] + # warning 3
|
||||||
|
([''] * 100) + # Make A and B longer than 100 lines
|
||||||
|
[' };',
|
||||||
|
' struct C {',
|
||||||
|
' protected:',
|
||||||
|
' private:', # C is too short for warnings
|
||||||
|
' };',
|
||||||
|
'};',
|
||||||
|
'class D',
|
||||||
|
' : public {',
|
||||||
|
' public:', # no warning
|
||||||
|
'};'],
|
||||||
|
error_collector)
|
||||||
|
self.assertEquals(2, error_collector.Results().count(
|
||||||
|
'"private:" should be preceded by a blank line'
|
||||||
|
' [whitespace/blank_line] [3]'))
|
||||||
|
self.assertEquals(1, error_collector.Results().count(
|
||||||
|
'"protected:" should be preceded by a blank line'
|
||||||
|
' [whitespace/blank_line] [3]'))
|
||||||
|
|
||||||
|
def testNoBlankLineAfterSectionKeyword(self):
|
||||||
|
error_collector = ErrorCollector(self.assert_)
|
||||||
|
cpplint.ProcessFileData('foo.cc', 'cc',
|
||||||
|
['class A {',
|
||||||
|
' public:',
|
||||||
|
'', # warning 1
|
||||||
|
' private:',
|
||||||
|
'', # warning 2
|
||||||
|
' struct B {',
|
||||||
|
' protected:',
|
||||||
|
'', # warning 3
|
||||||
|
' };',
|
||||||
|
'};'],
|
||||||
|
error_collector)
|
||||||
|
self.assertEquals(1, error_collector.Results().count(
|
||||||
|
'Do not leave a blank line after "public:"'
|
||||||
|
' [whitespace/blank_line] [3]'))
|
||||||
|
self.assertEquals(1, error_collector.Results().count(
|
||||||
|
'Do not leave a blank line after "protected:"'
|
||||||
|
' [whitespace/blank_line] [3]'))
|
||||||
|
self.assertEquals(1, error_collector.Results().count(
|
||||||
|
'Do not leave a blank line after "private:"'
|
||||||
|
' [whitespace/blank_line] [3]'))
|
||||||
|
|
||||||
def testElseOnSameLineAsClosingBraces(self):
|
def testElseOnSameLineAsClosingBraces(self):
|
||||||
error_collector = ErrorCollector(self.assert_)
|
error_collector = ErrorCollector(self.assert_)
|
||||||
cpplint.ProcessFileData('foo.cc', 'cc',
|
cpplint.ProcessFileData('foo.cc', 'cc',
|
||||||
|
@ -1838,19 +1983,19 @@ class CpplintTest(CpplintTestBase):
|
||||||
'class Foo;',
|
'class Foo;',
|
||||||
'')
|
'')
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''struct Foo*
|
"""struct Foo*
|
||||||
foo = NewFoo();''',
|
foo = NewFoo();""",
|
||||||
'')
|
'')
|
||||||
# Here is an example where the linter gets confused, even though
|
# Here is an example where the linter gets confused, even though
|
||||||
# the code doesn't violate the style guide.
|
# the code doesn't violate the style guide.
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo
|
"""class Foo
|
||||||
#ifdef DERIVE_FROM_GOO
|
#ifdef DERIVE_FROM_GOO
|
||||||
: public Goo {
|
: public Goo {
|
||||||
#else
|
#else
|
||||||
: public Hoo {
|
: public Hoo {
|
||||||
#endif
|
#endif
|
||||||
};''',
|
};""",
|
||||||
'Failed to find complete declaration of class Foo'
|
'Failed to find complete declaration of class Foo'
|
||||||
' [build/class] [5]')
|
' [build/class] [5]')
|
||||||
|
|
||||||
|
@ -2117,7 +2262,7 @@ class CpplintTest(CpplintTestBase):
|
||||||
' [runtime/printf_format] [3]')
|
' [runtime/printf_format] [3]')
|
||||||
|
|
||||||
self.TestLint(
|
self.TestLint(
|
||||||
r'snprintf(file, "Never mix %d and %1$d parmaeters!", value);',
|
r'snprintf(file, "Never mix %d and %1$d parameters!", value);',
|
||||||
'%N$ formats are unconventional. Try rewriting to avoid them.'
|
'%N$ formats are unconventional. Try rewriting to avoid them.'
|
||||||
' [runtime/printf_format] [2]')
|
' [runtime/printf_format] [2]')
|
||||||
|
|
||||||
|
@ -2774,48 +2919,48 @@ class NoNonVirtualDestructorsTest(CpplintTestBase):
|
||||||
|
|
||||||
def testNoError(self):
|
def testNoError(self):
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
virtual ~Foo();
|
virtual ~Foo();
|
||||||
virtual void foo();
|
virtual void foo();
|
||||||
};''',
|
};""",
|
||||||
'')
|
'')
|
||||||
|
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
virtual inline ~Foo();
|
virtual inline ~Foo();
|
||||||
virtual void foo();
|
virtual void foo();
|
||||||
};''',
|
};""",
|
||||||
'')
|
'')
|
||||||
|
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
inline virtual ~Foo();
|
inline virtual ~Foo();
|
||||||
virtual void foo();
|
virtual void foo();
|
||||||
};''',
|
};""",
|
||||||
'')
|
'')
|
||||||
|
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo::Goo {
|
"""class Foo::Goo {
|
||||||
virtual ~Goo();
|
virtual ~Goo();
|
||||||
virtual void goo();
|
virtual void goo();
|
||||||
};''',
|
};""",
|
||||||
'')
|
'')
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'class Foo { void foo(); };',
|
'class Foo { void foo(); };',
|
||||||
'More than one command on the same line [whitespace/newline] [4]')
|
'More than one command on the same line [whitespace/newline] [4]')
|
||||||
|
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Qualified::Goo : public Foo {
|
"""class Qualified::Goo : public Foo {
|
||||||
virtual void goo();
|
virtual void goo();
|
||||||
};''',
|
};""",
|
||||||
'')
|
'')
|
||||||
|
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
# Line-ending :
|
# Line-ending :
|
||||||
'''class Goo :
|
"""class Goo :
|
||||||
public Foo {
|
public Foo {
|
||||||
virtual void goo();
|
virtual void goo();
|
||||||
};''',
|
};""",
|
||||||
'Labels should always be indented at least one space. '
|
'Labels should always be indented at least one space. '
|
||||||
'If this is a member-initializer list in a constructor or '
|
'If this is a member-initializer list in a constructor or '
|
||||||
'the base class list in a class definition, the colon should '
|
'the base class list in a class definition, the colon should '
|
||||||
|
@ -2823,97 +2968,97 @@ class NoNonVirtualDestructorsTest(CpplintTestBase):
|
||||||
|
|
||||||
def testNoDestructorWhenVirtualNeeded(self):
|
def testNoDestructorWhenVirtualNeeded(self):
|
||||||
self.TestMultiLineLintRE(
|
self.TestMultiLineLintRE(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
virtual void foo();
|
virtual void foo();
|
||||||
};''',
|
};""",
|
||||||
'The class Foo probably needs a virtual destructor')
|
'The class Foo probably needs a virtual destructor')
|
||||||
|
|
||||||
def testDestructorNonVirtualWhenVirtualNeeded(self):
|
def testDestructorNonVirtualWhenVirtualNeeded(self):
|
||||||
self.TestMultiLineLintRE(
|
self.TestMultiLineLintRE(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
~Foo();
|
~Foo();
|
||||||
virtual void foo();
|
virtual void foo();
|
||||||
};''',
|
};""",
|
||||||
'The class Foo probably needs a virtual destructor')
|
'The class Foo probably needs a virtual destructor')
|
||||||
|
|
||||||
def testNoWarnWhenDerived(self):
|
def testNoWarnWhenDerived(self):
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo : public Goo {
|
"""class Foo : public Goo {
|
||||||
virtual void foo();
|
virtual void foo();
|
||||||
};''',
|
};""",
|
||||||
'')
|
'')
|
||||||
|
|
||||||
def testNoDestructorWhenVirtualNeededClassDecorated(self):
|
def testNoDestructorWhenVirtualNeededClassDecorated(self):
|
||||||
self.TestMultiLineLintRE(
|
self.TestMultiLineLintRE(
|
||||||
'''class LOCKABLE API Foo {
|
"""class LOCKABLE API Foo {
|
||||||
virtual void foo();
|
virtual void foo();
|
||||||
};''',
|
};""",
|
||||||
'The class Foo probably needs a virtual destructor')
|
'The class Foo probably needs a virtual destructor')
|
||||||
|
|
||||||
def testDestructorNonVirtualWhenVirtualNeededClassDecorated(self):
|
def testDestructorNonVirtualWhenVirtualNeededClassDecorated(self):
|
||||||
self.TestMultiLineLintRE(
|
self.TestMultiLineLintRE(
|
||||||
'''class LOCKABLE API Foo {
|
"""class LOCKABLE API Foo {
|
||||||
~Foo();
|
~Foo();
|
||||||
virtual void foo();
|
virtual void foo();
|
||||||
};''',
|
};""",
|
||||||
'The class Foo probably needs a virtual destructor')
|
'The class Foo probably needs a virtual destructor')
|
||||||
|
|
||||||
def testNoWarnWhenDerivedClassDecorated(self):
|
def testNoWarnWhenDerivedClassDecorated(self):
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class LOCKABLE API Foo : public Goo {
|
"""class LOCKABLE API Foo : public Goo {
|
||||||
virtual void foo();
|
virtual void foo();
|
||||||
};''',
|
};""",
|
||||||
'')
|
'')
|
||||||
|
|
||||||
def testInternalBraces(self):
|
def testInternalBraces(self):
|
||||||
self.TestMultiLineLintRE(
|
self.TestMultiLineLintRE(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
enum Goo {
|
enum Goo {
|
||||||
GOO
|
GOO
|
||||||
};
|
};
|
||||||
virtual void foo();
|
virtual void foo();
|
||||||
};''',
|
};""",
|
||||||
'The class Foo probably needs a virtual destructor')
|
'The class Foo probably needs a virtual destructor')
|
||||||
|
|
||||||
def testInnerClassNeedsVirtualDestructor(self):
|
def testInnerClassNeedsVirtualDestructor(self):
|
||||||
self.TestMultiLineLintRE(
|
self.TestMultiLineLintRE(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
class Goo {
|
class Goo {
|
||||||
virtual void goo();
|
virtual void goo();
|
||||||
};
|
};
|
||||||
};''',
|
};""",
|
||||||
'The class Goo probably needs a virtual destructor')
|
'The class Goo probably needs a virtual destructor')
|
||||||
|
|
||||||
def testOuterClassNeedsVirtualDestructor(self):
|
def testOuterClassNeedsVirtualDestructor(self):
|
||||||
self.TestMultiLineLintRE(
|
self.TestMultiLineLintRE(
|
||||||
'''class Foo {
|
"""class Foo {
|
||||||
class Goo {
|
class Goo {
|
||||||
};
|
};
|
||||||
virtual void foo();
|
virtual void foo();
|
||||||
};''',
|
};""",
|
||||||
'The class Foo probably needs a virtual destructor')
|
'The class Foo probably needs a virtual destructor')
|
||||||
|
|
||||||
def testQualifiedClassNeedsVirtualDestructor(self):
|
def testQualifiedClassNeedsVirtualDestructor(self):
|
||||||
self.TestMultiLineLintRE(
|
self.TestMultiLineLintRE(
|
||||||
'''class Qualified::Foo {
|
"""class Qualified::Foo {
|
||||||
virtual void foo();
|
virtual void foo();
|
||||||
};''',
|
};""",
|
||||||
'The class Qualified::Foo probably needs a virtual destructor')
|
'The class Qualified::Foo probably needs a virtual destructor')
|
||||||
|
|
||||||
def testMultiLineDeclarationNoError(self):
|
def testMultiLineDeclarationNoError(self):
|
||||||
self.TestMultiLineLintRE(
|
self.TestMultiLineLintRE(
|
||||||
'''class Foo
|
"""class Foo
|
||||||
: public Goo {
|
: public Goo {
|
||||||
virtual void foo();
|
virtual void foo();
|
||||||
};''',
|
};""",
|
||||||
'')
|
'')
|
||||||
|
|
||||||
def testMultiLineDeclarationWithError(self):
|
def testMultiLineDeclarationWithError(self):
|
||||||
self.TestMultiLineLint(
|
self.TestMultiLineLint(
|
||||||
'''class Foo
|
"""class Foo
|
||||||
{
|
{
|
||||||
virtual void foo();
|
virtual void foo();
|
||||||
};''',
|
};""",
|
||||||
['{ should almost always be at the end of the previous line '
|
['{ should almost always be at the end of the previous line '
|
||||||
'[whitespace/braces] [4]',
|
'[whitespace/braces] [4]',
|
||||||
'The class Foo probably needs a virtual destructor due to having '
|
'The class Foo probably needs a virtual destructor due to having '
|
||||||
|
@ -2925,6 +3070,18 @@ class NoNonVirtualDestructorsTest(CpplintTestBase):
|
||||||
'If you can, use sizeof(fisk) instead of 1 as the 2nd arg '
|
'If you can, use sizeof(fisk) instead of 1 as the 2nd arg '
|
||||||
'to snprintf. [runtime/printf] [3]')
|
'to snprintf. [runtime/printf] [3]')
|
||||||
|
|
||||||
|
def testExplicitMakePair(self):
|
||||||
|
self.TestLint('make_pair', '')
|
||||||
|
self.TestLint('make_pair(42, 42)', '')
|
||||||
|
self.TestLint('make_pair<',
|
||||||
|
'Omit template arguments from make_pair OR use pair directly'
|
||||||
|
' OR if appropriate, construct a pair directly'
|
||||||
|
' [build/explicit_make_pair] [4]')
|
||||||
|
self.TestLint('make_pair <',
|
||||||
|
'Omit template arguments from make_pair OR use pair directly'
|
||||||
|
' OR if appropriate, construct a pair directly'
|
||||||
|
' [build/explicit_make_pair] [4]')
|
||||||
|
self.TestLint('my_make_pair<int, int>', '')
|
||||||
|
|
||||||
# pylint: disable-msg=C6409
|
# pylint: disable-msg=C6409
|
||||||
def setUp():
|
def setUp():
|
||||||
|
|
Loading…
Reference in New Issue
Block a user