OLD | NEW |
1 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
2 # for details. All rights reserved. Use of this source code is governed by a | 2 # for details. All rights reserved. Use of this source code is governed by a |
3 # BSD-style license that can be found in the LICENSE file. | 3 # BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import os | 5 import os |
6 import cpplint | 6 import cpplint |
7 import re | 7 import re |
8 | 8 |
9 | 9 # memcpy does not handle overlapping memory regions. Even though this |
10 class PathHackException(Exception): | 10 # is well documented it seems to be used in error quite often. To avoid |
11 def __init__(self, error_msg): | 11 # problems we disallow the direct use of memcpy. The exceptions are in |
12 self.error_msg = error_msg | 12 # third-party code and in platform/globals.h which uses it to implement |
13 | 13 # bit_cast and bit_copy. |
14 def __str__(self): | 14 def CheckMemcpy(filename): |
15 return repr(self.error_msg) | 15 if filename.endswith(os.path.join('platform', 'globals.h')) or \ |
16 | 16 filename.find('third_party') != -1: |
17 def AddSvnPathIfNeeded(runtime_path): | 17 return 0 |
18 # Add the .svn into the runtime directory if needed for git or svn 1.7. | 18 fh = open(filename, 'r') |
19 fake_svn_path = os.path.join(runtime_path, '.svn') | 19 content = fh.read() |
20 if os.path.exists(fake_svn_path): | 20 match = re.search('\\bmemcpy\\b', content) |
21 return None | 21 if match: |
22 open(fake_svn_path, 'w').close() | 22 line_number = content[0:match.start()].count('\n') + 1 |
23 return lambda: os.remove(fake_svn_path) | 23 print "%s:%d: use of memcpy is forbidden" % (filename, line_number) |
24 | 24 return 1 |
25 | 25 return 0 |
26 def TrySvnPathHack(parent_path): | |
27 orig_path = os.path.join(parent_path, '.svn') | |
28 renamed_path = os.path.join(parent_path, '.svn_orig') | |
29 if os.path.exists(renamed_path): | |
30 error_msg = '".svn_orig" exists in presubmit parent directory(' | |
31 error_msg += parent_path | |
32 error_msg += '). Consider renaming it manually to ".svn".' | |
33 raise PathHackException(error_msg) | |
34 if os.path.exists(orig_path): | |
35 # Make the parent SVN directory non-discoverable by cpplint to get | |
36 # the correct header guard checks. This is needed if using all Dart | |
37 # checkout. | |
38 os.rename(orig_path, renamed_path) | |
39 return lambda: os.rename(renamed_path, orig_path) | |
40 | 26 |
41 | 27 |
42 def RunLint(input_api, output_api): | 28 def RunLint(input_api, output_api): |
43 result = [] | 29 result = [] |
44 cpplint._cpplint_state.ResetErrorCounts() | 30 cpplint._cpplint_state.ResetErrorCounts() |
45 memcpy_match_count = 0 | 31 memcpy_match_count = 0 |
46 # Find all .cc and .h files in the change list. | 32 # Find all .cc and .h files in the change list. |
47 for svn_file in input_api.AffectedTextFiles(): | 33 for git_file in input_api.AffectedTextFiles(): |
48 filename = svn_file.AbsoluteLocalPath() | 34 filename = git_file.AbsoluteLocalPath() |
49 if filename.endswith('.cc') or filename.endswith('.h'): | 35 if filename.endswith('.cc') or filename.endswith('.h'): |
50 cleanup_parent = None | |
51 cleanup_runtime = None | |
52 try: | |
53 runtime_path = input_api.PresubmitLocalPath() | |
54 parent_path = os.path.dirname(runtime_path) | |
55 if filename.endswith('.h'): | |
56 cleanup_runtime = AddSvnPathIfNeeded(runtime_path) | |
57 cleanup_parent = TrySvnPathHack(parent_path) | |
58 except PathHackException, exception: | |
59 return [output_api.PresubmitError(str(exception))] | |
60 # Run cpplint on the file. | 36 # Run cpplint on the file. |
61 cpplint.ProcessFile(filename, 1) | 37 cpplint.ProcessFile(filename, 1) |
62 if cleanup_parent is not None: | 38 # Check for memcpy use. |
63 cleanup_parent() | 39 memcpy_match_count += CheckMemcpy(filename) |
64 if cleanup_runtime is not None: | |
65 cleanup_runtime() | |
66 # memcpy does not handle overlapping memory regions. Even though this | |
67 # is well documented it seems to be used in error quite often. To avoid | |
68 # problems we disallow the direct use of memcpy. The exceptions are in | |
69 # third-party code and in platform/globals.h which uses it to implement | |
70 # bit_cast and bit_copy. | |
71 if not filename.endswith(os.path.join('platform', 'globals.h')) and \ | |
72 filename.find('third_party') == -1: | |
73 fh = open(filename, 'r') | |
74 content = fh.read() | |
75 match = re.search('\\bmemcpy\\b', content) | |
76 if match: | |
77 line_number = content[0:match.start()].count('\n') + 1 | |
78 print "%s:%d: use of memcpy is forbidden" % (filename, line_number) | |
79 memcpy_match_count += 1 | |
80 | 40 |
81 # Report a presubmit error if any of the files had an error. | 41 # Report a presubmit error if any of the files had an error. |
82 if cpplint._cpplint_state.error_count > 0 or memcpy_match_count > 0: | 42 if cpplint._cpplint_state.error_count > 0 or memcpy_match_count > 0: |
83 result = [output_api.PresubmitError('Failed cpplint check.')] | 43 result = [output_api.PresubmitError('Failed cpplint check.')] |
84 return result | 44 return result |
85 | 45 |
86 | 46 |
87 def CheckChangeOnUpload(input_api, output_api): | 47 def CheckChangeOnUpload(input_api, output_api): |
88 return RunLint(input_api, output_api) | 48 return RunLint(input_api, output_api) |
89 | 49 |
90 | 50 |
91 def CheckChangeOnCommit(input_api, output_api): | 51 def CheckChangeOnCommit(input_api, output_api): |
92 return RunLint(input_api, output_api) | 52 return RunLint(input_api, output_api) |
OLD | NEW |