File indexing completed on 2024-09-27 07:02:50
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067 """Does google-lint on c++ files.
0068
0069 The goal of this script is to identify places in the code that *may*
0070 be in non-compliance with google style. It does not attempt to fix
0071 up these problems -- the point is to educate. It does also not
0072 attempt to find all problems, or to ensure that everything it does
0073 find is legitimately a problem.
0074
0075 In particular, we can get very confused by /* and // inside strings!
0076 We do a small hack, which is to ignore //'s with "'s after them on the
0077 same line, but it is far from perfect (in either direction).
0078 """
0079
0080 import codecs
0081 import copy
0082 import getopt
0083 import math
0084 import os
0085 import re
0086 import sre_compile
0087 import string
0088 import sys
0089 import unicodedata
0090
0091
0092 _USAGE = """
0093 Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
0094 [--counting=total|toplevel|detailed]
0095 <file> [file] ...
0096
0097 The style guidelines this tries to follow are those in
0098 http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
0099
0100 Every problem is given a confidence score from 1-5, with 5 meaning we are
0101 certain of the problem, and 1 meaning it could be a legitimate construct.
0102 This will miss some errors, and is not a substitute for a code review.
0103
0104 To suppress false-positive errors of a certain category, add a
0105 'NOLINT(category)' comment to the line. NOLINT or NOLINT(*)
0106 suppresses errors of all categories on that line.
0107
0108 The files passed in will be linted; at least one file must be provided.
0109 Linted extensions are .cc, .cpp, and .h. Other file types will be ignored.
0110
0111 Flags:
0112
0113 output=vs7
0114 By default, the output is formatted to ease emacs parsing. Visual Studio
0115 compatible output (vs7) may also be used. Other formats are unsupported.
0116
0117 verbose=#
0118 Specify a number 0-5 to restrict errors to certain verbosity levels.
0119
0120 filter=-x,+y,...
0121 Specify a comma-separated list of category-filters to apply: only
0122 error messages whose category names pass the filters will be printed.
0123 (Category names are printed with the message and look like
0124 "[whitespace/indent]".) Filters are evaluated left to right.
0125 "-FOO" and "FOO" means "do not print categories that start with FOO".
0126 "+FOO" means "do print categories that start with FOO".
0127
0128 Examples: --filter=-whitespace,+whitespace/braces
0129 --filter=whitespace,runtime/printf,+runtime/printf_format
0130 --filter=-,+build/include_what_you_use
0131
0132 To see a list of all the categories used in cpplint, pass no arg:
0133 --filter=
0134
0135 counting=total|toplevel|detailed
0136 The total number of errors found is always printed. If
0137 'toplevel' is provided, then the count of errors in each of
0138 the top-level categories like 'build' and 'whitespace' will
0139 also be printed. If 'detailed' is provided, then a count
0140 is provided for each category like 'build/class'.
0141
0142 root=subdir
0143 The root directory used for deriving header guard CPP variable.
0144 By default, the header guard CPP variable is calculated as the relative
0145 path to the directory that contains .git, .hg, or .svn. When this flag
0146 is specified, the relative path is calculated from the specified
0147 directory. If the specified directory does not exist, this flag is
0148 ignored.
0149
0150 Examples:
0151 Assuing that src/.git exists, the header guard CPP variables for
0152 src/chrome/browser/ui/browser.h are:
0153
0154 No flag => CHROME_BROWSER_UI_BROWSER_H_
0155 --root=chrome => BROWSER_UI_BROWSER_H_
0156 --root=chrome/browser => UI_BROWSER_H_
0157 """
0158
0159
0160
0161
0162
0163
0164 _ERROR_CATEGORIES = [
0165 'build/class',
0166 'build/deprecated',
0167 'build/endif_comment',
0168 'build/explicit_make_pair',
0169 'build/forward_decl',
0170 'build/header_guard',
0171 'build/include',
0172 'build/include_alpha',
0173 'build/include_order',
0174 'build/include_what_you_use',
0175 'build/namespaces',
0176 'build/printf_format',
0177 'build/storage_class',
0178 'legal/copyright',
0179 'readability/alt_tokens',
0180 'readability/braces',
0181 'readability/casting',
0182 'readability/check',
0183 'readability/constructors',
0184 'readability/fn_size',
0185 'readability/function',
0186 'readability/multiline_comment',
0187 'readability/multiline_string',
0188 'readability/namespace',
0189 'readability/nolint',
0190 'readability/streams',
0191 'readability/todo',
0192 'readability/utf8',
0193 'runtime/arrays',
0194 'runtime/casting',
0195 'runtime/explicit',
0196 'runtime/int',
0197 'runtime/init',
0198 'runtime/invalid_increment',
0199 'runtime/member_string_references',
0200 'runtime/memset',
0201 'runtime/operator',
0202 'runtime/printf',
0203 'runtime/printf_format',
0204 'runtime/references',
0205 'runtime/rtti',
0206 'runtime/sizeof',
0207 'runtime/string',
0208 'runtime/threadsafe_fn',
0209 'whitespace/blank_line',
0210 'whitespace/braces',
0211 'whitespace/comma',
0212 'whitespace/comments',
0213 'whitespace/empty_loop_body',
0214 'whitespace/end_of_line',
0215 'whitespace/ending_newline',
0216 'whitespace/forcolon',
0217 'whitespace/indent',
0218 'whitespace/labels',
0219 'whitespace/line_length',
0220 'whitespace/newline',
0221 'whitespace/operators',
0222 'whitespace/parens',
0223 'whitespace/semicolon',
0224 'whitespace/tab',
0225 'whitespace/todo'
0226 ]
0227
0228
0229
0230
0231
0232 _DEFAULT_FILTERS = ['-build/include_alpha']
0233
0234
0235
0236
0237
0238
0239 _STL_HEADERS = frozenset([
0240 'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception',
0241 'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set',
0242 'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'new',
0243 'pair.h', 'pthread_alloc', 'queue', 'set', 'set.h', 'sstream', 'stack',
0244 'stl_alloc.h', 'stl_relops.h', 'type_traits.h',
0245 'utility', 'vector', 'vector.h',
0246 ])
0247
0248
0249
0250 _CPP_HEADERS = frozenset([
0251 'algo.h', 'builtinbuf.h', 'bvector.h', 'cassert', 'cctype',
0252 'cerrno', 'cfloat', 'ciso646', 'climits', 'clocale', 'cmath',
0253 'complex', 'complex.h', 'csetjmp', 'csignal', 'cstdarg', 'cstddef',
0254 'cstdio', 'cstdlib', 'cstring', 'ctime', 'cwchar', 'cwctype',
0255 'defalloc.h', 'deque.h', 'editbuf.h', 'exception', 'fstream',
0256 'fstream.h', 'hashtable.h', 'heap.h', 'indstream.h', 'iomanip',
0257 'iomanip.h', 'ios', 'iosfwd', 'iostream', 'iostream.h', 'istream',
0258 'istream.h', 'iterator.h', 'limits', 'map.h', 'multimap.h', 'multiset.h',
0259 'numeric', 'ostream', 'ostream.h', 'parsestream.h', 'pfstream.h',
0260 'PlotFile.h', 'procbuf.h', 'pthread_alloc.h', 'rope', 'rope.h',
0261 'ropeimpl.h', 'SFile.h', 'slist', 'slist.h', 'stack.h', 'stdexcept',
0262 'stdiostream.h', 'streambuf', 'streambuf.h', 'stream.h', 'strfile.h',
0263 'string', 'strstream', 'strstream.h', 'tempbuf.h', 'tree.h', 'typeinfo',
0264 'valarray',
0265 ])
0266
0267
0268
0269
0270
0271 _CHECK_MACROS = [
0272 'DCHECK', 'CHECK',
0273 'EXPECT_TRUE_M', 'EXPECT_TRUE',
0274 'ASSERT_TRUE_M', 'ASSERT_TRUE',
0275 'EXPECT_FALSE_M', 'EXPECT_FALSE',
0276 'ASSERT_FALSE_M', 'ASSERT_FALSE',
0277 ]
0278
0279
0280 _CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS])
0281
0282 for op, replacement in [('==', 'EQ'), ('!=', 'NE'),
0283 ('>=', 'GE'), ('>', 'GT'),
0284 ('<=', 'LE'), ('<', 'LT')]:
0285 _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement
0286 _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement
0287 _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement
0288 _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement
0289 _CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement
0290 _CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % replacement
0291
0292 for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'),
0293 ('>=', 'LT'), ('>', 'LE'),
0294 ('<=', 'GT'), ('<', 'GE')]:
0295 _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement
0296 _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement
0297 _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement
0298 _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % inv_replacement
0299
0300
0301
0302
0303
0304
0305 _ALT_TOKEN_REPLACEMENT = {
0306 'and': '&&',
0307 'bitor': '|',
0308 'or': '||',
0309 'xor': '^',
0310 'compl': '~',
0311 'bitand': '&',
0312 'and_eq': '&=',
0313 'or_eq': '|=',
0314 'xor_eq': '^=',
0315 'not': '!',
0316 'not_eq': '!='
0317 }
0318
0319
0320
0321
0322
0323
0324
0325 _ALT_TOKEN_REPLACEMENT_PATTERN = re.compile(
0326 r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)')
0327
0328
0329
0330
0331 _C_SYS_HEADER = 1
0332 _CPP_SYS_HEADER = 2
0333 _LIKELY_MY_HEADER = 3
0334 _POSSIBLE_MY_HEADER = 4
0335 _OTHER_HEADER = 5
0336
0337
0338 _NO_ASM = 0
0339 _INSIDE_ASM = 1
0340 _END_ASM = 2
0341 _BLOCK_ASM = 3
0342
0343
0344 _MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)'
0345 r'(?:\s+(volatile|__volatile__))?'
0346 r'\s*[{(]')
0347
0348
0349 _regexp_compile_cache = {}
0350
0351
0352 _RE_SUPPRESSION = re.compile(r'\bNOLINT\b(\([^)]*\))?')
0353
0354
0355
0356 _error_suppressions = {}
0357
0358
0359
0360 _root = None
0361
0362 def ParseNolintSuppressions(filename, raw_line, linenum, error):
0363 """Updates the global list of error-suppressions.
0364
0365 Parses any NOLINT comments on the current line, updating the global
0366 error_suppressions store. Reports an error if the NOLINT comment
0367 was malformed.
0368
0369 Args:
0370 filename: str, the name of the input file.
0371 raw_line: str, the line of input text, with comments.
0372 linenum: int, the number of the current line.
0373 error: function, an error handler.
0374 """
0375
0376 matched = _RE_SUPPRESSION.search(raw_line)
0377 if matched:
0378 category = matched.group(1)
0379 if category in (None, '(*)'):
0380 _error_suppressions.setdefault(None, set()).add(linenum)
0381 else:
0382 if category.startswith('(') and category.endswith(')'):
0383 category = category[1:-1]
0384 if category in _ERROR_CATEGORIES:
0385 _error_suppressions.setdefault(category, set()).add(linenum)
0386 else:
0387 error(filename, linenum, 'readability/nolint', 5,
0388 'Unknown NOLINT error category: %s' % category)
0389
0390
0391 def ResetNolintSuppressions():
0392 "Resets the set of NOLINT suppressions to empty."
0393 _error_suppressions.clear()
0394
0395
0396 def IsErrorSuppressedByNolint(category, linenum):
0397 """Returns true if the specified error category is suppressed on this line.
0398
0399 Consults the global error_suppressions map populated by
0400 ParseNolintSuppressions/ResetNolintSuppressions.
0401
0402 Args:
0403 category: str, the category of the error.
0404 linenum: int, the current line number.
0405 Returns:
0406 bool, True iff the error should be suppressed due to a NOLINT comment.
0407 """
0408 return (linenum in _error_suppressions.get(category, set()) or
0409 linenum in _error_suppressions.get(None, set()))
0410
0411 def Match(pattern, s):
0412 """Matches the string with the pattern, caching the compiled regexp."""
0413
0414
0415
0416 if not pattern in _regexp_compile_cache:
0417 _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
0418 return _regexp_compile_cache[pattern].match(s)
0419
0420
0421 def Search(pattern, s):
0422 """Searches the string for the pattern, caching the compiled regexp."""
0423 if not pattern in _regexp_compile_cache:
0424 _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
0425 return _regexp_compile_cache[pattern].search(s)
0426
0427
0428 class _IncludeState(dict):
0429 """Tracks line numbers for includes, and the order in which includes appear.
0430
0431 As a dict, an _IncludeState object serves as a mapping between include
0432 filename and line number on which that file was included.
0433
0434 Call CheckNextIncludeOrder() once for each header in the file, passing
0435 in the type constants defined above. Calls in an illegal order will
0436 raise an _IncludeError with an appropriate error message.
0437
0438 """
0439
0440
0441 _INITIAL_SECTION = 0
0442 _MY_H_SECTION = 1
0443 _C_SECTION = 2
0444 _CPP_SECTION = 3
0445 _OTHER_H_SECTION = 4
0446
0447 _TYPE_NAMES = {
0448 _C_SYS_HEADER: 'C system header',
0449 _CPP_SYS_HEADER: 'C++ system header',
0450 _LIKELY_MY_HEADER: 'header this file implements',
0451 _POSSIBLE_MY_HEADER: 'header this file may implement',
0452 _OTHER_HEADER: 'other header',
0453 }
0454 _SECTION_NAMES = {
0455 _INITIAL_SECTION: "... nothing. (This can't be an error.)",
0456 _MY_H_SECTION: 'a header this file implements',
0457 _C_SECTION: 'C system header',
0458 _CPP_SECTION: 'C++ system header',
0459 _OTHER_H_SECTION: 'other header',
0460 }
0461
0462 def __init__(self):
0463 dict.__init__(self)
0464
0465 self._section = self._INITIAL_SECTION
0466
0467 self._last_header = ''
0468
0469 def CanonicalizeAlphabeticalOrder(self, header_path):
0470 """Returns a path canonicalized for alphabetical comparison.
0471
0472 - replaces "-" with "_" so they both cmp the same.
0473 - removes '-inl' since we don't require them to be after the main header.
0474 - lowercase everything, just in case.
0475
0476 Args:
0477 header_path: Path to be canonicalized.
0478
0479 Returns:
0480 Canonicalized path.
0481 """
0482 return header_path.replace('-inl.h', '.h').replace('-', '_').lower()
0483
0484 def IsInAlphabeticalOrder(self, header_path):
0485 """Check if a header is in alphabetical order with the previous header.
0486
0487 Args:
0488 header_path: Header to be checked.
0489
0490 Returns:
0491 Returns true if the header is in alphabetical order.
0492 """
0493 canonical_header = self.CanonicalizeAlphabeticalOrder(header_path)
0494 if self._last_header > canonical_header:
0495 return False
0496 self._last_header = canonical_header
0497 return True
0498
0499 def CheckNextIncludeOrder(self, header_type):
0500 """Returns a non-empty error message if the next header is out of order.
0501
0502 This function also updates the internal state to be ready to check
0503 the next include.
0504
0505 Args:
0506 header_type: One of the _XXX_HEADER constants defined above.
0507
0508 Returns:
0509 The empty string if the header is in the right order, or an
0510 error message describing what's wrong.
0511
0512 """
0513 error_message = ('Found %s after %s' %
0514 (self._TYPE_NAMES[header_type],
0515 self._SECTION_NAMES[self._section]))
0516
0517 last_section = self._section
0518
0519 if header_type == _C_SYS_HEADER:
0520 if self._section <= self._C_SECTION:
0521 self._section = self._C_SECTION
0522 else:
0523 self._last_header = ''
0524 return error_message
0525 elif header_type == _CPP_SYS_HEADER:
0526 if self._section <= self._CPP_SECTION:
0527 self._section = self._CPP_SECTION
0528 else:
0529 self._last_header = ''
0530 return error_message
0531 elif header_type == _LIKELY_MY_HEADER:
0532 if self._section <= self._MY_H_SECTION:
0533 self._section = self._MY_H_SECTION
0534 else:
0535 self._section = self._OTHER_H_SECTION
0536 elif header_type == _POSSIBLE_MY_HEADER:
0537 if self._section <= self._MY_H_SECTION:
0538 self._section = self._MY_H_SECTION
0539 else:
0540
0541
0542 self._section = self._OTHER_H_SECTION
0543 else:
0544 assert header_type == _OTHER_HEADER
0545 self._section = self._OTHER_H_SECTION
0546
0547 if last_section != self._section:
0548 self._last_header = ''
0549
0550 return ''
0551
0552
0553 class _CppLintState(object):
0554 """Maintains module-wide state.."""
0555
0556 def __init__(self):
0557 self.verbose_level = 1
0558 self.error_count = 0
0559
0560 self.filters = _DEFAULT_FILTERS[:]
0561 self.counting = 'total'
0562 self.errors_by_category = {}
0563
0564
0565
0566
0567 self.output_format = 'emacs'
0568
0569 def SetOutputFormat(self, output_format):
0570 """Sets the output format for errors."""
0571 self.output_format = output_format
0572
0573 def SetVerboseLevel(self, level):
0574 """Sets the module's verbosity, and returns the previous setting."""
0575 last_verbose_level = self.verbose_level
0576 self.verbose_level = level
0577 return last_verbose_level
0578
0579 def SetCountingStyle(self, counting_style):
0580 """Sets the module's counting options."""
0581 self.counting = counting_style
0582
0583 def SetFilters(self, filters):
0584 """Sets the error-message filters.
0585
0586 These filters are applied when deciding whether to emit a given
0587 error message.
0588
0589 Args:
0590 filters: A string of comma-separated filters (eg "+whitespace/indent").
0591 Each filter should start with + or -; else we die.
0592
0593 Raises:
0594 ValueError: The comma-separated filters did not all start with '+' or '-'.
0595 E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter"
0596 """
0597
0598 self.filters = _DEFAULT_FILTERS[:]
0599 for filt in filters.split(','):
0600 clean_filt = filt.strip()
0601 if clean_filt:
0602 self.filters.append(clean_filt)
0603 for filt in self.filters:
0604 if not (filt.startswith('+') or filt.startswith('-')):
0605 raise ValueError('Every filter in --filters must start with + or -'
0606 ' (%s does not)' % filt)
0607
0608 def ResetErrorCounts(self):
0609 """Sets the module's error statistic back to zero."""
0610 self.error_count = 0
0611 self.errors_by_category = {}
0612
0613 def IncrementErrorCount(self, category):
0614 """Bumps the module's error statistic."""
0615 self.error_count += 1
0616 if self.counting in ('toplevel', 'detailed'):
0617 if self.counting != 'detailed':
0618 category = category.split('/')[0]
0619 if category not in self.errors_by_category:
0620 self.errors_by_category[category] = 0
0621 self.errors_by_category[category] += 1
0622
0623 def PrintErrorCounts(self):
0624 """Print a summary of errors by category, and the total."""
0625 for category, count in self.errors_by_category.iteritems():
0626 sys.stderr.write('Category \'%s\' errors found: %d\n' %
0627 (category, count))
0628 sys.stderr.write('Total errors found: %d\n' % self.error_count)
0629
0630 _cpplint_state = _CppLintState()
0631
0632
0633 def _OutputFormat():
0634 """Gets the module's output format."""
0635 return _cpplint_state.output_format
0636
0637
0638 def _SetOutputFormat(output_format):
0639 """Sets the module's output format."""
0640 _cpplint_state.SetOutputFormat(output_format)
0641
0642
0643 def _VerboseLevel():
0644 """Returns the module's verbosity setting."""
0645 return _cpplint_state.verbose_level
0646
0647
0648 def _SetVerboseLevel(level):
0649 """Sets the module's verbosity, and returns the previous setting."""
0650 return _cpplint_state.SetVerboseLevel(level)
0651
0652
0653 def _SetCountingStyle(level):
0654 """Sets the module's counting options."""
0655 _cpplint_state.SetCountingStyle(level)
0656
0657
0658 def _Filters():
0659 """Returns the module's list of output filters, as a list."""
0660 return _cpplint_state.filters
0661
0662
0663 def _SetFilters(filters):
0664 """Sets the module's error-message filters.
0665
0666 These filters are applied when deciding whether to emit a given
0667 error message.
0668
0669 Args:
0670 filters: A string of comma-separated filters (eg "whitespace/indent").
0671 Each filter should start with + or -; else we die.
0672 """
0673 _cpplint_state.SetFilters(filters)
0674
0675
0676 class _FunctionState(object):
0677 """Tracks current function name and the number of lines in its body."""
0678
0679 _NORMAL_TRIGGER = 250
0680 _TEST_TRIGGER = 400
0681
0682 def __init__(self):
0683 self.in_a_function = False
0684 self.lines_in_function = 0
0685 self.current_function = ''
0686
0687 def Begin(self, function_name):
0688 """Start analyzing function body.
0689
0690 Args:
0691 function_name: The name of the function being tracked.
0692 """
0693 self.in_a_function = True
0694 self.lines_in_function = 0
0695 self.current_function = function_name
0696
0697 def Count(self):
0698 """Count line in current function body."""
0699 if self.in_a_function:
0700 self.lines_in_function += 1
0701
0702 def Check(self, error, filename, linenum):
0703 """Report if too many lines in function body.
0704
0705 Args:
0706 error: The function to call with any errors found.
0707 filename: The name of the current file.
0708 linenum: The number of the line to check.
0709 """
0710 if Match(r'T(EST|est)', self.current_function):
0711 base_trigger = self._TEST_TRIGGER
0712 else:
0713 base_trigger = self._NORMAL_TRIGGER
0714 trigger = base_trigger * 2**_VerboseLevel()
0715
0716 if self.lines_in_function > trigger:
0717 error_level = int(math.log(self.lines_in_function / base_trigger, 2))
0718
0719 if error_level > 5:
0720 error_level = 5
0721 error(filename, linenum, 'readability/fn_size', error_level,
0722 'Small and focused functions are preferred:'
0723 ' %s has %d non-comment lines'
0724 ' (error triggered by exceeding %d lines).' % (
0725 self.current_function, self.lines_in_function, trigger))
0726
0727 def End(self):
0728 """Stop analyzing function body."""
0729 self.in_a_function = False
0730
0731
0732 class _IncludeError(Exception):
0733 """Indicates a problem with the include order in a file."""
0734 pass
0735
0736
0737 class FileInfo:
0738 """Provides utility functions for filenames.
0739
0740 FileInfo provides easy access to the components of a file's path
0741 relative to the project root.
0742 """
0743
0744 def __init__(self, filename):
0745 self._filename = filename
0746
0747 def FullName(self):
0748 """Make Windows paths like Unix."""
0749 return os.path.abspath(self._filename).replace('\\', '/')
0750
0751 def RepositoryName(self):
0752 """FullName after removing the local path to the repository.
0753
0754 If we have a real absolute path name here we can try to do something smart:
0755 detecting the root of the checkout and truncating /path/to/checkout from
0756 the name so that we get header guards that don't include things like
0757 "C:\Documents and Settings\..." or "/home/username/..." in them and thus
0758 people on different computers who have checked the source out to different
0759 locations won't see bogus errors.
0760 """
0761 fullname = self.FullName()
0762
0763 if os.path.exists(fullname):
0764 project_dir = os.path.dirname(fullname)
0765
0766 if os.path.exists(os.path.join(project_dir, ".svn")):
0767
0768
0769 root_dir = project_dir
0770 one_up_dir = os.path.dirname(root_dir)
0771 while os.path.exists(os.path.join(one_up_dir, ".svn")):
0772 root_dir = os.path.dirname(root_dir)
0773 one_up_dir = os.path.dirname(one_up_dir)
0774
0775 prefix = os.path.commonprefix([root_dir, project_dir])
0776 return fullname[len(prefix) + 1:]
0777
0778
0779
0780 root_dir = os.path.dirname(fullname)
0781 while (root_dir != os.path.dirname(root_dir) and
0782 not os.path.exists(os.path.join(root_dir, ".git")) and
0783 not os.path.exists(os.path.join(root_dir, ".hg")) and
0784 not os.path.exists(os.path.join(root_dir, ".svn"))):
0785 root_dir = os.path.dirname(root_dir)
0786
0787 if (os.path.exists(os.path.join(root_dir, ".git")) or
0788 os.path.exists(os.path.join(root_dir, ".hg")) or
0789 os.path.exists(os.path.join(root_dir, ".svn"))):
0790 prefix = os.path.commonprefix([root_dir, project_dir])
0791 return fullname[len(prefix) + 1:]
0792
0793
0794 return fullname
0795
0796 def Split(self):
0797 """Splits the file into the directory, basename, and extension.
0798
0799 For 'chrome/browser/browser.cc', Split() would
0800 return ('chrome/browser', 'browser', '.cc')
0801
0802 Returns:
0803 A tuple of (directory, basename, extension).
0804 """
0805
0806 googlename = self.RepositoryName()
0807 project, rest = os.path.split(googlename)
0808 return (project,) + os.path.splitext(rest)
0809
0810 def BaseName(self):
0811 """File base name - text after the final slash, before the final period."""
0812 return self.Split()[1]
0813
0814 def Extension(self):
0815 """File extension - text following the final period."""
0816 return self.Split()[2]
0817
0818 def NoExtension(self):
0819 """File has no source file extension."""
0820 return '/'.join(self.Split()[0:2])
0821
0822 def IsSource(self):
0823 """File has a source file extension."""
0824 return self.Extension()[1:] in ('c', 'cc', 'cpp', 'cxx')
0825
0826
0827 def _ShouldPrintError(category, confidence, linenum):
0828 """If confidence >= verbose, category passes filter and is not suppressed."""
0829
0830
0831
0832
0833 if IsErrorSuppressedByNolint(category, linenum):
0834 return False
0835 if confidence < _cpplint_state.verbose_level:
0836 return False
0837
0838 is_filtered = False
0839 for one_filter in _Filters():
0840 if one_filter.startswith('-'):
0841 if category.startswith(one_filter[1:]):
0842 is_filtered = True
0843 elif one_filter.startswith('+'):
0844 if category.startswith(one_filter[1:]):
0845 is_filtered = False
0846 else:
0847 assert False
0848 if is_filtered:
0849 return False
0850
0851 return True
0852
0853
0854 def Error(filename, linenum, category, confidence, message):
0855 """Logs the fact we've found a lint error.
0856
0857 We log where the error was found, and also our confidence in the error,
0858 that is, how certain we are this is a legitimate style regression, and
0859 not a misidentification or a use that's sometimes justified.
0860
0861 False positives can be suppressed by the use of
0862 "cpplint(category)" comments on the offending line. These are
0863 parsed into _error_suppressions.
0864
0865 Args:
0866 filename: The name of the file containing the error.
0867 linenum: The number of the line containing the error.
0868 category: A string used to describe the "category" this bug
0869 falls under: "whitespace", say, or "runtime". Categories
0870 may have a hierarchy separated by slashes: "whitespace/indent".
0871 confidence: A number from 1-5 representing a confidence score for
0872 the error, with 5 meaning that we are certain of the problem,
0873 and 1 meaning that it could be a legitimate construct.
0874 message: The error message.
0875 """
0876 if _ShouldPrintError(category, confidence, linenum):
0877 _cpplint_state.IncrementErrorCount(category)
0878 if _cpplint_state.output_format == 'vs7':
0879 sys.stderr.write('%s(%s): %s [%s] [%d]\n' % (
0880 filename, linenum, message, category, confidence))
0881 elif _cpplint_state.output_format == 'eclipse':
0882 sys.stderr.write('%s:%s: warning: %s [%s] [%d]\n' % (
0883 filename, linenum, message, category, confidence))
0884 else:
0885 sys.stderr.write('%s:%s: %s [%s] [%d]\n' % (
0886 filename, linenum, message, category, confidence))
0887
0888
0889
0890 _RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile(
0891 r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)')
0892
0893 _RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES = re.compile(r'"[^"]*"')
0894
0895 _RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES = re.compile(r"'.'")
0896
0897
0898
0899
0900
0901
0902
0903
0904 _RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile(
0905 r"""(\s*/\*.*\*/\s*$|
0906 /\*.*\*/\s+|
0907 \s+/\*.*\*/(?=\W)|
0908 /\*.*\*/)""", re.VERBOSE)
0909
0910
0911 def IsCppString(line):
0912 """Does line terminate so, that the next symbol is in string constant.
0913
0914 This function does not consider single-line nor multi-line comments.
0915
0916 Args:
0917 line: is a partial line of code starting from the 0..n.
0918
0919 Returns:
0920 True, if next character appended to 'line' is inside a
0921 string constant.
0922 """
0923
0924 line = line.replace(r'\\', 'XX')
0925 return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1
0926
0927
0928 def FindNextMultiLineCommentStart(lines, lineix):
0929 """Find the beginning marker for a multiline comment."""
0930 while lineix < len(lines):
0931 if lines[lineix].strip().startswith('/*'):
0932
0933 if lines[lineix].strip().find('*/', 2) < 0:
0934 return lineix
0935 lineix += 1
0936 return len(lines)
0937
0938
0939 def FindNextMultiLineCommentEnd(lines, lineix):
0940 """We are inside a comment, find the end marker."""
0941 while lineix < len(lines):
0942 if lines[lineix].strip().endswith('*/'):
0943 return lineix
0944 lineix += 1
0945 return len(lines)
0946
0947
0948 def RemoveMultiLineCommentsFromRange(lines, begin, end):
0949 """Clears a range of lines for multi-line comments."""
0950
0951
0952 for i in range(begin, end):
0953 lines[i] = '// dummy'
0954
0955
0956 def RemoveMultiLineComments(filename, lines, error):
0957 """Removes multiline (c-style) comments from lines."""
0958 lineix = 0
0959 while lineix < len(lines):
0960 lineix_begin = FindNextMultiLineCommentStart(lines, lineix)
0961 if lineix_begin >= len(lines):
0962 return
0963 lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin)
0964 if lineix_end >= len(lines):
0965 error(filename, lineix_begin + 1, 'readability/multiline_comment', 5,
0966 'Could not find end of multi-line comment')
0967 return
0968 RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1)
0969 lineix = lineix_end + 1
0970
0971
0972 def CleanseComments(line):
0973 """Removes //-comments and single-line C-style /* */ comments.
0974
0975 Args:
0976 line: A line of C++ source.
0977
0978 Returns:
0979 The line with single-line comments removed.
0980 """
0981 commentpos = line.find('//')
0982 if commentpos != -1 and not IsCppString(line[:commentpos]):
0983 line = line[:commentpos].rstrip()
0984
0985 return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line)
0986
0987
0988 class CleansedLines(object):
0989 """Holds 3 copies of all lines with different preprocessing applied to them.
0990
0991 1) elided member contains lines without strings and comments,
0992 2) lines member contains lines without comments, and
0993 3) raw_lines member contains all the lines without processing.
0994 All these three members are of <type 'list'>, and of the same length.
0995 """
0996
0997 def __init__(self, lines):
0998 self.elided = []
0999 self.lines = []
1000 self.raw_lines = lines
1001 self.num_lines = len(lines)
1002 for linenum in range(len(lines)):
1003 self.lines.append(CleanseComments(lines[linenum]))
1004 elided = self._CollapseStrings(lines[linenum])
1005 self.elided.append(CleanseComments(elided))
1006
1007 def NumLines(self):
1008 """Returns the number of lines represented."""
1009 return self.num_lines
1010
1011 @staticmethod
1012 def _CollapseStrings(elided):
1013 """Collapses strings and chars on a line to simple "" or '' blocks.
1014
1015 We nix strings first so we're not fooled by text like '"http://"'
1016
1017 Args:
1018 elided: The line being processed.
1019
1020 Returns:
1021 The line with collapsed strings.
1022 """
1023 if not _RE_PATTERN_INCLUDE.match(elided):
1024
1025
1026
1027 elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided)
1028 elided = _RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES.sub("''", elided)
1029 elided = _RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES.sub('""', elided)
1030 return elided
1031
1032
1033 def FindEndOfExpressionInLine(line, startpos, depth, startchar, endchar):
1034 """Find the position just after the matching endchar.
1035
1036 Args:
1037 line: a CleansedLines line.
1038 startpos: start searching at this position.
1039 depth: nesting level at startpos.
1040 startchar: expression opening character.
1041 endchar: expression closing character.
1042
1043 Returns:
1044 Index just after endchar.
1045 """
1046 for i in xrange(startpos, len(line)):
1047 if line[i] == startchar:
1048 depth += 1
1049 elif line[i] == endchar:
1050 depth -= 1
1051 if depth == 0:
1052 return i + 1
1053 return -1
1054
1055
1056 def CloseExpression(clean_lines, linenum, pos):
1057 """If input points to ( or { or [, finds the position that closes it.
1058
1059 If lines[linenum][pos] points to a '(' or '{' or '[', finds the
1060 linenum/pos that correspond to the closing of the expression.
1061
1062 Args:
1063 clean_lines: A CleansedLines instance containing the file.
1064 linenum: The number of the line to check.
1065 pos: A position on the line.
1066
1067 Returns:
1068 A tuple (line, linenum, pos) pointer *past* the closing brace, or
1069 (line, len(lines), -1) if we never find a close. Note we ignore
1070 strings and comments when matching; and the line we return is the
1071 'cleansed' line at linenum.
1072 """
1073
1074 line = clean_lines.elided[linenum]
1075 startchar = line[pos]
1076 if startchar not in '({[':
1077 return (line, clean_lines.NumLines(), -1)
1078 if startchar == '(': endchar = ')'
1079 if startchar == '[': endchar = ']'
1080 if startchar == '{': endchar = '}'
1081
1082
1083 end_pos = FindEndOfExpressionInLine(line, pos, 0, startchar, endchar)
1084 if end_pos > -1:
1085 return (line, linenum, end_pos)
1086 tail = line[pos:]
1087 num_open = tail.count(startchar) - tail.count(endchar)
1088 while linenum < clean_lines.NumLines() - 1:
1089 linenum += 1
1090 line = clean_lines.elided[linenum]
1091 delta = line.count(startchar) - line.count(endchar)
1092 if num_open + delta <= 0:
1093 return (line, linenum,
1094 FindEndOfExpressionInLine(line, 0, num_open, startchar, endchar))
1095 num_open += delta
1096
1097
1098 return (line, clean_lines.NumLines(), -1)
1099
1100 def CheckForCopyright(filename, lines, error):
1101 """Logs an error if no Copyright message appears at the top of the file."""
1102
1103
1104
1105 for line in xrange(1, min(len(lines), 11)):
1106 if re.search(r'Copyright', lines[line], re.I): break
1107 else:
1108 error(filename, 0, 'legal/copyright', 5,
1109 'No copyright message found. '
1110 'You should have a line: "Copyright [year] <Copyright Owner>"')
1111
1112
1113 def GetHeaderGuardCPPVariable(filename):
1114 """Returns the CPP variable that should be used as a header guard.
1115
1116 Args:
1117 filename: The name of a C++ header file.
1118
1119 Returns:
1120 The CPP variable that should be used as a header guard in the
1121 named file.
1122
1123 """
1124
1125
1126
1127 filename = re.sub(r'_flymake\.h$', '.h', filename)
1128 filename = re.sub(r'/\.flymake/([^/]*)$', r'/\1', filename)
1129
1130 fileinfo = FileInfo(filename)
1131 file_path_from_root = fileinfo.RepositoryName()
1132 if _root:
1133 file_path_from_root = re.sub('^' + _root + os.sep, '', file_path_from_root)
1134 return re.sub(r'[-./\s]', '_', file_path_from_root).upper() + '_'
1135
1136
1137 def CheckForHeaderGuard(filename, lines, error):
1138 """Checks that the file contains a header guard.
1139
1140 Logs an error if no #ifndef header guard is present. For other
1141 headers, checks that the full pathname is used.
1142
1143 Args:
1144 filename: The name of the C++ header file.
1145 lines: An array of strings, each representing a line of the file.
1146 error: The function to call with any errors found.
1147 """
1148
1149 cppvar = GetHeaderGuardCPPVariable(filename)
1150
1151 ifndef = None
1152 ifndef_linenum = 0
1153 define = None
1154 endif = None
1155 endif_linenum = 0
1156 for linenum, line in enumerate(lines):
1157 linesplit = line.split()
1158 if len(linesplit) >= 2:
1159
1160 if not ifndef and linesplit[0] == '#ifndef':
1161
1162 ifndef = linesplit[1]
1163 ifndef_linenum = linenum
1164 if not define and linesplit[0] == '#define':
1165 define = linesplit[1]
1166
1167 if line.startswith('#endif'):
1168 endif = line
1169 endif_linenum = linenum
1170
1171 if not ifndef:
1172 error(filename, 0, 'build/header_guard', 5,
1173 'No #ifndef header guard found, suggested CPP variable is: %s' %
1174 cppvar)
1175 return
1176
1177 if not define:
1178 error(filename, 0, 'build/header_guard', 5,
1179 'No #define header guard found, suggested CPP variable is: %s' %
1180 cppvar)
1181 return
1182
1183
1184
1185 if ifndef != cppvar:
1186 error_level = 0
1187 if ifndef != cppvar + '_':
1188 error_level = 5
1189
1190 ParseNolintSuppressions(filename, lines[ifndef_linenum], ifndef_linenum,
1191 error)
1192 error(filename, ifndef_linenum, 'build/header_guard', error_level,
1193 '#ifndef header guard has wrong style, please use: %s' % cppvar)
1194
1195 if define != ifndef:
1196 error(filename, 0, 'build/header_guard', 5,
1197 '#ifndef and #define don\'t match, suggested CPP variable is: %s' %
1198 cppvar)
1199 return
1200
1201 if endif != ('#endif // %s' % cppvar):
1202 error_level = 0
1203 if endif != ('#endif // %s' % (cppvar + '_')):
1204 error_level = 5
1205
1206 ParseNolintSuppressions(filename, lines[endif_linenum], endif_linenum,
1207 error)
1208 error(filename, endif_linenum, 'build/header_guard', error_level,
1209 '#endif line should be "#endif // %s"' % cppvar)
1210
1211
1212 def CheckForUnicodeReplacementCharacters(filename, lines, error):
1213 """Logs an error for each line containing Unicode replacement characters.
1214
1215 These indicate that either the file contained invalid UTF-8 (likely)
1216 or Unicode replacement characters (which it shouldn't). Note that
1217 it's possible for this to throw off line numbering if the invalid
1218 UTF-8 occurred adjacent to a newline.
1219
1220 Args:
1221 filename: The name of the current file.
1222 lines: An array of strings, each representing a line of the file.
1223 error: The function to call with any errors found.
1224 """
1225 for linenum, line in enumerate(lines):
1226 if u'\ufffd' in line:
1227 error(filename, linenum, 'readability/utf8', 5,
1228 'Line contains invalid UTF-8 (or Unicode replacement character).')
1229
1230
1231 def CheckForNewlineAtEOF(filename, lines, error):
1232 """Logs an error if there is no newline char at the end of the file.
1233
1234 Args:
1235 filename: The name of the current file.
1236 lines: An array of strings, each representing a line of the file.
1237 error: The function to call with any errors found.
1238 """
1239
1240
1241
1242
1243
1244 if len(lines) < 3 or lines[-2]:
1245 error(filename, len(lines) - 2, 'whitespace/ending_newline', 5,
1246 'Could not find a newline character at the end of the file.')
1247
1248
1249 def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error):
1250 """Logs an error if we see /* ... */ or "..." that extend past one line.
1251
1252 /* ... */ comments are legit inside macros, for one line.
1253 Otherwise, we prefer // comments, so it's ok to warn about the
1254 other. Likewise, it's ok for strings to extend across multiple
1255 lines, as long as a line continuation character (backslash)
1256 terminates each line. Although not currently prohibited by the C++
1257 style guide, it's ugly and unnecessary. We don't do well with either
1258 in this lint program, so we warn about both.
1259
1260 Args:
1261 filename: The name of the current file.
1262 clean_lines: A CleansedLines instance containing the file.
1263 linenum: The number of the line to check.
1264 error: The function to call with any errors found.
1265 """
1266 line = clean_lines.elided[linenum]
1267
1268
1269
1270 line = line.replace('\\\\', '')
1271
1272 if line.count('/*') > line.count('*/'):
1273 error(filename, linenum, 'readability/multiline_comment', 5,
1274 'Complex multi-line /*...*/-style comment found. '
1275 'Lint may give bogus warnings. '
1276 'Consider replacing these with //-style comments, '
1277 'with #if 0...#endif, '
1278 'or with more clearly structured multi-line comments.')
1279
1280 if (line.count('"') - line.count('\\"')) % 2:
1281 error(filename, linenum, 'readability/multiline_string', 5,
1282 'Multi-line string ("...") found. This lint script doesn\'t '
1283 'do well with such strings, and may give bogus warnings. They\'re '
1284 'ugly and unnecessary, and you should use concatenation instead".')
1285
1286
1287 threading_list = (
1288 ('asctime(', 'asctime_r('),
1289 ('ctime(', 'ctime_r('),
1290 ('getgrgid(', 'getgrgid_r('),
1291 ('getgrnam(', 'getgrnam_r('),
1292 ('getlogin(', 'getlogin_r('),
1293 ('getpwnam(', 'getpwnam_r('),
1294 ('getpwuid(', 'getpwuid_r('),
1295 ('gmtime(', 'gmtime_r('),
1296 ('localtime(', 'localtime_r('),
1297 ('rand(', 'rand_r('),
1298 ('readdir(', 'readdir_r('),
1299 ('strtok(', 'strtok_r('),
1300 ('ttyname(', 'ttyname_r('),
1301 )
1302
1303
1304 def CheckPosixThreading(filename, clean_lines, linenum, error):
1305 """Checks for calls to thread-unsafe functions.
1306
1307 Much code has been originally written without consideration of
1308 multi-threading. Also, engineers are relying on their old experience;
1309 they have learned posix before threading extensions were added. These
1310 tests guide the engineers to use thread-safe functions (when using
1311 posix directly).
1312
1313 Args:
1314 filename: The name of the current file.
1315 clean_lines: A CleansedLines instance containing the file.
1316 linenum: The number of the line to check.
1317 error: The function to call with any errors found.
1318 """
1319 line = clean_lines.elided[linenum]
1320 for single_thread_function, multithread_safe_function in threading_list:
1321 ix = line.find(single_thread_function)
1322
1323 if ix >= 0 and (ix == 0 or (not line[ix - 1].isalnum() and
1324 line[ix - 1] not in ('_', '.', '>'))):
1325 error(filename, linenum, 'runtime/threadsafe_fn', 2,
1326 'Consider using ' + multithread_safe_function +
1327 '...) instead of ' + single_thread_function +
1328 '...) for improved thread safety.')
1329
1330
1331
1332
1333 _RE_PATTERN_INVALID_INCREMENT = re.compile(
1334 r'^\s*\*\w+(\+\+|--);')
1335
1336
1337 def CheckInvalidIncrement(filename, clean_lines, linenum, error):
1338 """Checks for invalid increment *count++.
1339
1340 For example following function:
1341 void increment_counter(int* count) {
1342 *count++;
1343 }
1344 is invalid, because it effectively does count++, moving pointer, and should
1345 be replaced with ++*count, (*count)++ or *count += 1.
1346
1347 Args:
1348 filename: The name of the current file.
1349 clean_lines: A CleansedLines instance containing the file.
1350 linenum: The number of the line to check.
1351 error: The function to call with any errors found.
1352 """
1353 line = clean_lines.elided[linenum]
1354 if _RE_PATTERN_INVALID_INCREMENT.match(line):
1355 error(filename, linenum, 'runtime/invalid_increment', 5,
1356 'Changing pointer instead of value (or unused value of operator*).')
1357
1358
1359 class _BlockInfo(object):
1360 """Stores information about a generic block of code."""
1361
1362 def __init__(self, seen_open_brace):
1363 self.seen_open_brace = seen_open_brace
1364 self.open_parentheses = 0
1365 self.inline_asm = _NO_ASM
1366
1367 def CheckBegin(self, filename, clean_lines, linenum, error):
1368 """Run checks that applies to text up to the opening brace.
1369
1370 This is mostly for checking the text after the class identifier
1371 and the "{", usually where the base class is specified. For other
1372 blocks, there isn't much to check, so we always pass.
1373
1374 Args:
1375 filename: The name of the current file.
1376 clean_lines: A CleansedLines instance containing the file.
1377 linenum: The number of the line to check.
1378 error: The function to call with any errors found.
1379 """
1380 pass
1381
1382 def CheckEnd(self, filename, clean_lines, linenum, error):
1383 """Run checks that applies to text after the closing brace.
1384
1385 This is mostly used for checking end of namespace comments.
1386
1387 Args:
1388 filename: The name of the current file.
1389 clean_lines: A CleansedLines instance containing the file.
1390 linenum: The number of the line to check.
1391 error: The function to call with any errors found.
1392 """
1393 pass
1394
1395
1396 class _ClassInfo(_BlockInfo):
1397 """Stores information about a class."""
1398
1399 def __init__(self, name, class_or_struct, clean_lines, linenum):
1400 _BlockInfo.__init__(self, False)
1401 self.name = name
1402 self.starting_linenum = linenum
1403 self.is_derived = False
1404 if class_or_struct == 'struct':
1405 self.access = 'public'
1406 else:
1407 self.access = 'private'
1408
1409
1410
1411
1412
1413
1414 self.last_line = 0
1415 depth = 0
1416 for i in range(linenum, clean_lines.NumLines()):
1417 line = clean_lines.elided[i]
1418 depth += line.count('{') - line.count('}')
1419 if not depth:
1420 self.last_line = i
1421 break
1422
1423 def CheckBegin(self, filename, clean_lines, linenum, error):
1424
1425 if Search('(^|[^:]):($|[^:])', clean_lines.elided[linenum]):
1426 self.is_derived = True
1427
1428
1429 class _NamespaceInfo(_BlockInfo):
1430 """Stores information about a namespace."""
1431
1432 def __init__(self, name, linenum):
1433 _BlockInfo.__init__(self, False)
1434 self.name = name or ''
1435 self.starting_linenum = linenum
1436
1437 def CheckEnd(self, filename, clean_lines, linenum, error):
1438 """Check end of namespace comments."""
1439 line = clean_lines.raw_lines[linenum]
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452 if (linenum - self.starting_linenum < 10
1453 and not Match(r'};*\s*(//|/\*).*\bnamespace\b', line)):
1454 return
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468 if self.name:
1469
1470 if not Match((r'};*\s*(//|/\*).*\bnamespace\s+' + re.escape(self.name) +
1471 r'[\*/\.\\\s]*$'),
1472 line):
1473 error(filename, linenum, 'readability/namespace', 5,
1474 'Namespace should be terminated with "// namespace %s"' %
1475 self.name)
1476 else:
1477
1478 if not Match(r'};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line):
1479 error(filename, linenum, 'readability/namespace', 5,
1480 'Namespace should be terminated with "// namespace"')
1481
1482
1483 class _PreprocessorInfo(object):
1484 """Stores checkpoints of nesting stacks when #if/#else is seen."""
1485
1486 def __init__(self, stack_before_if):
1487
1488 self.stack_before_if = stack_before_if
1489
1490
1491 self.stack_before_else = []
1492
1493
1494 self.seen_else = False
1495
1496
1497 class _NestingState(object):
1498 """Holds states related to parsing braces."""
1499
1500 def __init__(self):
1501
1502
1503
1504
1505
1506
1507 self.stack = []
1508
1509
1510 self.pp_stack = []
1511
1512 def SeenOpenBrace(self):
1513 """Check if we have seen the opening brace for the innermost block.
1514
1515 Returns:
1516 True if we have seen the opening brace, False if the innermost
1517 block is still expecting an opening brace.
1518 """
1519 return (not self.stack) or self.stack[-1].seen_open_brace
1520
1521 def InNamespaceBody(self):
1522 """Check if we are currently one level inside a namespace body.
1523
1524 Returns:
1525 True if top of the stack is a namespace block, False otherwise.
1526 """
1527 return self.stack and isinstance(self.stack[-1], _NamespaceInfo)
1528
1529 def UpdatePreprocessor(self, line):
1530 """Update preprocessor stack.
1531
1532 We need to handle preprocessors due to classes like this:
1533 #ifdef SWIG
1534 struct ResultDetailsPageElementExtensionPoint {
1535 #else
1536 struct ResultDetailsPageElementExtensionPoint : public Extension {
1537 #endif
1538 (see http://go/qwddn for original example)
1539
1540 We make the following assumptions (good enough for most files):
1541 - Preprocessor condition evaluates to true from #if up to first
1542 #else/#elif/#endif.
1543
1544 - Preprocessor condition evaluates to false from #else/#elif up
1545 to #endif. We still perform lint checks on these lines, but
1546 these do not affect nesting stack.
1547
1548 Args:
1549 line: current line to check.
1550 """
1551 if Match(r'^\s*#\s*(if|ifdef|ifndef)\b', line):
1552
1553
1554 self.pp_stack.append(_PreprocessorInfo(copy.deepcopy(self.stack)))
1555 elif Match(r'^\s*#\s*(else|elif)\b', line):
1556
1557 if self.pp_stack:
1558 if not self.pp_stack[-1].seen_else:
1559
1560
1561
1562 self.pp_stack[-1].seen_else = True
1563 self.pp_stack[-1].stack_before_else = copy.deepcopy(self.stack)
1564
1565
1566 self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if)
1567 else:
1568
1569 pass
1570 elif Match(r'^\s*#\s*endif\b', line):
1571
1572 if self.pp_stack:
1573
1574
1575
1576 if self.pp_stack[-1].seen_else:
1577
1578
1579 self.stack = self.pp_stack[-1].stack_before_else
1580
1581 self.pp_stack.pop()
1582 else:
1583
1584 pass
1585
1586 def Update(self, filename, clean_lines, linenum, error):
1587 """Update nesting state with current line.
1588
1589 Args:
1590 filename: The name of the current file.
1591 clean_lines: A CleansedLines instance containing the file.
1592 linenum: The number of the line to check.
1593 error: The function to call with any errors found.
1594 """
1595 line = clean_lines.elided[linenum]
1596
1597
1598 self.UpdatePreprocessor(line)
1599
1600
1601
1602 if self.stack:
1603 inner_block = self.stack[-1]
1604 depth_change = line.count('(') - line.count(')')
1605 inner_block.open_parentheses += depth_change
1606
1607
1608 if inner_block.inline_asm in (_NO_ASM, _END_ASM):
1609 if (depth_change != 0 and
1610 inner_block.open_parentheses == 1 and
1611 _MATCH_ASM.match(line)):
1612
1613 inner_block.inline_asm = _INSIDE_ASM
1614 else:
1615
1616
1617 inner_block.inline_asm = _NO_ASM
1618 elif (inner_block.inline_asm == _INSIDE_ASM and
1619 inner_block.open_parentheses == 0):
1620
1621 inner_block.inline_asm = _END_ASM
1622
1623
1624
1625
1626 while True:
1627
1628
1629
1630
1631 namespace_decl_match = Match(r'^\s*namespace\b\s*([:\w]+)?(.*)$', line)
1632 if not namespace_decl_match:
1633 break
1634
1635 new_namespace = _NamespaceInfo(namespace_decl_match.group(1), linenum)
1636 self.stack.append(new_namespace)
1637
1638 line = namespace_decl_match.group(2)
1639 if line.find('{') != -1:
1640 new_namespace.seen_open_brace = True
1641 line = line[line.find('{') + 1:]
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664 class_decl_match = Match(
1665 r'\s*(template\s*<[\w\s<>,:]*>\s*)?'
1666 '(class|struct)\s+([A-Z_]+\s+)*(\w+(?:::\w+)*)'
1667 '(([^=>]|<[^<>]*>)*)$', line)
1668 if (class_decl_match and
1669 (not self.stack or self.stack[-1].open_parentheses == 0)):
1670 self.stack.append(_ClassInfo(
1671 class_decl_match.group(4), class_decl_match.group(2),
1672 clean_lines, linenum))
1673 line = class_decl_match.group(5)
1674
1675
1676
1677 if not self.SeenOpenBrace():
1678 self.stack[-1].CheckBegin(filename, clean_lines, linenum, error)
1679
1680
1681 if self.stack and isinstance(self.stack[-1], _ClassInfo):
1682 access_match = Match(r'\s*(public|private|protected)\s*:', line)
1683 if access_match:
1684 self.stack[-1].access = access_match.group(1)
1685
1686
1687 while True:
1688
1689 matched = Match(r'^[^{;)}]*([{;)}])(.*)$', line)
1690 if not matched:
1691 break
1692
1693 token = matched.group(1)
1694 if token == '{':
1695
1696
1697
1698 if not self.SeenOpenBrace():
1699 self.stack[-1].seen_open_brace = True
1700 else:
1701 self.stack.append(_BlockInfo(True))
1702 if _MATCH_ASM.match(line):
1703 self.stack[-1].inline_asm = _BLOCK_ASM
1704 elif token == ';' or token == ')':
1705
1706
1707
1708
1709
1710
1711
1712
1713 if not self.SeenOpenBrace():
1714 self.stack.pop()
1715 else:
1716
1717 if self.stack:
1718 self.stack[-1].CheckEnd(filename, clean_lines, linenum, error)
1719 self.stack.pop()
1720 line = matched.group(2)
1721
1722 def InnermostClass(self):
1723 """Get class info on the top of the stack.
1724
1725 Returns:
1726 A _ClassInfo object if we are inside a class, or None otherwise.
1727 """
1728 for i in range(len(self.stack), 0, -1):
1729 classinfo = self.stack[i - 1]
1730 if isinstance(classinfo, _ClassInfo):
1731 return classinfo
1732 return None
1733
1734 def CheckClassFinished(self, filename, error):
1735 """Checks that all classes have been completely parsed.
1736
1737 Call this when all lines in a file have been processed.
1738 Args:
1739 filename: The name of the current file.
1740 error: The function to call with any errors found.
1741 """
1742
1743
1744
1745 for obj in self.stack:
1746 if isinstance(obj, _ClassInfo):
1747 error(filename, obj.starting_linenum, 'build/class', 5,
1748 'Failed to find complete declaration of class %s' %
1749 obj.name)
1750
1751
1752 def CheckForNonStandardConstructs(filename, clean_lines, linenum,
1753 nesting_state, error):
1754 """Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
1755
1756 Complain about several constructs which gcc-2 accepts, but which are
1757 not standard C++. Warning about these in lint is one way to ease the
1758 transition to new compilers.
1759 - put storage class first (e.g. "static const" instead of "const static").
1760 - "%lld" instead of %qd" in printf-type functions.
1761 - "%1$d" is non-standard in printf-type functions.
1762 - "\%" is an undefined character escape sequence.
1763 - text after #endif is not allowed.
1764 - invalid inner-style forward declaration.
1765 - >? and <? operators, and their >?= and <?= cousins.
1766
1767 Additionally, check for constructor/destructor style violations and reference
1768 members, as it is very convenient to do so while checking for
1769 gcc-2 compliance.
1770
1771 Args:
1772 filename: The name of the current file.
1773 clean_lines: A CleansedLines instance containing the file.
1774 linenum: The number of the line to check.
1775 nesting_state: A _NestingState instance which maintains information about
1776 the current stack of nested blocks being parsed.
1777 error: A callable to which errors are reported, which takes 4 arguments:
1778 filename, line number, error level, and message
1779 """
1780
1781
1782 line = clean_lines.lines[linenum]
1783
1784 if Search(r'printf\s*\(.*".*%[-+ ]?\d*q', line):
1785 error(filename, linenum, 'runtime/printf_format', 3,
1786 '%q in format strings is deprecated. Use %ll instead.')
1787
1788 if Search(r'printf\s*\(.*".*%\d+\$', line):
1789 error(filename, linenum, 'runtime/printf_format', 2,
1790 '%N$ formats are unconventional. Try rewriting to avoid them.')
1791
1792
1793 line = line.replace('\\\\', '')
1794
1795 if Search(r'("|\').*\\(%|\[|\(|{)', line):
1796 error(filename, linenum, 'build/printf_format', 3,
1797 '%, [, (, and { are undefined character escapes. Unescape them.')
1798
1799
1800 line = clean_lines.elided[linenum]
1801
1802 if Search(r'\b(const|volatile|void|char|short|int|long'
1803 r'|float|double|signed|unsigned'
1804 r'|schar|u?int8|u?int16|u?int32|u?int64)'
1805 r'\s+(register|static|extern|typedef)\b',
1806 line):
1807 error(filename, linenum, 'build/storage_class', 5,
1808 'Storage class (static, extern, typedef, etc) should be first.')
1809
1810 if Match(r'\s*#\s*endif\s*[^/\s]+', line):
1811 error(filename, linenum, 'build/endif_comment', 5,
1812 'Uncommented text after #endif is non-standard. Use a comment.')
1813
1814 if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line):
1815 error(filename, linenum, 'build/forward_decl', 5,
1816 'Inner-style forward declarations are invalid. Remove this line.')
1817
1818 if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?',
1819 line):
1820 error(filename, linenum, 'build/deprecated', 3,
1821 '>? and <? (max and min) operators are non-standard and deprecated.')
1822
1823 if Search(r'^\s*const\s*string\s*&\s*\w+\s*;', line):
1824
1825
1826
1827
1828
1829
1830
1831 error(filename, linenum, 'runtime/member_string_references', 2,
1832 'const string& members are dangerous. It is much better to use '
1833 'alternatives, such as pointers or simple constants.')
1834
1835
1836
1837
1838 classinfo = nesting_state.InnermostClass()
1839 if not classinfo or not classinfo.seen_open_brace:
1840 return
1841
1842
1843
1844 base_classname = classinfo.name.split('::')[-1]
1845
1846
1847
1848 args = Match(r'\s+(?:inline\s+)?%s\s*\(([^,()]+)\)'
1849 % re.escape(base_classname),
1850 line)
1851 if (args and
1852 args.group(1) != 'void' and
1853 not Match(r'(const\s+)?%s\s*(?:<\w+>\s*)?&' % re.escape(base_classname),
1854 args.group(1).strip())):
1855 error(filename, linenum, 'runtime/explicit', 5,
1856 'Single-argument constructors should be marked explicit.')
1857
1858
1859 def CheckSpacingForFunctionCall(filename, line, linenum, error):
1860 """Checks for the correctness of various spacing around function calls.
1861
1862 Args:
1863 filename: The name of the current file.
1864 line: The text of the line to check.
1865 linenum: The number of the line to check.
1866 error: The function to call with any errors found.
1867 """
1868
1869
1870
1871
1872
1873 fncall = line
1874 for pattern in (r'\bif\s*\((.*)\)\s*{',
1875 r'\bfor\s*\((.*)\)\s*{',
1876 r'\bwhile\s*\((.*)\)\s*[{;]',
1877 r'\bswitch\s*\((.*)\)\s*{'):
1878 match = Search(pattern, line)
1879 if match:
1880 fncall = match.group(1)
1881 break
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896 if (
1897 not Search(r'\b(if|for|while|switch|return|delete)\b', fncall) and
1898
1899 not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and
1900
1901 not Search(r' \([^)]+\)\[[^\]]+\]', fncall)):
1902 if Search(r'\w\s*\(\s(?!\s*\\$)', fncall):
1903 error(filename, linenum, 'whitespace/parens', 4,
1904 'Extra space after ( in function call')
1905 elif Search(r'\(\s+(?!(\s*\\)|\()', fncall):
1906 error(filename, linenum, 'whitespace/parens', 2,
1907 'Extra space after (')
1908 if (Search(r'\w\s+\(', fncall) and
1909 not Search(r'#\s*define|typedef', fncall) and
1910 not Search(r'\w\s+\((\w+::)?\*\w+\)\(', fncall)):
1911 error(filename, linenum, 'whitespace/parens', 4,
1912 'Extra space before ( in function call')
1913
1914
1915 if Search(r'[^)]\s+\)\s*[^{\s]', fncall):
1916
1917
1918 if Search(r'^\s+\)', fncall):
1919 error(filename, linenum, 'whitespace/parens', 2,
1920 'Closing ) should be moved to the previous line')
1921 else:
1922 error(filename, linenum, 'whitespace/parens', 2,
1923 'Extra space before )')
1924
1925
1926 def IsBlankLine(line):
1927 """Returns true if the given line is blank.
1928
1929 We consider a line to be blank if the line is empty or consists of
1930 only white spaces.
1931
1932 Args:
1933 line: A line of a string.
1934
1935 Returns:
1936 True, if the given line is blank.
1937 """
1938 return not line or line.isspace()
1939
1940
1941 def CheckForFunctionLengths(filename, clean_lines, linenum,
1942 function_state, error):
1943 """Reports for long function bodies.
1944
1945 For an overview why this is done, see:
1946 http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions
1947
1948 Uses a simplistic algorithm assuming other style guidelines
1949 (especially spacing) are followed.
1950 Only checks unindented functions, so class members are unchecked.
1951 Trivial bodies are unchecked, so constructors with huge initializer lists
1952 may be missed.
1953 Blank/comment lines are not counted so as to avoid encouraging the removal
1954 of vertical space and comments just to get through a lint check.
1955 NOLINT *on the last line of a function* disables this check.
1956
1957 Args:
1958 filename: The name of the current file.
1959 clean_lines: A CleansedLines instance containing the file.
1960 linenum: The number of the line to check.
1961 function_state: Current function name and lines in body so far.
1962 error: The function to call with any errors found.
1963 """
1964 lines = clean_lines.lines
1965 line = lines[linenum]
1966 raw = clean_lines.raw_lines
1967 raw_line = raw[linenum]
1968 joined_line = ''
1969
1970 starting_func = False
1971 regexp = r'(\w(\w|::|\*|\&|\s)*)\('
1972 match_result = Match(regexp, line)
1973 if match_result:
1974
1975
1976 function_name = match_result.group(1).split()[-1]
1977 if function_name == 'TEST' or function_name == 'TEST_F' or (
1978 not Match(r'[A-Z_]+$', function_name)):
1979 starting_func = True
1980
1981 if starting_func:
1982 body_found = False
1983 for start_linenum in xrange(linenum, clean_lines.NumLines()):
1984 start_line = lines[start_linenum]
1985 joined_line += ' ' + start_line.lstrip()
1986 if Search(r'(;|})', start_line):
1987 body_found = True
1988 break
1989 elif Search(r'{', start_line):
1990 body_found = True
1991 function = Search(r'((\w|:)*)\(', line).group(1)
1992 if Match(r'TEST', function):
1993 parameter_regexp = Search(r'(\(.*\))', joined_line)
1994 if parameter_regexp:
1995 function += parameter_regexp.group(1)
1996 else:
1997 function += '()'
1998 function_state.Begin(function)
1999 break
2000 if not body_found:
2001
2002 error(filename, linenum, 'readability/fn_size', 5,
2003 'Lint failed to find start of function body.')
2004 elif Match(r'^\}\s*$', line):
2005 function_state.Check(error, filename, linenum)
2006 function_state.End()
2007 elif not Match(r'^\s*$', line):
2008 function_state.Count()
2009
2010
2011 _RE_PATTERN_TODO = re.compile(r'^//(\s*)TODO(\(.+?\))?:?(\s|$)?')
2012
2013
2014 def CheckComment(comment, filename, linenum, error):
2015 """Checks for common mistakes in TODO comments.
2016
2017 Args:
2018 comment: The text of the comment from the line in question.
2019 filename: The name of the current file.
2020 linenum: The number of the line to check.
2021 error: The function to call with any errors found.
2022 """
2023 match = _RE_PATTERN_TODO.match(comment)
2024 if match:
2025
2026 leading_whitespace = match.group(1)
2027 if len(leading_whitespace) > 1:
2028 error(filename, linenum, 'whitespace/todo', 2,
2029 'Too many spaces before TODO')
2030
2031 username = match.group(2)
2032 if not username:
2033 error(filename, linenum, 'readability/todo', 2,
2034 'Missing username in TODO; it should look like '
2035 '"// TODO(my_username): Stuff."')
2036
2037 middle_whitespace = match.group(3)
2038
2039 if middle_whitespace != ' ' and middle_whitespace != '':
2040 error(filename, linenum, 'whitespace/todo', 2,
2041 'TODO(my_username) should be followed by a space')
2042
2043 def CheckAccess(filename, clean_lines, linenum, nesting_state, error):
2044 """Checks for improper use of DISALLOW* macros.
2045
2046 Args:
2047 filename: The name of the current file.
2048 clean_lines: A CleansedLines instance containing the file.
2049 linenum: The number of the line to check.
2050 nesting_state: A _NestingState instance which maintains information about
2051 the current stack of nested blocks being parsed.
2052 error: The function to call with any errors found.
2053 """
2054 line = clean_lines.elided[linenum]
2055
2056 matched = Match((r'\s*(DISALLOW_COPY_AND_ASSIGN|'
2057 r'DISALLOW_EVIL_CONSTRUCTORS|'
2058 r'DISALLOW_IMPLICIT_CONSTRUCTORS)'), line)
2059 if not matched:
2060 return
2061 if nesting_state.stack and isinstance(nesting_state.stack[-1], _ClassInfo):
2062 if nesting_state.stack[-1].access != 'private':
2063 error(filename, linenum, 'readability/constructors', 3,
2064 '%s must be in the private: section' % matched.group(1))
2065
2066 else:
2067
2068
2069
2070
2071 pass
2072
2073
2074 def FindNextMatchingAngleBracket(clean_lines, linenum, init_suffix):
2075 """Find the corresponding > to close a template.
2076
2077 Args:
2078 clean_lines: A CleansedLines instance containing the file.
2079 linenum: Current line number.
2080 init_suffix: Remainder of the current line after the initial <.
2081
2082 Returns:
2083 True if a matching bracket exists.
2084 """
2085 line = init_suffix
2086 nesting_stack = ['<']
2087 while True:
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097 match = Search(r'^[^<>(),;\[\]]*([<>(),;\[\]])(.*)$', line)
2098 if match:
2099
2100 operator = match.group(1)
2101 line = match.group(2)
2102
2103 if nesting_stack[-1] == '<':
2104
2105 if operator in ('<', '(', '['):
2106 nesting_stack.append(operator)
2107 elif operator == '>':
2108 nesting_stack.pop()
2109 if not nesting_stack:
2110
2111 return True
2112 elif operator == ',':
2113
2114
2115
2116
2117 return True
2118 else:
2119
2120 return False
2121
2122 else:
2123
2124 if operator in ('<', '(', '['):
2125 nesting_stack.append(operator)
2126 elif operator in (')', ']'):
2127
2128
2129 nesting_stack.pop()
2130
2131 else:
2132
2133 linenum += 1
2134 if linenum >= len(clean_lines.elided):
2135 break
2136 line = clean_lines.elided[linenum]
2137
2138
2139
2140
2141 return True
2142
2143
2144 def FindPreviousMatchingAngleBracket(clean_lines, linenum, init_prefix):
2145 """Find the corresponding < that started a template.
2146
2147 Args:
2148 clean_lines: A CleansedLines instance containing the file.
2149 linenum: Current line number.
2150 init_prefix: Part of the current line before the initial >.
2151
2152 Returns:
2153 True if a matching bracket exists.
2154 """
2155 line = init_prefix
2156 nesting_stack = ['>']
2157 while True:
2158
2159 match = Search(r'^(.*)([<>(),;\[\]])[^<>(),;\[\]]*$', line)
2160 if match:
2161
2162 operator = match.group(2)
2163 line = match.group(1)
2164
2165 if nesting_stack[-1] == '>':
2166
2167 if operator in ('>', ')', ']'):
2168 nesting_stack.append(operator)
2169 elif operator == '<':
2170 nesting_stack.pop()
2171 if not nesting_stack:
2172
2173 return True
2174 elif operator == ',':
2175
2176
2177
2178 return True
2179 else:
2180
2181 return False
2182
2183 else:
2184
2185 if operator in ('>', ')', ']'):
2186 nesting_stack.append(operator)
2187 elif operator in ('(', '['):
2188 nesting_stack.pop()
2189
2190 else:
2191
2192 linenum -= 1
2193 if linenum < 0:
2194 break
2195 line = clean_lines.elided[linenum]
2196
2197
2198 return False
2199
2200
2201 def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
2202 """Checks for the correctness of various spacing issues in the code.
2203
2204 Things we check for: spaces around operators, spaces after
2205 if/for/while/switch, no spaces around parens in function calls, two
2206 spaces between code and comment, don't start a block with a blank
2207 line, don't end a function with a blank line, don't add a blank line
2208 after public/protected/private, don't have too many blank lines in a row.
2209
2210 Args:
2211 filename: The name of the current file.
2212 clean_lines: A CleansedLines instance containing the file.
2213 linenum: The number of the line to check.
2214 nesting_state: A _NestingState instance which maintains information about
2215 the current stack of nested blocks being parsed.
2216 error: The function to call with any errors found.
2217 """
2218
2219 raw = clean_lines.raw_lines
2220 line = raw[linenum]
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234 if IsBlankLine(line) and not nesting_state.InNamespaceBody():
2235 elided = clean_lines.elided
2236 prev_line = elided[linenum - 1]
2237 prevbrace = prev_line.rfind('{')
2238
2239
2240
2241
2242 if prevbrace != -1 and prev_line[prevbrace:].find('}') == -1:
2243
2244
2245
2246
2247
2248
2249
2250 exception = False
2251 if Match(r' {6}\w', prev_line):
2252
2253
2254 search_position = linenum-2
2255 while (search_position >= 0
2256 and Match(r' {6}\w', elided[search_position])):
2257 search_position -= 1
2258 exception = (search_position >= 0
2259 and elided[search_position][:5] == ' :')
2260 else:
2261
2262
2263
2264
2265
2266
2267 exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',
2268 prev_line)
2269 or Match(r' {4}:', prev_line))
2270
2271 if not exception:
2272 error(filename, linenum, 'whitespace/blank_line', 2,
2273 'Blank line at the start of a code block. Is this needed?')
2274
2275
2276
2277
2278
2279
2280
2281
2282 if linenum + 1 < clean_lines.NumLines():
2283 next_line = raw[linenum + 1]
2284 if (next_line
2285 and Match(r'\s*}', next_line)
2286 and next_line.find('} else ') == -1):
2287 error(filename, linenum, 'whitespace/blank_line', 3,
2288 'Blank line at the end of a code block. Is this needed?')
2289
2290 matched = Match(r'\s*(public|protected|private):', prev_line)
2291 if matched:
2292 error(filename, linenum, 'whitespace/blank_line', 3,
2293 'Do not leave a blank line after "%s:"' % matched.group(1))
2294
2295
2296 commentpos = line.find('//')
2297 if commentpos != -1:
2298
2299
2300 if (line.count('"', 0, commentpos) -
2301 line.count('\\"', 0, commentpos)) % 2 == 0:
2302
2303 if (not Match(r'^\s*{ //', line) and
2304 ((commentpos >= 1 and
2305 line[commentpos-1] not in string.whitespace) or
2306 (commentpos >= 2 and
2307 line[commentpos-2] not in string.whitespace))):
2308 error(filename, linenum, 'whitespace/comments', 2,
2309 'At least two spaces is best between code and comments')
2310
2311 commentend = commentpos + 2
2312 if commentend < len(line) and not line[commentend] == ' ':
2313
2314
2315
2316
2317
2318
2319
2320 match = (Search(r'[=/-]{4,}\s*$', line[commentend:]) or
2321 Search(r'^/$', line[commentend:]) or
2322 Search(r'^/+ ', line[commentend:]))
2323 if not match:
2324 error(filename, linenum, 'whitespace/comments', 4,
2325 'Should have a space between // and comment')
2326 CheckComment(line[commentpos:], filename, linenum, error)
2327
2328 line = clean_lines.elided[linenum]
2329
2330
2331 line = re.sub(r'operator(==|!=|<|<<|<=|>=|>>|>)\(', 'operator\(', line)
2332
2333
2334
2335
2336
2337 if Search(r'[\w.]=[\w.]', line) and not Search(r'\b(if|while) ', line):
2338 error(filename, linenum, 'whitespace/operators', 4,
2339 'Missing spaces around =')
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349 match = Search(r'[^<>=!\s](==|!=|<=|>=)[^<>=!\s]', line)
2350 if match:
2351 error(filename, linenum, 'whitespace/operators', 3,
2352 'Missing spaces around %s' % match.group(1))
2353
2354
2355 match = Search(r'(\S)(?:L|UL|ULL|l|ul|ull)?<<(\S)', line)
2356 if match and not (match.group(1).isdigit() and match.group(2).isdigit()):
2357 error(filename, linenum, 'whitespace/operators', 3,
2358 'Missing spaces around <<')
2359 elif not Match(r'#.*include', line):
2360
2361 reduced_line = line.replace('->', '')
2362
2363
2364
2365
2366
2367 match = Search(r'[^\s<]<([^\s=<].*)', reduced_line)
2368 if (match and
2369 not FindNextMatchingAngleBracket(clean_lines, linenum, match.group(1))):
2370 error(filename, linenum, 'whitespace/operators', 3,
2371 'Missing spaces around <')
2372
2373
2374
2375
2376 match = Search(r'^(.*[^\s>])>[^\s=>]', reduced_line)
2377 if (match and
2378 not FindPreviousMatchingAngleBracket(clean_lines, linenum,
2379 match.group(1))):
2380 error(filename, linenum, 'whitespace/operators', 3,
2381 'Missing spaces around >')
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395 match = Search(r'>>[a-zA-Z_]', line)
2396 if match:
2397 error(filename, linenum, 'whitespace/operators', 3,
2398 'Missing spaces around >>')
2399
2400
2401 match = Search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line)
2402 if match:
2403 error(filename, linenum, 'whitespace/operators', 4,
2404 'Extra space for operator %s' % match.group(1))
2405
2406
2407 match = Search(r' (if\(|for\(|while\(|switch\()', line)
2408 if match:
2409 error(filename, linenum, 'whitespace/parens', 5,
2410 'Missing space before ( in %s' % match.group(1))
2411
2412
2413
2414
2415
2416
2417 match = Search(r'\b(if|for|while|switch)\s*'
2418 r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$',
2419 line)
2420 if match:
2421 if len(match.group(2)) != len(match.group(4)):
2422 if not (match.group(3) == ';' and
2423 len(match.group(2)) == 1 + len(match.group(4)) or
2424 not match.group(2) and Search(r'\bfor\s*\(.*; \)', line)):
2425 error(filename, linenum, 'whitespace/parens', 5,
2426 'Mismatching spaces inside () in %s' % match.group(1))
2427 if not len(match.group(2)) in [0, 1]:
2428 error(filename, linenum, 'whitespace/parens', 5,
2429 'Should have zero or one spaces inside ( and ) in %s' %
2430 match.group(1))
2431
2432
2433 if Search(r',[^\s]', line):
2434 error(filename, linenum, 'whitespace/comma', 3,
2435 'Missing space after ,')
2436
2437
2438
2439
2440
2441 if Search(r';[^\s};\\)/]', line):
2442 error(filename, linenum, 'whitespace/semicolon', 3,
2443 'Missing space after ;')
2444
2445
2446 CheckSpacingForFunctionCall(filename, line, linenum, error)
2447
2448
2449
2450
2451
2452 if Search(r'[^ ({]{', line):
2453 error(filename, linenum, 'whitespace/braces', 5,
2454 'Missing space before {')
2455
2456
2457 if Search(r'}else', line):
2458 error(filename, linenum, 'whitespace/braces', 5,
2459 'Missing space before else')
2460
2461
2462
2463 if Search(r'\w\s+\[', line) and not Search(r'delete\s+\[', line):
2464 error(filename, linenum, 'whitespace/braces', 5,
2465 'Extra space before [')
2466
2467
2468
2469
2470 if Search(r':\s*;\s*$', line):
2471 error(filename, linenum, 'whitespace/semicolon', 5,
2472 'Semicolon defining empty statement. Use {} instead.')
2473 elif Search(r'^\s*;\s*$', line):
2474 error(filename, linenum, 'whitespace/semicolon', 5,
2475 'Line contains only semicolon. If this should be an empty statement, '
2476 'use {} instead.')
2477 elif (Search(r'\s+;\s*$', line) and
2478 not Search(r'\bfor\b', line)):
2479 error(filename, linenum, 'whitespace/semicolon', 5,
2480 'Extra space before last semicolon. If this should be an empty '
2481 'statement, use {} instead.')
2482
2483
2484
2485 if (Search('for *\(.*[^:]:[^: ]', line) or
2486 Search('for *\(.*[^: ]:[^:]', line)):
2487 error(filename, linenum, 'whitespace/forcolon', 2,
2488 'Missing space around colon in range-based for loop')
2489
2490
2491 def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error):
2492 """Checks for additional blank line issues related to sections.
2493
2494 Currently the only thing checked here is blank line before protected/private.
2495
2496 Args:
2497 filename: The name of the current file.
2498 clean_lines: A CleansedLines instance containing the file.
2499 class_info: A _ClassInfo objects.
2500 linenum: The number of the line to check.
2501 error: The function to call with any errors found.
2502 """
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514 if (class_info.last_line - class_info.starting_linenum <= 24 or
2515 linenum <= class_info.starting_linenum):
2516 return
2517
2518 matched = Match(r'\s*(public|protected|private):', clean_lines.lines[linenum])
2519 if matched:
2520
2521
2522
2523
2524
2525
2526
2527
2528 prev_line = clean_lines.lines[linenum - 1]
2529 if (not IsBlankLine(prev_line) and
2530 not Search(r'\b(class|struct)\b', prev_line) and
2531 not Search(r'\\$', prev_line)):
2532
2533
2534
2535
2536 end_class_head = class_info.starting_linenum
2537 for i in range(class_info.starting_linenum, linenum):
2538 if Search(r'\{\s*$', clean_lines.lines[i]):
2539 end_class_head = i
2540 break
2541 if end_class_head < linenum - 1:
2542 error(filename, linenum, 'whitespace/blank_line', 3,
2543 '"%s:" should be preceded by a blank line' % matched.group(1))
2544
2545
2546 def GetPreviousNonBlankLine(clean_lines, linenum):
2547 """Return the most recent non-blank line and its line number.
2548
2549 Args:
2550 clean_lines: A CleansedLines instance containing the file contents.
2551 linenum: The number of the line to check.
2552
2553 Returns:
2554 A tuple with two elements. The first element is the contents of the last
2555 non-blank line before the current line, or the empty string if this is the
2556 first non-blank line. The second is the line number of that line, or -1
2557 if this is the first non-blank line.
2558 """
2559
2560 prevlinenum = linenum - 1
2561 while prevlinenum >= 0:
2562 prevline = clean_lines.elided[prevlinenum]
2563 if not IsBlankLine(prevline):
2564 return (prevline, prevlinenum)
2565 prevlinenum -= 1
2566 return ('', -1)
2567
2568
2569 def CheckBraces(filename, clean_lines, linenum, error):
2570 """Looks for misplaced braces (e.g. at the end of line).
2571
2572 Args:
2573 filename: The name of the current file.
2574 clean_lines: A CleansedLines instance containing the file.
2575 linenum: The number of the line to check.
2576 error: The function to call with any errors found.
2577 """
2578
2579 line = clean_lines.elided[linenum]
2580
2581 if Match(r'\s*{\s*$', line):
2582
2583
2584
2585
2586
2587
2588
2589 prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
2590 if (not Search(r'[;:}{]\s*$', prevline) and
2591 not Match(r'\s*#', prevline)):
2592 error(filename, linenum, 'whitespace/braces', 4,
2593 '{ should almost always be at the end of the previous line')
2594
2595
2596 if Match(r'\s*else\s*', line):
2597 prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
2598 if Match(r'\s*}\s*$', prevline):
2599 error(filename, linenum, 'whitespace/newline', 4,
2600 'An else should appear on the same line as the preceding }')
2601
2602
2603
2604 if Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line):
2605 if Search(r'}\s*else if([^{]*)$', line):
2606
2607 pos = line.find('else if')
2608 pos = line.find('(', pos)
2609 if pos > 0:
2610 (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos)
2611 if endline[endpos:].find('{') == -1:
2612 error(filename, linenum, 'readability/braces', 5,
2613 'If an else has a brace on one side, it should have it on both')
2614 else:
2615 error(filename, linenum, 'readability/braces', 5,
2616 'If an else has a brace on one side, it should have it on both')
2617
2618
2619 if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line):
2620 error(filename, linenum, 'whitespace/newline', 4,
2621 'Else clause should never be on same line as else (use 2 lines)')
2622
2623
2624 if Match(r'\s*do [^\s{]', line):
2625 error(filename, linenum, 'whitespace/newline', 4,
2626 'do/while clauses should not be on a single line')
2627
2628
2629
2630
2631 prevlinenum = linenum
2632 while True:
2633 (prevline, prevlinenum) = GetPreviousNonBlankLine(clean_lines, prevlinenum)
2634 if Match(r'\s+{.*}\s*;', line) and not prevline.count(';'):
2635 line = prevline + line
2636 else:
2637 break
2638 if (Search(r'{.*}\s*;', line) and
2639 line.count('{') == line.count('}') and
2640 not Search(r'struct|class|enum|\s*=\s*{', line)):
2641 error(filename, linenum, 'readability/braces', 4,
2642 "You don't need a ; after a }")
2643
2644
2645 def CheckEmptyLoopBody(filename, clean_lines, linenum, error):
2646 """Loop for empty loop body with only a single semicolon.
2647
2648 Args:
2649 filename: The name of the current file.
2650 clean_lines: A CleansedLines instance containing the file.
2651 linenum: The number of the line to check.
2652 error: The function to call with any errors found.
2653 """
2654
2655
2656
2657
2658 line = clean_lines.elided[linenum]
2659 if Match(r'\s*(for|while)\s*\(', line):
2660
2661 (end_line, end_linenum, end_pos) = CloseExpression(
2662 clean_lines, linenum, line.find('('))
2663
2664
2665
2666
2667 if end_pos >= 0 and Match(r';', end_line[end_pos:]):
2668 error(filename, end_linenum, 'whitespace/empty_loop_body', 5,
2669 'Empty loop bodies should use {} or continue')
2670
2671
2672 def ReplaceableCheck(operator, macro, line):
2673 """Determine whether a basic CHECK can be replaced with a more specific one.
2674
2675 For example suggest using CHECK_EQ instead of CHECK(a == b) and
2676 similarly for CHECK_GE, CHECK_GT, CHECK_LE, CHECK_LT, CHECK_NE.
2677
2678 Args:
2679 operator: The C++ operator used in the CHECK.
2680 macro: The CHECK or EXPECT macro being called.
2681 line: The current source line.
2682
2683 Returns:
2684 True if the CHECK can be replaced with a more specific one.
2685 """
2686
2687
2688 match_constant = r'([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')'
2689
2690
2691
2692
2693
2694
2695 match_this = (r'\s*' + macro + r'\((\s*' +
2696 match_constant + r'\s*' + operator + r'[^<>].*|'
2697 r'.*[^<>]' + operator + r'\s*' + match_constant +
2698 r'\s*\))')
2699
2700
2701
2702
2703
2704 return Match(match_this, line) and not Search(r'NULL|&&|\|\|', line)
2705
2706
2707 def CheckCheck(filename, clean_lines, linenum, error):
2708 """Checks the use of CHECK and EXPECT macros.
2709
2710 Args:
2711 filename: The name of the current file.
2712 clean_lines: A CleansedLines instance containing the file.
2713 linenum: The number of the line to check.
2714 error: The function to call with any errors found.
2715 """
2716
2717
2718 raw_lines = clean_lines.raw_lines
2719 current_macro = ''
2720 for macro in _CHECK_MACROS:
2721 if raw_lines[linenum].find(macro) >= 0:
2722 current_macro = macro
2723 break
2724 if not current_macro:
2725
2726 return
2727
2728 line = clean_lines.elided[linenum]
2729
2730
2731 for operator in ['==', '!=', '>=', '>', '<=', '<']:
2732 if ReplaceableCheck(operator, current_macro, line):
2733 error(filename, linenum, 'readability/check', 2,
2734 'Consider using %s instead of %s(a %s b)' % (
2735 _CHECK_REPLACEMENT[current_macro][operator],
2736 current_macro, operator))
2737 break
2738
2739
2740 def CheckAltTokens(filename, clean_lines, linenum, error):
2741 """Check alternative keywords being used in boolean expressions.
2742
2743 Args:
2744 filename: The name of the current file.
2745 clean_lines: A CleansedLines instance containing the file.
2746 linenum: The number of the line to check.
2747 error: The function to call with any errors found.
2748 """
2749 line = clean_lines.elided[linenum]
2750
2751
2752 if Match(r'^\s*#', line):
2753 return
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763 if line.find('/*') >= 0 or line.find('*/') >= 0:
2764 return
2765
2766 for match in _ALT_TOKEN_REPLACEMENT_PATTERN.finditer(line):
2767 error(filename, linenum, 'readability/alt_tokens', 2,
2768 'Use operator %s instead of %s' % (
2769 _ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1)))
2770
2771
2772 def GetLineWidth(line):
2773 """Determines the width of the line in column positions.
2774
2775 Args:
2776 line: A string, which may be a Unicode string.
2777
2778 Returns:
2779 The width of the line in column positions, accounting for Unicode
2780 combining characters and wide characters.
2781 """
2782 if isinstance(line, unicode):
2783 width = 0
2784 for uc in unicodedata.normalize('NFC', line):
2785 if unicodedata.east_asian_width(uc) in ('W', 'F'):
2786 width += 2
2787 elif not unicodedata.combining(uc):
2788 width += 1
2789 return width
2790 else:
2791 return len(line)
2792
2793
2794 def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
2795 error):
2796 """Checks rules from the 'C++ style rules' section of cppguide.html.
2797
2798 Most of these rules are hard to test (naming, comment style), but we
2799 do what we can. In particular we check for 2-space indents, line lengths,
2800 tab usage, spaces inside code, etc.
2801
2802 Args:
2803 filename: The name of the current file.
2804 clean_lines: A CleansedLines instance containing the file.
2805 linenum: The number of the line to check.
2806 file_extension: The extension (without the dot) of the filename.
2807 nesting_state: A _NestingState instance which maintains information about
2808 the current stack of nested blocks being parsed.
2809 error: The function to call with any errors found.
2810 """
2811
2812 raw_lines = clean_lines.raw_lines
2813 line = raw_lines[linenum]
2814
2815 if line.find('\t') != -1:
2816 error(filename, linenum, 'whitespace/tab', 1,
2817 'Tab found; better to use spaces')
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831 initial_spaces = 0
2832 cleansed_line = clean_lines.elided[linenum]
2833 while initial_spaces < len(line) and line[initial_spaces] == ' ':
2834 initial_spaces += 1
2835 if line and line[-1].isspace():
2836 error(filename, linenum, 'whitespace/end_of_line', 4,
2837 'Line ends in whitespace. Consider deleting these extra spaces.')
2838
2839 elif ((initial_spaces == 1 or initial_spaces == 3) and
2840 not Match(r'\s*\w+\s*:\s*$', cleansed_line)):
2841 error(filename, linenum, 'whitespace/indent', 3,
2842 'Weird number of spaces at line-start. '
2843 'Are you using a 2-space indent?')
2844
2845 elif not initial_spaces and line[:2] != '//' and Search(r'[^:]:\s*$',
2846 line):
2847 error(filename, linenum, 'whitespace/labels', 4,
2848 'Labels should always be indented at least one space. '
2849 'If this is a member-initializer list in a constructor or '
2850 'the base class list in a class definition, the colon should '
2851 'be on the following line.')
2852
2853
2854
2855 is_header_guard = False
2856 if file_extension == 'h':
2857 cppvar = GetHeaderGuardCPPVariable(filename)
2858 if (line.startswith('#ifndef %s' % cppvar) or
2859 line.startswith('#define %s' % cppvar) or
2860 line.startswith('#endif // %s' % cppvar)):
2861 is_header_guard = True
2862
2863
2864
2865
2866
2867
2868
2869
2870 if (not line.startswith('#include') and not is_header_guard and
2871 not Match(r'^\s*//.*http(s?)://\S*$', line) and
2872 not Match(r'^// \$Id:.*#[0-9]+ \$$', line)):
2873 line_width = GetLineWidth(line)
2874 if line_width > 100:
2875 error(filename, linenum, 'whitespace/line_length', 4,
2876 'Lines should very rarely be longer than 100 characters')
2877 elif line_width > 80:
2878 error(filename, linenum, 'whitespace/line_length', 2,
2879 'Lines should be <= 80 characters long')
2880
2881 if (cleansed_line.count(';') > 1 and
2882
2883 cleansed_line.find('for') == -1 and
2884 (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1 or
2885 GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1) and
2886
2887 not ((cleansed_line.find('case ') != -1 or
2888 cleansed_line.find('default:') != -1) and
2889 cleansed_line.find('break;') != -1)):
2890 error(filename, linenum, 'whitespace/newline', 0,
2891 'More than one command on the same line')
2892
2893
2894 CheckBraces(filename, clean_lines, linenum, error)
2895 CheckEmptyLoopBody(filename, clean_lines, linenum, error)
2896 CheckAccess(filename, clean_lines, linenum, nesting_state, error)
2897 CheckSpacing(filename, clean_lines, linenum, nesting_state, error)
2898 CheckCheck(filename, clean_lines, linenum, error)
2899 CheckAltTokens(filename, clean_lines, linenum, error)
2900 classinfo = nesting_state.InnermostClass()
2901 if classinfo:
2902 CheckSectionSpacing(filename, clean_lines, classinfo, linenum, error)
2903
2904
2905 _RE_PATTERN_INCLUDE_NEW_STYLE = re.compile(r'#include +"[^/]+\.h"')
2906 _RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$')
2907
2908
2909
2910
2911
2912 _RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+')
2913
2914
2915 def _DropCommonSuffixes(filename):
2916 """Drops common suffixes like _test.cc or -inl.h from filename.
2917
2918 For example:
2919 >>> _DropCommonSuffixes('foo/foo-inl.h')
2920 'foo/foo'
2921 >>> _DropCommonSuffixes('foo/bar/foo.cc')
2922 'foo/bar/foo'
2923 >>> _DropCommonSuffixes('foo/foo_internal.h')
2924 'foo/foo'
2925 >>> _DropCommonSuffixes('foo/foo_unusualinternal.h')
2926 'foo/foo_unusualinternal'
2927
2928 Args:
2929 filename: The input filename.
2930
2931 Returns:
2932 The filename with the common suffix removed.
2933 """
2934 for suffix in ('test.cc', 'regtest.cc', 'unittest.cc',
2935 'inl.h', 'impl.h', 'internal.h'):
2936 if (filename.endswith(suffix) and len(filename) > len(suffix) and
2937 filename[-len(suffix) - 1] in ('-', '_')):
2938 return filename[:-len(suffix) - 1]
2939 return os.path.splitext(filename)[0]
2940
2941
2942 def _IsTestFilename(filename):
2943 """Determines if the given filename has a suffix that identifies it as a test.
2944
2945 Args:
2946 filename: The input filename.
2947
2948 Returns:
2949 True if 'filename' looks like a test, False otherwise.
2950 """
2951 if (filename.endswith('_test.cc') or
2952 filename.endswith('_unittest.cc') or
2953 filename.endswith('_regtest.cc')):
2954 return True
2955 else:
2956 return False
2957
2958
2959 def _ClassifyInclude(fileinfo, include, is_system):
2960 """Figures out what kind of header 'include' is.
2961
2962 Args:
2963 fileinfo: The current file cpplint is running over. A FileInfo instance.
2964 include: The path to a #included file.
2965 is_system: True if the #include used <> rather than "".
2966
2967 Returns:
2968 One of the _XXX_HEADER constants.
2969
2970 For example:
2971 >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'stdio.h', True)
2972 _C_SYS_HEADER
2973 >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'string', True)
2974 _CPP_SYS_HEADER
2975 >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', False)
2976 _LIKELY_MY_HEADER
2977 >>> _ClassifyInclude(FileInfo('foo/foo_unknown_extension.cc'),
2978 ... 'bar/foo_other_ext.h', False)
2979 _POSSIBLE_MY_HEADER
2980 >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/bar.h', False)
2981 _OTHER_HEADER
2982 """
2983
2984
2985 is_stl_h = include in _STL_HEADERS
2986 is_cpp_h = is_stl_h or include in _CPP_HEADERS
2987
2988 if is_system:
2989 if is_cpp_h:
2990 return _CPP_SYS_HEADER
2991 else:
2992 return _C_SYS_HEADER
2993
2994
2995
2996
2997 target_dir, target_base = (
2998 os.path.split(_DropCommonSuffixes(fileinfo.RepositoryName())))
2999 include_dir, include_base = os.path.split(_DropCommonSuffixes(include))
3000 if target_base == include_base and (
3001 include_dir == target_dir or
3002 include_dir == os.path.normpath(target_dir + '/../public')):
3003 return _LIKELY_MY_HEADER
3004
3005
3006
3007
3008
3009 target_first_component = _RE_FIRST_COMPONENT.match(target_base)
3010 include_first_component = _RE_FIRST_COMPONENT.match(include_base)
3011 if (target_first_component and include_first_component and
3012 target_first_component.group(0) ==
3013 include_first_component.group(0)):
3014 return _POSSIBLE_MY_HEADER
3015
3016 return _OTHER_HEADER
3017
3018
3019
3020 def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
3021 """Check rules that are applicable to #include lines.
3022
3023 Strings on #include lines are NOT removed from elided line, to make
3024 certain tasks easier. However, to prevent false positives, checks
3025 applicable to #include lines in CheckLanguage must be put here.
3026
3027 Args:
3028 filename: The name of the current file.
3029 clean_lines: A CleansedLines instance containing the file.
3030 linenum: The number of the line to check.
3031 include_state: An _IncludeState instance in which the headers are inserted.
3032 error: The function to call with any errors found.
3033 """
3034 fileinfo = FileInfo(filename)
3035
3036 line = clean_lines.lines[linenum]
3037
3038
3039 if _RE_PATTERN_INCLUDE_NEW_STYLE.search(line):
3040 error(filename, linenum, 'build/include', 4,
3041 'Include the directory when naming .h files')
3042
3043
3044
3045
3046 match = _RE_PATTERN_INCLUDE.search(line)
3047 if match:
3048 include = match.group(2)
3049 is_system = (match.group(1) == '<')
3050 if include in include_state:
3051 error(filename, linenum, 'build/include', 4,
3052 '"%s" already included at %s:%s' %
3053 (include, filename, include_state[include]))
3054 else:
3055 include_state[include] = linenum
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068 error_message = include_state.CheckNextIncludeOrder(
3069 _ClassifyInclude(fileinfo, include, is_system))
3070 if error_message:
3071 error(filename, linenum, 'build/include_order', 4,
3072 '%s. Should be: %s.h, c system, c++ system, other.' %
3073 (error_message, fileinfo.BaseName()))
3074 if not include_state.IsInAlphabeticalOrder(include):
3075 error(filename, linenum, 'build/include_alpha', 4,
3076 'Include "%s" not in alphabetical order' % include)
3077
3078
3079 match = _RE_PATTERN_INCLUDE.match(line)
3080 if match:
3081 include = match.group(2)
3082 if Match(r'(f|ind|io|i|o|parse|pf|stdio|str|)?stream$', include):
3083
3084 if not _IsTestFilename(filename):
3085 error(filename, linenum, 'readability/streams', 3,
3086 'Streams are highly discouraged.')
3087
3088
3089 def _GetTextInside(text, start_pattern):
3090 """Retrieves all the text between matching open and close parentheses.
3091
3092 Given a string of lines and a regular expression string, retrieve all the text
3093 following the expression and between opening punctuation symbols like
3094 (, [, or {, and the matching close-punctuation symbol. This properly nested
3095 occurrences of the punctuations, so for the text like
3096 printf(a(), b(c()));
3097 a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'.
3098 start_pattern must match string having an open punctuation symbol at the end.
3099
3100 Args:
3101 text: The lines to extract text. Its comments and strings must be elided.
3102 It can be single line and can span multiple lines.
3103 start_pattern: The regexp string indicating where to start extracting
3104 the text.
3105 Returns:
3106 The extracted text.
3107 None if either the opening string or ending punctuation could not be found.
3108 """
3109
3110
3111
3112
3113 matching_punctuation = {'(': ')', '{': '}', '[': ']'}
3114 closing_punctuation = set(matching_punctuation.itervalues())
3115
3116
3117 match = re.search(start_pattern, text, re.M)
3118 if not match:
3119 return None
3120 start_position = match.end(0)
3121
3122 assert start_position > 0, (
3123 'start_pattern must ends with an opening punctuation.')
3124 assert text[start_position - 1] in matching_punctuation, (
3125 'start_pattern must ends with an opening punctuation.')
3126
3127 punctuation_stack = [matching_punctuation[text[start_position - 1]]]
3128 position = start_position
3129 while punctuation_stack and position < len(text):
3130 if text[position] == punctuation_stack[-1]:
3131 punctuation_stack.pop()
3132 elif text[position] in closing_punctuation:
3133
3134 return None
3135 elif text[position] in matching_punctuation:
3136 punctuation_stack.append(matching_punctuation[text[position]])
3137 position += 1
3138 if punctuation_stack:
3139
3140 return None
3141
3142 return text[start_position:position - 1]
3143
3144
3145 def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
3146 error):
3147 """Checks rules from the 'C++ language rules' section of cppguide.html.
3148
3149 Some of these rules are hard to test (function overloading, using
3150 uint32 inappropriately), but we do the best we can.
3151
3152 Args:
3153 filename: The name of the current file.
3154 clean_lines: A CleansedLines instance containing the file.
3155 linenum: The number of the line to check.
3156 file_extension: The extension (without the dot) of the filename.
3157 include_state: An _IncludeState instance in which the headers are inserted.
3158 error: The function to call with any errors found.
3159 """
3160
3161
3162 line = clean_lines.elided[linenum]
3163 if not line:
3164 return
3165
3166 match = _RE_PATTERN_INCLUDE.search(line)
3167 if match:
3168 CheckIncludeLine(filename, clean_lines, linenum, include_state, error)
3169 return
3170
3171
3172
3173
3174 if linenum + 1 < clean_lines.NumLines():
3175 extended_line = line + clean_lines.elided[linenum + 1]
3176 else:
3177 extended_line = line
3178
3179
3180 fullname = os.path.abspath(filename).replace('\\', '/')
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191 fnline = line.split('{', 1)[0]
3192 if (len(re.findall(r'\([^()]*\b(?:[\w:]|<[^()]*>)+(\s?&|&\s?)\w+', fnline)) >
3193 len(re.findall(r'\([^()]*\bconst\s+(?:typename\s+)?(?:struct\s+)?'
3194 r'(?:[\w:]|<[^()]*>)+(\s?&|&\s?)\w+', fnline)) +
3195 len(re.findall(r'\([^()]*\b(?:[\w:]|<[^()]*>)+\s+const(\s?&|&\s?)[\w]+',
3196 fnline))):
3197
3198
3199
3200
3201 if not Search(
3202 r'(for|swap|Swap|operator[<>][<>])\s*\(\s*'
3203 r'(?:(?:typename\s*)?[\w:]|<.*>)+\s*&',
3204 fnline):
3205 error(filename, linenum, 'runtime/references', 2,
3206 'Is this a non-const reference? '
3207 'If so, make const or use a pointer.')
3208
3209
3210
3211
3212
3213 match = Search(
3214 r'(\bnew\s+)?\b'
3215 r'(int|float|double|bool|char|int32|uint32|int64|uint64)\([^)]', line)
3216 if match:
3217
3218
3219
3220
3221
3222 if (match.group(1) is None and
3223 not (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) or
3224 Match(r'^\s*MockCallback<.*>', line))):
3225
3226
3227
3228
3229
3230
3231 if (linenum == 0 or
3232 not Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(\S+,\s*$',
3233 clean_lines.elided[linenum - 1])):
3234 error(filename, linenum, 'readability/casting', 4,
3235 'Using deprecated casting style. '
3236 'Use static_cast<%s>(...) instead' %
3237 match.group(2))
3238
3239 CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
3240 'static_cast',
3241 r'\((int|float|double|bool|char|u?int(16|32|64))\)', error)
3242
3243
3244
3245
3246
3247 if CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
3248 'const_cast', r'\((char\s?\*+\s?)\)\s*"', error):
3249 pass
3250 else:
3251
3252 CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum],
3253 'reinterpret_cast', r'\((\w+\s?\*+\s?)\)', error)
3254
3255
3256
3257
3258 if Search(
3259 r'(&\([^)]+\)[\w(])|(&(static|dynamic|reinterpret)_cast\b)', line):
3260 error(filename, linenum, 'runtime/casting', 4,
3261 ('Are you taking an address of a cast? '
3262 'This is dangerous: could be a temp var. '
3263 'Take the address before doing the cast, rather than after'))
3264
3265
3266
3267
3268 match = Match(
3269 r'((?:|static +)(?:|const +))string +([a-zA-Z0-9_:]+)\b(.*)',
3270 line)
3271
3272
3273
3274 if match and not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)?\s*\(([^"]|$)',
3275 match.group(3)):
3276 error(filename, linenum, 'runtime/string', 4,
3277 'For a static/global string constant, use a C style string instead: '
3278 '"%schar %s[]".' %
3279 (match.group(1), match.group(2)))
3280
3281
3282 if Search(r'\bdynamic_cast<', line) and not _IsTestFilename(filename):
3283 error(filename, linenum, 'runtime/rtti', 5,
3284 'Do not use dynamic_cast<>. If you need to cast within a class '
3285 "hierarchy, use static_cast<> to upcast. Google doesn't support "
3286 'RTTI.')
3287
3288 if Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line):
3289 error(filename, linenum, 'runtime/init', 4,
3290 'You seem to be initializing a member variable with itself.')
3291
3292 if file_extension == 'h':
3293
3294
3295
3296
3297
3298 pass
3299
3300
3301
3302 if Search(r'\bshort port\b', line):
3303 if not Search(r'\bunsigned short port\b', line):
3304 error(filename, linenum, 'runtime/int', 4,
3305 'Use "unsigned short" for ports, not "short"')
3306 else:
3307 match = Search(r'\b(short|long(?! +double)|long long)\b', line)
3308 if match:
3309 error(filename, linenum, 'runtime/int', 4,
3310 'Use int16/int64/etc, rather than the C type %s' % match.group(1))
3311
3312
3313 match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line)
3314 if match and match.group(2) != '0':
3315
3316 error(filename, linenum, 'runtime/printf', 3,
3317 'If you can, use sizeof(%s) instead of %s as the 2nd arg '
3318 'to snprintf.' % (match.group(1), match.group(2)))
3319
3320
3321 if Search(r'\bsprintf\b', line):
3322 error(filename, linenum, 'runtime/printf', 5,
3323 'Never use sprintf. Use snprintf instead.')
3324 match = Search(r'\b(strcpy|strcat)\b', line)
3325 if match:
3326 error(filename, linenum, 'runtime/printf', 4,
3327 'Almost always, snprintf is better than %s' % match.group(1))
3328
3329 if Search(r'\bsscanf\b', line):
3330 error(filename, linenum, 'runtime/printf', 1,
3331 'sscanf can be ok, but is slow and can overflow buffers.')
3332
3333
3334
3335
3336
3337
3338
3339 if Search(r'\boperator\s*&\s*\(\s*\)', line):
3340 error(filename, linenum, 'runtime/operator', 4,
3341 'Unary operator& is dangerous. Do not use it.')
3342
3343
3344
3345 if Search(r'\}\s*if\s*\(', line):
3346 error(filename, linenum, 'readability/braces', 4,
3347 'Did you mean "else if"? If not, start a new line for "if".')
3348
3349
3350
3351
3352
3353
3354
3355
3356 printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(')
3357 if printf_args:
3358 match = Match(r'([\w.\->()]+)$', printf_args)
3359 if match and match.group(1) != '__VA_ARGS__':
3360 function_name = re.search(r'\b((?:string)?printf)\s*\(',
3361 line, re.I).group(1)
3362 error(filename, linenum, 'runtime/printf', 4,
3363 'Potential format string bug. Do %s("%%s", %s) instead.'
3364 % (function_name, match.group(1)))
3365
3366
3367 match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line)
3368 if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)):
3369 error(filename, linenum, 'runtime/memset', 4,
3370 'Did you mean "memset(%s, 0, %s)"?'
3371 % (match.group(1), match.group(2)))
3372
3373 if Search(r'\busing namespace\b', line):
3374 error(filename, linenum, 'build/namespaces', 5,
3375 'Do not use namespace using-directives. '
3376 'Use using-declarations instead.')
3377
3378
3379 match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line)
3380 if (match and match.group(2) != 'return' and match.group(2) != 'delete' and
3381 match.group(3).find(']') == -1):
3382
3383
3384
3385 tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3))
3386 is_const = True
3387 skip_next = False
3388 for tok in tokens:
3389 if skip_next:
3390 skip_next = False
3391 continue
3392
3393 if Search(r'sizeof\(.+\)', tok): continue
3394 if Search(r'arraysize\(\w+\)', tok): continue
3395
3396 tok = tok.lstrip('(')
3397 tok = tok.rstrip(')')
3398 if not tok: continue
3399 if Match(r'\d+', tok): continue
3400 if Match(r'0[xX][0-9a-fA-F]+', tok): continue
3401 if Match(r'k[A-Z0-9]\w*', tok): continue
3402 if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue
3403 if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue
3404
3405
3406
3407 if tok.startswith('sizeof'):
3408 skip_next = True
3409 continue
3410 is_const = False
3411 break
3412 if not is_const:
3413 error(filename, linenum, 'runtime/arrays', 1,
3414 'Do not use variable-length arrays. Use an appropriately named '
3415 "('k' followed by CamelCase) compile-time constant for the size.")
3416
3417
3418
3419
3420 match = Match(
3421 (r'\s*'
3422 r'(DISALLOW_(EVIL_CONSTRUCTORS|COPY_AND_ASSIGN|IMPLICIT_CONSTRUCTORS))'
3423 r'\(.*\);$'),
3424 line)
3425 if match and linenum + 1 < clean_lines.NumLines():
3426 next_line = clean_lines.elided[linenum + 1]
3427
3428
3429
3430
3431
3432
3433 if not Search(r'^\s*}[\w\*,\s]*;', next_line):
3434 error(filename, linenum, 'readability/constructors', 3,
3435 match.group(1) + ' should be the last thing in the class')
3436
3437
3438
3439
3440 if (file_extension == 'h'
3441 and Search(r'\bnamespace\s*{', line)
3442 and line[-1] != '\\'):
3443 error(filename, linenum, 'build/namespaces', 4,
3444 'Do not use unnamed namespaces in header files. See '
3445 'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'
3446 ' for more information.')
3447
3448
3449 def CheckCStyleCast(filename, linenum, line, raw_line, cast_type, pattern,
3450 error):
3451 """Checks for a C-style cast by looking for the pattern.
3452
3453 This also handles sizeof(type) warnings, due to similarity of content.
3454
3455 Args:
3456 filename: The name of the current file.
3457 linenum: The number of the line to check.
3458 line: The line of code to check.
3459 raw_line: The raw line of code to check, with comments.
3460 cast_type: The string for the C++ cast to recommend. This is either
3461 reinterpret_cast, static_cast, or const_cast, depending.
3462 pattern: The regular expression used to find C-style casts.
3463 error: The function to call with any errors found.
3464
3465 Returns:
3466 True if an error was emitted.
3467 False otherwise.
3468 """
3469 match = Search(pattern, line)
3470 if not match:
3471 return False
3472
3473
3474 sizeof_match = Match(r'.*sizeof\s*$', line[0:match.start(1) - 1])
3475 if sizeof_match:
3476 error(filename, linenum, 'runtime/sizeof', 1,
3477 'Using sizeof(type). Use sizeof(varname) instead if possible')
3478 return True
3479
3480
3481 if (line[0:match.start(1) - 1].endswith(' operator++') or
3482 line[0:match.start(1) - 1].endswith(' operator--')):
3483 return False
3484
3485 remainder = line[match.end(0):]
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499 function_match = Match(r'\s*(\)|=|(const)?\s*(;|\{|throw\(\)|>))', remainder)
3500 if function_match:
3501 if (not function_match.group(3) or
3502 function_match.group(3) == ';' or
3503 ('MockCallback<' not in raw_line and
3504 '/*' not in raw_line)):
3505 error(filename, linenum, 'readability/function', 3,
3506 'All parameters should be named in a function')
3507 return True
3508
3509
3510 error(filename, linenum, 'readability/casting', 4,
3511 'Using C-style cast. Use %s<%s>(...) instead' %
3512 (cast_type, match.group(1)))
3513
3514 return True
3515
3516
3517 _HEADERS_CONTAINING_TEMPLATES = (
3518 ('<deque>', ('deque',)),
3519 ('<functional>', ('unary_function', 'binary_function',
3520 'plus', 'minus', 'multiplies', 'divides', 'modulus',
3521 'negate',
3522 'equal_to', 'not_equal_to', 'greater', 'less',
3523 'greater_equal', 'less_equal',
3524 'logical_and', 'logical_or', 'logical_not',
3525 'unary_negate', 'not1', 'binary_negate', 'not2',
3526 'bind1st', 'bind2nd',
3527 'pointer_to_unary_function',
3528 'pointer_to_binary_function',
3529 'ptr_fun',
3530 'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t',
3531 'mem_fun_ref_t',
3532 'const_mem_fun_t', 'const_mem_fun1_t',
3533 'const_mem_fun_ref_t', 'const_mem_fun1_ref_t',
3534 'mem_fun_ref',
3535 )),
3536 ('<limits>', ('numeric_limits',)),
3537 ('<list>', ('list',)),
3538 ('<map>', ('map', 'multimap',)),
3539 ('<memory>', ('allocator',)),
3540 ('<queue>', ('queue', 'priority_queue',)),
3541 ('<set>', ('set', 'multiset',)),
3542 ('<stack>', ('stack',)),
3543 ('<string>', ('char_traits', 'basic_string',)),
3544 ('<utility>', ('pair',)),
3545 ('<vector>', ('vector',)),
3546
3547
3548
3549 ('<hash_map>', ('hash_map', 'hash_multimap',)),
3550 ('<hash_set>', ('hash_set', 'hash_multiset',)),
3551 ('<slist>', ('slist',)),
3552 )
3553
3554 _RE_PATTERN_STRING = re.compile(r'\bstring\b')
3555
3556 _re_pattern_algorithm_header = []
3557 for _template in ('copy', 'max', 'min', 'min_element', 'sort', 'swap',
3558 'transform'):
3559
3560
3561 _re_pattern_algorithm_header.append(
3562 (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'),
3563 _template,
3564 '<algorithm>'))
3565
3566 _re_pattern_templates = []
3567 for _header, _templates in _HEADERS_CONTAINING_TEMPLATES:
3568 for _template in _templates:
3569 _re_pattern_templates.append(
3570 (re.compile(r'(\<|\b)' + _template + r'\s*\<'),
3571 _template + '<>',
3572 _header))
3573
3574
3575 def FilesBelongToSameModule(filename_cc, filename_h):
3576 """Check if these two filenames belong to the same module.
3577
3578 The concept of a 'module' here is a as follows:
3579 foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the
3580 same 'module' if they are in the same directory.
3581 some/path/public/xyzzy and some/path/internal/xyzzy are also considered
3582 to belong to the same module here.
3583
3584 If the filename_cc contains a longer path than the filename_h, for example,
3585 '/absolute/path/to/base/sysinfo.cc', and this file would include
3586 'base/sysinfo.h', this function also produces the prefix needed to open the
3587 header. This is used by the caller of this function to more robustly open the
3588 header file. We don't have access to the real include paths in this context,
3589 so we need this guesswork here.
3590
3591 Known bugs: tools/base/bar.cc and base/bar.h belong to the same module
3592 according to this implementation. Because of this, this function gives
3593 some false positives. This should be sufficiently rare in practice.
3594
3595 Args:
3596 filename_cc: is the path for the .cc file
3597 filename_h: is the path for the header path
3598
3599 Returns:
3600 Tuple with a bool and a string:
3601 bool: True if filename_cc and filename_h belong to the same module.
3602 string: the additional prefix needed to open the header file.
3603 """
3604
3605 if not filename_cc.endswith('.cc'):
3606 return (False, '')
3607 filename_cc = filename_cc[:-len('.cc')]
3608 if filename_cc.endswith('_unittest'):
3609 filename_cc = filename_cc[:-len('_unittest')]
3610 elif filename_cc.endswith('_test'):
3611 filename_cc = filename_cc[:-len('_test')]
3612 filename_cc = filename_cc.replace('/public/', '/')
3613 filename_cc = filename_cc.replace('/internal/', '/')
3614
3615 if not filename_h.endswith('.h'):
3616 return (False, '')
3617 filename_h = filename_h[:-len('.h')]
3618 if filename_h.endswith('-inl'):
3619 filename_h = filename_h[:-len('-inl')]
3620 filename_h = filename_h.replace('/public/', '/')
3621 filename_h = filename_h.replace('/internal/', '/')
3622
3623 files_belong_to_same_module = filename_cc.endswith(filename_h)
3624 common_path = ''
3625 if files_belong_to_same_module:
3626 common_path = filename_cc[:-len(filename_h)]
3627 return files_belong_to_same_module, common_path
3628
3629
3630 def UpdateIncludeState(filename, include_state, io=codecs):
3631 """Fill up the include_state with new includes found from the file.
3632
3633 Args:
3634 filename: the name of the header to read.
3635 include_state: an _IncludeState instance in which the headers are inserted.
3636 io: The io factory to use to read the file. Provided for testability.
3637
3638 Returns:
3639 True if a header was succesfully added. False otherwise.
3640 """
3641 headerfile = None
3642 try:
3643 headerfile = io.open(filename, 'r', 'utf8', 'replace')
3644 except IOError:
3645 return False
3646 linenum = 0
3647 for line in headerfile:
3648 linenum += 1
3649 clean_line = CleanseComments(line)
3650 match = _RE_PATTERN_INCLUDE.search(clean_line)
3651 if match:
3652 include = match.group(2)
3653
3654
3655 include_state.setdefault(include, '%s:%d' % (filename, linenum))
3656 return True
3657
3658
3659 def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
3660 io=codecs):
3661 """Reports for missing stl includes.
3662
3663 This function will output warnings to make sure you are including the headers
3664 necessary for the stl containers and functions that you use. We only give one
3665 reason to include a header. For example, if you use both equal_to<> and
3666 less<> in a .h file, only one (the latter in the file) of these will be
3667 reported as a reason to include the <functional>.
3668
3669 Args:
3670 filename: The name of the current file.
3671 clean_lines: A CleansedLines instance containing the file.
3672 include_state: An _IncludeState instance.
3673 error: The function to call with any errors found.
3674 io: The IO factory to use to read the header file. Provided for unittest
3675 injection.
3676 """
3677 required = {}
3678
3679
3680 for linenum in xrange(clean_lines.NumLines()):
3681 line = clean_lines.elided[linenum]
3682 if not line or line[0] == '#':
3683 continue
3684
3685
3686 matched = _RE_PATTERN_STRING.search(line)
3687 if matched:
3688
3689
3690 prefix = line[:matched.start()]
3691 if prefix.endswith('std::') or not prefix.endswith('::'):
3692 required['<string>'] = (linenum, 'string')
3693
3694 for pattern, template, header in _re_pattern_algorithm_header:
3695 if pattern.search(line):
3696 required[header] = (linenum, template)
3697
3698
3699 if not '<' in line:
3700 continue
3701
3702 for pattern, template, header in _re_pattern_templates:
3703 if pattern.search(line):
3704 required[header] = (linenum, template)
3705
3706
3707
3708
3709 include_state = include_state.copy()
3710
3711
3712 header_found = False
3713
3714
3715 abs_filename = FileInfo(filename).FullName()
3716
3717
3718
3719
3720
3721
3722
3723
3724 abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename)
3725
3726
3727
3728 header_keys = include_state.keys()
3729 for header in header_keys:
3730 (same_module, common_path) = FilesBelongToSameModule(abs_filename, header)
3731 fullpath = common_path + header
3732 if same_module and UpdateIncludeState(fullpath, include_state, io):
3733 header_found = True
3734
3735
3736
3737
3738
3739
3740 if filename.endswith('.cc') and not header_found:
3741 return
3742
3743
3744 for required_header_unstripped in required:
3745 template = required[required_header_unstripped][1]
3746 if required_header_unstripped.strip('<>"') not in include_state:
3747 error(filename, required[required_header_unstripped][0],
3748 'build/include_what_you_use', 4,
3749 'Add #include ' + required_header_unstripped + ' for ' + template)
3750
3751
3752 _RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<')
3753
3754
3755 def CheckMakePairUsesDeduction(filename, clean_lines, linenum, error):
3756 """Check that make_pair's template arguments are deduced.
3757
3758 G++ 4.6 in C++0x mode fails badly if make_pair's template arguments are
3759 specified explicitly, and such use isn't intended in any case.
3760
3761 Args:
3762 filename: The name of the current file.
3763 clean_lines: A CleansedLines instance containing the file.
3764 linenum: The number of the line to check.
3765 error: The function to call with any errors found.
3766 """
3767 raw = clean_lines.raw_lines
3768 line = raw[linenum]
3769 match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line)
3770 if match:
3771 error(filename, linenum, 'build/explicit_make_pair',
3772 4,
3773 'For C++11-compatibility, omit template arguments from make_pair'
3774 ' OR use pair directly OR if appropriate, construct a pair directly')
3775
3776
3777 def ProcessLine(filename, file_extension, clean_lines, line,
3778 include_state, function_state, nesting_state, error,
3779 extra_check_functions=[]):
3780 """Processes a single line in the file.
3781
3782 Args:
3783 filename: Filename of the file that is being processed.
3784 file_extension: The extension (dot not included) of the file.
3785 clean_lines: An array of strings, each representing a line of the file,
3786 with comments stripped.
3787 line: Number of line being processed.
3788 include_state: An _IncludeState instance in which the headers are inserted.
3789 function_state: A _FunctionState instance which counts function lines, etc.
3790 nesting_state: A _NestingState instance which maintains information about
3791 the current stack of nested blocks being parsed.
3792 error: A callable to which errors are reported, which takes 4 arguments:
3793 filename, line number, error level, and message
3794 extra_check_functions: An array of additional check functions that will be
3795 run on each source line. Each function takes 4
3796 arguments: filename, clean_lines, line, error
3797 """
3798 raw_lines = clean_lines.raw_lines
3799 ParseNolintSuppressions(filename, raw_lines[line], line, error)
3800 nesting_state.Update(filename, clean_lines, line, error)
3801 if nesting_state.stack and nesting_state.stack[-1].inline_asm != _NO_ASM:
3802 return
3803 CheckForFunctionLengths(filename, clean_lines, line, function_state, error)
3804 CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
3805 CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error)
3806 CheckLanguage(filename, clean_lines, line, file_extension, include_state,
3807 error)
3808 CheckForNonStandardConstructs(filename, clean_lines, line,
3809 nesting_state, error)
3810 CheckPosixThreading(filename, clean_lines, line, error)
3811 CheckInvalidIncrement(filename, clean_lines, line, error)
3812 CheckMakePairUsesDeduction(filename, clean_lines, line, error)
3813 for check_fn in extra_check_functions:
3814 check_fn(filename, clean_lines, line, error)
3815
3816 def ProcessFileData(filename, file_extension, lines, error,
3817 extra_check_functions=[]):
3818 """Performs lint checks and reports any errors to the given error function.
3819
3820 Args:
3821 filename: Filename of the file that is being processed.
3822 file_extension: The extension (dot not included) of the file.
3823 lines: An array of strings, each representing a line of the file, with the
3824 last element being empty if the file is terminated with a newline.
3825 error: A callable to which errors are reported, which takes 4 arguments:
3826 filename, line number, error level, and message
3827 extra_check_functions: An array of additional check functions that will be
3828 run on each source line. Each function takes 4
3829 arguments: filename, clean_lines, line, error
3830 """
3831 lines = (['// marker so line numbers and indices both start at 1'] + lines +
3832 ['// marker so line numbers end in a known way'])
3833
3834 include_state = _IncludeState()
3835 function_state = _FunctionState()
3836 nesting_state = _NestingState()
3837
3838 ResetNolintSuppressions()
3839
3840 CheckForCopyright(filename, lines, error)
3841
3842 if file_extension == 'h':
3843 CheckForHeaderGuard(filename, lines, error)
3844
3845 RemoveMultiLineComments(filename, lines, error)
3846 clean_lines = CleansedLines(lines)
3847 for line in xrange(clean_lines.NumLines()):
3848 ProcessLine(filename, file_extension, clean_lines, line,
3849 include_state, function_state, nesting_state, error,
3850 extra_check_functions)
3851 nesting_state.CheckClassFinished(filename, error)
3852
3853 CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error)
3854
3855
3856
3857 CheckForUnicodeReplacementCharacters(filename, lines, error)
3858
3859 CheckForNewlineAtEOF(filename, lines, error)
3860
3861 def ProcessFile(filename, vlevel, extra_check_functions=[]):
3862 """Does google-lint on a single file.
3863
3864 Args:
3865 filename: The name of the file to parse.
3866
3867 vlevel: The level of errors to report. Every error of confidence
3868 >= verbose_level will be reported. 0 is a good default.
3869
3870 extra_check_functions: An array of additional check functions that will be
3871 run on each source line. Each function takes 4
3872 arguments: filename, clean_lines, line, error
3873 """
3874
3875 _SetVerboseLevel(vlevel)
3876
3877 try:
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888 if filename == '-':
3889 lines = codecs.StreamReaderWriter(sys.stdin,
3890 codecs.getreader('utf8'),
3891 codecs.getwriter('utf8'),
3892 'replace').read().split('\n')
3893 else:
3894 lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n')
3895
3896 carriage_return_found = False
3897
3898 for linenum in range(len(lines)):
3899 if lines[linenum].endswith('\r'):
3900 lines[linenum] = lines[linenum].rstrip('\r')
3901 carriage_return_found = True
3902
3903 except IOError:
3904 sys.stderr.write(
3905 "Skipping input '%s': Can't open for reading\n" % filename)
3906 return
3907
3908
3909 file_extension = filename[filename.rfind('.') + 1:]
3910
3911
3912
3913 if (filename != '-' and file_extension != 'cc' and file_extension != 'h'
3914 and file_extension != 'cpp' and file_extension != 'cxx'):
3915 sys.stderr.write('Ignoring %s; not a .cpp, .cxx, .cc or .h file\n'
3916 % filename)
3917 else:
3918 ProcessFileData(filename, file_extension, lines, Error,
3919 extra_check_functions)
3920 if carriage_return_found and os.linesep != '\r\n':
3921
3922
3923 Error(filename, 0, 'whitespace/newline', 1,
3924 'One or more unexpected \\r (^M) found;'
3925 'better to use only a \\n')
3926
3927 sys.stderr.write('Done processing %s\n' % filename)
3928
3929
3930 def PrintUsage(message):
3931 """Prints a brief usage string and exits, optionally with an error message.
3932
3933 Args:
3934 message: The optional error message.
3935 """
3936 sys.stderr.write(_USAGE)
3937 if message:
3938 sys.exit('\nFATAL ERROR: ' + message)
3939 else:
3940 sys.exit(1)
3941
3942
3943 def PrintCategories():
3944 """Prints a list of all the error-categories used by error messages.
3945
3946 These are the categories used to filter messages via --filter.
3947 """
3948 sys.stderr.write(''.join(' %s\n' % cat for cat in _ERROR_CATEGORIES))
3949 sys.exit(0)
3950
3951
3952 def ParseArguments(args):
3953 """Parses the command line arguments.
3954
3955 This may set the output format and verbosity level as side-effects.
3956
3957 Args:
3958 args: The command line arguments:
3959
3960 Returns:
3961 The list of filenames to lint.
3962 """
3963 try:
3964 (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=',
3965 'counting=',
3966 'filter=',
3967 'root='])
3968 except getopt.GetoptError:
3969 PrintUsage('Invalid arguments.')
3970
3971 verbosity = _VerboseLevel()
3972 output_format = _OutputFormat()
3973 filters = ''
3974 counting_style = ''
3975
3976 for (opt, val) in opts:
3977 if opt == '--help':
3978 PrintUsage(None)
3979 elif opt == '--output':
3980 if not val in ('emacs', 'vs7', 'eclipse'):
3981 PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.')
3982 output_format = val
3983 elif opt == '--verbose':
3984 verbosity = int(val)
3985 elif opt == '--filter':
3986 filters = val
3987 if not filters:
3988 PrintCategories()
3989 elif opt == '--counting':
3990 if val not in ('total', 'toplevel', 'detailed'):
3991 PrintUsage('Valid counting options are total, toplevel, and detailed')
3992 counting_style = val
3993 elif opt == '--root':
3994 global _root
3995 _root = val
3996
3997 if not filenames:
3998 PrintUsage('No files were specified.')
3999
4000 _SetOutputFormat(output_format)
4001 _SetVerboseLevel(verbosity)
4002 _SetFilters(filters)
4003 _SetCountingStyle(counting_style)
4004
4005 return filenames
4006
4007
4008 def main():
4009 filenames = ParseArguments(sys.argv[1:])
4010
4011
4012
4013 sys.stderr = codecs.StreamReaderWriter(sys.stderr,
4014 codecs.getreader('utf8'),
4015 codecs.getwriter('utf8'),
4016 'replace')
4017
4018 _cpplint_state.ResetErrorCounts()
4019 for filename in filenames:
4020 ProcessFile(filename, _cpplint_state.verbose_level)
4021 _cpplint_state.PrintErrorCounts()
4022
4023 sys.exit(_cpplint_state.error_count > 0)
4024
4025
4026 if __name__ == '__main__':
4027 main()