Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(153)

Side by Side Diff: cpplint.py

Issue 406373002: depot_tools: modify cpplint.py to allow CPPLINT.cfg overrides (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Final revision, simplified code to removed duplicated assignment Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # 2 #
3 # Copyright (c) 2009 Google Inc. All rights reserved. 3 # Copyright (c) 2009 Google Inc. All rights reserved.
4 # 4 #
5 # Redistribution and use in source and binary forms, with or without 5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are 6 # modification, are permitted provided that the following conditions are
7 # met: 7 # met:
8 # 8 #
9 # * Redistributions of source code must retain the above copyright 9 # * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer. 10 # notice, this list of conditions and the following disclaimer.
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 80 characters. 126 80 characters.
127 127
128 Examples: 128 Examples:
129 --linelength=120 129 --linelength=120
130 130
131 extensions=extension,extension,... 131 extensions=extension,extension,...
132 The allowed file extensions that cpplint will check 132 The allowed file extensions that cpplint will check
133 133
134 Examples: 134 Examples:
135 --extensions=hpp,cpp 135 --extensions=hpp,cpp
136
137 cpplint.py supports per-directory configurations specified in CPPLINT.cfg
138 files. CPPLINT.cfg file can contain a number of key=value pairs.
139 Currently the following options are supported:
140
141 set noparent
142 filter=+filter1,-filter2,...
143 exclude_files=regex
144
145 "set noparent" option prevents cpplint from traversing directory tree
146 upwards looking for more .cfg files in parent directories. This option
147 is usually placed in the top-level project directory.
148
149 The "filter" option is similar in function to --filter flag. It specifies
150 message filters in addition to the |_DEFAULT_FILTERS| and those specified
151 through --filter command-line flag.
152
153 "exclude_files" allows to specify a regular expression to be matched against
154 a file name. If the expression matches, the file is skipped and not run
155 through liner.
156
157 CPPLINT.cfg has an effect on files in the same directory and all
158 sub-directories, unless overridden by a nested configuration file.
159
160 Example file:
161 filter=-build/include_order,+build/include_alpha
162 exclude_files=.*\.cc
163
164 The above example disables build/include_order warning and enables
165 build/include_alpha as well as excludes all .cc from being
166 processed by linter, in the current directory (where the .cfg
167 file is located) and all sub-directories.
136 """ 168 """
137 169
138 # We categorize each error message we print. Here are the categories. 170 # We categorize each error message we print. Here are the categories.
139 # We want an explicit list so we can list them all in cpplint --filter=. 171 # We want an explicit list so we can list them all in cpplint --filter=.
140 # If you add a new error message with a new category, add it to the list 172 # If you add a new error message with a new category, add it to the list
141 # here! cpplint_unittest.py should tell you if you forget to do this. 173 # here! cpplint_unittest.py should tell you if you forget to do this.
142 _ERROR_CATEGORIES = [ 174 _ERROR_CATEGORIES = [
143 'build/class', 175 'build/class',
144 'build/c++11', 176 'build/c++11',
145 'build/deprecated', 177 'build/deprecated',
(...skipping 529 matching lines...) Expand 10 before | Expand all | Expand 10 after
675 707
676 708
677 class _CppLintState(object): 709 class _CppLintState(object):
678 """Maintains module-wide state..""" 710 """Maintains module-wide state.."""
679 711
680 def __init__(self): 712 def __init__(self):
681 self.verbose_level = 1 # global setting. 713 self.verbose_level = 1 # global setting.
682 self.error_count = 0 # global count of reported errors 714 self.error_count = 0 # global count of reported errors
683 # filters to apply when emitting error messages 715 # filters to apply when emitting error messages
684 self.filters = _DEFAULT_FILTERS[:] 716 self.filters = _DEFAULT_FILTERS[:]
717 # backup of filter list. Used to restore the state after each file.
718 self._filters_backup = self.filters[:]
685 self.counting = 'total' # In what way are we counting errors? 719 self.counting = 'total' # In what way are we counting errors?
686 self.errors_by_category = {} # string to int dict storing error counts 720 self.errors_by_category = {} # string to int dict storing error counts
687 721
688 # output format: 722 # output format:
689 # "emacs" - format that emacs can parse (default) 723 # "emacs" - format that emacs can parse (default)
690 # "vs7" - format that Microsoft Visual Studio 7 can parse 724 # "vs7" - format that Microsoft Visual Studio 7 can parse
691 self.output_format = 'emacs' 725 self.output_format = 'emacs'
692 726
693 def SetOutputFormat(self, output_format): 727 def SetOutputFormat(self, output_format):
694 """Sets the output format for errors.""" 728 """Sets the output format for errors."""
(...skipping 18 matching lines...) Expand all
713 Args: 747 Args:
714 filters: A string of comma-separated filters (eg "+whitespace/indent"). 748 filters: A string of comma-separated filters (eg "+whitespace/indent").
715 Each filter should start with + or -; else we die. 749 Each filter should start with + or -; else we die.
716 750
717 Raises: 751 Raises:
718 ValueError: The comma-separated filters did not all start with '+' or '-'. 752 ValueError: The comma-separated filters did not all start with '+' or '-'.
719 E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter" 753 E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter"
720 """ 754 """
721 # Default filters always have less priority than the flag ones. 755 # Default filters always have less priority than the flag ones.
722 self.filters = _DEFAULT_FILTERS[:] 756 self.filters = _DEFAULT_FILTERS[:]
757 self.AddFilters(filters)
758
759 def AddFilters(self, filters):
760 """ Adds more filters to the existing list of error-message filters. """
723 for filt in filters.split(','): 761 for filt in filters.split(','):
724 clean_filt = filt.strip() 762 clean_filt = filt.strip()
725 if clean_filt: 763 if clean_filt:
726 self.filters.append(clean_filt) 764 self.filters.append(clean_filt)
727 for filt in self.filters: 765 for filt in self.filters:
728 if not (filt.startswith('+') or filt.startswith('-')): 766 if not (filt.startswith('+') or filt.startswith('-')):
729 raise ValueError('Every filter in --filters must start with + or -' 767 raise ValueError('Every filter in --filters must start with + or -'
730 ' (%s does not)' % filt) 768 ' (%s does not)' % filt)
731 769
770 def BackupFilters(self):
771 """ Saves the current filter list to backup storage."""
772 self._filters_backup = self.filters[:]
773
774 def RestoreFilters(self):
775 """ Restores filters previously backed up."""
776 self.filters = self._filters_backup[:]
777
732 def ResetErrorCounts(self): 778 def ResetErrorCounts(self):
733 """Sets the module's error statistic back to zero.""" 779 """Sets the module's error statistic back to zero."""
734 self.error_count = 0 780 self.error_count = 0
735 self.errors_by_category = {} 781 self.errors_by_category = {}
736 782
737 def IncrementErrorCount(self, category): 783 def IncrementErrorCount(self, category):
738 """Bumps the module's error statistic.""" 784 """Bumps the module's error statistic."""
739 self.error_count += 1 785 self.error_count += 1
740 if self.counting in ('toplevel', 'detailed'): 786 if self.counting in ('toplevel', 'detailed'):
741 if self.counting != 'detailed': 787 if self.counting != 'detailed':
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
789 835
790 These filters are applied when deciding whether to emit a given 836 These filters are applied when deciding whether to emit a given
791 error message. 837 error message.
792 838
793 Args: 839 Args:
794 filters: A string of comma-separated filters (eg "whitespace/indent"). 840 filters: A string of comma-separated filters (eg "whitespace/indent").
795 Each filter should start with + or -; else we die. 841 Each filter should start with + or -; else we die.
796 """ 842 """
797 _cpplint_state.SetFilters(filters) 843 _cpplint_state.SetFilters(filters)
798 844
845 def _AddFilters(filters):
846 """Adds more filter overrides.
847
848 Unlike _SetFilters, this function does not reset the current list of filters
849 available.
850
851 Args:
852 filters: A string of comma-separated filters (eg "whitespace/indent").
853 Each filter should start with + or -; else we die.
854 """
855 _cpplint_state.AddFilters(filters)
856
857 def _BackupFilters():
858 """ Saves the current filter list to backup storage."""
859 _cpplint_state.BackupFilters()
860
861 def _RestoreFilters():
862 """ Restores filters previously backed up."""
863 _cpplint_state.RestoreFilters()
799 864
800 class _FunctionState(object): 865 class _FunctionState(object):
801 """Tracks current function name and the number of lines in its body.""" 866 """Tracks current function name and the number of lines in its body."""
802 867
803 _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc. 868 _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc.
804 _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER. 869 _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER.
805 870
806 def __init__(self): 871 def __init__(self):
807 self.in_a_function = False 872 self.in_a_function = False
808 self.lines_in_function = 0 873 self.lines_in_function = 0
(...skipping 4512 matching lines...) Expand 10 before | Expand all | Expand 10 after
5321 CheckForNonConstReference(filename, clean_lines, line, nesting_state, error) 5386 CheckForNonConstReference(filename, clean_lines, line, nesting_state, error)
5322 CheckForNonStandardConstructs(filename, clean_lines, line, 5387 CheckForNonStandardConstructs(filename, clean_lines, line,
5323 nesting_state, error) 5388 nesting_state, error)
5324 CheckVlogArguments(filename, clean_lines, line, error) 5389 CheckVlogArguments(filename, clean_lines, line, error)
5325 CheckPosixThreading(filename, clean_lines, line, error) 5390 CheckPosixThreading(filename, clean_lines, line, error)
5326 CheckInvalidIncrement(filename, clean_lines, line, error) 5391 CheckInvalidIncrement(filename, clean_lines, line, error)
5327 CheckMakePairUsesDeduction(filename, clean_lines, line, error) 5392 CheckMakePairUsesDeduction(filename, clean_lines, line, error)
5328 CheckDefaultLambdaCaptures(filename, clean_lines, line, error) 5393 CheckDefaultLambdaCaptures(filename, clean_lines, line, error)
5329 for check_fn in extra_check_functions: 5394 for check_fn in extra_check_functions:
5330 check_fn(filename, clean_lines, line, error) 5395 check_fn(filename, clean_lines, line, error)
5331 » 5396
5332 def FlagCxx11Features(filename, clean_lines, linenum, error): 5397 def FlagCxx11Features(filename, clean_lines, linenum, error):
5333 """Flag those c++11 features that we only allow in certain places. 5398 """Flag those c++11 features that we only allow in certain places.
5334 5399
5335 Args: 5400 Args:
5336 filename: The name of the current file. 5401 filename: The name of the current file.
5337 clean_lines: A CleansedLines instance containing the file. 5402 clean_lines: A CleansedLines instance containing the file.
5338 linenum: The number of the line to check. 5403 linenum: The number of the line to check.
5339 error: The function to call with any errors found. 5404 error: The function to call with any errors found.
5340 """ 5405 """
5341 line = clean_lines.elided[linenum] 5406 line = clean_lines.elided[linenum]
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
5417 nesting_state.CheckCompletedBlocks(filename, error) 5482 nesting_state.CheckCompletedBlocks(filename, error)
5418 5483
5419 CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error) 5484 CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error)
5420 5485
5421 # We check here rather than inside ProcessLine so that we see raw 5486 # We check here rather than inside ProcessLine so that we see raw
5422 # lines rather than "cleaned" lines. 5487 # lines rather than "cleaned" lines.
5423 CheckForBadCharacters(filename, lines, error) 5488 CheckForBadCharacters(filename, lines, error)
5424 5489
5425 CheckForNewlineAtEOF(filename, lines, error) 5490 CheckForNewlineAtEOF(filename, lines, error)
5426 5491
5492 def ProcessConfigOverrides(filename):
5493 """ Loads the configuration files and processes the config overrides.
5494
5495 Args:
5496 filename: The name of the file being processed by the linter.
5497
5498 Returns:
5499 False if the current |filename| should not be processed further.
5500 """
5501
5502 abs_filename = os.path.abspath(filename)
5503 cfg_filters = []
5504 keep_looking = True
5505 while keep_looking:
5506 abs_path, base_name = os.path.split(abs_filename)
5507 if not base_name:
5508 break # Reached the root directory.
5509
5510 cfg_file = os.path.join(abs_path, "CPPLINT.cfg")
5511 abs_filename = abs_path
5512 if not os.path.isfile(cfg_file):
5513 continue
5514
5515 try:
5516 with open(cfg_file) as file_handle:
5517 for line in file_handle:
5518 line, _, _ = line.partition('#') # Remove comments.
5519 if not line.strip():
5520 continue
5521
5522 name, _, val = line.partition('=')
5523 name = name.strip()
5524 val = val.strip()
5525 if name == 'set noparent':
5526 keep_looking = False
5527 elif name == 'filter':
5528 cfg_filters.append(val)
5529 elif name == 'exclude_files':
5530 # When matching exclude_files pattern, use the base_name of
5531 # the current file name or the directory name we are processing.
5532 # For example, if we are checking for lint errors in /foo/bar/baz.cc
5533 # and we found the .cfg file at /foo/CPPLINT.cfg, then the config
5534 # file's "exclude_files" filter is meant to be checked against "bar"
5535 # and not "baz" nor "bar/baz.cc".
5536 if base_name:
5537 pattern = re.compile(val)
5538 if pattern.match(base_name):
5539 sys.stderr.write('Ignoring "%s": file excluded by "%s". '
5540 'File path component "%s" matches '
5541 'pattern "%s"\n' %
5542 (filename, cfg_file, base_name, val))
5543 return False
5544 else:
5545 sys.stderr.write(
5546 'Invalid configuration option (%s) in file %s\n' %
5547 (name, cfg_file))
5548
5549 except IOError:
5550 sys.stderr.write(
5551 "Skipping config file '%s': Can't open for reading\n" % cfg_file)
5552 keep_looking = False
5553
5554 # Apply all the accumulated filters in reverse order (top-level directory
5555 # config options having the least priority).
5556 for filter in reversed(cfg_filters):
5557 _AddFilters(filter)
5558
5559 return True
5560
5427 5561
5428 def ProcessFile(filename, vlevel, extra_check_functions=[]): 5562 def ProcessFile(filename, vlevel, extra_check_functions=[]):
5429 """Does google-lint on a single file. 5563 """Does google-lint on a single file.
5430 5564
5431 Args: 5565 Args:
5432 filename: The name of the file to parse. 5566 filename: The name of the file to parse.
5433 5567
5434 vlevel: The level of errors to report. Every error of confidence 5568 vlevel: The level of errors to report. Every error of confidence
5435 >= verbose_level will be reported. 0 is a good default. 5569 >= verbose_level will be reported. 0 is a good default.
5436 5570
5437 extra_check_functions: An array of additional check functions that will be 5571 extra_check_functions: An array of additional check functions that will be
5438 run on each source line. Each function takes 4 5572 run on each source line. Each function takes 4
5439 arguments: filename, clean_lines, line, error 5573 arguments: filename, clean_lines, line, error
5440 """ 5574 """
5441 5575
5442 _SetVerboseLevel(vlevel) 5576 _SetVerboseLevel(vlevel)
5577 _BackupFilters()
5578
5579 if not ProcessConfigOverrides(filename):
5580 _RestoreFilters()
5581 return
5443 5582
5444 lf_lines = [] 5583 lf_lines = []
5445 crlf_lines = [] 5584 crlf_lines = []
5446 try: 5585 try:
5447 # Support the UNIX convention of using "-" for stdin. Note that 5586 # Support the UNIX convention of using "-" for stdin. Note that
5448 # we are not opening the file with universal newline support 5587 # we are not opening the file with universal newline support
5449 # (which codecs doesn't support anyway), so the resulting lines do 5588 # (which codecs doesn't support anyway), so the resulting lines do
5450 # contain trailing '\r' characters if we are reading a file that 5589 # contain trailing '\r' characters if we are reading a file that
5451 # has CRLF endings. 5590 # has CRLF endings.
5452 # If after the split a trailing '\r' is present, it is removed 5591 # If after the split a trailing '\r' is present, it is removed
(...skipping 11 matching lines...) Expand all
5464 for linenum in range(len(lines) - 1): 5603 for linenum in range(len(lines) - 1):
5465 if lines[linenum].endswith('\r'): 5604 if lines[linenum].endswith('\r'):
5466 lines[linenum] = lines[linenum].rstrip('\r') 5605 lines[linenum] = lines[linenum].rstrip('\r')
5467 crlf_lines.append(linenum + 1) 5606 crlf_lines.append(linenum + 1)
5468 else: 5607 else:
5469 lf_lines.append(linenum + 1) 5608 lf_lines.append(linenum + 1)
5470 5609
5471 except IOError: 5610 except IOError:
5472 sys.stderr.write( 5611 sys.stderr.write(
5473 "Skipping input '%s': Can't open for reading\n" % filename) 5612 "Skipping input '%s': Can't open for reading\n" % filename)
5613 _RestoreFilters()
5474 return 5614 return
5475 5615
5476 # Note, if no dot is found, this will give the entire filename as the ext. 5616 # Note, if no dot is found, this will give the entire filename as the ext.
5477 file_extension = filename[filename.rfind('.') + 1:] 5617 file_extension = filename[filename.rfind('.') + 1:]
5478 5618
5479 # When reading from stdin, the extension is unknown, so no cpplint tests 5619 # When reading from stdin, the extension is unknown, so no cpplint tests
5480 # should rely on the extension. 5620 # should rely on the extension.
5481 if filename != '-' and file_extension not in _valid_extensions: 5621 if filename != '-' and file_extension not in _valid_extensions:
5482 sys.stderr.write('Ignoring %s; not a valid file name ' 5622 sys.stderr.write('Ignoring %s; not a valid file name '
5483 '(%s)\n' % (filename, ', '.join(_valid_extensions))) 5623 '(%s)\n' % (filename, ', '.join(_valid_extensions)))
(...skipping 13 matching lines...) Expand all
5497 # server-side end-of-line sequence. 5637 # server-side end-of-line sequence.
5498 if lf_lines and crlf_lines: 5638 if lf_lines and crlf_lines:
5499 # Warn on every line with CR. An alternative approach might be to 5639 # Warn on every line with CR. An alternative approach might be to
5500 # check whether the file is mostly CRLF or just LF, and warn on the 5640 # check whether the file is mostly CRLF or just LF, and warn on the
5501 # minority, we bias toward LF here since most tools prefer LF. 5641 # minority, we bias toward LF here since most tools prefer LF.
5502 for linenum in crlf_lines: 5642 for linenum in crlf_lines:
5503 Error(filename, linenum, 'whitespace/newline', 1, 5643 Error(filename, linenum, 'whitespace/newline', 1,
5504 'Unexpected \\r (^M) found; better to use only \\n') 5644 'Unexpected \\r (^M) found; better to use only \\n')
5505 5645
5506 sys.stderr.write('Done processing %s\n' % filename) 5646 sys.stderr.write('Done processing %s\n' % filename)
5647 _RestoreFilters()
5507 5648
5508 5649
5509 def PrintUsage(message): 5650 def PrintUsage(message):
5510 """Prints a brief usage string and exits, optionally with an error message. 5651 """Prints a brief usage string and exits, optionally with an error message.
5511 5652
5512 Args: 5653 Args:
5513 message: The optional error message. 5654 message: The optional error message.
5514 """ 5655 """
5515 sys.stderr.write(_USAGE) 5656 sys.stderr.write(_USAGE)
5516 if message: 5657 if message:
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
5611 _cpplint_state.ResetErrorCounts() 5752 _cpplint_state.ResetErrorCounts()
5612 for filename in filenames: 5753 for filename in filenames:
5613 ProcessFile(filename, _cpplint_state.verbose_level) 5754 ProcessFile(filename, _cpplint_state.verbose_level)
5614 _cpplint_state.PrintErrorCounts() 5755 _cpplint_state.PrintErrorCounts()
5615 5756
5616 sys.exit(_cpplint_state.error_count > 0) 5757 sys.exit(_cpplint_state.error_count > 0)
5617 5758
5618 5759
5619 if __name__ == '__main__': 5760 if __name__ == '__main__':
5620 main() 5761 main()
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698