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) |
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) |
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() | |
Dirk Pranke
2013/10/23 17:42:52
Note that this would be problematic if we had mult
| |
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 |