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

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: Changed the way .cfg files are processed and added "set noparent" option to prevent going to parent… 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.
sosa 2014/07/28 20:28:45 Too much indentation
5509 cfg_file = os.path.join(abs_path, "CPPLINT.cfg")
5510 if os.path.isfile(cfg_file):
sosa 2014/07/28 20:28:45 This is very nesty. I'd consider negating these if
5511 try:
5512 with open(cfg_file) as file_handle:
5513 for line in file_handle:
5514 line, _, _ = line.partition('#') # Remove comments.
5515 if line.strip():
5516 name, _, val = line.partition('=')
5517 name = name.strip()
5518 val = val.strip()
5519 if name == 'set noparent':
5520 keep_looking = False
5521 elif name == 'filter':
5522 cfg_filters.append(val)
5523 elif name == 'exclude_files':
5524 # When matching exclude_files pattern, use the base_name of
5525 # the current file name or the directory name we are processing.
5526 # For example, if we are checking for lint errors /foo/bar/baz
5527 # and we found the .cfg file in the parent directory (/foo),
5528 # then the config file's "exclude_files" filter is meant to
5529 # be checked against "bar" and not "baz" or "bar/baz".
5530 if base_name:
5531 pattern = re.compile(val)
5532 if pattern.match(base_name):
5533 sys.stderr.write('Ignoring "%s": file excluded by "%s". '
5534 'File path component "%s" matches '
5535 'pattern "%s"\n' %
5536 (filename, cfg_file, base_name, val))
5537 return False
5538 else:
5539 sys.stderr.write(
5540 'Invalid configuration option (%s) in file %s\n' %
5541 (name, cfg_file))
5542
5543 except IOError:
5544 sys.stderr.write(
5545 "Skipping config file '%s': Can't open for reading\n" % cfg_file)
5546 keep_looking = False
5547
5548 abs_filename = abs_path
5549
5550 # Apply all the accumulated filters in reverse order (top-level directory
5551 # config options having the least priority).
5552 for filter in reversed(cfg_filters):
5553 _AddFilters(filter)
5554
5555 return True
5556
5427 5557
5428 def ProcessFile(filename, vlevel, extra_check_functions=[]): 5558 def ProcessFile(filename, vlevel, extra_check_functions=[]):
5429 """Does google-lint on a single file. 5559 """Does google-lint on a single file.
5430 5560
5431 Args: 5561 Args:
5432 filename: The name of the file to parse. 5562 filename: The name of the file to parse.
5433 5563
5434 vlevel: The level of errors to report. Every error of confidence 5564 vlevel: The level of errors to report. Every error of confidence
5435 >= verbose_level will be reported. 0 is a good default. 5565 >= verbose_level will be reported. 0 is a good default.
5436 5566
5437 extra_check_functions: An array of additional check functions that will be 5567 extra_check_functions: An array of additional check functions that will be
5438 run on each source line. Each function takes 4 5568 run on each source line. Each function takes 4
5439 arguments: filename, clean_lines, line, error 5569 arguments: filename, clean_lines, line, error
5440 """ 5570 """
5441 5571
5442 _SetVerboseLevel(vlevel) 5572 _SetVerboseLevel(vlevel)
5573 _BackupFilters()
5574
5575 if not ProcessConfigOverrides(filename):
5576 _RestoreFilters()
5577 return
5443 5578
5444 lf_lines = [] 5579 lf_lines = []
5445 crlf_lines = [] 5580 crlf_lines = []
5446 try: 5581 try:
5447 # Support the UNIX convention of using "-" for stdin. Note that 5582 # Support the UNIX convention of using "-" for stdin. Note that
5448 # we are not opening the file with universal newline support 5583 # we are not opening the file with universal newline support
5449 # (which codecs doesn't support anyway), so the resulting lines do 5584 # (which codecs doesn't support anyway), so the resulting lines do
5450 # contain trailing '\r' characters if we are reading a file that 5585 # contain trailing '\r' characters if we are reading a file that
5451 # has CRLF endings. 5586 # has CRLF endings.
5452 # If after the split a trailing '\r' is present, it is removed 5587 # 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): 5599 for linenum in range(len(lines) - 1):
5465 if lines[linenum].endswith('\r'): 5600 if lines[linenum].endswith('\r'):
5466 lines[linenum] = lines[linenum].rstrip('\r') 5601 lines[linenum] = lines[linenum].rstrip('\r')
5467 crlf_lines.append(linenum + 1) 5602 crlf_lines.append(linenum + 1)
5468 else: 5603 else:
5469 lf_lines.append(linenum + 1) 5604 lf_lines.append(linenum + 1)
5470 5605
5471 except IOError: 5606 except IOError:
5472 sys.stderr.write( 5607 sys.stderr.write(
5473 "Skipping input '%s': Can't open for reading\n" % filename) 5608 "Skipping input '%s': Can't open for reading\n" % filename)
5609 _RestoreFilters()
5474 return 5610 return
5475 5611
5476 # Note, if no dot is found, this will give the entire filename as the ext. 5612 # Note, if no dot is found, this will give the entire filename as the ext.
5477 file_extension = filename[filename.rfind('.') + 1:] 5613 file_extension = filename[filename.rfind('.') + 1:]
5478 5614
5479 # When reading from stdin, the extension is unknown, so no cpplint tests 5615 # When reading from stdin, the extension is unknown, so no cpplint tests
5480 # should rely on the extension. 5616 # should rely on the extension.
5481 if filename != '-' and file_extension not in _valid_extensions: 5617 if filename != '-' and file_extension not in _valid_extensions:
5482 sys.stderr.write('Ignoring %s; not a valid file name ' 5618 sys.stderr.write('Ignoring %s; not a valid file name '
5483 '(%s)\n' % (filename, ', '.join(_valid_extensions))) 5619 '(%s)\n' % (filename, ', '.join(_valid_extensions)))
(...skipping 13 matching lines...) Expand all
5497 # server-side end-of-line sequence. 5633 # server-side end-of-line sequence.
5498 if lf_lines and crlf_lines: 5634 if lf_lines and crlf_lines:
5499 # Warn on every line with CR. An alternative approach might be to 5635 # 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 5636 # 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. 5637 # minority, we bias toward LF here since most tools prefer LF.
5502 for linenum in crlf_lines: 5638 for linenum in crlf_lines:
5503 Error(filename, linenum, 'whitespace/newline', 1, 5639 Error(filename, linenum, 'whitespace/newline', 1,
5504 'Unexpected \\r (^M) found; better to use only \\n') 5640 'Unexpected \\r (^M) found; better to use only \\n')
5505 5641
5506 sys.stderr.write('Done processing %s\n' % filename) 5642 sys.stderr.write('Done processing %s\n' % filename)
5643 _RestoreFilters()
5507 5644
5508 5645
5509 def PrintUsage(message): 5646 def PrintUsage(message):
5510 """Prints a brief usage string and exits, optionally with an error message. 5647 """Prints a brief usage string and exits, optionally with an error message.
5511 5648
5512 Args: 5649 Args:
5513 message: The optional error message. 5650 message: The optional error message.
5514 """ 5651 """
5515 sys.stderr.write(_USAGE) 5652 sys.stderr.write(_USAGE)
5516 if message: 5653 if message:
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
5611 _cpplint_state.ResetErrorCounts() 5748 _cpplint_state.ResetErrorCounts()
5612 for filename in filenames: 5749 for filename in filenames:
5613 ProcessFile(filename, _cpplint_state.verbose_level) 5750 ProcessFile(filename, _cpplint_state.verbose_level)
5614 _cpplint_state.PrintErrorCounts() 5751 _cpplint_state.PrintErrorCounts()
5615 5752
5616 sys.exit(_cpplint_state.error_count > 0) 5753 sys.exit(_cpplint_state.error_count > 0)
5617 5754
5618 5755
5619 if __name__ == '__main__': 5756 if __name__ == '__main__':
5620 main() 5757 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