OLD | NEW |
---|---|
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 Loading... | |
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 filter=+filter1,-filter2,... | |
142 exclude_files=regex | |
143 | |
144 The "filter" option is similar in function to --filter flag. It specifies | |
145 message filters in addition to the |_DEFAULT_FILTERS| and those specified | |
146 through --filter command-line flag. | |
147 | |
148 "exclude_files" allows to specify a regular expression to be matched against | |
149 a file name. If the expression matches, the file is skipped and not run | |
150 through liner. | |
151 | |
152 CPPLINT.cfg has an effect on files in the same directory and all | |
153 sub-directories, unless overridden by a nested configuration file. | |
154 | |
155 Example file: | |
156 filter=-build/include_order,+build/include_alpha | |
157 exclude_files=.*\.cc | |
158 | |
159 The above example disables build/include_order warning and enables | |
160 build/include_alpha as well as excludes all .cc from being | |
161 processed by linter, in the current directory (where the .cfg | |
162 file is located) and all sub-directories. | |
136 """ | 163 """ |
137 | 164 |
138 # We categorize each error message we print. Here are the categories. | 165 # 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=. | 166 # 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 | 167 # 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. | 168 # here! cpplint_unittest.py should tell you if you forget to do this. |
142 _ERROR_CATEGORIES = [ | 169 _ERROR_CATEGORIES = [ |
143 'build/class', | 170 'build/class', |
144 'build/c++11', | 171 'build/c++11', |
145 'build/deprecated', | 172 'build/deprecated', |
(...skipping 529 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
675 | 702 |
676 | 703 |
677 class _CppLintState(object): | 704 class _CppLintState(object): |
678 """Maintains module-wide state..""" | 705 """Maintains module-wide state..""" |
679 | 706 |
680 def __init__(self): | 707 def __init__(self): |
681 self.verbose_level = 1 # global setting. | 708 self.verbose_level = 1 # global setting. |
682 self.error_count = 0 # global count of reported errors | 709 self.error_count = 0 # global count of reported errors |
683 # filters to apply when emitting error messages | 710 # filters to apply when emitting error messages |
684 self.filters = _DEFAULT_FILTERS[:] | 711 self.filters = _DEFAULT_FILTERS[:] |
712 # backup of filter list. Used to restore the state after each file. | |
713 self._filters_backup = self.filters[:] | |
685 self.counting = 'total' # In what way are we counting errors? | 714 self.counting = 'total' # In what way are we counting errors? |
686 self.errors_by_category = {} # string to int dict storing error counts | 715 self.errors_by_category = {} # string to int dict storing error counts |
687 | 716 |
688 # output format: | 717 # output format: |
689 # "emacs" - format that emacs can parse (default) | 718 # "emacs" - format that emacs can parse (default) |
690 # "vs7" - format that Microsoft Visual Studio 7 can parse | 719 # "vs7" - format that Microsoft Visual Studio 7 can parse |
691 self.output_format = 'emacs' | 720 self.output_format = 'emacs' |
692 | 721 |
693 def SetOutputFormat(self, output_format): | 722 def SetOutputFormat(self, output_format): |
694 """Sets the output format for errors.""" | 723 """Sets the output format for errors.""" |
(...skipping 18 matching lines...) Expand all Loading... | |
713 Args: | 742 Args: |
714 filters: A string of comma-separated filters (eg "+whitespace/indent"). | 743 filters: A string of comma-separated filters (eg "+whitespace/indent"). |
715 Each filter should start with + or -; else we die. | 744 Each filter should start with + or -; else we die. |
716 | 745 |
717 Raises: | 746 Raises: |
718 ValueError: The comma-separated filters did not all start with '+' or '-'. | 747 ValueError: The comma-separated filters did not all start with '+' or '-'. |
719 E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter" | 748 E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter" |
720 """ | 749 """ |
721 # Default filters always have less priority than the flag ones. | 750 # Default filters always have less priority than the flag ones. |
722 self.filters = _DEFAULT_FILTERS[:] | 751 self.filters = _DEFAULT_FILTERS[:] |
752 self.AddFilters(filters) | |
753 | |
754 def AddFilters(self, filters): | |
755 """ Adds more filters to the existing list of error-message filters. """ | |
723 for filt in filters.split(','): | 756 for filt in filters.split(','): |
724 clean_filt = filt.strip() | 757 clean_filt = filt.strip() |
725 if clean_filt: | 758 if clean_filt: |
726 self.filters.append(clean_filt) | 759 self.filters.append(clean_filt) |
727 for filt in self.filters: | 760 for filt in self.filters: |
728 if not (filt.startswith('+') or filt.startswith('-')): | 761 if not (filt.startswith('+') or filt.startswith('-')): |
729 raise ValueError('Every filter in --filters must start with + or -' | 762 raise ValueError('Every filter in --filters must start with + or -' |
730 ' (%s does not)' % filt) | 763 ' (%s does not)' % filt) |
731 | 764 |
765 def BackupFilters(self): | |
766 """ Saves the current filter list to backup storage.""" | |
767 self._filters_backup = self.filters[:] | |
768 | |
769 def RestoreFilters(self): | |
770 """ Restores filters previously backed up.""" | |
771 self.filters = self._filters_backup[:] | |
772 | |
732 def ResetErrorCounts(self): | 773 def ResetErrorCounts(self): |
733 """Sets the module's error statistic back to zero.""" | 774 """Sets the module's error statistic back to zero.""" |
734 self.error_count = 0 | 775 self.error_count = 0 |
735 self.errors_by_category = {} | 776 self.errors_by_category = {} |
736 | 777 |
737 def IncrementErrorCount(self, category): | 778 def IncrementErrorCount(self, category): |
738 """Bumps the module's error statistic.""" | 779 """Bumps the module's error statistic.""" |
739 self.error_count += 1 | 780 self.error_count += 1 |
740 if self.counting in ('toplevel', 'detailed'): | 781 if self.counting in ('toplevel', 'detailed'): |
741 if self.counting != 'detailed': | 782 if self.counting != 'detailed': |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
789 | 830 |
790 These filters are applied when deciding whether to emit a given | 831 These filters are applied when deciding whether to emit a given |
791 error message. | 832 error message. |
792 | 833 |
793 Args: | 834 Args: |
794 filters: A string of comma-separated filters (eg "whitespace/indent"). | 835 filters: A string of comma-separated filters (eg "whitespace/indent"). |
795 Each filter should start with + or -; else we die. | 836 Each filter should start with + or -; else we die. |
796 """ | 837 """ |
797 _cpplint_state.SetFilters(filters) | 838 _cpplint_state.SetFilters(filters) |
798 | 839 |
840 def _AddFilters(filters): | |
841 """Adds more filter overrides. | |
842 | |
843 Unlike _SetFilters, this function does not reset the current list of filters | |
844 available. | |
845 | |
846 Args: | |
847 filters: A string of comma-separated filters (eg "whitespace/indent"). | |
848 Each filter should start with + or -; else we die. | |
849 """ | |
850 _cpplint_state.AddFilters(filters) | |
851 | |
852 def _BackupFilters(): | |
853 """ Saves the current filter list to backup storage.""" | |
854 _cpplint_state.BackupFilters() | |
855 | |
856 def _RestoreFilters(): | |
857 """ Restores filters previously backed up.""" | |
858 _cpplint_state.RestoreFilters() | |
799 | 859 |
800 class _FunctionState(object): | 860 class _FunctionState(object): |
801 """Tracks current function name and the number of lines in its body.""" | 861 """Tracks current function name and the number of lines in its body.""" |
802 | 862 |
803 _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc. | 863 _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc. |
804 _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER. | 864 _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER. |
805 | 865 |
806 def __init__(self): | 866 def __init__(self): |
807 self.in_a_function = False | 867 self.in_a_function = False |
808 self.lines_in_function = 0 | 868 self.lines_in_function = 0 |
(...skipping 4512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5321 CheckForNonConstReference(filename, clean_lines, line, nesting_state, error) | 5381 CheckForNonConstReference(filename, clean_lines, line, nesting_state, error) |
5322 CheckForNonStandardConstructs(filename, clean_lines, line, | 5382 CheckForNonStandardConstructs(filename, clean_lines, line, |
5323 nesting_state, error) | 5383 nesting_state, error) |
5324 CheckVlogArguments(filename, clean_lines, line, error) | 5384 CheckVlogArguments(filename, clean_lines, line, error) |
5325 CheckPosixThreading(filename, clean_lines, line, error) | 5385 CheckPosixThreading(filename, clean_lines, line, error) |
5326 CheckInvalidIncrement(filename, clean_lines, line, error) | 5386 CheckInvalidIncrement(filename, clean_lines, line, error) |
5327 CheckMakePairUsesDeduction(filename, clean_lines, line, error) | 5387 CheckMakePairUsesDeduction(filename, clean_lines, line, error) |
5328 CheckDefaultLambdaCaptures(filename, clean_lines, line, error) | 5388 CheckDefaultLambdaCaptures(filename, clean_lines, line, error) |
5329 for check_fn in extra_check_functions: | 5389 for check_fn in extra_check_functions: |
5330 check_fn(filename, clean_lines, line, error) | 5390 check_fn(filename, clean_lines, line, error) |
5331 » | 5391 |
5332 def FlagCxx11Features(filename, clean_lines, linenum, error): | 5392 def FlagCxx11Features(filename, clean_lines, linenum, error): |
5333 """Flag those c++11 features that we only allow in certain places. | 5393 """Flag those c++11 features that we only allow in certain places. |
5334 | 5394 |
5335 Args: | 5395 Args: |
5336 filename: The name of the current file. | 5396 filename: The name of the current file. |
5337 clean_lines: A CleansedLines instance containing the file. | 5397 clean_lines: A CleansedLines instance containing the file. |
5338 linenum: The number of the line to check. | 5398 linenum: The number of the line to check. |
5339 error: The function to call with any errors found. | 5399 error: The function to call with any errors found. |
5340 """ | 5400 """ |
5341 line = clean_lines.elided[linenum] | 5401 line = clean_lines.elided[linenum] |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5417 nesting_state.CheckCompletedBlocks(filename, error) | 5477 nesting_state.CheckCompletedBlocks(filename, error) |
5418 | 5478 |
5419 CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error) | 5479 CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error) |
5420 | 5480 |
5421 # We check here rather than inside ProcessLine so that we see raw | 5481 # We check here rather than inside ProcessLine so that we see raw |
5422 # lines rather than "cleaned" lines. | 5482 # lines rather than "cleaned" lines. |
5423 CheckForBadCharacters(filename, lines, error) | 5483 CheckForBadCharacters(filename, lines, error) |
5424 | 5484 |
5425 CheckForNewlineAtEOF(filename, lines, error) | 5485 CheckForNewlineAtEOF(filename, lines, error) |
5426 | 5486 |
5487 def GetConfigOverrideFiles(filename): | |
5488 """ Looks for CPPLINT.cfg files in the directory containing |filename| and | |
sosa
2014/07/23 20:25:42
docstring issue
Alex Vakulenko (Google)
2014/07/23 20:44:32
Done.
| |
5489 its parents and returns a list of configuration files found. | |
5490 | |
5491 Args: | |
5492 filename: The name of the file being processed by the linter. | |
5493 """ | |
5494 | |
5495 cfg_override_files = [] | |
5496 abs_path = os.path.abspath(os.path.dirname(filename)) | |
5497 | |
5498 while True: | |
5499 file = os.path.join(abs_path, "CPPLINT.cfg") | |
5500 if os.path.isfile(file): | |
5501 cfg_override_files.append(file) | |
5502 parent = os.path.dirname(abs_path) | |
5503 if parent == abs_path: | |
5504 break | |
5505 abs_path = parent | |
5506 | |
5507 return reversed(cfg_override_files) | |
5508 | |
5509 def ProcessConfigFile(cfg_file, filename): | |
5510 """ Loads the configuration file and processes the config overrides. | |
5511 | |
5512 Args: | |
5513 cfg_file: config file to process | |
5514 filename: The name of the file being processed by the linter. | |
5515 | |
5516 Returns: | |
5517 false if the current |filename| should not be processed further. | |
5518 """ | |
5519 | |
5520 try: | |
5521 with open(cfg_file) as file_handle: | |
5522 for line in file_handle: | |
5523 line, _, _ = line.partition('#') # Remove comments. | |
5524 if line.strip(): | |
5525 name, _, val = line.partition('=') | |
5526 name = name.strip() | |
5527 val = val.strip() | |
5528 if name == 'filter': | |
5529 _AddFilters(val) | |
5530 elif name == 'exclude_files': | |
5531 pattern = re.compile(val) | |
5532 if pattern.match(filename): | |
5533 sys.stderr.write('Ignoring %s; file excluded by (%s)\n' % | |
5534 (filename, cfg_file)) | |
5535 return False | |
5536 else: | |
5537 sys.stderr.write('Invalid configuration option (%s) in file %s\n' % | |
5538 (name, cfg_file)) | |
5539 | |
5540 except IOError: | |
5541 sys.stderr.write( | |
5542 "Skipping config file '%s': Can't open for reading\n" % cfg_file) | |
5543 _RestoreFilters() | |
5544 return True | |
5545 | |
5546 return True | |
5547 | |
5548 | |
5549 def ProcessConfigOverrides(cfg_override_files, filename): | |
5550 """ Loads the configuration files and processes the config overrides. | |
5551 | |
5552 Args: | |
5553 cfg_override_files: list of cfg files to process | |
5554 filename: The name of the file being processed by the linter. | |
5555 | |
5556 Returns: | |
5557 false if the current |filename| should not be processed further. | |
5558 """ | |
5559 for cfg_file in cfg_override_files: | |
5560 if not ProcessConfigFile(cfg_file, filename): | |
5561 return False | |
5562 | |
5563 return True | |
5427 | 5564 |
5428 def ProcessFile(filename, vlevel, extra_check_functions=[]): | 5565 def ProcessFile(filename, vlevel, extra_check_functions=[]): |
5429 """Does google-lint on a single file. | 5566 """Does google-lint on a single file. |
5430 | 5567 |
5431 Args: | 5568 Args: |
5432 filename: The name of the file to parse. | 5569 filename: The name of the file to parse. |
5433 | 5570 |
5434 vlevel: The level of errors to report. Every error of confidence | 5571 vlevel: The level of errors to report. Every error of confidence |
5435 >= verbose_level will be reported. 0 is a good default. | 5572 >= verbose_level will be reported. 0 is a good default. |
5436 | 5573 |
5437 extra_check_functions: An array of additional check functions that will be | 5574 extra_check_functions: An array of additional check functions that will be |
5438 run on each source line. Each function takes 4 | 5575 run on each source line. Each function takes 4 |
5439 arguments: filename, clean_lines, line, error | 5576 arguments: filename, clean_lines, line, error |
5440 """ | 5577 """ |
5441 | 5578 |
5442 _SetVerboseLevel(vlevel) | 5579 _SetVerboseLevel(vlevel) |
5580 _BackupFilters() | |
5581 | |
5582 cfg_override_files = GetConfigOverrideFiles(filename) | |
5583 if not ProcessConfigOverrides(cfg_override_files, filename): | |
5584 _RestoreFilters() | |
5585 return | |
5443 | 5586 |
5444 lf_lines = [] | 5587 lf_lines = [] |
5445 crlf_lines = [] | 5588 crlf_lines = [] |
5446 try: | 5589 try: |
5447 # Support the UNIX convention of using "-" for stdin. Note that | 5590 # Support the UNIX convention of using "-" for stdin. Note that |
5448 # we are not opening the file with universal newline support | 5591 # we are not opening the file with universal newline support |
5449 # (which codecs doesn't support anyway), so the resulting lines do | 5592 # (which codecs doesn't support anyway), so the resulting lines do |
5450 # contain trailing '\r' characters if we are reading a file that | 5593 # contain trailing '\r' characters if we are reading a file that |
5451 # has CRLF endings. | 5594 # has CRLF endings. |
5452 # If after the split a trailing '\r' is present, it is removed | 5595 # If after the split a trailing '\r' is present, it is removed |
(...skipping 11 matching lines...) Expand all Loading... | |
5464 for linenum in range(len(lines) - 1): | 5607 for linenum in range(len(lines) - 1): |
5465 if lines[linenum].endswith('\r'): | 5608 if lines[linenum].endswith('\r'): |
5466 lines[linenum] = lines[linenum].rstrip('\r') | 5609 lines[linenum] = lines[linenum].rstrip('\r') |
5467 crlf_lines.append(linenum + 1) | 5610 crlf_lines.append(linenum + 1) |
5468 else: | 5611 else: |
5469 lf_lines.append(linenum + 1) | 5612 lf_lines.append(linenum + 1) |
5470 | 5613 |
5471 except IOError: | 5614 except IOError: |
5472 sys.stderr.write( | 5615 sys.stderr.write( |
5473 "Skipping input '%s': Can't open for reading\n" % filename) | 5616 "Skipping input '%s': Can't open for reading\n" % filename) |
5617 _RestoreFilters() | |
5474 return | 5618 return |
5475 | 5619 |
5476 # Note, if no dot is found, this will give the entire filename as the ext. | 5620 # Note, if no dot is found, this will give the entire filename as the ext. |
5477 file_extension = filename[filename.rfind('.') + 1:] | 5621 file_extension = filename[filename.rfind('.') + 1:] |
5478 | 5622 |
5479 # When reading from stdin, the extension is unknown, so no cpplint tests | 5623 # When reading from stdin, the extension is unknown, so no cpplint tests |
5480 # should rely on the extension. | 5624 # should rely on the extension. |
5481 if filename != '-' and file_extension not in _valid_extensions: | 5625 if filename != '-' and file_extension not in _valid_extensions: |
5482 sys.stderr.write('Ignoring %s; not a valid file name ' | 5626 sys.stderr.write('Ignoring %s; not a valid file name ' |
5483 '(%s)\n' % (filename, ', '.join(_valid_extensions))) | 5627 '(%s)\n' % (filename, ', '.join(_valid_extensions))) |
(...skipping 13 matching lines...) Expand all Loading... | |
5497 # server-side end-of-line sequence. | 5641 # server-side end-of-line sequence. |
5498 if lf_lines and crlf_lines: | 5642 if lf_lines and crlf_lines: |
5499 # Warn on every line with CR. An alternative approach might be to | 5643 # 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 | 5644 # 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. | 5645 # minority, we bias toward LF here since most tools prefer LF. |
5502 for linenum in crlf_lines: | 5646 for linenum in crlf_lines: |
5503 Error(filename, linenum, 'whitespace/newline', 1, | 5647 Error(filename, linenum, 'whitespace/newline', 1, |
5504 'Unexpected \\r (^M) found; better to use only \\n') | 5648 'Unexpected \\r (^M) found; better to use only \\n') |
5505 | 5649 |
5506 sys.stderr.write('Done processing %s\n' % filename) | 5650 sys.stderr.write('Done processing %s\n' % filename) |
5651 _RestoreFilters() | |
5507 | 5652 |
5508 | 5653 |
5509 def PrintUsage(message): | 5654 def PrintUsage(message): |
5510 """Prints a brief usage string and exits, optionally with an error message. | 5655 """Prints a brief usage string and exits, optionally with an error message. |
5511 | 5656 |
5512 Args: | 5657 Args: |
5513 message: The optional error message. | 5658 message: The optional error message. |
5514 """ | 5659 """ |
5515 sys.stderr.write(_USAGE) | 5660 sys.stderr.write(_USAGE) |
5516 if message: | 5661 if message: |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5611 _cpplint_state.ResetErrorCounts() | 5756 _cpplint_state.ResetErrorCounts() |
5612 for filename in filenames: | 5757 for filename in filenames: |
5613 ProcessFile(filename, _cpplint_state.verbose_level) | 5758 ProcessFile(filename, _cpplint_state.verbose_level) |
5614 _cpplint_state.PrintErrorCounts() | 5759 _cpplint_state.PrintErrorCounts() |
5615 | 5760 |
5616 sys.exit(_cpplint_state.error_count > 0) | 5761 sys.exit(_cpplint_state.error_count > 0) |
5617 | 5762 |
5618 | 5763 |
5619 if __name__ == '__main__': | 5764 if __name__ == '__main__': |
5620 main() | 5765 main() |
OLD | NEW |