提交 9115ab1c 编写于 作者: Y Yu Yang 提交者: GitHub

Merge pull request #450 from reyoung/feature/pre-commit-hooks-scripts

Feature/pre commit hooks scripts
...@@ -13,8 +13,6 @@ ...@@ -13,8 +13,6 @@
# The document of clang-format is # The document of clang-format is
# http://clang.llvm.org/docs/ClangFormat.html # http://clang.llvm.org/docs/ClangFormat.html
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html # http://clang.llvm.org/docs/ClangFormatStyleOptions.html
#
# TODO(yuyang18): Add python and other language code style
--- ---
Language: Cpp Language: Cpp
BasedOnStyle: Google BasedOnStyle: Google
...@@ -22,8 +20,9 @@ IndentWidth: 2 ...@@ -22,8 +20,9 @@ IndentWidth: 2
TabWidth: 2 TabWidth: 2
ContinuationIndentWidth: 4 ContinuationIndentWidth: 4
AccessModifierOffset: -2 # The private/protected/public has no indent in class AccessModifierOffset: -2 # The private/protected/public has no indent in class
PointerAlignment: Left # int* p/int& p, not int *p/int &p
Standard: Cpp11 Standard: Cpp11
AllowAllParametersOfDeclarationOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: true
BinPackParameters: false
BinPackArguments: false
... ...
- repo: https://github.com/Lucas-C/pre-commit-hooks.git
sha: c25201a00e6b0514370501050cf2a8538ac12270
hooks:
- id: remove-crlf
- repo: https://github.com/reyoung/mirrors-yapf.git
sha: v0.13.2
hooks:
- id: yapf
- repo: https://github.com/pre-commit/pre-commit-hooks
sha: 4ef03c4223ad322c7adaa6c6c0efb26b57df3b71
hooks:
- id: check-added-large-files
- id: check-merge-conflict
- id: check-symlinks
- id: detect-private-key
- id: end-of-file-fixer
# TODO(yuyang): trailing whitespace has some bugs on markdown
# files now, please not add it to pre-commit hook now
# - id: trailing-whitespace
#
# TODO(yuyang): debug-statements not fit for Paddle, because
# not all of our python code is runnable. Some are used for
# documenation
# - id: debug-statements
This folder contains scripts used in PaddlePaddle introduction. This folder contains scripts used in PaddlePaddle introduction.
- use `bash train.sh` to train a simple linear regression model - use `bash train.sh` to train a simple linear regression model
- use `python evaluate_model.py` to read model parameters. You can see that `w` and `b` are very close to [2, 0.3]. - use `python evaluate_model.py` to read model parameters. You can see that `w` and `b` are very close to [2, 0.3].
...@@ -19,4 +19,3 @@ done ...@@ -19,4 +19,3 @@ done
cd $DIR cd $DIR
rm -f *.list rm -f *.list
python generate_list.py python generate_list.py
...@@ -14,4 +14,3 @@ ...@@ -14,4 +14,3 @@
"fields": ["id", "title", "genres"] "fields": ["id", "title", "genres"]
} }
} }
...@@ -37,4 +37,3 @@ paddle train \ ...@@ -37,4 +37,3 @@ paddle train \
--use_gpu=false \ --use_gpu=false \
--config_args=is_test=1 \ --config_args=is_test=1 \
2>&1 | tee 'test.log' 2>&1 | tee 'test.log'
...@@ -24,4 +24,3 @@ paddle train \ ...@@ -24,4 +24,3 @@ paddle train \
--show_parameter_stats_period=10 \ --show_parameter_stats_period=10 \
--test_all_data_in_one_period=1 \ --test_all_data_in_one_period=1 \
2>&1 | tee 'train.log' 2>&1 | tee 'train.log'
...@@ -98,4 +98,3 @@ There, you have recovered the underlying pattern between `X` and `Y` only from o ...@@ -98,4 +98,3 @@ There, you have recovered the underlying pattern between `X` and `Y` only from o
- <a href="../build/index.html"> Build and Installation </a> - <a href="../build/index.html"> Build and Installation </a>
- <a href="../demo/quick_start/index_en.html">Quick Start</a> - <a href="../demo/quick_start/index_en.html">Quick Start</a>
- <a href="../demo/index.html">Example and Demo</a> - <a href="../demo/index.html">Example and Demo</a>
...@@ -17,5 +17,3 @@ endif() ...@@ -17,5 +17,3 @@ endif()
if(WITH_SWIG_PY) if(WITH_SWIG_PY)
add_subdirectory(api) add_subdirectory(api)
endif() endif()
...@@ -65,4 +65,3 @@ struct ArgumentsPrivate { ...@@ -65,4 +65,3 @@ struct ArgumentsPrivate {
return *(std::shared_ptr<T>*)(rawPtr); return *(std::shared_ptr<T>*)(rawPtr);
} }
}; };
...@@ -69,8 +69,8 @@ class TestMatrix(unittest.TestCase): ...@@ -69,8 +69,8 @@ class TestMatrix(unittest.TestCase):
def test_numpy(self): def test_numpy(self):
numpy_mat = np.matrix([[1, 2], [3, 4], [5, 6]], dtype="float32") numpy_mat = np.matrix([[1, 2], [3, 4], [5, 6]], dtype="float32")
m = swig_paddle.Matrix.createCpuDenseFromNumpy(numpy_mat) m = swig_paddle.Matrix.createCpuDenseFromNumpy(numpy_mat)
self.assertEqual( self.assertEqual((int(m.getHeight()), int(m.getWidth())),
(int(m.getHeight()), int(m.getWidth())), numpy_mat.shape) numpy_mat.shape)
# the numpy matrix and paddle matrix shared the same memory. # the numpy matrix and paddle matrix shared the same memory.
numpy_mat[0, 1] = 342.23 numpy_mat[0, 1] = 342.23
......
...@@ -254,4 +254,3 @@ extern __thread cudaStream_t default_stream; ...@@ -254,4 +254,3 @@ extern __thread cudaStream_t default_stream;
#endif /* __NVCC__ */ #endif /* __NVCC__ */
#endif /* HL_BASE_H_ */ #endif /* HL_BASE_H_ */
...@@ -199,4 +199,3 @@ inline void hl_batch_norm_backward(hl_tensor_descriptor inputDesc, ...@@ -199,4 +199,3 @@ inline void hl_batch_norm_backward(hl_tensor_descriptor inputDesc,
real *savedInvVar) {} real *savedInvVar) {}
#endif // HL_CUDA_CUDNN_STUB_H_ #endif // HL_CUDA_CUDNN_STUB_H_
...@@ -718,4 +718,3 @@ void sincos256_ps(v8sf x, v8sf *s, v8sf *c) { ...@@ -718,4 +718,3 @@ void sincos256_ps(v8sf x, v8sf *s, v8sf *c) {
*s = _mm256_xor_ps(xmm1, sign_bit_sin); *s = _mm256_xor_ps(xmm1, sign_bit_sin);
*c = _mm256_xor_ps(xmm2, sign_bit_cos); *c = _mm256_xor_ps(xmm2, sign_bit_cos);
} }
...@@ -48,4 +48,3 @@ public: ...@@ -48,4 +48,3 @@ public:
}; };
} // namespace paddle } // namespace paddle
...@@ -80,4 +80,3 @@ void vTanh(const int n, const T* a, T* r); ...@@ -80,4 +80,3 @@ void vTanh(const int n, const T* a, T* r);
} // namespace paddle } // namespace paddle
#endif // MATHFUNCTIONS_H_ #endif // MATHFUNCTIONS_H_
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Does google-lint on c++ files. """Does google-lint on c++ files.
The goal of this script is to identify places in the code that *may* The goal of this script is to identify places in the code that *may*
...@@ -55,7 +54,6 @@ import string ...@@ -55,7 +54,6 @@ import string
import sys import sys
import unicodedata import unicodedata
_USAGE = """ _USAGE = """
Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...] Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
[--counting=total|toplevel|detailed] [--root=subdir] [--counting=total|toplevel|detailed] [--root=subdir]
...@@ -242,13 +240,11 @@ _ERROR_CATEGORIES = [ ...@@ -242,13 +240,11 @@ _ERROR_CATEGORIES = [
'whitespace/semicolon', 'whitespace/semicolon',
'whitespace/tab', 'whitespace/tab',
'whitespace/todo', 'whitespace/todo',
] ]
# These error categories are no longer enforced by cpplint, but for backwards- # These error categories are no longer enforced by cpplint, but for backwards-
# compatibility they may still appear in NOLINT comments. # compatibility they may still appear in NOLINT comments.
_LEGACY_ERROR_CATEGORIES = [ _LEGACY_ERROR_CATEGORIES = ['readability/streams', ]
'readability/streams',
]
# The default state of the category filter. This is overridden by the --filter= # The default state of the category filter. This is overridden by the --filter=
# flag. By default all errors are on, so only add here categories that should be # flag. By default all errors are on, so only add here categories that should be
...@@ -394,8 +390,7 @@ _CPP_HEADERS = frozenset([ ...@@ -394,8 +390,7 @@ _CPP_HEADERS = frozenset([
'cuchar', 'cuchar',
'cwchar', 'cwchar',
'cwctype', 'cwctype',
]) ])
# These headers are excluded from [build/include] and [build/include_order] # These headers are excluded from [build/include] and [build/include_order]
# checks: # checks:
...@@ -405,23 +400,26 @@ _CPP_HEADERS = frozenset([ ...@@ -405,23 +400,26 @@ _CPP_HEADERS = frozenset([
_THIRD_PARTY_HEADERS_PATTERN = re.compile( _THIRD_PARTY_HEADERS_PATTERN = re.compile(
r'^(?:[^/]*[A-Z][^/]*\.h|lua\.h|lauxlib\.h|lualib\.h)$') r'^(?:[^/]*[A-Z][^/]*\.h|lua\.h|lauxlib\.h|lualib\.h)$')
# Assertion macros. These are defined in base/logging.h and # Assertion macros. These are defined in base/logging.h and
# testing/base/gunit.h. Note that the _M versions need to come first # testing/base/gunit.h. Note that the _M versions need to come first
# for substring matching to work. # for substring matching to work.
_CHECK_MACROS = [ _CHECK_MACROS = [
'DCHECK', 'CHECK', 'DCHECK',
'EXPECT_TRUE_M', 'EXPECT_TRUE', 'CHECK',
'ASSERT_TRUE_M', 'ASSERT_TRUE', 'EXPECT_TRUE_M',
'EXPECT_FALSE_M', 'EXPECT_FALSE', 'EXPECT_TRUE',
'ASSERT_FALSE_M', 'ASSERT_FALSE', 'ASSERT_TRUE_M',
] 'ASSERT_TRUE',
'EXPECT_FALSE_M',
'EXPECT_FALSE',
'ASSERT_FALSE_M',
'ASSERT_FALSE',
]
# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE # Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE
_CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS]) _CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS])
for op, replacement in [('==', 'EQ'), ('!=', 'NE'), for op, replacement in [('==', 'EQ'), ('!=', 'NE'), ('>=', 'GE'), ('>', 'GT'),
('>=', 'GE'), ('>', 'GT'),
('<=', 'LE'), ('<', 'LT')]: ('<=', 'LE'), ('<', 'LT')]:
_CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement
_CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement
...@@ -430,9 +428,8 @@ for op, replacement in [('==', 'EQ'), ('!=', 'NE'), ...@@ -430,9 +428,8 @@ for op, replacement in [('==', 'EQ'), ('!=', 'NE'),
_CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement _CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement
_CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % replacement _CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % replacement
for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'), for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'), ('>=', 'LT'),
('>=', 'LT'), ('>', 'LE'), ('>', 'LE'), ('<=', 'GT'), ('<', 'GE')]:
('<=', 'GT'), ('<', 'GE')]:
_CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement
_CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement
_CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement
...@@ -455,16 +452,15 @@ _ALT_TOKEN_REPLACEMENT = { ...@@ -455,16 +452,15 @@ _ALT_TOKEN_REPLACEMENT = {
'xor_eq': '^=', 'xor_eq': '^=',
'not': '!', 'not': '!',
'not_eq': '!=' 'not_eq': '!='
} }
# Compile regular expression that matches all the above keywords. The "[ =()]" # Compile regular expression that matches all the above keywords. The "[ =()]"
# bit is meant to avoid matching these keywords outside of boolean expressions. # bit is meant to avoid matching these keywords outside of boolean expressions.
# #
# False positives include C-style multi-line comments and multi-line strings # False positives include C-style multi-line comments and multi-line strings
# but those have always been troublesome for cpplint. # but those have always been troublesome for cpplint.
_ALT_TOKEN_REPLACEMENT_PATTERN = re.compile( _ALT_TOKEN_REPLACEMENT_PATTERN = re.compile(r'[ =()](' + ('|'.join(
r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)') _ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)')
# These constants define types of headers for use with # These constants define types of headers for use with
# _IncludeState.CheckNextIncludeOrder(). # _IncludeState.CheckNextIncludeOrder().
...@@ -485,7 +481,6 @@ _MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)' ...@@ -485,7 +481,6 @@ _MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)'
r'(?:\s+(volatile|__volatile__))?' r'(?:\s+(volatile|__volatile__))?'
r'\s*[{(]') r'\s*[{(]')
_regexp_compile_cache = {} _regexp_compile_cache = {}
# {str, set(int)}: a map from error categories to sets of linenumbers # {str, set(int)}: a map from error categories to sets of linenumbers
...@@ -504,6 +499,7 @@ _line_length = 80 ...@@ -504,6 +499,7 @@ _line_length = 80
# This is set by --extensions flag. # This is set by --extensions flag.
_valid_extensions = set(['cc', 'h', 'cpp', 'cu', 'cuh']) _valid_extensions = set(['cc', 'h', 'cpp', 'cu', 'cuh'])
def ParseNolintSuppressions(filename, raw_line, linenum, error): def ParseNolintSuppressions(filename, raw_line, linenum, error):
"""Updates the global list of error-suppressions. """Updates the global list of error-suppressions.
...@@ -521,9 +517,9 @@ def ParseNolintSuppressions(filename, raw_line, linenum, error): ...@@ -521,9 +517,9 @@ def ParseNolintSuppressions(filename, raw_line, linenum, error):
if matched: if matched:
if matched.group(1): if matched.group(1):
lines = matched.group(2) lines = matched.group(2)
if lines : if lines:
lines=int(lines[2:]) lines = int(lines[2:])
suppressed_line = [ linenum + i for i in xrange(lines) ] suppressed_line = [linenum + i for i in xrange(lines)]
else: else:
suppressed_line = linenum + 1 suppressed_line = linenum + 1
else: else:
...@@ -540,10 +536,12 @@ def ParseNolintSuppressions(filename, raw_line, linenum, error): ...@@ -540,10 +536,12 @@ def ParseNolintSuppressions(filename, raw_line, linenum, error):
category = category[1:-1] category = category[1:-1]
if category in _ERROR_CATEGORIES: if category in _ERROR_CATEGORIES:
if isinstance(suppressed_line, int): if isinstance(suppressed_line, int):
_error_suppressions.setdefault(category, set()).add(suppressed_line) _error_suppressions.setdefault(
category, set()).add(suppressed_line)
else: else:
for _line in suppressed_line: for _line in suppressed_line:
_error_suppressions.setdefault(category, set()).add(_line) _error_suppressions.setdefault(category,
set()).add(_line)
elif category not in _LEGACY_ERROR_CATEGORIES: elif category not in _LEGACY_ERROR_CATEGORIES:
error(filename, linenum, 'readability/nolint', 5, error(filename, linenum, 'readability/nolint', 5,
'Unknown NOLINT error category: %s' % category) 'Unknown NOLINT error category: %s' % category)
...@@ -730,9 +728,8 @@ class _IncludeState(object): ...@@ -730,9 +728,8 @@ class _IncludeState(object):
error message describing what's wrong. error message describing what's wrong.
""" """
error_message = ('Found %s after %s' % error_message = ('Found %s after %s' % (
(self._TYPE_NAMES[header_type], self._TYPE_NAMES[header_type], self._SECTION_NAMES[self._section]))
self._SECTION_NAMES[self._section]))
last_section = self._section last_section = self._section
...@@ -828,7 +825,8 @@ class _CppLintState(object): ...@@ -828,7 +825,8 @@ class _CppLintState(object):
self.filters.append(clean_filt) self.filters.append(clean_filt)
for filt in self.filters: for filt in self.filters:
if not (filt.startswith('+') or filt.startswith('-')): if not (filt.startswith('+') or filt.startswith('-')):
raise ValueError('Every filter in --filters must start with + or -' raise ValueError(
'Every filter in --filters must start with + or -'
' (%s does not)' % filt) ' (%s does not)' % filt)
def BackupFilters(self): def BackupFilters(self):
...@@ -861,6 +859,7 @@ class _CppLintState(object): ...@@ -861,6 +859,7 @@ class _CppLintState(object):
(category, count)) (category, count))
sys.stdout.write('Total errors found: %d\n' % self.error_count) sys.stdout.write('Total errors found: %d\n' % self.error_count)
_cpplint_state = _CppLintState() _cpplint_state = _CppLintState()
...@@ -906,6 +905,7 @@ def _SetFilters(filters): ...@@ -906,6 +905,7 @@ def _SetFilters(filters):
""" """
_cpplint_state.SetFilters(filters) _cpplint_state.SetFilters(filters)
def _AddFilters(filters): def _AddFilters(filters):
"""Adds more filter overrides. """Adds more filter overrides.
...@@ -918,14 +918,17 @@ def _AddFilters(filters): ...@@ -918,14 +918,17 @@ def _AddFilters(filters):
""" """
_cpplint_state.AddFilters(filters) _cpplint_state.AddFilters(filters)
def _BackupFilters(): def _BackupFilters():
""" Saves the current filter list to backup storage.""" """ Saves the current filter list to backup storage."""
_cpplint_state.BackupFilters() _cpplint_state.BackupFilters()
def _RestoreFilters(): def _RestoreFilters():
""" Restores filters previously backed up.""" """ Restores filters previously backed up."""
_cpplint_state.RestoreFilters() _cpplint_state.RestoreFilters()
class _FunctionState(object): class _FunctionState(object):
"""Tracks current function name and the number of lines in its body.""" """Tracks current function name and the number of lines in its body."""
...@@ -967,7 +970,8 @@ class _FunctionState(object): ...@@ -967,7 +970,8 @@ class _FunctionState(object):
trigger = base_trigger * 2**_VerboseLevel() trigger = base_trigger * 2**_VerboseLevel()
if self.lines_in_function > trigger: if self.lines_in_function > trigger:
error_level = int(math.log(self.lines_in_function / base_trigger, 2)) error_level = int(
math.log(self.lines_in_function / base_trigger, 2))
# 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ... # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ...
if error_level > 5: if error_level > 5:
error_level = 5 error_level = 5
...@@ -1058,7 +1062,7 @@ class FileInfo(object): ...@@ -1058,7 +1062,7 @@ class FileInfo(object):
googlename = self.RepositoryName() googlename = self.RepositoryName()
project, rest = os.path.split(googlename) project, rest = os.path.split(googlename)
return (project,) + os.path.splitext(rest) return (project, ) + os.path.splitext(rest)
def BaseName(self): def BaseName(self):
"""File base name - text after the final slash, before the final period.""" """File base name - text after the final slash, before the final period."""
...@@ -1130,14 +1134,14 @@ def Error(filename, linenum, category, confidence, message): ...@@ -1130,14 +1134,14 @@ def Error(filename, linenum, category, confidence, message):
if _ShouldPrintError(category, confidence, linenum): if _ShouldPrintError(category, confidence, linenum):
_cpplint_state.IncrementErrorCount(category) _cpplint_state.IncrementErrorCount(category)
if _cpplint_state.output_format == 'vs7': if _cpplint_state.output_format == 'vs7':
sys.stderr.write('%s(%s): %s [%s] [%d]\n' % ( sys.stderr.write('%s(%s): %s [%s] [%d]\n' %
filename, linenum, message, category, confidence)) (filename, linenum, message, category, confidence))
elif _cpplint_state.output_format == 'eclipse': elif _cpplint_state.output_format == 'eclipse':
sys.stderr.write('%s:%s: warning: %s [%s] [%d]\n' % ( sys.stderr.write('%s:%s: warning: %s [%s] [%d]\n' %
filename, linenum, message, category, confidence)) (filename, linenum, message, category, confidence))
else: else:
sys.stderr.write('%s:%s: %s [%s] [%d]\n' % ( sys.stderr.write('%s:%s: %s [%s] [%d]\n' %
filename, linenum, message, category, confidence)) (filename, linenum, message, category, confidence))
# Matches standard C++ escape sequences per 2.13.2.3 of the C++ standard. # Matches standard C++ escape sequences per 2.13.2.3 of the C++ standard.
...@@ -1154,9 +1158,8 @@ _RE_PATTERN_C_COMMENTS = r'/\*(?:[^*]|\*(?!/))*\*/' ...@@ -1154,9 +1158,8 @@ _RE_PATTERN_C_COMMENTS = r'/\*(?:[^*]|\*(?!/))*\*/'
# if this doesn't work we try on left side but only if there's a non-character # if this doesn't work we try on left side but only if there's a non-character
# on the right. # on the right.
_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile( _RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile(
r'(\s*' + _RE_PATTERN_C_COMMENTS + r'\s*$|' + r'(\s*' + _RE_PATTERN_C_COMMENTS + r'\s*$|' + _RE_PATTERN_C_COMMENTS +
_RE_PATTERN_C_COMMENTS + r'\s+|' + r'\s+|' + r'\s+' + _RE_PATTERN_C_COMMENTS + r'(?=\W)|' +
r'\s+' + _RE_PATTERN_C_COMMENTS + r'(?=\W)|' +
_RE_PATTERN_C_COMMENTS + r')') _RE_PATTERN_C_COMMENTS + r')')
...@@ -1208,7 +1211,8 @@ def CleanseRawStrings(raw_lines): ...@@ -1208,7 +1211,8 @@ def CleanseRawStrings(raw_lines):
# line and resume copying the original lines, and also insert # line and resume copying the original lines, and also insert
# a "" on the last line. # a "" on the last line.
leading_space = Match(r'^(\s*)\S', line) leading_space = Match(r'^(\s*)\S', line)
line = leading_space.group(1) + '""' + line[end + len(delimiter):] line = leading_space.group(1) + '""' + line[end + len(
delimiter):]
delimiter = None delimiter = None
else: else:
# Haven't found the end yet, append a blank line. # Haven't found the end yet, append a blank line.
...@@ -1220,7 +1224,8 @@ def CleanseRawStrings(raw_lines): ...@@ -1220,7 +1224,8 @@ def CleanseRawStrings(raw_lines):
while delimiter is None: while delimiter is None:
# Look for beginning of a raw string. # Look for beginning of a raw string.
# See 2.14.15 [lex.string] for syntax. # See 2.14.15 [lex.string] for syntax.
matched = Match(r'^(.*)\b(?:R|u8R|uR|UR|LR)"([^\s\\()]*)\((.*)$', line) matched = Match(r'^(.*)\b(?:R|u8R|uR|UR|LR)"([^\s\\()]*)\((.*)$',
line)
if matched: if matched:
delimiter = ')' + matched.group(2) + '"' delimiter = ')' + matched.group(2) + '"'
...@@ -1280,8 +1285,8 @@ def RemoveMultiLineComments(filename, lines, error): ...@@ -1280,8 +1285,8 @@ def RemoveMultiLineComments(filename, lines, error):
return return
lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin) lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin)
if lineix_end >= len(lines): if lineix_end >= len(lines):
error(filename, lineix_begin + 1, 'readability/multiline_comment', 5, error(filename, lineix_begin + 1, 'readability/multiline_comment',
'Could not find end of multi-line comment') 5, 'Could not find end of multi-line comment')
return return
RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1) RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1)
lineix = lineix_end + 1 lineix = lineix_end + 1
...@@ -1321,9 +1326,10 @@ class CleansedLines(object): ...@@ -1321,9 +1326,10 @@ class CleansedLines(object):
self.num_lines = len(lines) self.num_lines = len(lines)
self.lines_without_raw_strings = CleanseRawStrings(lines) self.lines_without_raw_strings = CleanseRawStrings(lines)
for linenum in range(len(self.lines_without_raw_strings)): for linenum in range(len(self.lines_without_raw_strings)):
self.lines.append(CleanseComments( self.lines.append(
self.lines_without_raw_strings[linenum])) CleanseComments(self.lines_without_raw_strings[linenum]))
elided = self._CollapseStrings(self.lines_without_raw_strings[linenum]) elided = self._CollapseStrings(self.lines_without_raw_strings[
linenum])
self.elided.append(CleanseComments(elided)) self.elided.append(CleanseComments(elided))
def NumLines(self): def NumLines(self):
...@@ -1382,7 +1388,8 @@ class CleansedLines(object): ...@@ -1382,7 +1388,8 @@ class CleansedLines(object):
# separator. So we are fine as long as we don't see something # separator. So we are fine as long as we don't see something
# like "0.'3" (gcc 4.9.0 will not allow this literal). # like "0.'3" (gcc 4.9.0 will not allow this literal).
if Search(r'\b(?:0[bBxX]?|[1-9])[0-9a-fA-F]*$', head): if Search(r'\b(?:0[bBxX]?|[1-9])[0-9a-fA-F]*$', head):
match_literal = Match(r'^((?:\'?[0-9a-zA-Z_])*)(.*)$', "'" + tail) match_literal = Match(r'^((?:\'?[0-9a-zA-Z_])*)(.*)$',
"'" + tail)
collapsed += head + match_literal.group(1).replace("'", '') collapsed += head + match_literal.group(1).replace("'", '')
elided = match_literal.group(2) elided = match_literal.group(2)
else: else:
...@@ -1452,8 +1459,8 @@ def FindEndOfExpressionInLine(line, startpos, stack): ...@@ -1452,8 +1459,8 @@ def FindEndOfExpressionInLine(line, startpos, stack):
# Found potential end of template argument list. # Found potential end of template argument list.
# Ignore "->" and operator functions # Ignore "->" and operator functions
if (i > 0 and if (i > 0 and (line[i - 1] == '-' or Search(r'\boperator\s*$',
(line[i - 1] == '-' or Search(r'\boperator\s*$', line[0:i - 1]))): line[0:i - 1]))):
continue continue
# Pop the stack if there is a matching '<'. Otherwise, ignore # Pop the stack if there is a matching '<'. Otherwise, ignore
...@@ -1547,8 +1554,7 @@ def FindStartOfExpressionInLine(line, endpos, stack): ...@@ -1547,8 +1554,7 @@ def FindStartOfExpressionInLine(line, endpos, stack):
# #
# Ignore it if it's a "->" or ">=" or "operator>" # Ignore it if it's a "->" or ">=" or "operator>"
if (i > 0 and if (i > 0 and
(line[i - 1] == '-' or (line[i - 1] == '-' or Match(r'\s>=\s', line[i - 1:]) or
Match(r'\s>=\s', line[i - 1:]) or
Search(r'\boperator\s*$', line[0:i]))): Search(r'\boperator\s*$', line[0:i]))):
i -= 1 i -= 1
else: else:
...@@ -1627,7 +1633,8 @@ def ReverseCloseExpression(clean_lines, linenum, pos): ...@@ -1627,7 +1633,8 @@ def ReverseCloseExpression(clean_lines, linenum, pos):
while stack and linenum > 0: while stack and linenum > 0:
linenum -= 1 linenum -= 1
line = clean_lines.elided[linenum] line = clean_lines.elided[linenum]
(start_pos, stack) = FindStartOfExpressionInLine(line, len(line) - 1, stack) (start_pos, stack) = FindStartOfExpressionInLine(line,
len(line) - 1, stack)
if start_pos > -1: if start_pos > -1:
return (line, linenum, start_pos) return (line, linenum, start_pos)
...@@ -1643,8 +1650,7 @@ def CheckForCopyright(filename, lines, error): ...@@ -1643,8 +1650,7 @@ def CheckForCopyright(filename, lines, error):
for line in xrange(1, min(len(lines), 11)): for line in xrange(1, min(len(lines), 11)):
if re.search(r'Copyright', lines[line], re.I): break if re.search(r'Copyright', lines[line], re.I): break
else: # means no copyright line was found else: # means no copyright line was found
error(filename, 0, 'legal/copyright', 5, error(filename, 0, 'legal/copyright', 5, 'No copyright message found. '
'No copyright message found. '
'You should have a line: "Copyright [year] <Copyright Owner>"') 'You should have a line: "Copyright [year] <Copyright Owner>"')
...@@ -1741,8 +1747,8 @@ def CheckForHeaderGuard(filename, clean_lines, error): ...@@ -1741,8 +1747,8 @@ def CheckForHeaderGuard(filename, clean_lines, error):
if ifndef != cppvar + '_': if ifndef != cppvar + '_':
error_level = 5 error_level = 5
ParseNolintSuppressions(filename, raw_lines[ifndef_linenum], ifndef_linenum, ParseNolintSuppressions(filename, raw_lines[ifndef_linenum],
error) ifndef_linenum, error)
error(filename, ifndef_linenum, 'build/header_guard', error_level, error(filename, ifndef_linenum, 'build/header_guard', error_level,
'#ifndef header guard has wrong style, please use: %s' % cppvar) '#ifndef header guard has wrong style, please use: %s' % cppvar)
...@@ -1763,7 +1769,8 @@ def CheckForHeaderGuard(filename, clean_lines, error): ...@@ -1763,7 +1769,8 @@ def CheckForHeaderGuard(filename, clean_lines, error):
no_single_line_comments = True no_single_line_comments = True
for i in xrange(1, len(raw_lines) - 1): for i in xrange(1, len(raw_lines) - 1):
line = raw_lines[i] line = raw_lines[i]
if Match(r'^(?:(?:\'(?:\.|[^\'])*\')|(?:"(?:\.|[^"])*")|[^\'"])*//', line): if Match(r'^(?:(?:\'(?:\.|[^\'])*\')|(?:"(?:\.|[^"])*")|[^\'"])*//',
line):
no_single_line_comments = False no_single_line_comments = False
break break
...@@ -1825,10 +1832,13 @@ def CheckForBadCharacters(filename, lines, error): ...@@ -1825,10 +1832,13 @@ def CheckForBadCharacters(filename, lines, error):
""" """
for linenum, line in enumerate(lines): for linenum, line in enumerate(lines):
if u'\ufffd' in line: if u'\ufffd' in line:
error(filename, linenum, 'readability/utf8', 5, error(
'Line contains invalid UTF-8 (or Unicode replacement character).') filename, linenum, 'readability/utf8', 5,
'Line contains invalid UTF-8 (or Unicode replacement character).'
)
if '\0' in line: if '\0' in line:
error(filename, linenum, 'readability/nul', 5, 'Line contains NUL byte.') error(filename, linenum, 'readability/nul', 5,
'Line contains NUL byte.')
def CheckForNewlineAtEOF(filename, lines, error): def CheckForNewlineAtEOF(filename, lines, error):
...@@ -1845,7 +1855,8 @@ def CheckForNewlineAtEOF(filename, lines, error): ...@@ -1845,7 +1855,8 @@ def CheckForNewlineAtEOF(filename, lines, error):
# To verify that the file ends in \n, we just have to make sure the # To verify that the file ends in \n, we just have to make sure the
# last-but-two element of lines() exists and is empty. # last-but-two element of lines() exists and is empty.
if len(lines) < 3 or lines[-2]: if len(lines) < 3 or lines[-2]:
error(filename, len(lines) - 2, 'whitespace/ending_newline', 5, error(filename,
len(lines) - 2, 'whitespace/ending_newline', 5,
'Could not find a newline character at the end of the file.') 'Could not find a newline character at the end of the file.')
...@@ -1911,10 +1922,8 @@ _THREADING_LIST = ( ...@@ -1911,10 +1922,8 @@ _THREADING_LIST = (
('gmtime(', 'gmtime_r(', _UNSAFE_FUNC_PREFIX + r'gmtime\([^)]+\)'), ('gmtime(', 'gmtime_r(', _UNSAFE_FUNC_PREFIX + r'gmtime\([^)]+\)'),
('localtime(', 'localtime_r(', _UNSAFE_FUNC_PREFIX + r'localtime\([^)]+\)'), ('localtime(', 'localtime_r(', _UNSAFE_FUNC_PREFIX + r'localtime\([^)]+\)'),
('rand(', 'rand_r(', _UNSAFE_FUNC_PREFIX + r'rand\(\)'), ('rand(', 'rand_r(', _UNSAFE_FUNC_PREFIX + r'rand\(\)'),
('strtok(', 'strtok_r(', ('strtok(', 'strtok_r(', _UNSAFE_FUNC_PREFIX + r'strtok\([^)]+\)'),
_UNSAFE_FUNC_PREFIX + r'strtok\([^)]+\)'), ('ttyname(', 'ttyname_r(', _UNSAFE_FUNC_PREFIX + r'ttyname\([^)]+\)'), )
('ttyname(', 'ttyname_r(', _UNSAFE_FUNC_PREFIX + r'ttyname\([^)]+\)'),
)
def CheckPosixThreading(filename, clean_lines, linenum, error): def CheckPosixThreading(filename, clean_lines, linenum, error):
...@@ -1938,9 +1947,8 @@ def CheckPosixThreading(filename, clean_lines, linenum, error): ...@@ -1938,9 +1947,8 @@ def CheckPosixThreading(filename, clean_lines, linenum, error):
# function we are looking for # function we are looking for
if Search(pattern, line): if Search(pattern, line):
error(filename, linenum, 'runtime/threadsafe_fn', 2, error(filename, linenum, 'runtime/threadsafe_fn', 2,
'Consider using ' + multithread_safe_func + 'Consider using ' + multithread_safe_func + '...) instead of '
'...) instead of ' + single_thread_func + + single_thread_func + '...) for improved thread safety.')
'...) for improved thread safety.')
def CheckVlogArguments(filename, clean_lines, linenum, error): def CheckVlogArguments(filename, clean_lines, linenum, error):
...@@ -1961,10 +1969,10 @@ def CheckVlogArguments(filename, clean_lines, linenum, error): ...@@ -1961,10 +1969,10 @@ def CheckVlogArguments(filename, clean_lines, linenum, error):
'VLOG() should be used with numeric verbosity level. ' 'VLOG() should be used with numeric verbosity level. '
'Use LOG() if you want symbolic severity levels.') 'Use LOG() if you want symbolic severity levels.')
# Matches invalid increment: *count++, which moves pointer instead of # Matches invalid increment: *count++, which moves pointer instead of
# incrementing a value. # incrementing a value.
_RE_PATTERN_INVALID_INCREMENT = re.compile( _RE_PATTERN_INVALID_INCREMENT = re.compile(r'^\s*\*\w+(\+\+|--);')
r'^\s*\*\w+(\+\+|--);')
def CheckInvalidIncrement(filename, clean_lines, linenum, error): def CheckInvalidIncrement(filename, clean_lines, linenum, error):
...@@ -1985,7 +1993,8 @@ def CheckInvalidIncrement(filename, clean_lines, linenum, error): ...@@ -1985,7 +1993,8 @@ def CheckInvalidIncrement(filename, clean_lines, linenum, error):
""" """
line = clean_lines.elided[linenum] line = clean_lines.elided[linenum]
if _RE_PATTERN_INVALID_INCREMENT.match(line): if _RE_PATTERN_INVALID_INCREMENT.match(line):
error(filename, linenum, 'runtime/invalid_increment', 5, error(
filename, linenum, 'runtime/invalid_increment', 5,
'Changing pointer instead of value (or unused value of operator*).') 'Changing pointer instead of value (or unused value of operator*).')
...@@ -2104,13 +2113,13 @@ class _ClassInfo(_BlockInfo): ...@@ -2104,13 +2113,13 @@ class _ClassInfo(_BlockInfo):
seen_last_thing_in_class = False seen_last_thing_in_class = False
for i in xrange(linenum - 1, self.starting_linenum, -1): for i in xrange(linenum - 1, self.starting_linenum, -1):
match = Search( match = Search(
r'\b(DISALLOW_COPY_AND_ASSIGN|DISALLOW_IMPLICIT_CONSTRUCTORS)\(' + r'\b(DISALLOW_COPY_AND_ASSIGN|DISALLOW_IMPLICIT_CONSTRUCTORS)\('
self.name + r'\)', + self.name + r'\)', clean_lines.elided[i])
clean_lines.elided[i])
if match: if match:
if seen_last_thing_in_class: if seen_last_thing_in_class:
error(filename, i, 'readability/constructors', 3, error(filename, i, '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')
break break
if not Match(r'^\s*$', clean_lines.elided[i]): if not Match(r'^\s*$', clean_lines.elided[i]):
...@@ -2126,7 +2135,8 @@ class _ClassInfo(_BlockInfo): ...@@ -2126,7 +2135,8 @@ class _ClassInfo(_BlockInfo):
else: else:
parent = 'class ' + self.name parent = 'class ' + self.name
error(filename, linenum, 'whitespace/indent', 3, error(filename, linenum, 'whitespace/indent', 3,
'Closing brace should be aligned with beginning of %s' % parent) 'Closing brace should be aligned with beginning of %s' %
parent)
class _NamespaceInfo(_BlockInfo): class _NamespaceInfo(_BlockInfo):
...@@ -2153,8 +2163,8 @@ class _NamespaceInfo(_BlockInfo): ...@@ -2153,8 +2163,8 @@ class _NamespaceInfo(_BlockInfo):
# other than forward declarations). There is currently no logic on # other than forward declarations). There is currently no logic on
# deciding what these nontrivial things are, so this check is # deciding what these nontrivial things are, so this check is
# triggered by namespace size only, which works most of the time. # triggered by namespace size only, which works most of the time.
if (linenum - self.starting_linenum < 10 if (linenum - self.starting_linenum < 10 and
and not Match(r'};*\s*(//|/\*).*\bnamespace\b', line)): not Match(r'};*\s*(//|/\*).*\bnamespace\b', line)):
return return
# Look for matching comment at end of namespace. # Look for matching comment at end of namespace.
...@@ -2171,9 +2181,8 @@ class _NamespaceInfo(_BlockInfo): ...@@ -2171,9 +2181,8 @@ class _NamespaceInfo(_BlockInfo):
# expected namespace. # expected namespace.
if self.name: if self.name:
# Named namespace # Named namespace
if not Match((r'};*\s*(//|/\*).*\bnamespace\s+' + re.escape(self.name) + if not Match((r'};*\s*(//|/\*).*\bnamespace\s+' +
r'[\*/\.\\\s]*$'), re.escape(self.name) + r'[\*/\.\\\s]*$'), line):
line):
error(filename, linenum, 'readability/namespace', 5, error(filename, linenum, 'readability/namespace', 5,
'Namespace should be terminated with "// namespace %s"' % 'Namespace should be terminated with "// namespace %s"' %
self.name) self.name)
...@@ -2182,13 +2191,17 @@ class _NamespaceInfo(_BlockInfo): ...@@ -2182,13 +2191,17 @@ class _NamespaceInfo(_BlockInfo):
if not Match(r'};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line): if not Match(r'};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line):
# If "// namespace anonymous" or "// anonymous namespace (more text)", # If "// namespace anonymous" or "// anonymous namespace (more text)",
# mention "// anonymous namespace" as an acceptable form # mention "// anonymous namespace" as an acceptable form
if Match(r'}.*\b(namespace anonymous|anonymous namespace)\b', line): if Match(r'}.*\b(namespace anonymous|anonymous namespace)\b',
error(filename, linenum, 'readability/namespace', 5, line):
error(
filename, linenum, 'readability/namespace', 5,
'Anonymous namespace should be terminated with "// namespace"' 'Anonymous namespace should be terminated with "// namespace"'
' or "// anonymous namespace"') ' or "// anonymous namespace"')
else: else:
error(filename, linenum, 'readability/namespace', 5, error(
'Anonymous namespace should be terminated with "// namespace"') filename, linenum, 'readability/namespace', 5,
'Anonymous namespace should be terminated with "// namespace"'
)
class _PreprocessorInfo(object): class _PreprocessorInfo(object):
...@@ -2316,7 +2329,8 @@ class NestingState(object): ...@@ -2316,7 +2329,8 @@ class NestingState(object):
# We can't be sure if we just find a single '<', and need to # We can't be sure if we just find a single '<', and need to
# find the matching '>'. # find the matching '>'.
(_, end_line, end_pos) = CloseExpression(clean_lines, linenum, pos - 1) (_, end_line, end_pos) = CloseExpression(clean_lines, linenum,
pos - 1)
if end_pos < 0: if end_pos < 0:
# Not sure if template argument list or syntax error in file # Not sure if template argument list or syntax error in file
return False return False
...@@ -2357,7 +2371,8 @@ class NestingState(object): ...@@ -2357,7 +2371,8 @@ class NestingState(object):
# whole nesting stack up to this point. This is what we # whole nesting stack up to this point. This is what we
# keep after the #endif. # keep after the #endif.
self.pp_stack[-1].seen_else = True self.pp_stack[-1].seen_else = True
self.pp_stack[-1].stack_before_else = copy.deepcopy(self.stack) self.pp_stack[-1].stack_before_else = copy.deepcopy(
self.stack)
# Restore the stack to how it was before the #if # Restore the stack to how it was before the #if
self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if) self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if)
...@@ -2414,8 +2429,7 @@ class NestingState(object): ...@@ -2414,8 +2429,7 @@ class NestingState(object):
# Also check if we are starting or ending an inline assembly block. # Also check if we are starting or ending an inline assembly block.
if inner_block.inline_asm in (_NO_ASM, _END_ASM): if inner_block.inline_asm in (_NO_ASM, _END_ASM):
if (depth_change != 0 and if (depth_change != 0 and inner_block.open_parentheses == 1 and
inner_block.open_parentheses == 1 and
_MATCH_ASM.match(line)): _MATCH_ASM.match(line)):
# Enter assembly block # Enter assembly block
inner_block.inline_asm = _INSIDE_ASM inner_block.inline_asm = _INSIDE_ASM
...@@ -2436,11 +2450,13 @@ class NestingState(object): ...@@ -2436,11 +2450,13 @@ class NestingState(object):
# declarations even if it weren't followed by a whitespace, this # declarations even if it weren't followed by a whitespace, this
# is so that we don't confuse our namespace checker. The # is so that we don't confuse our namespace checker. The
# missing spaces will be flagged by CheckSpacing. # missing spaces will be flagged by CheckSpacing.
namespace_decl_match = Match(r'^\s*namespace\b\s*([:\w]+)?(.*)$', line) namespace_decl_match = Match(r'^\s*namespace\b\s*([:\w]+)?(.*)$',
line)
if not namespace_decl_match: if not namespace_decl_match:
break break
new_namespace = _NamespaceInfo(namespace_decl_match.group(1), linenum) new_namespace = _NamespaceInfo(
namespace_decl_match.group(1), linenum)
self.stack.append(new_namespace) self.stack.append(new_namespace)
line = namespace_decl_match.group(2) line = namespace_decl_match.group(2)
...@@ -2469,10 +2485,12 @@ class NestingState(object): ...@@ -2469,10 +2485,12 @@ class NestingState(object):
# an unmatched '>'. If we see one, assume we are inside a # an unmatched '>'. If we see one, assume we are inside a
# template argument list. # template argument list.
end_declaration = len(class_decl_match.group(1)) end_declaration = len(class_decl_match.group(1))
if not self.InTemplateArgumentList(clean_lines, linenum, end_declaration): if not self.InTemplateArgumentList(clean_lines, linenum,
self.stack.append(_ClassInfo( end_declaration):
class_decl_match.group(3), class_decl_match.group(2), self.stack.append(
clean_lines, linenum)) _ClassInfo(
class_decl_match.group(3),
class_decl_match.group(2), clean_lines, linenum))
line = class_decl_match.group(4) line = class_decl_match.group(4)
# If we have not yet seen the opening brace for the innermost block, # If we have not yet seen the opening brace for the innermost block,
...@@ -2485,8 +2503,7 @@ class NestingState(object): ...@@ -2485,8 +2503,7 @@ class NestingState(object):
classinfo = self.stack[-1] classinfo = self.stack[-1]
access_match = Match( access_match = Match(
r'^(.*)\b(public|private|protected|signals)(\s+(?:slots\s*)?)?' r'^(.*)\b(public|private|protected|signals)(\s+(?:slots\s*)?)?'
r':(?:[^:]|$)', r':(?:[^:]|$)', line)
line)
if access_match: if access_match:
classinfo.access = access_match.group(2) classinfo.access = access_match.group(2)
...@@ -2541,7 +2558,8 @@ class NestingState(object): ...@@ -2541,7 +2558,8 @@ class NestingState(object):
else: # token == '}' else: # token == '}'
# Perform end of block checks and pop the stack. # Perform end of block checks and pop the stack.
if self.stack: if self.stack:
self.stack[-1].CheckEnd(filename, clean_lines, linenum, error) self.stack[-1].CheckEnd(filename, clean_lines, linenum,
error)
self.stack.pop() self.stack.pop()
line = matched.group(2) line = matched.group(2)
...@@ -2579,8 +2597,8 @@ class NestingState(object): ...@@ -2579,8 +2597,8 @@ class NestingState(object):
obj.name) obj.name)
def CheckForNonStandardConstructs(filename, clean_lines, linenum, def CheckForNonStandardConstructs(filename, clean_lines, linenum, nesting_state,
nesting_state, error): error):
r"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2. r"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
Complain about several constructs which gcc-2 accepts, but which are Complain about several constructs which gcc-2 accepts, but which are
...@@ -2632,8 +2650,7 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum, ...@@ -2632,8 +2650,7 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum,
if Search(r'\b(const|volatile|void|char|short|int|long' if Search(r'\b(const|volatile|void|char|short|int|long'
r'|float|double|signed|unsigned' r'|float|double|signed|unsigned'
r'|schar|u?int8|u?int16|u?int32|u?int64)' r'|schar|u?int8|u?int16|u?int32|u?int64)'
r'\s+(register|static|extern|typedef)\b', r'\s+(register|static|extern|typedef)\b', line):
line):
error(filename, linenum, 'build/storage_class', 5, error(filename, linenum, 'build/storage_class', 5,
'Storage class (static, extern, typedef, etc) should be first.') 'Storage class (static, extern, typedef, etc) should be first.')
...@@ -2642,12 +2659,14 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum, ...@@ -2642,12 +2659,14 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum,
'Uncommented text after #endif is non-standard. Use a comment.') 'Uncommented text after #endif is non-standard. Use a comment.')
if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line): if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line):
error(filename, linenum, 'build/forward_decl', 5, error(
filename, linenum, 'build/forward_decl', 5,
'Inner-style forward declarations are invalid. Remove this line.') 'Inner-style forward declarations are invalid. Remove this line.')
if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?', if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?',
line): line):
error(filename, linenum, 'build/deprecated', 3, error(
filename, linenum, 'build/deprecated', 3,
'>? and <? (max and min) operators are non-standard and deprecated.') '>? and <? (max and min) operators are non-standard and deprecated.')
if Search(r'^\s*const\s*string\s*&\s*\w+\s*;', line): if Search(r'^\s*const\s*string\s*&\s*\w+\s*;', line):
...@@ -2679,9 +2698,7 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum, ...@@ -2679,9 +2698,7 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum,
# strongly suggest something is wrong. # strongly suggest something is wrong.
explicit_constructor_match = Match( explicit_constructor_match = Match(
r'\s+(?:inline\s+)?(explicit\s+)?(?:inline\s+)?%s\s*' r'\s+(?:inline\s+)?(explicit\s+)?(?:inline\s+)?%s\s*'
r'\(((?:[^()]|\([^()]*\))*)\)' r'\(((?:[^()]|\([^()]*\))*)\)' % re.escape(base_classname), line)
% re.escape(base_classname),
line)
if explicit_constructor_match: if explicit_constructor_match:
is_marked_explicit = explicit_constructor_match.group(1) is_marked_explicit = explicit_constructor_match.group(1)
...@@ -2704,38 +2721,40 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum, ...@@ -2704,38 +2721,40 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum,
i += 1 i += 1
defaulted_args = [arg for arg in constructor_args if '=' in arg] defaulted_args = [arg for arg in constructor_args if '=' in arg]
noarg_constructor = (not constructor_args or # empty arg list noarg_constructor = (
not constructor_args or # empty arg list
# 'void' arg specifier # 'void' arg specifier
(len(constructor_args) == 1 and (len(constructor_args) == 1 and
constructor_args[0].strip() == 'void')) constructor_args[0].strip() == 'void'))
onearg_constructor = ((len(constructor_args) == 1 and # exactly one arg onearg_constructor = (
(
len(constructor_args) == 1 and # exactly one arg
not noarg_constructor) or not noarg_constructor) or
# all but at most one arg defaulted # all but at most one arg defaulted
(len(constructor_args) >= 1 and (len(constructor_args) >= 1 and not noarg_constructor and
not noarg_constructor and
len(defaulted_args) >= len(constructor_args) - 1)) len(defaulted_args) >= len(constructor_args) - 1))
initializer_list_constructor = bool( initializer_list_constructor = bool(
onearg_constructor and onearg_constructor and
Search(r'\bstd\s*::\s*initializer_list\b', constructor_args[0])) Search(r'\bstd\s*::\s*initializer_list\b', constructor_args[0]))
copy_constructor = bool( copy_constructor = bool(
onearg_constructor and onearg_constructor and
Match(r'(const\s+)?%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&' Match(r'(const\s+)?%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&' %
% re.escape(base_classname), constructor_args[0].strip())) re.escape(base_classname), constructor_args[0].strip()))
if (not is_marked_explicit and if (not is_marked_explicit and onearg_constructor and
onearg_constructor and not initializer_list_constructor and not copy_constructor):
not initializer_list_constructor and
not copy_constructor):
if defaulted_args: if defaulted_args:
error(filename, linenum, 'runtime/explicit', 5, error(filename, linenum, 'runtime/explicit', 5,
'Constructors callable with one argument ' 'Constructors callable with one argument '
'should be marked explicit.') 'should be marked explicit.')
else: else:
error(filename, linenum, 'runtime/explicit', 5, error(
filename, linenum, 'runtime/explicit', 5,
'Single-parameter constructors should be marked explicit.') 'Single-parameter constructors should be marked explicit.')
elif is_marked_explicit and not onearg_constructor: elif is_marked_explicit and not onearg_constructor:
if noarg_constructor: if noarg_constructor:
error(filename, linenum, 'runtime/explicit', 5, error(
filename, linenum, 'runtime/explicit', 5,
'Zero-parameter constructors should not be marked explicit.') 'Zero-parameter constructors should not be marked explicit.')
else: else:
error(filename, linenum, 'runtime/explicit', 0, error(filename, linenum, 'runtime/explicit', 0,
...@@ -2759,10 +2778,8 @@ def CheckSpacingForFunctionCall(filename, clean_lines, linenum, error): ...@@ -2759,10 +2778,8 @@ def CheckSpacingForFunctionCall(filename, clean_lines, linenum, error):
# first see if we should be looking inside such an expression for a # first see if we should be looking inside such an expression for a
# function call, to which we can apply more strict standards. # function call, to which we can apply more strict standards.
fncall = line # if there's no control flow construct, look at whole line fncall = line # if there's no control flow construct, look at whole line
for pattern in (r'\bif\s*\((.*)\)\s*{', for pattern in (r'\bif\s*\((.*)\)\s*{', r'\bfor\s*\((.*)\)\s*{',
r'\bfor\s*\((.*)\)\s*{', r'\bwhile\s*\((.*)\)\s*[{;]', r'\bswitch\s*\((.*)\)\s*{'):
r'\bwhile\s*\((.*)\)\s*[{;]',
r'\bswitch\s*\((.*)\)\s*{'):
match = Search(pattern, line) match = Search(pattern, line)
if match: if match:
fncall = match.group(1) # look inside the parens for function calls fncall = match.group(1) # look inside the parens for function calls
...@@ -2782,7 +2799,8 @@ def CheckSpacingForFunctionCall(filename, clean_lines, linenum, error): ...@@ -2782,7 +2799,8 @@ def CheckSpacingForFunctionCall(filename, clean_lines, linenum, error):
# Note that we assume the contents of [] to be short enough that # Note that we assume the contents of [] to be short enough that
# they'll never need to wrap. # they'll never need to wrap.
if ( # Ignore control structures. if ( # Ignore control structures.
not Search(r'\b(if|for|while|switch|return|new|delete|catch|sizeof)\b', not Search(
r'\b(if|for|while|switch|return|new|delete|catch|sizeof)\b',
fncall) and fncall) and
# Ignore pointers/references to functions. # Ignore pointers/references to functions.
not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and
...@@ -2844,12 +2862,12 @@ def CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line, ...@@ -2844,12 +2862,12 @@ def CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line,
if ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item, if ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item,
clean_lines.elided, line): clean_lines.elided, line):
CheckItemIndentationInNamespace(filename, clean_lines.elided, CheckItemIndentationInNamespace(filename, clean_lines.elided, line,
line, error) error)
def CheckForFunctionLengths(filename, clean_lines, linenum, def CheckForFunctionLengths(filename, clean_lines, linenum, function_state,
function_state, error): error):
"""Reports for long function bodies. """Reports for long function bodies.
For an overview why this is done, see: For an overview why this is done, see:
...@@ -2891,7 +2909,8 @@ def CheckForFunctionLengths(filename, clean_lines, linenum, ...@@ -2891,7 +2909,8 @@ def CheckForFunctionLengths(filename, clean_lines, linenum,
for start_linenum in xrange(linenum, clean_lines.NumLines()): for start_linenum in xrange(linenum, clean_lines.NumLines()):
start_line = lines[start_linenum] start_line = lines[start_linenum]
joined_line += ' ' + start_line.lstrip() joined_line += ' ' + start_line.lstrip()
if Search(r'(;|})', start_line): # Declarations and trivial functions if Search(r'(;|})',
start_line): # Declarations and trivial functions
body_found = True body_found = True
break # ... ignore break # ... ignore
elif Search(r'{', start_line): elif Search(r'{', start_line):
...@@ -2933,14 +2952,14 @@ def CheckComment(line, filename, linenum, next_line_start, error): ...@@ -2933,14 +2952,14 @@ def CheckComment(line, filename, linenum, next_line_start, error):
if commentpos != -1: if commentpos != -1:
# Check if the // may be in quotes. If so, ignore it # Check if the // may be in quotes. If so, ignore it
# Comparisons made explicit for clarity -- pylint: disable=g-explicit-bool-comparison # Comparisons made explicit for clarity -- pylint: disable=g-explicit-bool-comparison
if (line.count('"', 0, commentpos) - if (line.count('"', 0, commentpos) - line.count('\\"', 0, commentpos)
line.count('\\"', 0, commentpos)) % 2 == 0: # not in quotes ) % 2 == 0: # not in quotes
# Allow one space for new scopes, two spaces otherwise: # Allow one space for new scopes, two spaces otherwise:
if (not (Match(r'^.*{ *//', line) and next_line_start == commentpos) and if (not (Match(r'^.*{ *//', line) and next_line_start == commentpos)
((commentpos >= 1 and and ((commentpos >= 1 and
line[commentpos-1] not in string.whitespace) or line[commentpos - 1] not in string.whitespace) or
(commentpos >= 2 and (commentpos >= 2 and
line[commentpos-2] not in string.whitespace))): line[commentpos - 2] not in string.whitespace))):
error(filename, linenum, 'whitespace/comments', 2, error(filename, linenum, 'whitespace/comments', 2,
'At least two spaces is best between code and comments') 'At least two spaces is best between code and comments')
...@@ -3044,8 +3063,7 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error): ...@@ -3044,8 +3063,7 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
# #
# Also skip blank line checks for 'extern "C"' blocks, which are formatted # Also skip blank line checks for 'extern "C"' blocks, which are formatted
# like namespaces. # like namespaces.
if (IsBlankLine(line) and if (IsBlankLine(line) and not nesting_state.InNamespaceBody() and
not nesting_state.InNamespaceBody() and
not nesting_state.InExternC()): not nesting_state.InExternC()):
elided = clean_lines.elided elided = clean_lines.elided
prev_line = elided[linenum - 1] prev_line = elided[linenum - 1]
...@@ -3066,12 +3084,12 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error): ...@@ -3066,12 +3084,12 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
if Match(r' {6}\w', prev_line): # Initializer list? if Match(r' {6}\w', prev_line): # Initializer list?
# We are looking for the opening column of initializer list, which # We are looking for the opening column of initializer list, which
# should be indented 4 spaces to cause 6 space indentation afterwards. # should be indented 4 spaces to cause 6 space indentation afterwards.
search_position = linenum-2 search_position = linenum - 2
while (search_position >= 0 while (search_position >= 0 and
and Match(r' {6}\w', elided[search_position])): Match(r' {6}\w', elided[search_position])):
search_position -= 1 search_position -= 1
exception = (search_position >= 0 exception = (search_position >= 0 and
and elided[search_position][:5] == ' :') elided[search_position][:5] == ' :')
else: else:
# Search for the function arguments or an initializer list. We use a # Search for the function arguments or an initializer list. We use a
# simple heuristic here: If the line is indented 4 spaces; and we have a # simple heuristic here: If the line is indented 4 spaces; and we have a
...@@ -3080,8 +3098,7 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error): ...@@ -3080,8 +3098,7 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
# a function header. If we have a colon indented 4 spaces, it is an # a function header. If we have a colon indented 4 spaces, it is an
# initializer list. # initializer list.
exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)', exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',
prev_line) prev_line) or Match(r' {4}:', prev_line))
or Match(r' {4}:', prev_line))
if not exception: if not exception:
error(filename, linenum, 'whitespace/blank_line', 2, error(filename, linenum, 'whitespace/blank_line', 2,
...@@ -3097,9 +3114,8 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error): ...@@ -3097,9 +3114,8 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
# } # }
if linenum + 1 < clean_lines.NumLines(): if linenum + 1 < clean_lines.NumLines():
next_line = raw[linenum + 1] next_line = raw[linenum + 1]
if (next_line if (next_line and Match(r'\s*}', next_line) and
and Match(r'\s*}', next_line) next_line.find('} else ') == -1):
and next_line.find('} else ') == -1):
error(filename, linenum, 'whitespace/blank_line', 3, error(filename, linenum, 'whitespace/blank_line', 3,
'Redundant blank line at the end of a code block ' 'Redundant blank line at the end of a code block '
'should be deleted.') 'should be deleted.')
...@@ -3122,8 +3138,7 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error): ...@@ -3122,8 +3138,7 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
# You shouldn't have spaces before your brackets, except maybe after # You shouldn't have spaces before your brackets, except maybe after
# 'delete []' or 'return []() {};' # 'delete []' or 'return []() {};'
if Search(r'\w\s+\[', line) and not Search(r'(?:delete|return)\s+\[', line): if Search(r'\w\s+\[', line) and not Search(r'(?:delete|return)\s+\[', line):
error(filename, linenum, 'whitespace/braces', 5, error(filename, linenum, 'whitespace/braces', 5, 'Extra space before [')
'Extra space before [')
# In range-based for, we wanted spaces before and after the colon, but # In range-based for, we wanted spaces before and after the colon, but
# not around "::" tokens that might appear. # not around "::" tokens that might appear.
...@@ -3162,11 +3177,11 @@ def CheckOperatorSpacing(filename, clean_lines, linenum, error): ...@@ -3162,11 +3177,11 @@ def CheckOperatorSpacing(filename, clean_lines, linenum, error):
# sometimes people put non-spaces on one side when aligning ='s among # sometimes people put non-spaces on one side when aligning ='s among
# many lines (not that this is behavior that I approve of...) # many lines (not that this is behavior that I approve of...)
if ((Search(r'[\w.]=', line) or if ((Search(r'[\w.]=', line) or
Search(r'=[\w.]', line)) Search(r'=[\w.]', line)) and not Search(r'\b(if|while|for) ', line)
and not Search(r'\b(if|while|for) ', line)
# Operators taken from [lex.operators] in C++11 standard. # Operators taken from [lex.operators] in C++11 standard.
and not Search(r'(>=|<=|==|!=|&=|\^=|\|=|\+=|\*=|\/=|\%=)', line) and
and not Search(r'operator=', line)): not Search(r'(>=|<=|==|!=|&=|\^=|\|=|\+=|\*=|\/=|\%=)', line) and
not Search(r'operator=', line)):
error(filename, linenum, 'whitespace/operators', 4, error(filename, linenum, 'whitespace/operators', 4,
'Missing spaces around =') 'Missing spaces around =')
...@@ -3196,8 +3211,8 @@ def CheckOperatorSpacing(filename, clean_lines, linenum, error): ...@@ -3196,8 +3211,8 @@ def CheckOperatorSpacing(filename, clean_lines, linenum, error):
# space. This is done to avoid some false positives with shifts. # space. This is done to avoid some false positives with shifts.
match = Match(r'^(.*[^\s<])<[^\s=<,]', line) match = Match(r'^(.*[^\s<])<[^\s=<,]', line)
if match: if match:
(_, _, end_pos) = CloseExpression( (_, _, end_pos) = CloseExpression(clean_lines, linenum,
clean_lines, linenum, len(match.group(1))) len(match.group(1)))
if end_pos <= -1: if end_pos <= -1:
error(filename, linenum, 'whitespace/operators', 3, error(filename, linenum, 'whitespace/operators', 3,
'Missing spaces around <') 'Missing spaces around <')
...@@ -3207,8 +3222,8 @@ def CheckOperatorSpacing(filename, clean_lines, linenum, error): ...@@ -3207,8 +3222,8 @@ def CheckOperatorSpacing(filename, clean_lines, linenum, error):
# false positives with shifts. # false positives with shifts.
match = Match(r'^(.*[^-\s>])>[^\s=>,]', line) match = Match(r'^(.*[^-\s>])>[^\s=>,]', line)
if match: if match:
(_, _, start_pos) = ReverseCloseExpression( (_, _, start_pos) = ReverseCloseExpression(clean_lines, linenum,
clean_lines, linenum, len(match.group(1))) len(match.group(1)))
if start_pos <= -1: if start_pos <= -1:
error(filename, linenum, 'whitespace/operators', 3, error(filename, linenum, 'whitespace/operators', 3,
'Missing spaces around >') 'Missing spaces around >')
...@@ -3218,8 +3233,10 @@ def CheckOperatorSpacing(filename, clean_lines, linenum, error): ...@@ -3218,8 +3233,10 @@ def CheckOperatorSpacing(filename, clean_lines, linenum, error):
# #
# We also allow operators following an opening parenthesis, since # We also allow operators following an opening parenthesis, since
# those tend to be macros that deal with operators. # those tend to be macros that deal with operators.
match = Search(r'(operator|[^\s(<])(?:L|UL|ULL|l|ul|ull)?<<([^\s,=<])', line) match = Search(r'(operator|[^\s(<])(?:L|UL|ULL|l|ul|ull)?<<([^\s,=<])',
if (match and not (match.group(1).isdigit() and match.group(2).isdigit()) and line)
if (match and
not (match.group(1).isdigit() and match.group(2).isdigit()) and
not (match.group(1) == 'operator' and match.group(2) == ';')): not (match.group(1) == 'operator' and match.group(2) == ';')):
error(filename, linenum, 'whitespace/operators', 3, error(filename, linenum, 'whitespace/operators', 3,
'Missing spaces around <<') 'Missing spaces around <<')
...@@ -3271,8 +3288,7 @@ def CheckParenthesisSpacing(filename, clean_lines, linenum, error): ...@@ -3271,8 +3288,7 @@ def CheckParenthesisSpacing(filename, clean_lines, linenum, error):
# We don't want: "if ( foo)" or "if ( foo )". # We don't want: "if ( foo)" or "if ( foo )".
# Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed. # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed.
match = Search(r'\b(if|for|while|switch)\s*' match = Search(r'\b(if|for|while|switch)\s*'
r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$', r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$', line)
line)
if match: if match:
if len(match.group(2)) != len(match.group(4)): if len(match.group(2)) != len(match.group(4)):
if not (match.group(3) == ';' and if not (match.group(3) == ';' and
...@@ -3310,8 +3326,7 @@ def CheckCommaSpacing(filename, clean_lines, linenum, error): ...@@ -3310,8 +3326,7 @@ def CheckCommaSpacing(filename, clean_lines, linenum, error):
# elided comments. # elided comments.
if (Search(r',[^,\s]', ReplaceAll(r'\boperator\s*,\s*\(', 'F(', line)) and if (Search(r',[^,\s]', ReplaceAll(r'\boperator\s*,\s*\(', 'F(', line)) and
Search(r',[^,\s]', raw[linenum])): Search(r',[^,\s]', raw[linenum])):
error(filename, linenum, 'whitespace/comma', 3, error(filename, linenum, 'whitespace/comma', 3, 'Missing space after ,')
'Missing space after ,')
# You should always have a space after a semicolon # You should always have a space after a semicolon
# except for few corner cases # except for few corner cases
...@@ -3367,8 +3382,8 @@ def CheckBracesSpacing(filename, clean_lines, linenum, error): ...@@ -3367,8 +3382,8 @@ def CheckBracesSpacing(filename, clean_lines, linenum, error):
# There is a false negative with this approach if people inserted # There is a false negative with this approach if people inserted
# spurious semicolons, e.g. "if (cond){};", but we will catch the # spurious semicolons, e.g. "if (cond){};", but we will catch the
# spurious semicolon with a separate check. # spurious semicolon with a separate check.
(endline, endlinenum, endpos) = CloseExpression( (endline, endlinenum, endpos) = CloseExpression(clean_lines, linenum,
clean_lines, linenum, len(match.group(1))) len(match.group(1)))
trailing_text = '' trailing_text = ''
if endpos > -1: if endpos > -1:
trailing_text = endline[endpos:] trailing_text = endline[endpos:]
...@@ -3391,11 +3406,11 @@ def CheckBracesSpacing(filename, clean_lines, linenum, error): ...@@ -3391,11 +3406,11 @@ def CheckBracesSpacing(filename, clean_lines, linenum, error):
error(filename, linenum, 'whitespace/semicolon', 5, error(filename, linenum, 'whitespace/semicolon', 5,
'Semicolon defining empty statement. Use {} instead.') 'Semicolon defining empty statement. Use {} instead.')
elif Search(r'^\s*;\s*$', line): elif Search(r'^\s*;\s*$', line):
error(filename, linenum, 'whitespace/semicolon', 5, error(
filename, linenum, 'whitespace/semicolon', 5,
'Line contains only semicolon. If this should be an empty statement, ' 'Line contains only semicolon. If this should be an empty statement, '
'use {} instead.') 'use {} instead.')
elif (Search(r'\s+;\s*$', line) and elif (Search(r'\s+;\s*$', line) and not Search(r'\bfor\b', line)):
not Search(r'\bfor\b', line)):
error(filename, linenum, 'whitespace/semicolon', 5, error(filename, linenum, 'whitespace/semicolon', 5,
'Extra space before last semicolon. If this should be an empty ' 'Extra space before last semicolon. If this should be an empty '
'statement, use {} instead.') 'statement, use {} instead.')
...@@ -3429,10 +3444,10 @@ def IsTemplateParameterList(clean_lines, linenum, column): ...@@ -3429,10 +3444,10 @@ def IsTemplateParameterList(clean_lines, linenum, column):
Returns: Returns:
True if this token is end of a template parameter list, False otherwise. True if this token is end of a template parameter list, False otherwise.
""" """
(_, startline, startpos) = ReverseCloseExpression( (_, startline, startpos) = ReverseCloseExpression(clean_lines, linenum,
clean_lines, linenum, column) column)
if (startpos > -1 and if (startpos > -1 and Search(r'\btemplate\s*$',
Search(r'\btemplate\s*$', clean_lines.elided[startline][0:startpos])): clean_lines.elided[startline][0:startpos])):
return True return True
return False return False
...@@ -3476,18 +3491,19 @@ def IsRValueType(typenames, clean_lines, nesting_state, linenum, column): ...@@ -3476,18 +3491,19 @@ def IsRValueType(typenames, clean_lines, nesting_state, linenum, column):
# recognize pointer and reference types: # recognize pointer and reference types:
# int* Function() # int* Function()
# int& Function() # int& Function()
if (match.group(2) in typenames or if (match.group(2) in typenames or match.group(2) in [
match.group(2) in ['char', 'char16_t', 'char32_t', 'wchar_t', 'bool', 'char', 'char16_t', 'char32_t', 'wchar_t', 'bool', 'short', 'int',
'short', 'int', 'long', 'signed', 'unsigned', 'long', 'signed', 'unsigned', 'float', 'double', 'void', 'auto',
'float', 'double', 'void', 'auto', '>', '*', '&']): '>', '*', '&'
]):
return True return True
# If we see a close parenthesis, look for decltype on the other side. # If we see a close parenthesis, look for decltype on the other side.
# decltype would unambiguously identify a type, anything else is # decltype would unambiguously identify a type, anything else is
# probably a parenthesized expression and not a type. # probably a parenthesized expression and not a type.
if match.group(2) == ')': if match.group(2) == ')':
return IsDecltype( return IsDecltype(clean_lines, linenum,
clean_lines, linenum, len(match.group(1)) + len(match.group(2)) - 1) len(match.group(1)) + len(match.group(2)) - 1)
# Check for casts and cv-qualifiers. # Check for casts and cv-qualifiers.
# match.group(1) remainder # match.group(1) remainder
...@@ -3496,8 +3512,7 @@ def IsRValueType(typenames, clean_lines, nesting_state, linenum, column): ...@@ -3496,8 +3512,7 @@ def IsRValueType(typenames, clean_lines, nesting_state, linenum, column):
# const type&& # const type&&
# type const&& # type const&&
if Search(r'\b(?:const_cast\s*<|static_cast\s*<|dynamic_cast\s*<|' if Search(r'\b(?:const_cast\s*<|static_cast\s*<|dynamic_cast\s*<|'
r'reinterpret_cast\s*<|\w+\s)\s*$', r'reinterpret_cast\s*<|\w+\s)\s*$', match.group(1)):
match.group(1)):
return True return True
# Look for a preceding symbol that might help differentiate the context. # Look for a preceding symbol that might help differentiate the context.
...@@ -3594,7 +3609,8 @@ def IsRValueType(typenames, clean_lines, nesting_state, linenum, column): ...@@ -3594,7 +3609,8 @@ def IsRValueType(typenames, clean_lines, nesting_state, linenum, column):
# sizeof(type&& # sizeof(type&&
# operator=(type&& # operator=(type&&
# #
if Search(r'(?:\]|\bfor|\bsizeof|\boperator\s*\S+\s*)\s*$', before_text): if Search(r'(?:\]|\bfor|\bsizeof|\boperator\s*\S+\s*)\s*$',
before_text):
return True return True
# Patterns that are likely to be expressions: # Patterns that are likely to be expressions:
...@@ -3618,9 +3634,10 @@ def IsRValueType(typenames, clean_lines, nesting_state, linenum, column): ...@@ -3618,9 +3634,10 @@ def IsRValueType(typenames, clean_lines, nesting_state, linenum, column):
# Check for constructors, which don't have return types. # Check for constructors, which don't have return types.
if Search(r'\b(?:explicit|inline)$', match_func.group(1)): if Search(r'\b(?:explicit|inline)$', match_func.group(1)):
return True return True
implicit_constructor = Match(r'\s*(\w+)\((?:const\s+)?(\w+)', prefix) implicit_constructor = Match(r'\s*(\w+)\((?:const\s+)?(\w+)',
if (implicit_constructor and prefix)
implicit_constructor.group(1) == implicit_constructor.group(2)): if (implicit_constructor and implicit_constructor.group(1) ==
implicit_constructor.group(2)):
return True return True
return IsRValueType(typenames, clean_lines, nesting_state, linenum, return IsRValueType(typenames, clean_lines, nesting_state, linenum,
len(match_func.group(1))) len(match_func.group(1)))
...@@ -3633,8 +3650,8 @@ def IsRValueType(typenames, clean_lines, nesting_state, linenum, column): ...@@ -3633,8 +3650,8 @@ def IsRValueType(typenames, clean_lines, nesting_state, linenum, column):
if match_symbol.group(2) == '>': if match_symbol.group(2) == '>':
# Possibly a closing bracket, check that what's on the other side # Possibly a closing bracket, check that what's on the other side
# looks like the start of a template. # looks like the start of a template.
return IsTemplateParameterList( return IsTemplateParameterList(clean_lines, start,
clean_lines, start, len(match_symbol.group(1))) len(match_symbol.group(1)))
# Some other symbol, usually something like "a=b&&c". This is most # Some other symbol, usually something like "a=b&&c". This is most
# likely not a type. # likely not a type.
...@@ -3653,8 +3670,8 @@ def IsDeletedOrDefault(clean_lines, linenum): ...@@ -3653,8 +3670,8 @@ def IsDeletedOrDefault(clean_lines, linenum):
open_paren = clean_lines.elided[linenum].find('(') open_paren = clean_lines.elided[linenum].find('(')
if open_paren < 0: if open_paren < 0:
return False return False
(close_line, _, close_paren) = CloseExpression( (close_line, _, close_paren) = CloseExpression(clean_lines, linenum,
clean_lines, linenum, open_paren) open_paren)
if close_paren < 0: if close_paren < 0:
return False return False
return Match(r'\s*=\s*(?:delete|default)\b', close_line[close_paren:]) return Match(r'\s*=\s*(?:delete|default)\b', close_line[close_paren:])
...@@ -3697,7 +3714,8 @@ def IsRValueAllowed(clean_lines, linenum, typenames): ...@@ -3697,7 +3714,8 @@ def IsRValueAllowed(clean_lines, linenum, typenames):
previous_line = 'ReturnType' previous_line = 'ReturnType'
if linenum > 0: if linenum > 0:
previous_line = clean_lines.elided[linenum - 1] previous_line = clean_lines.elided[linenum - 1]
if Match(r'^\s*$', previous_line) or Search(r'[{}:;]\s*$', previous_line): if Match(r'^\s*$', previous_line) or Search(r'[{}:;]\s*$',
previous_line):
return IsDeletedOrDefault(clean_lines, linenum) return IsDeletedOrDefault(clean_lines, linenum)
# Reject types not mentioned in template-argument-list # Reject types not mentioned in template-argument-list
...@@ -3747,7 +3765,8 @@ def GetTemplateArgs(clean_lines, linenum): ...@@ -3747,7 +3765,8 @@ def GetTemplateArgs(clean_lines, linenum):
if match: if match:
# template-argument-list on the same line as function name # template-argument-list on the same line as function name
start_col = len(match.group(1)) start_col = len(match.group(1))
_, end_line, end_col = CloseExpression(clean_lines, func_line, start_col) _, end_line, end_col = CloseExpression(clean_lines, func_line,
start_col)
if end_col > -1 and end_line == func_line: if end_col > -1 and end_line == func_line:
start_col += 1 # Skip the opening bracket start_col += 1 # Skip the opening bracket
argument_list = clean_lines.elided[func_line][start_col:end_col] argument_list = clean_lines.elided[func_line][start_col:end_col]
...@@ -3765,7 +3784,8 @@ def GetTemplateArgs(clean_lines, linenum): ...@@ -3765,7 +3784,8 @@ def GetTemplateArgs(clean_lines, linenum):
argument_list += clean_lines.elided[start_line][start_col:] argument_list += clean_lines.elided[start_line][start_col:]
start_col = 0 start_col = 0
start_line += 1 start_line += 1
argument_list += clean_lines.elided[func_line - 1][start_col:end_col] argument_list += clean_lines.elided[func_line - 1][start_col:
end_col]
if not argument_list: if not argument_list:
return set() return set()
...@@ -3801,7 +3821,8 @@ def CheckRValueReference(filename, clean_lines, linenum, nesting_state, error): ...@@ -3801,7 +3821,8 @@ def CheckRValueReference(filename, clean_lines, linenum, nesting_state, error):
match = Match(r'^(.*\S)&&', line) match = Match(r'^(.*\S)&&', line)
if not match: if not match:
match = Match(r'(.*)&&\S', line) match = Match(r'(.*)&&\S', line)
if (not match) or '(&&)' in line or Search(r'\boperator\s*$', match.group(1)): if (not match) or '(&&)' in line or Search(r'\boperator\s*$',
match.group(1)):
return return
# Either poorly formed && or an rvalue reference, check the context # Either poorly formed && or an rvalue reference, check the context
...@@ -3845,7 +3866,8 @@ def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error): ...@@ -3845,7 +3866,8 @@ def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error):
linenum <= class_info.starting_linenum): linenum <= class_info.starting_linenum):
return return
matched = Match(r'\s*(public|protected|private):', clean_lines.lines[linenum]) matched = Match(r'\s*(public|protected|private):',
clean_lines.lines[linenum])
if matched: if matched:
# Issue warning if the line before public/protected/private was # Issue warning if the line before public/protected/private was
# not a blank line, but don't do this if the previous line contains # not a blank line, but don't do this if the previous line contains
...@@ -3870,7 +3892,8 @@ def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error): ...@@ -3870,7 +3892,8 @@ def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error):
break break
if end_class_head < linenum - 1: if end_class_head < linenum - 1:
error(filename, linenum, 'whitespace/blank_line', 3, error(filename, linenum, 'whitespace/blank_line', 3,
'"%s:" should be preceded by a blank line' % matched.group(1)) '"%s:" should be preceded by a blank line' %
matched.group(1))
def GetPreviousNonBlankLine(clean_lines, linenum): def GetPreviousNonBlankLine(clean_lines, linenum):
...@@ -3940,8 +3963,10 @@ def CheckBraces(filename, clean_lines, linenum, error): ...@@ -3940,8 +3963,10 @@ def CheckBraces(filename, clean_lines, linenum, error):
(endline, _, endpos) = CloseExpression(clean_lines, linenum, pos) (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos)
brace_on_right = endline[endpos:].find('{') != -1 brace_on_right = endline[endpos:].find('{') != -1
if brace_on_left != brace_on_right: # must be brace after if if brace_on_left != brace_on_right: # must be brace after if
error(filename, linenum, 'readability/braces', 5, error(
'If an else has a brace on one side, it should have it on both') filename, linenum, 'readability/braces', 5,
'If an else has a brace on one side, it should have it on both'
)
elif Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line): elif Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line):
error(filename, linenum, 'readability/braces', 5, error(filename, linenum, 'readability/braces', 5,
'If an else has a brace on one side, it should have it on both') 'If an else has a brace on one side, it should have it on both')
...@@ -3971,15 +3996,16 @@ def CheckBraces(filename, clean_lines, linenum, error): ...@@ -3971,15 +3996,16 @@ def CheckBraces(filename, clean_lines, linenum, error):
if if_match: if if_match:
# This could be a multiline if condition, so find the end first. # This could be a multiline if condition, so find the end first.
pos = if_match.end() - 1 pos = if_match.end() - 1
(endline, endlinenum, endpos) = CloseExpression(clean_lines, linenum, pos) (endline, endlinenum, endpos) = CloseExpression(clean_lines,
linenum, pos)
# Check for an opening brace, either directly after the if or on the next # Check for an opening brace, either directly after the if or on the next
# line. If found, this isn't a single-statement conditional. # line. If found, this isn't a single-statement conditional.
if (not Match(r'\s*{', endline[endpos:]) if (not Match(r'\s*{', endline[endpos:]) and
and not (Match(r'\s*$', endline[endpos:]) not (Match(r'\s*$', endline[endpos:]) and endlinenum <
and endlinenum < (len(clean_lines.elided) - 1) (len(clean_lines.elided) - 1) and
and Match(r'\s*{', clean_lines.elided[endlinenum + 1]))): Match(r'\s*{', clean_lines.elided[endlinenum + 1]))):
while (endlinenum < len(clean_lines.elided) while (endlinenum < len(clean_lines.elided) and
and ';' not in clean_lines.elided[endlinenum][endpos:]): ';' not in clean_lines.elided[endlinenum][endpos:]):
endlinenum += 1 endlinenum += 1
endpos = 0 endpos = 0
if endlinenum < len(clean_lines.elided): if endlinenum < len(clean_lines.elided):
...@@ -3991,10 +4017,13 @@ def CheckBraces(filename, clean_lines, linenum, error): ...@@ -3991,10 +4017,13 @@ def CheckBraces(filename, clean_lines, linenum, error):
# Semicolon isn't the last character, there's something trailing. # Semicolon isn't the last character, there's something trailing.
# Output a warning if the semicolon is not contained inside # Output a warning if the semicolon is not contained inside
# a lambda expression. # a lambda expression.
if not Match(r'^[^{};]*\[[^\[\]]*\][^{}]*\{[^{}]*\}\s*\)*[;,]\s*$', if not Match(
r'^[^{};]*\[[^\[\]]*\][^{}]*\{[^{}]*\}\s*\)*[;,]\s*$',
endline): endline):
error(filename, linenum, 'readability/braces', 4, error(
'If/else bodies with multiple statements require braces') filename, linenum, 'readability/braces', 4,
'If/else bodies with multiple statements require braces'
)
elif endlinenum < len(clean_lines.elided) - 1: elif endlinenum < len(clean_lines.elided) - 1:
# Make sure the next line is dedented # Make sure the next line is dedented
next_line = clean_lines.elided[endlinenum + 1] next_line = clean_lines.elided[endlinenum + 1]
...@@ -4002,14 +4031,17 @@ def CheckBraces(filename, clean_lines, linenum, error): ...@@ -4002,14 +4031,17 @@ def CheckBraces(filename, clean_lines, linenum, error):
# With ambiguous nested if statements, this will error out on the # With ambiguous nested if statements, this will error out on the
# if that *doesn't* match the else, regardless of whether it's the # if that *doesn't* match the else, regardless of whether it's the
# inner one or outer one. # inner one or outer one.
if (if_match and Match(r'\s*else\b', next_line) if (if_match and Match(r'\s*else\b', next_line) and
and next_indent != if_indent): next_indent != if_indent):
error(filename, linenum, 'readability/braces', 4, error(
filename, linenum, 'readability/braces', 4,
'Else clause should be indented at the same level as if. ' 'Else clause should be indented at the same level as if. '
'Ambiguous nested if/else chains require braces.') 'Ambiguous nested if/else chains require braces.')
elif next_indent > if_indent: elif next_indent > if_indent:
error(filename, linenum, 'readability/braces', 4, error(
'If/else bodies with multiple statements require braces') filename, linenum, 'readability/braces', 4,
'If/else bodies with multiple statements require braces'
)
def CheckTrailingSemicolon(filename, clean_lines, linenum, error): def CheckTrailingSemicolon(filename, clean_lines, linenum, error):
...@@ -4096,24 +4128,22 @@ def CheckTrailingSemicolon(filename, clean_lines, linenum, error): ...@@ -4096,24 +4128,22 @@ def CheckTrailingSemicolon(filename, clean_lines, linenum, error):
# - Lambdas # - Lambdas
# - alignas specifier with anonymous structs: # - alignas specifier with anonymous structs:
closing_brace_pos = match.group(1).rfind(')') closing_brace_pos = match.group(1).rfind(')')
opening_parenthesis = ReverseCloseExpression( opening_parenthesis = ReverseCloseExpression(clean_lines, linenum,
clean_lines, linenum, closing_brace_pos) closing_brace_pos)
if opening_parenthesis[2] > -1: if opening_parenthesis[2] > -1:
line_prefix = opening_parenthesis[0][0:opening_parenthesis[2]] line_prefix = opening_parenthesis[0][0:opening_parenthesis[2]]
macro = Search(r'\b([A-Z_]+)\s*$', line_prefix) macro = Search(r'\b([A-Z_]+)\s*$', line_prefix)
func = Match(r'^(.*\])\s*$', line_prefix) func = Match(r'^(.*\])\s*$', line_prefix)
if ((macro and if ((macro and macro.group(1) not in
macro.group(1) not in ( ('TEST', 'TEST_F', 'MATCHER', 'MATCHER_P', 'TYPED_TEST',
'TEST', 'TEST_F', 'MATCHER', 'MATCHER_P', 'TYPED_TEST',
'EXCLUSIVE_LOCKS_REQUIRED', 'SHARED_LOCKS_REQUIRED', 'EXCLUSIVE_LOCKS_REQUIRED', 'SHARED_LOCKS_REQUIRED',
'LOCKS_EXCLUDED', 'INTERFACE_DEF')) or 'LOCKS_EXCLUDED', 'INTERFACE_DEF')) or
(func and not Search(r'\boperator\s*\[\s*\]', func.group(1))) or (func and not Search(r'\boperator\s*\[\s*\]', func.group(1))) or
Search(r'\b(?:struct|union)\s+alignas\s*$', line_prefix) or Search(r'\b(?:struct|union)\s+alignas\s*$', line_prefix) or
Search(r'\s+=\s*$', line_prefix)): Search(r'\s+=\s*$', line_prefix)):
match = None match = None
if (match and if (match and opening_parenthesis[1] > 1 and Search(
opening_parenthesis[1] > 1 and r'\]\s*$', clean_lines.elided[opening_parenthesis[1] - 1])):
Search(r'\]\s*$', clean_lines.elided[opening_parenthesis[1] - 1])):
# Multi-line lambda-expression # Multi-line lambda-expression
match = None match = None
...@@ -4135,8 +4165,8 @@ def CheckTrailingSemicolon(filename, clean_lines, linenum, error): ...@@ -4135,8 +4165,8 @@ def CheckTrailingSemicolon(filename, clean_lines, linenum, error):
# Check matching closing brace # Check matching closing brace
if match: if match:
(endline, endlinenum, endpos) = CloseExpression( (endline, endlinenum, endpos) = CloseExpression(clean_lines, linenum,
clean_lines, linenum, len(match.group(1))) len(match.group(1)))
if endpos > -1 and Match(r'^\s*;', endline[endpos:]): if endpos > -1 and Match(r'^\s*;', endline[endpos:]):
# Current {} pair is eligible for semicolon check, and we have found # Current {} pair is eligible for semicolon check, and we have found
# the redundant semicolon, output warning here. # the redundant semicolon, output warning here.
...@@ -4169,15 +4199,16 @@ def CheckEmptyBlockBody(filename, clean_lines, linenum, error): ...@@ -4169,15 +4199,16 @@ def CheckEmptyBlockBody(filename, clean_lines, linenum, error):
matched = Match(r'\s*(for|while|if)\s*\(', line) matched = Match(r'\s*(for|while|if)\s*\(', line)
if matched: if matched:
# Find the end of the conditional expression # Find the end of the conditional expression
(end_line, end_linenum, end_pos) = CloseExpression( (end_line, end_linenum, end_pos) = CloseExpression(clean_lines, linenum,
clean_lines, linenum, line.find('(')) line.find('('))
# Output warning if what follows the condition expression is a semicolon. # Output warning if what follows the condition expression is a semicolon.
# No warning for all other cases, including whitespace or newline, since we # No warning for all other cases, including whitespace or newline, since we
# have a separate check for semicolons preceded by whitespace. # have a separate check for semicolons preceded by whitespace.
if end_pos >= 0 and Match(r';', end_line[end_pos:]): if end_pos >= 0 and Match(r';', end_line[end_pos:]):
if matched.group(1) == 'if': if matched.group(1) == 'if':
error(filename, end_linenum, 'whitespace/empty_conditional_body', 5, error(filename, end_linenum,
'whitespace/empty_conditional_body', 5,
'Empty conditional bodies should use {}') 'Empty conditional bodies should use {}')
else: else:
error(filename, end_linenum, 'whitespace/empty_loop_body', 5, error(filename, end_linenum, 'whitespace/empty_loop_body', 5,
...@@ -4224,8 +4255,8 @@ def CheckCheck(filename, clean_lines, linenum, error): ...@@ -4224,8 +4255,8 @@ def CheckCheck(filename, clean_lines, linenum, error):
return return
# Find end of the boolean expression by matching parentheses # Find end of the boolean expression by matching parentheses
(last_line, end_line, end_pos) = CloseExpression( (last_line, end_line, end_pos) = CloseExpression(clean_lines, linenum,
clean_lines, linenum, start_pos) start_pos)
if end_pos < 0: if end_pos < 0:
return return
...@@ -4320,9 +4351,9 @@ def CheckCheck(filename, clean_lines, linenum, error): ...@@ -4320,9 +4351,9 @@ def CheckCheck(filename, clean_lines, linenum, error):
# We are still keeping the less descriptive message because if lhs # We are still keeping the less descriptive message because if lhs
# or rhs gets long, the error message might become unreadable. # or rhs gets long, the error message might become unreadable.
error(filename, linenum, 'readability/check', 2, error(filename, linenum, 'readability/check', 2,
'Consider using %s instead of %s(a %s b)' % ( 'Consider using %s instead of %s(a %s b)' %
_CHECK_REPLACEMENT[check_macro][operator], (_CHECK_REPLACEMENT[check_macro][operator], check_macro,
check_macro, operator)) operator))
def CheckAltTokens(filename, clean_lines, linenum, error): def CheckAltTokens(filename, clean_lines, linenum, error):
...@@ -4526,8 +4557,8 @@ def _DropCommonSuffixes(filename): ...@@ -4526,8 +4557,8 @@ def _DropCommonSuffixes(filename):
Returns: Returns:
The filename with the common suffix removed. The filename with the common suffix removed.
""" """
for suffix in ('test.cc', 'regtest.cc', 'unittest.cc', for suffix in ('test.cc', 'regtest.cc', 'unittest.cc', 'inl.h', 'impl.h',
'inl.h', 'impl.h', 'internal.h'): 'internal.h'):
if (filename.endswith(suffix) and len(filename) > len(suffix) and if (filename.endswith(suffix) and len(filename) > len(suffix) and
filename[-len(suffix) - 1] in ('-', '_')): filename[-len(suffix) - 1] in ('-', '_')):
return filename[:-len(suffix) - 1] return filename[:-len(suffix) - 1]
...@@ -4543,8 +4574,7 @@ def _IsTestFilename(filename): ...@@ -4543,8 +4574,7 @@ def _IsTestFilename(filename):
Returns: Returns:
True if 'filename' looks like a test, False otherwise. True if 'filename' looks like a test, False otherwise.
""" """
if (filename.endswith('_test.cc') or if (filename.endswith('_test.cc') or filename.endswith('_unittest.cc') or
filename.endswith('_unittest.cc') or
filename.endswith('_regtest.cc')): filename.endswith('_regtest.cc')):
return True return True
else: else:
...@@ -4610,7 +4640,6 @@ def _ClassifyInclude(fileinfo, include, is_system): ...@@ -4610,7 +4640,6 @@ def _ClassifyInclude(fileinfo, include, is_system):
return _OTHER_HEADER return _OTHER_HEADER
def CheckIncludeLine(filename, clean_lines, linenum, include_state, error): def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
"""Check rules that are applicable to #include lines. """Check rules that are applicable to #include lines.
...@@ -4653,7 +4682,8 @@ def CheckIncludeLine(filename, clean_lines, linenum, include_state, error): ...@@ -4653,7 +4682,8 @@ def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
'"%s" already included at %s:%s' % '"%s" already included at %s:%s' %
(include, filename, duplicate_line)) (include, filename, duplicate_line))
elif (include.endswith('.cc') and elif (include.endswith('.cc') and
os.path.dirname(fileinfo.RepositoryName()) != os.path.dirname(include)): os.path.dirname(fileinfo.RepositoryName()) !=
os.path.dirname(include)):
error(filename, linenum, 'build/include', 4, error(filename, linenum, 'build/include', 4,
'Do not include .cc files from other packages') 'Do not include .cc files from other packages')
elif not _THIRD_PARTY_HEADERS_PATTERN.match(include): elif not _THIRD_PARTY_HEADERS_PATTERN.match(include):
...@@ -4676,15 +4706,15 @@ def CheckIncludeLine(filename, clean_lines, linenum, include_state, error): ...@@ -4676,15 +4706,15 @@ def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
error(filename, linenum, 'build/include_order', 4, error(filename, linenum, 'build/include_order', 4,
'%s. Should be: %s.h, c system, c++ system, other.' % '%s. Should be: %s.h, c system, c++ system, other.' %
(error_message, fileinfo.BaseName())) (error_message, fileinfo.BaseName()))
canonical_include = include_state.CanonicalizeAlphabeticalOrder(include) canonical_include = include_state.CanonicalizeAlphabeticalOrder(
if not include_state.IsInAlphabeticalOrder( include)
clean_lines, linenum, canonical_include): if not include_state.IsInAlphabeticalOrder(clean_lines, linenum,
canonical_include):
error(filename, linenum, 'build/include_alpha', 4, error(filename, linenum, 'build/include_alpha', 4,
'Include "%s" not in alphabetical order' % include) 'Include "%s" not in alphabetical order' % include)
include_state.SetLastHeader(canonical_include) include_state.SetLastHeader(canonical_include)
def _GetTextInside(text, start_pattern): def _GetTextInside(text, start_pattern):
r"""Retrieves all the text between matching open and close parentheses. r"""Retrieves all the text between matching open and close parentheses.
...@@ -4763,12 +4793,12 @@ _RE_PATTERN_REF_PARAM = re.compile( ...@@ -4763,12 +4793,12 @@ _RE_PATTERN_REF_PARAM = re.compile(
# A call-by-const-reference parameter either ends with 'const& identifier' # A call-by-const-reference parameter either ends with 'const& identifier'
# or looks like 'const type& identifier' when 'type' is atomic. # or looks like 'const type& identifier' when 'type' is atomic.
_RE_PATTERN_CONST_REF_PARAM = ( _RE_PATTERN_CONST_REF_PARAM = (
r'(?:.*\s*\bconst\s*&\s*' + _RE_PATTERN_IDENT + r'(?:.*\s*\bconst\s*&\s*' + _RE_PATTERN_IDENT + r'|const\s+' +
r'|const\s+' + _RE_PATTERN_TYPE + r'\s*&\s*' + _RE_PATTERN_IDENT + r')') _RE_PATTERN_TYPE + r'\s*&\s*' + _RE_PATTERN_IDENT + r')')
def CheckLanguage(filename, clean_lines, linenum, file_extension, def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
include_state, nesting_state, error): nesting_state, error):
"""Checks rules from the 'C++ language rules' section of cppguide.html. """Checks rules from the 'C++ language rules' section of cppguide.html.
Some of these rules are hard to test (function overloading, using Some of these rules are hard to test (function overloading, using
...@@ -4827,7 +4857,8 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, ...@@ -4827,7 +4857,8 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
match = Search(r'\b(short|long(?! +double)|long long)\b', line) match = Search(r'\b(short|long(?! +double)|long long)\b', line)
if match: if match:
error(filename, linenum, 'runtime/int', 4, error(filename, linenum, 'runtime/int', 4,
'Use int16/int64/etc, rather than the C type %s' % match.group(1)) 'Use int16/int64/etc, rather than the C type %s' %
match.group(1))
# Check if some verboten operator overloading is going on # Check if some verboten operator overloading is going on
# TODO(unknown): catch out-of-line unary operator&: # TODO(unknown): catch out-of-line unary operator&:
...@@ -4856,18 +4887,18 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, ...@@ -4856,18 +4887,18 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
if printf_args: if printf_args:
match = Match(r'([\w.\->()]+)$', printf_args) match = Match(r'([\w.\->()]+)$', printf_args)
if match and match.group(1) != '__VA_ARGS__': if match and match.group(1) != '__VA_ARGS__':
function_name = re.search(r'\b((?:string)?printf)\s*\(', function_name = re.search(r'\b((?:string)?printf)\s*\(', line,
line, re.I).group(1) 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.' %
% (function_name, match.group(1))) (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)
if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)): if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)):
error(filename, linenum, 'runtime/memset', 4, error(filename, linenum, 'runtime/memset', 4,
'Did you mean "memset(%s, 0, %s)"?' 'Did you mean "memset(%s, 0, %s)"?' %
% (match.group(1), match.group(2))) (match.group(1), match.group(2)))
if Search(r'\busing namespace\b', line): if Search(r'\busing namespace\b', line):
error(filename, linenum, 'build/namespaces', 5, error(filename, linenum, 'build/namespaces', 5,
...@@ -4909,17 +4940,19 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, ...@@ -4909,17 +4940,19 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
is_const = False is_const = False
break break
if not is_const: if not is_const:
error(filename, linenum, 'runtime/arrays', 1, error(
filename, linenum, 'runtime/arrays', 1,
'Do not use variable-length arrays. Use an appropriately named ' 'Do not use variable-length arrays. Use an appropriately named '
"('k' followed by CamelCase) compile-time constant for the size.") "('k' followed by CamelCase) compile-time constant for the size."
)
# Check for use of unnamed namespaces in header files. Registration # Check for use of unnamed namespaces in header files. Registration
# macros are typically OK, so we allow use of "namespace {" on lines # macros are typically OK, so we allow use of "namespace {" on lines
# that end with backslashes. # that end with backslashes.
if (file_extension == 'h' if (file_extension == 'h' and Search(r'\bnamespace\s*{', line) and
and Search(r'\bnamespace\s*{', line) line[-1] != '\\'):
and line[-1] != '\\'): error(
error(filename, linenum, 'build/namespaces', 4, filename, linenum, 'build/namespaces', 4,
'Do not use unnamed namespaces in header files. See ' 'Do not use unnamed namespaces in header files. See '
'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces' 'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'
' for more information.') ' for more information.')
...@@ -4943,8 +4976,7 @@ def CheckGlobalStatic(filename, clean_lines, linenum, error): ...@@ -4943,8 +4976,7 @@ def CheckGlobalStatic(filename, clean_lines, linenum, error):
# Check for people declaring static/global STL strings at the top level. # Check for people declaring static/global STL strings at the top level.
# This is dangerous because the C++ language does not guarantee that # This is dangerous because the C++ language does not guarantee that
# globals with constructors are initialized before the first access. # globals with constructors are initialized before the first access.
match = Match( match = Match(r'((?:|static +)(?:|const +))string +([a-zA-Z0-9_:]+)\b(.*)',
r'((?:|static +)(?:|const +))string +([a-zA-Z0-9_:]+)\b(.*)',
line) line)
# Remove false positives: # Remove false positives:
...@@ -4965,12 +4997,12 @@ def CheckGlobalStatic(filename, clean_lines, linenum, error): ...@@ -4965,12 +4997,12 @@ def CheckGlobalStatic(filename, clean_lines, linenum, error):
# string Class::operator*() # string Class::operator*()
if (match and if (match and
not Search(r'\bstring\b(\s+const)?\s*\*\s*(const\s+)?\w', line) and not Search(r'\bstring\b(\s+const)?\s*\*\s*(const\s+)?\w', line) and
not Search(r'\boperator\W', line) and not Search(r'\boperator\W', line) and not Match(
not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)*\s*\(([^"]|$)', match.group(3))): r'\s*(<.*>)?(::[a-zA-Z0-9_]+)*\s*\(([^"]|$)', match.group(3))):
error(filename, linenum, 'runtime/string', 4, error(
filename, linenum, 'runtime/string', 4,
'For a static/global string constant, use a C style string instead: ' 'For a static/global string constant, use a C style string instead: '
'"%schar %s[]".' % '"%schar %s[]".' % (match.group(1), match.group(2)))
(match.group(1), match.group(2)))
if Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line): if Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line):
error(filename, linenum, 'runtime/init', 4, error(filename, linenum, 'runtime/init', 4,
...@@ -5021,8 +5053,8 @@ def IsDerivedFunction(clean_lines, linenum): ...@@ -5021,8 +5053,8 @@ def IsDerivedFunction(clean_lines, linenum):
match = Match(r'^([^()]*\w+)\(', clean_lines.elided[i]) match = Match(r'^([^()]*\w+)\(', clean_lines.elided[i])
if match: if match:
# Look for "override" after the matching closing parenthesis # Look for "override" after the matching closing parenthesis
line, _, closing_paren = CloseExpression( line, _, closing_paren = CloseExpression(clean_lines, i,
clean_lines, i, len(match.group(1))) len(match.group(1)))
return (closing_paren >= 0 and return (closing_paren >= 0 and
Search(r'\boverride\b', line[closing_paren:])) Search(r'\boverride\b', line[closing_paren:]))
return False return False
...@@ -5040,7 +5072,8 @@ def IsOutOfLineMethodDefinition(clean_lines, linenum): ...@@ -5040,7 +5072,8 @@ def IsOutOfLineMethodDefinition(clean_lines, linenum):
# Scan back a few lines for start of current function # Scan back a few lines for start of current function
for i in xrange(linenum, max(-1, linenum - 10), -1): for i in xrange(linenum, max(-1, linenum - 10), -1):
if Match(r'^([^()]*\w+)\(', clean_lines.elided[i]): if Match(r'^([^()]*\w+)\(', clean_lines.elided[i]):
return Match(r'^[^()]*\w+::\w+\(', clean_lines.elided[i]) is not None return Match(r'^[^()]*\w+::\w+\(',
clean_lines.elided[i]) is not None
return False return False
...@@ -5086,8 +5119,8 @@ def IsInitializerList(clean_lines, linenum): ...@@ -5086,8 +5119,8 @@ def IsInitializerList(clean_lines, linenum):
return False return False
def CheckForNonConstReference(filename, clean_lines, linenum, def CheckForNonConstReference(filename, clean_lines, linenum, nesting_state,
nesting_state, error): error):
"""Check for non-const references. """Check for non-const references.
Separate from CheckLanguage since it scans backwards from current Separate from CheckLanguage since it scans backwards from current
...@@ -5211,8 +5244,8 @@ def CheckForNonConstReference(filename, clean_lines, linenum, ...@@ -5211,8 +5244,8 @@ def CheckForNonConstReference(filename, clean_lines, linenum,
# didn't see any function name on this line, so this is likely a # 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. # multi-line parameter list. Try a bit harder to catch this case.
for i in xrange(2): for i in xrange(2):
if (linenum > i and if (linenum > i and Search(whitelisted_functions,
Search(whitelisted_functions, clean_lines.elided[linenum - i - 1])): clean_lines.elided[linenum - i - 1])):
return return
decls = ReplaceAll(r'{[^}]*}', ' ', line) # exclude function body decls = ReplaceAll(r'{[^}]*}', ' ', line) # exclude function body
...@@ -5220,8 +5253,8 @@ def CheckForNonConstReference(filename, clean_lines, linenum, ...@@ -5220,8 +5253,8 @@ def CheckForNonConstReference(filename, clean_lines, linenum,
if not Match(_RE_PATTERN_CONST_REF_PARAM, parameter): if not Match(_RE_PATTERN_CONST_REF_PARAM, parameter):
error(filename, linenum, 'runtime/references', 2, error(filename, linenum, 'runtime/references', 2,
'Is this a non-const reference? ' 'Is this a non-const reference? '
'If so, make const or use a pointer: ' + 'If so, make const or use a pointer: ' + ReplaceAll(
ReplaceAll(' *<', '<', parameter)) ' *<', '<', parameter))
def CheckCasts(filename, clean_lines, linenum, error): def CheckCasts(filename, clean_lines, linenum, error):
...@@ -5239,8 +5272,7 @@ def CheckCasts(filename, clean_lines, linenum, error): ...@@ -5239,8 +5272,7 @@ def CheckCasts(filename, clean_lines, linenum, error):
# I just try to capture the most common basic types, though there are more. # I just try to capture the most common basic types, though there are more.
# Parameterless conversion functions, such as bool(), are allowed as they are # Parameterless conversion functions, such as bool(), are allowed as they are
# probably a member operator declaration or default constructor. # probably a member operator declaration or default constructor.
match = Search( match = Search(r'(\bnew\s+|\S<\s*(?:const\s+)?)?\b'
r'(\bnew\s+|\S<\s*(?:const\s+)?)?\b'
r'(int|float|double|bool|char|int32|uint32|int64|uint64)' r'(int|float|double|bool|char|int32|uint32|int64|uint64)'
r'(\([^)].*)', line) r'(\([^)].*)', line)
expecting_function = ExpectingFunctionArgs(clean_lines, linenum) expecting_function = ExpectingFunctionArgs(clean_lines, linenum)
...@@ -5272,21 +5304,19 @@ def CheckCasts(filename, clean_lines, linenum, error): ...@@ -5272,21 +5304,19 @@ def CheckCasts(filename, clean_lines, linenum, error):
# - Placement new # - Placement new
# - Alias declarations # - Alias declarations
matched_funcptr = match.group(3) matched_funcptr = match.group(3)
if (matched_new_or_template is None and if (matched_new_or_template is None and not (matched_funcptr and (Match(
not (matched_funcptr and r'\((?:[^() ]+::\s*\*\s*)?[^() ]+\)\s*\(',
(Match(r'\((?:[^() ]+::\s*\*\s*)?[^() ]+\)\s*\(', matched_funcptr) or matched_funcptr.startswith('(*)'))) and
matched_funcptr) or
matched_funcptr.startswith('(*)'))) and
not Match(r'\s*using\s+\S+\s*=\s*' + matched_type, line) and not Match(r'\s*using\s+\S+\s*=\s*' + matched_type, line) and
not Search(r'new\(\S+\)\s*' + matched_type, line)): not Search(r'new\(\S+\)\s*' + matched_type, line)):
error(filename, linenum, 'readability/casting', 4, error(filename, linenum, 'readability/casting', 4,
'Using deprecated casting style. ' 'Using deprecated casting style. '
'Use static_cast<%s>(...) instead' % 'Use static_cast<%s>(...) instead' % matched_type)
matched_type)
if not expecting_function: if not expecting_function:
CheckCStyleCast(filename, clean_lines, linenum, 'static_cast', CheckCStyleCast(filename, clean_lines, linenum, 'static_cast',
r'\((int|float|double|bool|char|u?int(16|32|64))\)', error) r'\((int|float|double|bool|char|u?int(16|32|64))\)',
error)
# This doesn't catch all cases. Consider (const char * const)"hello". # This doesn't catch all cases. Consider (const char * const)"hello".
# #
...@@ -5311,17 +5341,18 @@ def CheckCasts(filename, clean_lines, linenum, error): ...@@ -5311,17 +5341,18 @@ def CheckCasts(filename, clean_lines, linenum, error):
# #
# This is not a cast: # This is not a cast:
# reference_type&(int* function_param); # reference_type&(int* function_param);
match = Search( match = Search(r'(?:[^\w]&\(([^)*][^)]*)\)[\w(])|'
r'(?:[^\w]&\(([^)*][^)]*)\)[\w(])|'
r'(?:[^\w]&(static|dynamic|down|reinterpret)_cast\b)', line) r'(?:[^\w]&(static|dynamic|down|reinterpret)_cast\b)', line)
if match: if match:
# Try a better error message when the & is bound to something # Try a better error message when the & is bound to something
# dereferenced by the casted pointer, as opposed to the casted # dereferenced by the casted pointer, as opposed to the casted
# pointer itself. # pointer itself.
parenthesis_error = False parenthesis_error = False
match = Match(r'^(.*&(?:static|dynamic|down|reinterpret)_cast\b)<', line) match = Match(r'^(.*&(?:static|dynamic|down|reinterpret)_cast\b)<',
line)
if match: if match:
_, y1, x1 = CloseExpression(clean_lines, linenum, len(match.group(1))) _, y1, x1 = CloseExpression(clean_lines, linenum,
len(match.group(1)))
if x1 >= 0 and clean_lines.elided[y1][x1] == '(': if x1 >= 0 and clean_lines.elided[y1][x1] == '(':
_, y2, x2 = CloseExpression(clean_lines, y1, x1) _, y2, x2 = CloseExpression(clean_lines, y1, x1)
if x2 >= 0: if x2 >= 0:
...@@ -5470,42 +5501,73 @@ def ExpectingFunctionArgs(clean_lines, linenum): ...@@ -5470,42 +5501,73 @@ def ExpectingFunctionArgs(clean_lines, linenum):
_HEADERS_CONTAINING_TEMPLATES = ( _HEADERS_CONTAINING_TEMPLATES = (
('<deque>', ('deque',)), ('<deque>', ('deque', )),
('<functional>', ('unary_function', 'binary_function', ('<functional>', (
'plus', 'minus', 'multiplies', 'divides', 'modulus', 'unary_function',
'binary_function',
'plus',
'minus',
'multiplies',
'divides',
'modulus',
'negate', 'negate',
'equal_to', 'not_equal_to', 'greater', 'less', 'equal_to',
'greater_equal', 'less_equal', 'not_equal_to',
'logical_and', 'logical_or', 'logical_not', 'greater',
'unary_negate', 'not1', 'binary_negate', 'not2', 'less',
'bind1st', 'bind2nd', 'greater_equal',
'less_equal',
'logical_and',
'logical_or',
'logical_not',
'unary_negate',
'not1',
'binary_negate',
'not2',
'bind1st',
'bind2nd',
'pointer_to_unary_function', 'pointer_to_unary_function',
'pointer_to_binary_function', 'pointer_to_binary_function',
'ptr_fun', 'ptr_fun',
'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t', 'mem_fun_t',
'mem_fun',
'mem_fun1_t',
'mem_fun1_ref_t',
'mem_fun_ref_t', 'mem_fun_ref_t',
'const_mem_fun_t', 'const_mem_fun1_t', 'const_mem_fun_t',
'const_mem_fun_ref_t', 'const_mem_fun1_ref_t', 'const_mem_fun1_t',
'mem_fun_ref', 'const_mem_fun_ref_t',
)), 'const_mem_fun1_ref_t',
('<limits>', ('numeric_limits',)), 'mem_fun_ref', )),
('<list>', ('list',)), ('<limits>', ('numeric_limits', )),
('<map>', ('map', 'multimap',)), ('<list>', ('list', )),
('<memory>', ('allocator',)), ('<map>', (
('<queue>', ('queue', 'priority_queue',)), 'map',
('<set>', ('set', 'multiset',)), 'multimap', )),
('<stack>', ('stack',)), ('<memory>', ('allocator', )),
('<string>', ('char_traits', 'basic_string',)), ('<queue>', (
('<tuple>', ('tuple',)), 'queue',
('<utility>', ('pair',)), 'priority_queue', )),
('<vector>', ('vector',)), ('<set>', (
'set',
'multiset', )),
('<stack>', ('stack', )),
('<string>', (
'char_traits',
'basic_string', )),
('<tuple>', ('tuple', )),
('<utility>', ('pair', )),
('<vector>', ('vector', )),
# gcc extensions. # gcc extensions.
# Note: std::hash is their hash, ::hash is our hash # Note: std::hash is their hash, ::hash is our hash
('<hash_map>', ('hash_map', 'hash_multimap',)), ('<hash_map>', (
('<hash_set>', ('hash_set', 'hash_multiset',)), 'hash_map',
('<slist>', ('slist',)), 'hash_multimap', )),
) ('<hash_set>', (
'hash_set',
'hash_multiset', )),
('<slist>', ('slist', )), )
_RE_PATTERN_STRING = re.compile(r'\bstring\b') _RE_PATTERN_STRING = re.compile(r'\bstring\b')
...@@ -5515,16 +5577,14 @@ for _template in ('copy', 'max', 'min', 'min_element', 'sort', 'swap', ...@@ -5515,16 +5577,14 @@ for _template in ('copy', 'max', 'min', 'min_element', 'sort', 'swap',
# Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or # Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or
# type::max(). # type::max().
_re_pattern_algorithm_header.append( _re_pattern_algorithm_header.append(
(re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'), (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'), _template,
_template,
'<algorithm>')) '<algorithm>'))
_re_pattern_templates = [] _re_pattern_templates = []
for _header, _templates in _HEADERS_CONTAINING_TEMPLATES: for _header, _templates in _HEADERS_CONTAINING_TEMPLATES:
for _template in _templates: for _template in _templates:
_re_pattern_templates.append( _re_pattern_templates.append(
(re.compile(r'(\<|\b)' + _template + r'\s*\<'), (re.compile(r'(\<|\b)' + _template + r'\s*\<'), _template + '<>',
_template + '<>',
_header)) _header))
...@@ -5610,7 +5670,10 @@ def UpdateIncludeState(filename, include_dict, io=codecs): ...@@ -5610,7 +5670,10 @@ def UpdateIncludeState(filename, include_dict, io=codecs):
return True return True
def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, def CheckForIncludeWhatYouUse(filename,
clean_lines,
include_state,
error,
io=codecs): io=codecs):
"""Reports for missing stl includes. """Reports for missing stl includes.
...@@ -5660,8 +5723,8 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, ...@@ -5660,8 +5723,8 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
# The policy is that if you #include something in foo.h you don't need to # The policy is that if you #include something in foo.h you don't need to
# include it again in foo.cc. Here, we will look at possible includes. # include it again in foo.cc. Here, we will look at possible includes.
# Let's flatten the include_state include_list and copy it into a dictionary. # Let's flatten the include_state include_list and copy it into a dictionary.
include_dict = dict([item for sublist in include_state.include_list include_dict = dict(
for item in sublist]) [item for sublist in include_state.include_list for item in sublist])
# Did we find the header for this file (if any) and successfully load it? # Did we find the header for this file (if any) and successfully load it?
header_found = False header_found = False
...@@ -5682,7 +5745,8 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, ...@@ -5682,7 +5745,8 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
# the keys. # the keys.
header_keys = include_dict.keys() header_keys = include_dict.keys()
for header in header_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_dict, io): if same_module and UpdateIncludeState(fullpath, include_dict, io):
header_found = True header_found = True
...@@ -5700,8 +5764,8 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, ...@@ -5700,8 +5764,8 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
template = required[required_header_unstripped][1] template = required[required_header_unstripped][1]
if required_header_unstripped.strip('<>"') not in include_dict: if required_header_unstripped.strip('<>"') not in include_dict:
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 ' +
'Add #include ' + required_header_unstripped + ' for ' + template) required_header_unstripped + ' for ' + template)
_RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<') _RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<')
...@@ -5722,7 +5786,10 @@ def CheckMakePairUsesDeduction(filename, clean_lines, linenum, error): ...@@ -5722,7 +5786,10 @@ def CheckMakePairUsesDeduction(filename, clean_lines, linenum, error):
line = clean_lines.elided[linenum] line = clean_lines.elided[linenum]
match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line) match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line)
if match: if match:
error(filename, linenum, 'build/explicit_make_pair', error(
filename,
linenum,
'build/explicit_make_pair',
4, # 4 = high confidence 4, # 4 = high confidence
'For C++11-compatibility, omit template arguments from make_pair' 'For C++11-compatibility, omit template arguments from make_pair'
' OR use pair directly OR if appropriate, construct a pair directly') ' OR use pair directly OR if appropriate, construct a pair directly')
...@@ -5746,9 +5813,13 @@ def CheckDefaultLambdaCaptures(filename, clean_lines, linenum, error): ...@@ -5746,9 +5813,13 @@ def CheckDefaultLambdaCaptures(filename, clean_lines, linenum, error):
# Found a potential error, check what comes after the lambda-introducer. # Found a potential error, check what comes after the lambda-introducer.
# If it's not open parenthesis (for lambda-declarator) or open brace # If it's not open parenthesis (for lambda-declarator) or open brace
# (for compound-statement), it's not a lambda. # (for compound-statement), it's not a lambda.
line, _, pos = CloseExpression(clean_lines, linenum, len(match.group(1))) line, _, pos = CloseExpression(clean_lines, linenum,
len(match.group(1)))
if pos >= 0 and Match(r'^\s*[{(]', line[pos:]): if pos >= 0 and Match(r'^\s*[{(]', line[pos:]):
error(filename, linenum, 'build/c++11', error(
filename,
linenum,
'build/c++11',
4, # 4 = high confidence 4, # 4 = high confidence
'Default lambda captures are an unapproved C++ feature.') 'Default lambda captures are an unapproved C++ feature.')
...@@ -5793,7 +5864,8 @@ def CheckRedundantVirtual(filename, clean_lines, linenum, error): ...@@ -5793,7 +5864,8 @@ def CheckRedundantVirtual(filename, clean_lines, linenum, error):
if parameter_list: if parameter_list:
# Match parentheses to find the end of the parameter list # Match parentheses to find the end of the parameter list
(_, end_line, end_col) = CloseExpression( (_, end_line, end_col) = CloseExpression(
clean_lines, start_line, start_col + len(parameter_list.group(1))) clean_lines, start_line,
start_col + len(parameter_list.group(1)))
break break
start_col = 0 start_col = 0
...@@ -5846,8 +5918,6 @@ def CheckRedundantOverrideOrFinal(filename, clean_lines, linenum, error): ...@@ -5846,8 +5918,6 @@ def CheckRedundantOverrideOrFinal(filename, clean_lines, linenum, error):
'already declared as "final"')) 'already declared as "final"'))
# Returns true if we are at a new block, and it is directly # Returns true if we are at a new block, and it is directly
# inside of a namespace. # inside of a namespace.
def IsBlockInNameSpace(nesting_state, is_forward_declaration): def IsBlockInNameSpace(nesting_state, is_forward_declaration):
...@@ -5912,8 +5982,14 @@ def CheckItemIndentationInNamespace(filename, raw_lines_no_comments, linenum, ...@@ -5912,8 +5982,14 @@ def CheckItemIndentationInNamespace(filename, raw_lines_no_comments, linenum,
'Do not indent within a namespace') 'Do not indent within a namespace')
def ProcessLine(filename, file_extension, clean_lines, line, def ProcessLine(filename,
include_state, function_state, nesting_state, error, file_extension,
clean_lines,
line,
include_state,
function_state,
nesting_state,
error,
extra_check_functions=[]): extra_check_functions=[]):
"""Processes a single line in the file. """Processes a single line in the file.
...@@ -5941,12 +6017,13 @@ def ProcessLine(filename, file_extension, clean_lines, line, ...@@ -5941,12 +6017,13 @@ def ProcessLine(filename, file_extension, clean_lines, line,
if nesting_state.InAsmBlock(): return if nesting_state.InAsmBlock(): return
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, nesting_state, error) CheckStyle(filename, clean_lines, line, file_extension, nesting_state,
error)
CheckLanguage(filename, clean_lines, line, file_extension, include_state, CheckLanguage(filename, clean_lines, line, file_extension, include_state,
nesting_state, error) nesting_state, error)
CheckForNonConstReference(filename, clean_lines, line, nesting_state, error) CheckForNonConstReference(filename, clean_lines, line, nesting_state, error)
CheckForNonStandardConstructs(filename, clean_lines, line, CheckForNonStandardConstructs(filename, clean_lines, line, nesting_state,
nesting_state, error) error)
CheckVlogArguments(filename, clean_lines, line, error) CheckVlogArguments(filename, clean_lines, line, 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)
...@@ -5957,6 +6034,7 @@ def ProcessLine(filename, file_extension, clean_lines, line, ...@@ -5957,6 +6034,7 @@ def ProcessLine(filename, file_extension, clean_lines, line,
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)
def FlagCxx11Features(filename, clean_lines, linenum, error): def FlagCxx11Features(filename, clean_lines, linenum, error):
"""Flag those c++11 features that we only allow in certain places. """Flag those c++11 features that we only allow in certain places.
...@@ -5970,7 +6048,8 @@ def FlagCxx11Features(filename, clean_lines, linenum, error): ...@@ -5970,7 +6048,8 @@ def FlagCxx11Features(filename, clean_lines, linenum, error):
# Flag unapproved C++11 headers. # Flag unapproved C++11 headers.
include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line) include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line)
if include and include.group(1) in ('cfenv', if include and include.group(1) in (
'cfenv',
'condition_variable', 'condition_variable',
'fenv.h', 'fenv.h',
'future', 'future',
...@@ -5979,8 +6058,7 @@ def FlagCxx11Features(filename, clean_lines, linenum, error): ...@@ -5979,8 +6058,7 @@ def FlagCxx11Features(filename, clean_lines, linenum, error):
'chrono', 'chrono',
'ratio', 'ratio',
'regex', 'regex',
'system_error', 'system_error', ):
):
error(filename, linenum, 'build/c++11', 5, error(filename, linenum, 'build/c++11', 5,
('<%s> is an unapproved C++11 header.') % include.group(1)) ('<%s> is an unapproved C++11 header.') % include.group(1))
...@@ -5994,16 +6072,18 @@ def FlagCxx11Features(filename, clean_lines, linenum, error): ...@@ -5994,16 +6072,18 @@ def FlagCxx11Features(filename, clean_lines, linenum, error):
for top_name in ( for top_name in (
# type_traits # type_traits
'alignment_of', 'alignment_of',
'aligned_union', 'aligned_union', ):
):
if Search(r'\bstd::%s\b' % top_name, line): if Search(r'\bstd::%s\b' % top_name, line):
error(filename, linenum, 'build/c++11', 5, error(filename, linenum, 'build/c++11', 5, (
('std::%s is an unapproved C++11 class or function. Send c-style ' 'std::%s is an unapproved C++11 class or function. Send c-style '
'an example of where it would make your code more readable, and ' 'an example of where it would make your code more readable, and '
'they may let you use it.') % top_name) 'they may let you use it.') % top_name)
def ProcessFileData(filename, file_extension, lines, error, def ProcessFileData(filename,
file_extension,
lines,
error,
extra_check_functions=[]): extra_check_functions=[]):
"""Performs lint checks and reports any errors to the given error function. """Performs lint checks and reports any errors to the given error function.
...@@ -6036,9 +6116,8 @@ def ProcessFileData(filename, file_extension, lines, error, ...@@ -6036,9 +6116,8 @@ def ProcessFileData(filename, file_extension, lines, error,
CheckForHeaderGuard(filename, clean_lines, error) CheckForHeaderGuard(filename, clean_lines, error)
for line in xrange(clean_lines.NumLines()): for line in xrange(clean_lines.NumLines()):
ProcessLine(filename, file_extension, clean_lines, line, ProcessLine(filename, file_extension, clean_lines, line, include_state,
include_state, function_state, nesting_state, error, function_state, nesting_state, error, extra_check_functions)
extra_check_functions)
FlagCxx11Features(filename, clean_lines, line, error) FlagCxx11Features(filename, clean_lines, line, error)
nesting_state.CheckCompletedBlocks(filename, error) nesting_state.CheckCompletedBlocks(filename, error)
...@@ -6054,6 +6133,7 @@ def ProcessFileData(filename, file_extension, lines, error, ...@@ -6054,6 +6133,7 @@ def ProcessFileData(filename, file_extension, lines, error,
CheckForNewlineAtEOF(filename, lines, error) CheckForNewlineAtEOF(filename, lines, error)
def ProcessConfigOverrides(filename): def ProcessConfigOverrides(filename):
""" Loads the configuration files and processes the config overrides. """ Loads the configuration files and processes the config overrides.
...@@ -6101,7 +6181,8 @@ def ProcessConfigOverrides(filename): ...@@ -6101,7 +6181,8 @@ def ProcessConfigOverrides(filename):
if base_name: if base_name:
pattern = re.compile(val) pattern = re.compile(val)
if pattern.match(base_name): if pattern.match(base_name):
sys.stderr.write('Ignoring "%s": file excluded by "%s". ' sys.stderr.write(
'Ignoring "%s": file excluded by "%s". '
'File path component "%s" matches ' 'File path component "%s" matches '
'pattern "%s"\n' % 'pattern "%s"\n' %
(filename, cfg_file, base_name, val)) (filename, cfg_file, base_name, val))
...@@ -6119,7 +6200,8 @@ def ProcessConfigOverrides(filename): ...@@ -6119,7 +6200,8 @@ def ProcessConfigOverrides(filename):
except IOError: except IOError:
sys.stderr.write( sys.stderr.write(
"Skipping config file '%s': Can't open for reading\n" % cfg_file) "Skipping config file '%s': Can't open for reading\n" %
cfg_file)
keep_looking = False keep_looking = False
# Apply all the accumulated filters in reverse order (top-level directory # Apply all the accumulated filters in reverse order (top-level directory
...@@ -6167,7 +6249,8 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]): ...@@ -6167,7 +6249,8 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]):
codecs.getwriter('utf8'), codecs.getwriter('utf8'),
'replace').read().split('\n') 'replace').read().split('\n')
else: else:
lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n') lines = codecs.open(filename, 'r', 'utf8',
'replace').read().split('\n')
# Remove trailing '\r'. # Remove trailing '\r'.
# The -1 accounts for the extra trailing blank line we get from split() # The -1 accounts for the extra trailing blank line we get from split()
...@@ -6179,8 +6262,8 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]): ...@@ -6179,8 +6262,8 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]):
lf_lines.append(linenum + 1) lf_lines.append(linenum + 1)
except IOError: except IOError:
sys.stderr.write( sys.stderr.write("Skipping input '%s': Can't open for reading\n" %
"Skipping input '%s': Can't open for reading\n" % filename) filename)
_RestoreFilters() _RestoreFilters()
return return
...@@ -6252,12 +6335,10 @@ def ParseArguments(args): ...@@ -6252,12 +6335,10 @@ def ParseArguments(args):
The list of filenames to lint. The list of filenames to lint.
""" """
try: try:
(opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=', (opts, filenames) = getopt.getopt(args, '', [
'counting=', 'help', 'output=', 'verbose=', 'counting=', 'filter=', 'root=',
'filter=', 'linelength=', 'extensions='
'root=', ])
'linelength=',
'extensions='])
except getopt.GetoptError: except getopt.GetoptError:
PrintUsage('Invalid arguments.') PrintUsage('Invalid arguments.')
...@@ -6271,7 +6352,9 @@ def ParseArguments(args): ...@@ -6271,7 +6352,9 @@ def ParseArguments(args):
PrintUsage(None) PrintUsage(None)
elif opt == '--output': elif opt == '--output':
if val not in ('emacs', 'vs7', 'eclipse'): if val not in ('emacs', 'vs7', 'eclipse'):
PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.') PrintUsage(
'The only allowed output formats are emacs, vs7 and eclipse.'
)
output_format = val output_format = val
elif opt == '--verbose': elif opt == '--verbose':
verbosity = int(val) verbosity = int(val)
...@@ -6281,7 +6364,8 @@ def ParseArguments(args): ...@@ -6281,7 +6364,8 @@ def ParseArguments(args):
PrintCategories() PrintCategories()
elif opt == '--counting': elif opt == '--counting':
if val not in ('total', 'toplevel', 'detailed'): if val not in ('total', 'toplevel', 'detailed'):
PrintUsage('Valid counting options are total, toplevel, and detailed') PrintUsage(
'Valid counting options are total, toplevel, and detailed')
counting_style = val counting_style = val
elif opt == '--root': elif opt == '--root':
global _root global _root
...@@ -6317,8 +6401,7 @@ def main(): ...@@ -6317,8 +6401,7 @@ def main():
# if we try to print something containing non-ASCII characters. # if we try to print something containing non-ASCII characters.
sys.stderr = codecs.StreamReaderWriter(sys.stderr, sys.stderr = codecs.StreamReaderWriter(sys.stderr,
codecs.getreader('utf8'), codecs.getreader('utf8'),
codecs.getwriter('utf8'), codecs.getwriter('utf8'), 'replace')
'replace')
_cpplint_state.ResetErrorCounts() _cpplint_state.ResetErrorCounts()
for filename in filenames: for filename in filenames:
......
...@@ -33,5 +33,3 @@ cmake .. -DWITH_GPU=ON -DWITH_SWIG_PY=ON -DWITH_AVX=OFF -DCUDNN_ROOT=/usr/ ...@@ -33,5 +33,3 @@ cmake .. -DWITH_GPU=ON -DWITH_SWIG_PY=ON -DWITH_AVX=OFF -DCUDNN_ROOT=/usr/
make -j `nproc` make -j `nproc`
cpack -D CPACK_GENERATOR='DEB' .. cpack -D CPACK_GENERATOR='DEB' ..
mv *.deb ~/dist/gpu-noavx mv *.deb ~/dist/gpu-noavx
...@@ -58,4 +58,3 @@ m4 -DPADDLE_WITH_GPU=ON -DPADDLE_IS_DEVEL=ON -DPADDLE_WITH_DEMO=ON \ ...@@ -58,4 +58,3 @@ m4 -DPADDLE_WITH_GPU=ON -DPADDLE_IS_DEVEL=ON -DPADDLE_WITH_DEMO=ON \
-DPADDLE_BASE_IMAGE=nvidia/cuda:7.5-cudnn5-devel-ubuntu14.04 \ -DPADDLE_BASE_IMAGE=nvidia/cuda:7.5-cudnn5-devel-ubuntu14.04 \
-DPADDLE_WITH_AVX=OFF \ -DPADDLE_WITH_AVX=OFF \
Dockerfile.m4 > Dockerfile.gpu-noavx-demo Dockerfile.m4 > Dockerfile.gpu-noavx-demo
...@@ -2,4 +2,3 @@ ...@@ -2,4 +2,3 @@
set -e set -e
mkdir -p ../../../build mkdir -p ../../../build
cd ../../../build cd ../../../build
...@@ -998,4 +998,3 @@ from IN B-PP ...@@ -998,4 +998,3 @@ from IN B-PP
Friday NNP B-NP Friday NNP B-NP
's POS B-NP 's POS B-NP
Tokyo NNP I-NP Tokyo NNP I-NP
...@@ -4998,4 +4998,3 @@ However RB B-ADVP ...@@ -4998,4 +4998,3 @@ However RB B-ADVP
the DT B-NP the DT B-NP
disclosure NN I-NP disclosure NN I-NP
of IN B-PP of IN B-PP
...@@ -109,4 +109,3 @@ int main(int argc, char** argv) { ...@@ -109,4 +109,3 @@ int main(int argc, char** argv) {
} }
#endif #endif
...@@ -410,8 +410,8 @@ def RecurrentLayerGroupEnd(name): ...@@ -410,8 +410,8 @@ def RecurrentLayerGroupEnd(name):
"RecurrentLayerGroup not begin") "RecurrentLayerGroup not begin")
for pair in g_current_submodel.memories: #check exist for pair in g_current_submodel.memories: #check exist
layer = g_layer_map[pair.layer_name] layer = g_layer_map[pair.layer_name]
config_assert(layer is not None, "memory declare wrong name:%s" % config_assert(layer is not None,
pair.layer_name) "memory declare wrong name:%s" % pair.layer_name)
memory_link = g_layer_map[pair.link_name] memory_link = g_layer_map[pair.link_name]
config_assert(layer.size == memory_link.size, config_assert(layer.size == memory_link.size,
"memory declare wrong size:%d" % memory_link.size) "memory declare wrong size:%d" % memory_link.size)
...@@ -686,8 +686,8 @@ class ConvProjection(Projection): ...@@ -686,8 +686,8 @@ class ConvProjection(Projection):
parse_conv(conv_conf, input_layer_name, self.proj_conf.conv_conf, parse_conv(conv_conf, input_layer_name, self.proj_conf.conv_conf,
num_filters) num_filters)
# TODO: support rectangle input # TODO: support rectangle input
self.proj_conf.output_size = (self.proj_conf.conv_conf.output_x** self.proj_conf.output_size = (self.proj_conf.conv_conf.output_x
2) * num_filters **2) * num_filters
def calc_output_size(self, input_layer_config): def calc_output_size(self, input_layer_config):
return self.proj_conf.output_size return self.proj_conf.output_size
...@@ -2793,8 +2793,8 @@ class ConcatenateLayer2(LayerBase): ...@@ -2793,8 +2793,8 @@ class ConcatenateLayer2(LayerBase):
@config_layer('recurrent') @config_layer('recurrent')
class RecurrentLayer(LayerBase): class RecurrentLayer(LayerBase):
def __init__(self, name, inputs, reversed=False, bias=True, **xargs): def __init__(self, name, inputs, reversed=False, bias=True, **xargs):
super(RecurrentLayer, self).__init__(name, 'recurrent', 0, inputs, ** super(RecurrentLayer, self).__init__(name, 'recurrent', 0, inputs,
xargs) **xargs)
config_assert(len(self.inputs) == 1, 'RecurrentLayer must have 1 input') config_assert(len(self.inputs) == 1, 'RecurrentLayer must have 1 input')
input_layer = self.get_input_layer(0) input_layer = self.get_input_layer(0)
size = input_layer.size size = input_layer.size
...@@ -2876,22 +2876,22 @@ class MDLstmLayer(LayerBase): ...@@ -2876,22 +2876,22 @@ class MDLstmLayer(LayerBase):
active_state_type="sigmoid", active_state_type="sigmoid",
bias=True, bias=True,
**xargs): **xargs):
super(MDLstmLayer, self).__init__(name, 'mdlstmemory', 0, inputs, ** super(MDLstmLayer, self).__init__(name, 'mdlstmemory', 0, inputs,
xargs) **xargs)
config_assert(len(self.inputs) == 1, 'MDLstmLayer must have 1 input') config_assert(len(self.inputs) == 1, 'MDLstmLayer must have 1 input')
input_layer = self.get_input_layer(0) input_layer = self.get_input_layer(0)
dim_num = len(directions) dim_num = len(directions)
#check input_layer.size is divided by (3+dim_num) #check input_layer.size is divided by (3+dim_num)
config_assert(input_layer.size % config_assert(input_layer.size % (3 + dim_num) == 0,
(3 + dim_num) == 0, "size % (dim_num) should be 0!") "size % (dim_num) should be 0!")
size = input_layer.size / (3 + dim_num) size = input_layer.size / (3 + dim_num)
self.set_layer_size(size) self.set_layer_size(size)
self.config.active_gate_type = active_gate_type self.config.active_gate_type = active_gate_type
self.config.active_state_type = active_state_type self.config.active_state_type = active_state_type
for i in xrange(len(directions)): for i in xrange(len(directions)):
self.config.directions.append(int(directions[i])) self.config.directions.append(int(directions[i]))
self.create_input_parameter(0, size * size * self.create_input_parameter(0, size * size * (3 + dim_num),
(3 + dim_num), [size, size, 3 + dim_num]) [size, size, 3 + dim_num])
#bias includes 3 kinds of peephole, 3+dim_num+2+dim_num #bias includes 3 kinds of peephole, 3+dim_num+2+dim_num
self.create_bias_parameter(bias, size * (5 + 2 * dim_num)) self.create_bias_parameter(bias, size * (5 + 2 * dim_num))
...@@ -2929,8 +2929,8 @@ class GruStepLayer(LayerBase): ...@@ -2929,8 +2929,8 @@ class GruStepLayer(LayerBase):
active_gate_type="sigmoid", active_gate_type="sigmoid",
bias=True, bias=True,
**xargs): **xargs):
super(GruStepLayer, self).__init__(name, 'gru_step', size, inputs, ** super(GruStepLayer, self).__init__(name, 'gru_step', size, inputs,
xargs) **xargs)
config_assert(len(self.inputs) == 2, 'GruStepLayer must have 2 input') config_assert(len(self.inputs) == 2, 'GruStepLayer must have 2 input')
input_layer0 = self.get_input_layer(0) input_layer0 = self.get_input_layer(0)
input_layer1 = self.get_input_layer(1) input_layer1 = self.get_input_layer(1)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册