| OLD | NEW |
| 1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
| 2 # | 2 # |
| 3 # Copyright (C) 2009, 2010, 2012 Google Inc. All rights reserved. | 3 # Copyright (C) 2009, 2010, 2012 Google Inc. All rights reserved. |
| 4 # Copyright (C) 2009 Torch Mobile Inc. | 4 # Copyright (C) 2009 Torch Mobile Inc. |
| 5 # Copyright (C) 2009 Apple Inc. All rights reserved. | 5 # Copyright (C) 2009 Apple Inc. All rights reserved. |
| 6 # Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org) | 6 # Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org) |
| 7 # | 7 # |
| 8 # Redistribution and use in source and binary forms, with or without | 8 # Redistribution and use in source and binary forms, with or without |
| 9 # modification, are permitted provided that the following conditions are | 9 # modification, are permitted provided that the following conditions are |
| 10 # met: | 10 # met: |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 29 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 30 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 30 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 31 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 31 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 32 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 32 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 33 | 33 |
| 34 # This is the modified version of Google's cpplint. The original code is | 34 # This is the modified version of Google's cpplint. The original code is |
| 35 # http://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py | 35 # http://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py |
| 36 | 36 |
| 37 """Support for check-webkit-style.""" | 37 """Support for check-webkit-style.""" |
| 38 | 38 |
| 39 import codecs | |
| 40 import math # for log | 39 import math # for log |
| 41 import os | 40 import os |
| 42 import os.path | 41 import os.path |
| 43 import re | 42 import re |
| 44 import sre_compile | 43 import sre_compile |
| 45 import string | 44 import string |
| 46 import sys | 45 import sys |
| 47 import unicodedata | 46 import unicodedata |
| 48 | 47 |
| 49 from webkitpy.common.memoized import memoized | 48 from webkitpy.common.memoized import memoized |
| 50 from webkitpy.common.system.filesystem import FileSystem | 49 from webkitpy.common.system.filesystem import FileSystem |
| 51 | 50 |
| 52 # The key to use to provide a class to fake loading a header file. | |
| 53 INCLUDE_IO_INJECTION_KEY = 'include_header_io' | |
| 54 | |
| 55 # Headers that we consider STL headers. | 51 # Headers that we consider STL headers. |
| 56 _STL_HEADERS = frozenset([ | 52 _STL_HEADERS = frozenset([ |
| 57 'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception', | 53 'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception', |
| 58 'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set', | 54 'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set', |
| 59 'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'pair.h', | 55 'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'pair.h', |
| 60 'pthread_alloc', 'queue', 'set', 'set.h', 'sstream', 'stack', | 56 'pthread_alloc', 'queue', 'set', 'set.h', 'sstream', 'stack', |
| 61 'stl_alloc.h', 'stl_relops.h', 'type_traits.h', | 57 'stl_alloc.h', 'stl_relops.h', 'type_traits.h', |
| 62 'utility', 'vector', 'vector.h', | 58 'utility', 'vector', 'vector.h', |
| 63 ]) | 59 ]) |
| 64 | 60 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 115 | 111 |
| 116 | 112 |
| 117 # These constants define types of headers for use with | 113 # These constants define types of headers for use with |
| 118 # _IncludeState.check_next_include_order(). | 114 # _IncludeState.check_next_include_order(). |
| 119 _CONFIG_HEADER = 0 | 115 _CONFIG_HEADER = 0 |
| 120 _PRIMARY_HEADER = 1 | 116 _PRIMARY_HEADER = 1 |
| 121 _OTHER_HEADER = 2 | 117 _OTHER_HEADER = 2 |
| 122 _MOC_HEADER = 3 | 118 _MOC_HEADER = 3 |
| 123 | 119 |
| 124 | 120 |
| 125 # A dictionary of items customize behavior for unit test. For example, | |
| 126 # INCLUDE_IO_INJECTION_KEY allows providing a custom io class which allows | |
| 127 # for faking a header file. | |
| 128 _unit_test_config = {} | |
| 129 | |
| 130 | |
| 131 # The regexp compilation caching is inlined in all regexp functions for | 121 # The regexp compilation caching is inlined in all regexp functions for |
| 132 # performance reasons; factoring it out into a separate function turns out | 122 # performance reasons; factoring it out into a separate function turns out |
| 133 # to be noticeably expensive. | 123 # to be noticeably expensive. |
| 134 _regexp_compile_cache = {} | 124 _regexp_compile_cache = {} |
| 135 | 125 |
| 136 | 126 |
| 137 def match(pattern, s): | 127 def match(pattern, s): |
| 138 """Matches the string with the pattern, caching the compiled regexp.""" | 128 """Matches the string with the pattern, caching the compiled regexp.""" |
| 139 if not pattern in _regexp_compile_cache: | 129 if not pattern in _regexp_compile_cache: |
| 140 _regexp_compile_cache[pattern] = sre_compile.compile(pattern) | 130 _regexp_compile_cache[pattern] = sre_compile.compile(pattern) |
| (...skipping 3319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3460 matches.append([line, function_state.body_start_position
.row, function_state.end_position.row + 1]) | 3450 matches.append([line, function_state.body_start_position
.row, function_state.end_position.row + 1]) |
| 3461 function_state = None | 3451 function_state = None |
| 3462 except UnicodeDecodeError: | 3452 except UnicodeDecodeError: |
| 3463 # There would be no non-ascii characters in the codebase ever. T
he only exception | 3453 # There would be no non-ascii characters in the codebase ever. T
he only exception |
| 3464 # would be comments/copyright text which might have non-ascii ch
aracters. Hence, | 3454 # would be comments/copyright text which might have non-ascii ch
aracters. Hence, |
| 3465 # it is prefectly safe to catch the UnicodeDecodeError and just
pass the line. | 3455 # it is prefectly safe to catch the UnicodeDecodeError and just
pass the line. |
| 3466 pass | 3456 pass |
| 3467 | 3457 |
| 3468 return matches | 3458 return matches |
| 3469 | 3459 |
| 3470 def check_in_mock_header(filename, matches=None, io=codecs): | 3460 def check_in_mock_header(filename, matches=None): |
| 3471 if not filename == 'Foo.h': | 3461 if not filename == 'Foo.h': |
| 3472 return False | 3462 return False |
| 3473 | 3463 |
| 3474 io = _unit_test_config.get(INCLUDE_IO_INJECTION_KEY, codecs) | |
| 3475 header_file = None | 3464 header_file = None |
| 3476 try: | 3465 try: |
| 3477 header_file = io.open(filename, 'r', 'utf8', 'replace') | 3466 header_file = CppChecker.fs.read_text_file(filename, 'replace') |
| 3478 except IOError: | 3467 except IOError: |
| 3479 return False | 3468 return False |
| 3480 line_number = 0 | 3469 line_number = 0 |
| 3481 for line in header_file: | 3470 for line in header_file: |
| 3482 line_number += 1 | 3471 line_number += 1 |
| 3483 matched = re.search(r'\btoFoo\b', line) | 3472 matched = re.search(r'\btoFoo\b', line) |
| 3484 if matched: | 3473 if matched: |
| 3485 matches.append(['toFoo', line_number, line_number + 3]) | 3474 matches.append(['toFoo', line_number, line_number + 3]) |
| 3486 return True | 3475 return True |
| 3487 | 3476 |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3724 filename_h = filename_h.replace('/public/', '/') | 3713 filename_h = filename_h.replace('/public/', '/') |
| 3725 filename_h = filename_h.replace('/internal/', '/') | 3714 filename_h = filename_h.replace('/internal/', '/') |
| 3726 | 3715 |
| 3727 files_belong_to_same_module = filename_cpp.endswith(filename_h) | 3716 files_belong_to_same_module = filename_cpp.endswith(filename_h) |
| 3728 common_path = '' | 3717 common_path = '' |
| 3729 if files_belong_to_same_module: | 3718 if files_belong_to_same_module: |
| 3730 common_path = filename_cpp[:-len(filename_h)] | 3719 common_path = filename_cpp[:-len(filename_h)] |
| 3731 return files_belong_to_same_module, common_path | 3720 return files_belong_to_same_module, common_path |
| 3732 | 3721 |
| 3733 | 3722 |
| 3734 def update_include_state(filename, include_state, io=codecs): | 3723 def update_include_state(filename, include_state): |
| 3735 """Fill up the include_state with new includes found from the file. | 3724 """Fill up the include_state with new includes found from the file. |
| 3736 | 3725 |
| 3737 Args: | 3726 Args: |
| 3738 filename: the name of the header to read. | 3727 filename: the name of the header to read. |
| 3739 include_state: an _IncludeState instance in which the headers are inserted
. | 3728 include_state: an _IncludeState instance in which the headers are inserted
. |
| 3740 io: The io factory to use to read the file. Provided for testability. | 3729 io: The io factory to use to read the file. Provided for testability. |
| 3741 | 3730 |
| 3742 Returns: | 3731 Returns: |
| 3743 True if a header was succesfully added. False otherwise. | 3732 True if a header was succesfully added. False otherwise. |
| 3744 """ | 3733 """ |
| 3745 io = _unit_test_config.get(INCLUDE_IO_INJECTION_KEY, codecs) | |
| 3746 header_file = None | 3734 header_file = None |
| 3747 try: | 3735 try: |
| 3748 header_file = io.open(filename, 'r', 'utf8', 'replace') | 3736 header_file = CppChecker.fs.read_text_file(filename, 'replace') |
| 3749 except IOError: | 3737 except IOError: |
| 3750 return False | 3738 return False |
| 3751 line_number = 0 | 3739 line_number = 0 |
| 3752 for line in header_file: | 3740 for line in header_file: |
| 3753 line_number += 1 | 3741 line_number += 1 |
| 3754 clean_line = cleanse_comments(line) | 3742 clean_line = cleanse_comments(line) |
| 3755 matched = _RE_PATTERN_INCLUDE.search(clean_line) | 3743 matched = _RE_PATTERN_INCLUDE.search(clean_line) |
| 3756 if matched: | 3744 if matched: |
| 3757 include = matched.group(2) | 3745 include = matched.group(2) |
| 3758 # The value formatting is cute, but not really used right now. | 3746 # The value formatting is cute, but not really used right now. |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4006 'whitespace/indent', | 3994 'whitespace/indent', |
| 4007 'whitespace/line_length', | 3995 'whitespace/line_length', |
| 4008 'whitespace/newline', | 3996 'whitespace/newline', |
| 4009 'whitespace/operators', | 3997 'whitespace/operators', |
| 4010 'whitespace/parens', | 3998 'whitespace/parens', |
| 4011 'whitespace/semicolon', | 3999 'whitespace/semicolon', |
| 4012 'whitespace/tab', | 4000 'whitespace/tab', |
| 4013 'whitespace/todo', | 4001 'whitespace/todo', |
| 4014 ]) | 4002 ]) |
| 4015 | 4003 |
| 4004 fs = None |
| 4005 |
| 4016 def __init__(self, file_path, file_extension, handle_style_error, | 4006 def __init__(self, file_path, file_extension, handle_style_error, |
| 4017 min_confidence): | 4007 min_confidence, fs=None): |
| 4018 """Create a CppChecker instance. | 4008 """Create a CppChecker instance. |
| 4019 | 4009 |
| 4020 Args: | 4010 Args: |
| 4021 file_extension: A string that is the file extension, without | 4011 file_extension: A string that is the file extension, without |
| 4022 the leading dot. | 4012 the leading dot. |
| 4023 | 4013 |
| 4024 """ | 4014 """ |
| 4025 self.file_extension = file_extension | 4015 self.file_extension = file_extension |
| 4026 self.file_path = file_path | 4016 self.file_path = file_path |
| 4027 self.handle_style_error = handle_style_error | 4017 self.handle_style_error = handle_style_error |
| 4028 self.min_confidence = min_confidence | 4018 self.min_confidence = min_confidence |
| 4019 CppChecker.fs = fs or FileSystem() |
| 4029 | 4020 |
| 4030 # Useful for unit testing. | 4021 # Useful for unit testing. |
| 4031 def __eq__(self, other): | 4022 def __eq__(self, other): |
| 4032 """Return whether this CppChecker instance is equal to another.""" | 4023 """Return whether this CppChecker instance is equal to another.""" |
| 4033 if self.file_extension != other.file_extension: | 4024 if self.file_extension != other.file_extension: |
| 4034 return False | 4025 return False |
| 4035 if self.file_path != other.file_path: | 4026 if self.file_path != other.file_path: |
| 4036 return False | 4027 return False |
| 4037 if self.handle_style_error != other.handle_style_error: | 4028 if self.handle_style_error != other.handle_style_error: |
| 4038 return False | 4029 return False |
| 4039 if self.min_confidence != other.min_confidence: | 4030 if self.min_confidence != other.min_confidence: |
| 4040 return False | 4031 return False |
| 4041 | 4032 |
| 4042 return True | 4033 return True |
| 4043 | 4034 |
| 4044 # Useful for unit testing. | 4035 # Useful for unit testing. |
| 4045 def __ne__(self, other): | 4036 def __ne__(self, other): |
| 4046 # Python does not automatically deduce __ne__() from __eq__(). | 4037 # Python does not automatically deduce __ne__() from __eq__(). |
| 4047 return not self.__eq__(other) | 4038 return not self.__eq__(other) |
| 4048 | 4039 |
| 4049 def check(self, lines): | 4040 def check(self, lines): |
| 4050 _process_lines(self.file_path, self.file_extension, lines, | 4041 _process_lines(self.file_path, self.file_extension, lines, |
| 4051 self.handle_style_error, self.min_confidence) | 4042 self.handle_style_error, self.min_confidence) |
| 4052 | 4043 |
| 4053 | 4044 |
| 4054 # FIXME: Remove this function (requires refactoring unit tests). | 4045 # FIXME: Remove this function (requires refactoring unit tests). |
| 4055 def process_file_data(filename, file_extension, lines, error, min_confidence, un
it_test_config): | 4046 def process_file_data(filename, file_extension, lines, error, min_confidence, fs
=None): |
| 4056 global _unit_test_config | 4047 checker = CppChecker(filename, file_extension, error, min_confidence, fs) |
| 4057 _unit_test_config = unit_test_config | |
| 4058 checker = CppChecker(filename, file_extension, error, min_confidence) | |
| 4059 checker.check(lines) | 4048 checker.check(lines) |
| 4060 _unit_test_config = {} | |
| OLD | NEW |