Chromium Code Reviews| 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 664 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 675 | 675 |
| 676 | 676 |
| 677 class _CppLintState(object): | 677 class _CppLintState(object): |
| 678 """Maintains module-wide state..""" | 678 """Maintains module-wide state..""" |
| 679 | 679 |
| 680 def __init__(self): | 680 def __init__(self): |
| 681 self.verbose_level = 1 # global setting. | 681 self.verbose_level = 1 # global setting. |
| 682 self.error_count = 0 # global count of reported errors | 682 self.error_count = 0 # global count of reported errors |
| 683 # filters to apply when emitting error messages | 683 # filters to apply when emitting error messages |
| 684 self.filters = _DEFAULT_FILTERS[:] | 684 self.filters = _DEFAULT_FILTERS[:] |
| 685 # backup of filter list. Used to restore the state after each file. | |
|
sosa
2014/07/23 17:35:00
indentation also this seems super private to the c
Alex Vakulenko (Google)
2014/07/23 19:04:50
Done.
| |
| 686 self.filters_backup = self.filters[:] | |
| 685 self.counting = 'total' # In what way are we counting errors? | 687 self.counting = 'total' # In what way are we counting errors? |
| 686 self.errors_by_category = {} # string to int dict storing error counts | 688 self.errors_by_category = {} # string to int dict storing error counts |
| 687 | 689 |
| 688 # output format: | 690 # output format: |
| 689 # "emacs" - format that emacs can parse (default) | 691 # "emacs" - format that emacs can parse (default) |
| 690 # "vs7" - format that Microsoft Visual Studio 7 can parse | 692 # "vs7" - format that Microsoft Visual Studio 7 can parse |
| 691 self.output_format = 'emacs' | 693 self.output_format = 'emacs' |
| 692 | 694 |
| 693 def SetOutputFormat(self, output_format): | 695 def SetOutputFormat(self, output_format): |
| 694 """Sets the output format for errors.""" | 696 """Sets the output format for errors.""" |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 713 Args: | 715 Args: |
| 714 filters: A string of comma-separated filters (eg "+whitespace/indent"). | 716 filters: A string of comma-separated filters (eg "+whitespace/indent"). |
| 715 Each filter should start with + or -; else we die. | 717 Each filter should start with + or -; else we die. |
| 716 | 718 |
| 717 Raises: | 719 Raises: |
| 718 ValueError: The comma-separated filters did not all start with '+' or '-'. | 720 ValueError: The comma-separated filters did not all start with '+' or '-'. |
| 719 E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter" | 721 E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter" |
| 720 """ | 722 """ |
| 721 # Default filters always have less priority than the flag ones. | 723 # Default filters always have less priority than the flag ones. |
| 722 self.filters = _DEFAULT_FILTERS[:] | 724 self.filters = _DEFAULT_FILTERS[:] |
| 725 self.AddFilters(filters) | |
| 726 | |
| 727 def AddFilters(self, filters): | |
| 728 """ Adds more filters to the existing list of error-message filters. """ | |
| 723 for filt in filters.split(','): | 729 for filt in filters.split(','): |
| 724 clean_filt = filt.strip() | 730 clean_filt = filt.strip() |
| 725 if clean_filt: | 731 if clean_filt: |
| 726 self.filters.append(clean_filt) | 732 self.filters.append(clean_filt) |
| 727 for filt in self.filters: | 733 for filt in self.filters: |
| 728 if not (filt.startswith('+') or filt.startswith('-')): | 734 if not (filt.startswith('+') or filt.startswith('-')): |
| 729 raise ValueError('Every filter in --filters must start with + or -' | 735 raise ValueError('Every filter in --filters must start with + or -' |
| 730 ' (%s does not)' % filt) | 736 ' (%s does not)' % filt) |
| 731 | 737 |
| 738 def BackupFilters(self): | |
| 739 """ Saves the current filter list to backup storage.""" | |
| 740 self.filters_backup = self.filters[:] | |
| 741 | |
| 742 def RestoreFilters(self): | |
| 743 """ Restores filters previously backed up.""" | |
| 744 self.filters = self.filters_backup[:] | |
| 745 | |
| 732 def ResetErrorCounts(self): | 746 def ResetErrorCounts(self): |
| 733 """Sets the module's error statistic back to zero.""" | 747 """Sets the module's error statistic back to zero.""" |
| 734 self.error_count = 0 | 748 self.error_count = 0 |
| 735 self.errors_by_category = {} | 749 self.errors_by_category = {} |
| 736 | 750 |
| 737 def IncrementErrorCount(self, category): | 751 def IncrementErrorCount(self, category): |
| 738 """Bumps the module's error statistic.""" | 752 """Bumps the module's error statistic.""" |
| 739 self.error_count += 1 | 753 self.error_count += 1 |
| 740 if self.counting in ('toplevel', 'detailed'): | 754 if self.counting in ('toplevel', 'detailed'): |
| 741 if self.counting != 'detailed': | 755 if self.counting != 'detailed': |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 789 | 803 |
| 790 These filters are applied when deciding whether to emit a given | 804 These filters are applied when deciding whether to emit a given |
| 791 error message. | 805 error message. |
| 792 | 806 |
| 793 Args: | 807 Args: |
| 794 filters: A string of comma-separated filters (eg "whitespace/indent"). | 808 filters: A string of comma-separated filters (eg "whitespace/indent"). |
| 795 Each filter should start with + or -; else we die. | 809 Each filter should start with + or -; else we die. |
| 796 """ | 810 """ |
| 797 _cpplint_state.SetFilters(filters) | 811 _cpplint_state.SetFilters(filters) |
| 798 | 812 |
| 813 def _AddFilters(filters): | |
| 814 """Adds more filter overrides. Unlike _SetFilters, this function does not | |
|
sosa
2014/07/23 17:35:00
Unlike should be on a newline. We usually keep the
Alex Vakulenko (Google)
2014/07/23 19:04:50
Done.
| |
| 815 reset the current list of filters available. | |
| 816 Args: | |
| 817 filters: A string of comma-separated filters (eg "whitespace/indent"). | |
| 818 Each filter should start with + or -; else we die. | |
| 819 """ | |
| 820 _cpplint_state.AddFilters(filters) | |
| 821 | |
| 822 def _BackupFilters(): | |
| 823 """ Saves the current filter list to backup storage.""" | |
| 824 _cpplint_state.BackupFilters() | |
| 825 | |
| 826 def _RestoreFilters(): | |
| 827 """ Restores filters previously backed up.""" | |
| 828 _cpplint_state.RestoreFilters() | |
| 799 | 829 |
| 800 class _FunctionState(object): | 830 class _FunctionState(object): |
| 801 """Tracks current function name and the number of lines in its body.""" | 831 """Tracks current function name and the number of lines in its body.""" |
| 802 | 832 |
| 803 _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc. | 833 _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc. |
| 804 _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER. | 834 _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER. |
| 805 | 835 |
| 806 def __init__(self): | 836 def __init__(self): |
| 807 self.in_a_function = False | 837 self.in_a_function = False |
| 808 self.lines_in_function = 0 | 838 self.lines_in_function = 0 |
| (...skipping 4608 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5417 nesting_state.CheckCompletedBlocks(filename, error) | 5447 nesting_state.CheckCompletedBlocks(filename, error) |
| 5418 | 5448 |
| 5419 CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error) | 5449 CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error) |
| 5420 | 5450 |
| 5421 # We check here rather than inside ProcessLine so that we see raw | 5451 # We check here rather than inside ProcessLine so that we see raw |
| 5422 # lines rather than "cleaned" lines. | 5452 # lines rather than "cleaned" lines. |
| 5423 CheckForBadCharacters(filename, lines, error) | 5453 CheckForBadCharacters(filename, lines, error) |
| 5424 | 5454 |
| 5425 CheckForNewlineAtEOF(filename, lines, error) | 5455 CheckForNewlineAtEOF(filename, lines, error) |
| 5426 | 5456 |
| 5457 def GetConfigOverrideFiles(filename): | |
| 5458 """ Looks for CPPLINT.cfg files in the directory containing |filename| and | |
| 5459 its parents and returns a list of configuration files found. | |
| 5460 | |
| 5461 Args: | |
| 5462 filename: The name of the file being processed by the linter. | |
| 5463 """ | |
| 5464 | |
| 5465 cfg_override_files = [] | |
| 5466 abs_path = os.path.abspath(os.path.dirname(filename)) | |
| 5467 | |
| 5468 while True: | |
| 5469 file = os.path.join(abs_path, "CPPLINT.cfg") | |
| 5470 if os.path.isfile(file): | |
| 5471 cfg_override_files.append(file) | |
| 5472 parent = os.path.dirname(abs_path) | |
| 5473 if parent == abs_path: | |
| 5474 break | |
| 5475 abs_path = parent | |
| 5476 | |
| 5477 return reversed(cfg_override_files) | |
| 5478 | |
| 5479 def ProcessConfigFile(cfg_file, filename): | |
| 5480 """ Loads the configuration file and processes the config overrides | |
|
sosa
2014/07/23 17:35:00
nit about docstring
Alex Vakulenko (Google)
2014/07/23 19:04:51
Done.
| |
| 5481 specified in it. | |
| 5482 | |
| 5483 Config file contains a bunch of key=value pairs. Currently | |
|
sosa
2014/07/23 17:35:00
This should probably go in the module docstring /
Alex Vakulenko (Google)
2014/07/23 19:04:50
Done.
| |
| 5484 we are looking only for: | |
| 5485 filter=+filter1,-filter2,... | |
| 5486 exclude_files=regex | |
| 5487 | |
| 5488 Args: | |
| 5489 cfg_file: config file to process | |
| 5490 filename: The name of the file being processed by the linter. | |
| 5491 | |
| 5492 Returns: | |
| 5493 false if the current |filename| should not be processed further. | |
| 5494 """ | |
| 5495 | |
| 5496 try: | |
| 5497 #lines = codecs.open(cfg_file, 'r', 'utf8', 'replace').read().split('\n') | |
|
sosa
2014/07/23 17:35:00
What's the line commented out for?
Alex Vakulenko (Google)
2014/07/23 19:04:50
Just forgot to remove. Done.
| |
| 5498 with open(cfg_file) as lines: | |
|
sosa
2014/07/23 17:35:00
Not completely correct naming. This is the file_ha
Alex Vakulenko (Google)
2014/07/23 19:04:50
Done.
| |
| 5499 for line in lines: | |
| 5500 name, val = line.partition('=')[::2] | |
|
sosa
2014/07/23 17:35:00
mmm, this works but not really the correct usage o
Alex Vakulenko (Google)
2014/07/23 19:04:50
I copied this from somewhere.
Fixed
| |
| 5501 name = name.strip() | |
|
sosa
2014/07/23 17:35:00
val = val.strip() here
Alex Vakulenko (Google)
2014/07/23 19:04:50
Done.
| |
| 5502 if name == 'filter': | |
| 5503 _AddFilters(val.strip()) | |
| 5504 elif name == 'exclude_files': | |
|
sosa
2014/07/23 17:35:00
Should support comments but also error out for nam
Alex Vakulenko (Google)
2014/07/23 19:04:50
Done.
| |
| 5505 pattern = re.compile(val.strip()) | |
| 5506 if pattern.match(filename): | |
| 5507 sys.stderr.write('Ignoring %s; file excluded by (%s)\n' % | |
| 5508 (filename, cfg_file)) | |
| 5509 return False | |
| 5510 | |
| 5511 except IOError: | |
| 5512 sys.stderr.write( | |
| 5513 "Skipping config file '%s': Can't open for reading\n" % cfg_file) | |
| 5514 _RestoreFilters() | |
| 5515 return True | |
| 5516 | |
| 5517 return True | |
| 5518 | |
|
sosa
2014/07/23 17:35:00
2 lines should separate top-level methods
Alex Vakulenko (Google)
2014/07/23 19:04:50
Done.
| |
| 5519 def ProcessConfigOverrides(cfg_override_files, filename): | |
| 5520 """ Loads the configuration files and processes the config overrides | |
|
sosa
2014/07/23 17:35:00
same nit about docstrings.
Alex Vakulenko (Google)
2014/07/23 19:04:50
Done.
| |
| 5521 specified in those files.. | |
| 5522 | |
| 5523 Args: | |
| 5524 cfg_override_files: list of cfg files to process | |
| 5525 filename: The name of the file being processed by the linter. | |
| 5526 | |
| 5527 Returns: | |
| 5528 false if the current |filename| should not be processed further. | |
| 5529 """ | |
| 5530 for cfg_file in cfg_override_files: | |
| 5531 if not ProcessConfigFile(cfg_file, filename): | |
| 5532 return False | |
| 5533 | |
| 5534 return True | |
| 5427 | 5535 |
| 5428 def ProcessFile(filename, vlevel, extra_check_functions=[]): | 5536 def ProcessFile(filename, vlevel, extra_check_functions=[]): |
| 5429 """Does google-lint on a single file. | 5537 """Does google-lint on a single file. |
| 5430 | 5538 |
| 5431 Args: | 5539 Args: |
| 5432 filename: The name of the file to parse. | 5540 filename: The name of the file to parse. |
| 5433 | 5541 |
| 5434 vlevel: The level of errors to report. Every error of confidence | 5542 vlevel: The level of errors to report. Every error of confidence |
| 5435 >= verbose_level will be reported. 0 is a good default. | 5543 >= verbose_level will be reported. 0 is a good default. |
| 5436 | 5544 |
| 5437 extra_check_functions: An array of additional check functions that will be | 5545 extra_check_functions: An array of additional check functions that will be |
| 5438 run on each source line. Each function takes 4 | 5546 run on each source line. Each function takes 4 |
| 5439 arguments: filename, clean_lines, line, error | 5547 arguments: filename, clean_lines, line, error |
| 5440 """ | 5548 """ |
| 5441 | 5549 |
| 5442 _SetVerboseLevel(vlevel) | 5550 _SetVerboseLevel(vlevel) |
| 5551 _BackupFilters() | |
| 5552 | |
| 5553 cfg_override_files = GetConfigOverrideFiles(filename) | |
| 5554 if not ProcessConfigOverrides(cfg_override_files, filename): | |
| 5555 _RestoreFilters() | |
| 5556 return | |
| 5443 | 5557 |
| 5444 lf_lines = [] | 5558 lf_lines = [] |
| 5445 crlf_lines = [] | 5559 crlf_lines = [] |
| 5446 try: | 5560 try: |
| 5447 # Support the UNIX convention of using "-" for stdin. Note that | 5561 # Support the UNIX convention of using "-" for stdin. Note that |
| 5448 # we are not opening the file with universal newline support | 5562 # we are not opening the file with universal newline support |
| 5449 # (which codecs doesn't support anyway), so the resulting lines do | 5563 # (which codecs doesn't support anyway), so the resulting lines do |
| 5450 # contain trailing '\r' characters if we are reading a file that | 5564 # contain trailing '\r' characters if we are reading a file that |
| 5451 # has CRLF endings. | 5565 # has CRLF endings. |
| 5452 # If after the split a trailing '\r' is present, it is removed | 5566 # 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): | 5578 for linenum in range(len(lines) - 1): |
| 5465 if lines[linenum].endswith('\r'): | 5579 if lines[linenum].endswith('\r'): |
| 5466 lines[linenum] = lines[linenum].rstrip('\r') | 5580 lines[linenum] = lines[linenum].rstrip('\r') |
| 5467 crlf_lines.append(linenum + 1) | 5581 crlf_lines.append(linenum + 1) |
| 5468 else: | 5582 else: |
| 5469 lf_lines.append(linenum + 1) | 5583 lf_lines.append(linenum + 1) |
| 5470 | 5584 |
| 5471 except IOError: | 5585 except IOError: |
| 5472 sys.stderr.write( | 5586 sys.stderr.write( |
| 5473 "Skipping input '%s': Can't open for reading\n" % filename) | 5587 "Skipping input '%s': Can't open for reading\n" % filename) |
| 5588 _RestoreFilters() | |
| 5474 return | 5589 return |
| 5475 | 5590 |
| 5476 # Note, if no dot is found, this will give the entire filename as the ext. | 5591 # Note, if no dot is found, this will give the entire filename as the ext. |
| 5477 file_extension = filename[filename.rfind('.') + 1:] | 5592 file_extension = filename[filename.rfind('.') + 1:] |
| 5478 | 5593 |
| 5479 # When reading from stdin, the extension is unknown, so no cpplint tests | 5594 # When reading from stdin, the extension is unknown, so no cpplint tests |
| 5480 # should rely on the extension. | 5595 # should rely on the extension. |
| 5481 if filename != '-' and file_extension not in _valid_extensions: | 5596 if filename != '-' and file_extension not in _valid_extensions: |
| 5482 sys.stderr.write('Ignoring %s; not a valid file name ' | 5597 sys.stderr.write('Ignoring %s; not a valid file name ' |
| 5483 '(%s)\n' % (filename, ', '.join(_valid_extensions))) | 5598 '(%s)\n' % (filename, ', '.join(_valid_extensions))) |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 5497 # server-side end-of-line sequence. | 5612 # server-side end-of-line sequence. |
| 5498 if lf_lines and crlf_lines: | 5613 if lf_lines and crlf_lines: |
| 5499 # Warn on every line with CR. An alternative approach might be to | 5614 # 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 | 5615 # 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. | 5616 # minority, we bias toward LF here since most tools prefer LF. |
| 5502 for linenum in crlf_lines: | 5617 for linenum in crlf_lines: |
| 5503 Error(filename, linenum, 'whitespace/newline', 1, | 5618 Error(filename, linenum, 'whitespace/newline', 1, |
| 5504 'Unexpected \\r (^M) found; better to use only \\n') | 5619 'Unexpected \\r (^M) found; better to use only \\n') |
| 5505 | 5620 |
| 5506 sys.stderr.write('Done processing %s\n' % filename) | 5621 sys.stderr.write('Done processing %s\n' % filename) |
| 5622 _RestoreFilters() | |
| 5507 | 5623 |
| 5508 | 5624 |
| 5509 def PrintUsage(message): | 5625 def PrintUsage(message): |
| 5510 """Prints a brief usage string and exits, optionally with an error message. | 5626 """Prints a brief usage string and exits, optionally with an error message. |
| 5511 | 5627 |
| 5512 Args: | 5628 Args: |
| 5513 message: The optional error message. | 5629 message: The optional error message. |
| 5514 """ | 5630 """ |
| 5515 sys.stderr.write(_USAGE) | 5631 sys.stderr.write(_USAGE) |
| 5516 if message: | 5632 if message: |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5611 _cpplint_state.ResetErrorCounts() | 5727 _cpplint_state.ResetErrorCounts() |
| 5612 for filename in filenames: | 5728 for filename in filenames: |
| 5613 ProcessFile(filename, _cpplint_state.verbose_level) | 5729 ProcessFile(filename, _cpplint_state.verbose_level) |
| 5614 _cpplint_state.PrintErrorCounts() | 5730 _cpplint_state.PrintErrorCounts() |
| 5615 | 5731 |
| 5616 sys.exit(_cpplint_state.error_count > 0) | 5732 sys.exit(_cpplint_state.error_count > 0) |
| 5617 | 5733 |
| 5618 | 5734 |
| 5619 if __name__ == '__main__': | 5735 if __name__ == '__main__': |
| 5620 main() | 5736 main() |
| OLD | NEW |