blob: 9a569234ac7332033177b978ba16f8fdd3741093 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d19842009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5413 r"^breakpad[\\\/].*",
[email protected]40d1dbb2012-10-26 07:18:0014 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
15 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2816 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0817 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5418 r"^skia[\\\/].*",
primiano0166ccc82015-10-06 12:12:2819 r"^third_party[\\\/]WebKit[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
calamity8ec9430c2016-08-23 03:56:2926 r".*vulcanized.html$",
27 r".*crisper.js$",
vapierb2053f542017-03-09 19:46:1028 r"tools[\\\/]md_browser[\\\/].*\.css$",
[email protected]4306417642009-06-11 00:33:4029)
[email protected]ca8d19842009-02-19 16:33:1230
wnwenbdc444e2016-05-25 13:44:1531
[email protected]06e6d0ff2012-12-11 01:36:4432# Fragment of a regular expression that matches C++ and Objective-C++
33# implementation files.
34_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
35
wnwenbdc444e2016-05-25 13:44:1536
[email protected]06e6d0ff2012-12-11 01:36:4437# Regular expression that matches code only used for test binaries
38# (best effort).
39_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4940 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4441 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
sdefresne1fccb0a2016-12-19 08:10:5342 r'.+_(api|browser|eg|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1243 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4444 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4945 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0546 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4947 r'content[\\\/]shell[\\\/].*',
[email protected]7b054982013-11-27 00:44:4748 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4949 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0850 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4951 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4452)
[email protected]ca8d19842009-02-19 16:33:1253
wnwenbdc444e2016-05-25 13:44:1554
[email protected]eea609a2011-11-18 13:10:1255_TEST_ONLY_WARNING = (
56 'You might be calling functions intended only for testing from\n'
57 'production code. It is OK to ignore this warning if you know what\n'
58 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5859 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1260
61
[email protected]cf9b78f2012-11-14 11:40:2862_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4063 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2164 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
65 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2866
wnwenbdc444e2016-05-25 13:44:1567
[email protected]127f18ec2012-06-16 05:05:5968_BANNED_OBJC_FUNCTIONS = (
69 (
70 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2071 (
72 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5973 'prohibited. Please use CrTrackingArea instead.',
74 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
75 ),
76 False,
77 ),
78 (
[email protected]eaae1972014-04-16 04:17:2679 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:2080 (
81 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5982 'instead.',
83 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
84 ),
85 False,
86 ),
87 (
88 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2089 (
90 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5991 'Please use |convertPoint:(point) fromView:nil| instead.',
92 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
93 ),
94 True,
95 ),
96 (
97 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:2098 (
99 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59100 'Please use |convertPoint:(point) toView:nil| instead.',
101 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
102 ),
103 True,
104 ),
105 (
106 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20107 (
108 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59109 'Please use |convertRect:(point) fromView:nil| instead.',
110 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
111 ),
112 True,
113 ),
114 (
115 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20116 (
117 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59118 'Please use |convertRect:(point) toView:nil| instead.',
119 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
120 ),
121 True,
122 ),
123 (
124 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20125 (
126 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59127 'Please use |convertSize:(point) fromView:nil| instead.',
128 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
129 ),
130 True,
131 ),
132 (
133 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20134 (
135 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59136 'Please use |convertSize:(point) toView:nil| instead.',
137 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
138 ),
139 True,
140 ),
jif65398702016-10-27 10:19:48141 (
142 r"/\s+UTF8String\s*]",
143 (
144 'The use of -[NSString UTF8String] is dangerous as it can return null',
145 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
146 'Please use |SysNSStringToUTF8| instead.',
147 ),
148 True,
149 ),
[email protected]127f18ec2012-06-16 05:05:59150)
151
152
153_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20154 # Make sure that gtest's FRIEND_TEST() macro is not used; the
155 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30156 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20157 (
158 'FRIEND_TEST(',
159 (
[email protected]e3c945502012-06-26 20:01:49160 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20161 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
162 ),
163 False,
[email protected]7345da02012-11-27 14:31:49164 (),
[email protected]23e6cbc2012-06-16 18:51:20165 ),
166 (
thomasanderson4b569052016-09-14 20:15:53167 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
168 (
169 'Chrome clients wishing to select events on X windows should use',
170 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
171 'you are selecting events from the GPU process, or if you are using',
172 'an XDisplay other than gfx::GetXDisplay().',
173 ),
174 True,
175 (
176 r"^ui[\\\/]gl[\\\/].*\.cc$",
177 r"^media[\\\/]gpu[\\\/].*\.cc$",
178 r"^gpu[\\\/].*\.cc$",
179 ),
180 ),
181 (
[email protected]23e6cbc2012-06-16 18:51:20182 'ScopedAllowIO',
183 (
[email protected]e3c945502012-06-26 20:01:49184 'New code should not use ScopedAllowIO. Post a task to the blocking',
185 'pool or the FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20186 ),
[email protected]e3c945502012-06-26 20:01:49187 True,
[email protected]7345da02012-11-27 14:31:49188 (
hajimehoshi2acea432017-03-08 08:55:37189 r"^base[\\\/]memory[\\\/]shared_memory_posix\.cc$",
nyad2c548b2015-12-09 03:22:32190 r"^base[\\\/]process[\\\/]process_linux\.cc$",
thestig75844fdb2014-09-09 19:47:10191 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
tfarina0923ac52015-01-07 03:21:22192 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
sky0e07a142016-03-25 21:27:31193 r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$",
alematee4016bb2014-11-12 17:38:51194 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
195 "customization_document_browsertest\.cc$",
philipj3f9d5bde2014-08-28 14:09:09196 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49197 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
198 r"test_info_extractor\.cc$",
lukasza7947ccd2016-07-28 21:56:25199 r"^content[\\\/].*browser(|_)test[a-zA-Z_]*\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41200 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
201 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
lukasza7947ccd2016-07-28 21:56:25202 r"^content[\\\/]test[\\\/]ppapi[\\\/]ppapi_test\.cc$",
jamesra03ae492014-10-03 04:26:48203 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
204 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01205 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
lukasza7947ccd2016-07-28 21:56:25206 r"^net[\\\/]cert[\\\/]test_root_certs\.cc$",
207 r"^net[\\\/]test[\\\/]embedded_test_server[\\\/]" +
208 r"embedded_test_server\.cc$",
209 r"^net[\\\/]test[\\\/]spawned_test_server[\\\/]local_test_server\.cc$",
210 r"^net[\\\/]test[\\\/]test_data_directory\.cc$",
[email protected]1f52a572014-05-12 23:21:54211 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
sergeyu2c41f9842016-12-10 01:45:16212 r"^remoting[\\\/]protocol[\\\/]webrtc_transport\.cc$",
lambroslambrouf6fb94ea2016-06-27 21:21:53213 r"^ui[\\\/]base[\\\/]material_design[\\\/]"
214 "material_design_controller\.cc$",
kylechar16666242016-07-04 20:54:45215 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_mac\.cc$",
216 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_win\.cc$",
217 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_x11\.cc$",
218 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
219 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49220 ),
[email protected]23e6cbc2012-06-16 18:51:20221 ),
[email protected]52657f62013-05-20 05:30:31222 (
tomhudsone2c14d552016-05-26 17:07:46223 'setMatrixClip',
224 (
225 'Overriding setMatrixClip() is prohibited; ',
226 'the base function is deprecated. ',
227 ),
228 True,
229 (),
230 ),
231 (
[email protected]52657f62013-05-20 05:30:31232 'SkRefPtr',
233 (
234 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22235 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31236 ),
237 True,
238 (),
239 ),
240 (
241 'SkAutoRef',
242 (
243 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22244 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31245 ),
246 True,
247 (),
248 ),
249 (
250 'SkAutoTUnref',
251 (
252 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22253 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31254 ),
255 True,
256 (),
257 ),
258 (
259 'SkAutoUnref',
260 (
261 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
262 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22263 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31264 ),
265 True,
266 (),
267 ),
[email protected]d89eec82013-12-03 14:10:59268 (
269 r'/HANDLE_EINTR\(.*close',
270 (
271 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
272 'descriptor will be closed, and it is incorrect to retry the close.',
273 'Either call close directly and ignore its return value, or wrap close',
274 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
275 ),
276 True,
277 (),
278 ),
279 (
280 r'/IGNORE_EINTR\((?!.*close)',
281 (
282 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
283 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
284 ),
285 True,
286 (
287 # Files that #define IGNORE_EINTR.
288 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
289 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
290 ),
291 ),
[email protected]ec5b3f02014-04-04 18:43:43292 (
293 r'/v8::Extension\(',
294 (
295 'Do not introduce new v8::Extensions into the code base, use',
296 'gin::Wrappable instead. See http://crbug.com/334679',
297 ),
298 True,
[email protected]f55c90ee62014-04-12 00:50:03299 (
joaodasilva718f87672014-08-30 09:25:49300 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03301 ),
[email protected]ec5b3f02014-04-04 18:43:43302 ),
skyostilf9469f72015-04-20 10:38:52303 (
jame2d1a952016-04-02 00:27:10304 '#pragma comment(lib,',
305 (
306 'Specify libraries to link with in build files and not in the source.',
307 ),
308 True,
309 (),
310 ),
[email protected]127f18ec2012-06-16 05:05:59311)
312
wnwenbdc444e2016-05-25 13:44:15313
mlamouria82272622014-09-16 18:45:04314_IPC_ENUM_TRAITS_DEPRECATED = (
315 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
316 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
317
[email protected]127f18ec2012-06-16 05:05:59318
[email protected]b00342e7f2013-03-26 16:21:54319_VALID_OS_MACROS = (
320 # Please keep sorted.
321 'OS_ANDROID',
322 'OS_BSD',
323 'OS_CAT', # For testing.
324 'OS_CHROMEOS',
325 'OS_FREEBSD',
326 'OS_IOS',
327 'OS_LINUX',
328 'OS_MACOSX',
329 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21330 'OS_NACL_NONSFI',
331 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12332 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54333 'OS_OPENBSD',
334 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37335 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54336 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54337 'OS_WIN',
338)
339
340
agrievef32bcc72016-04-04 14:57:40341_ANDROID_SPECIFIC_PYDEPS_FILES = [
342 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04343 'build/android/test_wrapper/logdog_wrapper.pydeps',
agrieve732db3a2016-04-26 19:18:19344 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40345]
346
wnwenbdc444e2016-05-25 13:44:15347
agrievef32bcc72016-04-04 14:57:40348_GENERIC_PYDEPS_FILES = [
agrievef32bcc72016-04-04 14:57:40349]
350
wnwenbdc444e2016-05-25 13:44:15351
agrievef32bcc72016-04-04 14:57:40352_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
353
354
[email protected]55459852011-08-10 15:17:19355def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
356 """Attempts to prevent use of functions intended only for testing in
357 non-testing code. For now this is just a best-effort implementation
358 that ignores header files and may have some false positives. A
359 better implementation would probably need a proper C++ parser.
360 """
361 # We only scan .cc files and the like, as the declaration of
362 # for-testing functions in header files are hard to distinguish from
363 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44364 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19365
jochenc0d4808c2015-07-27 09:25:42366 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19367 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09368 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19369 exclusion_pattern = input_api.re.compile(
370 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
371 base_function_pattern, base_function_pattern))
372
373 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44374 black_list = (_EXCLUDED_PATHS +
375 _TEST_CODE_EXCLUDED_PATHS +
376 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19377 return input_api.FilterSourceFile(
378 affected_file,
379 white_list=(file_inclusion_pattern, ),
380 black_list=black_list)
381
382 problems = []
383 for f in input_api.AffectedSourceFiles(FilterFile):
384 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24385 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03386 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46387 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03388 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19389 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03390 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19391
392 if problems:
[email protected]f7051d52013-04-02 18:31:42393 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03394 else:
395 return []
[email protected]55459852011-08-10 15:17:19396
397
[email protected]10689ca2011-09-02 02:31:54398def _CheckNoIOStreamInHeaders(input_api, output_api):
399 """Checks to make sure no .h files include <iostream>."""
400 files = []
401 pattern = input_api.re.compile(r'^#include\s*<iostream>',
402 input_api.re.MULTILINE)
403 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
404 if not f.LocalPath().endswith('.h'):
405 continue
406 contents = input_api.ReadFile(f)
407 if pattern.search(contents):
408 files.append(f)
409
410 if len(files):
yolandyandaabc6d2016-04-18 18:29:39411 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06412 'Do not #include <iostream> in header files, since it inserts static '
413 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54414 '#include <ostream>. See http://crbug.com/94794',
415 files) ]
416 return []
417
418
[email protected]72df4e782012-06-21 16:28:18419def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52420 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18421 problems = []
422 for f in input_api.AffectedFiles():
423 if (not f.LocalPath().endswith(('.cc', '.mm'))):
424 continue
425
426 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04427 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18428 problems.append(' %s:%d' % (f.LocalPath(), line_num))
429
430 if not problems:
431 return []
432 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
433 '\n'.join(problems))]
434
435
danakj61c1aa22015-10-26 19:55:52436def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57437 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52438 errors = []
439 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
440 input_api.re.MULTILINE)
441 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
442 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
443 continue
444 for lnum, line in f.ChangedContents():
445 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17446 errors.append(output_api.PresubmitError(
447 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57448 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17449 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52450 return errors
451
452
mcasasb7440c282015-02-04 14:52:19453def _FindHistogramNameInLine(histogram_name, line):
454 """Tries to find a histogram name or prefix in a line."""
455 if not "affected-histogram" in line:
456 return histogram_name in line
457 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
458 # the histogram_name.
459 if not '"' in line:
460 return False
461 histogram_prefix = line.split('\"')[1]
462 return histogram_prefix in histogram_name
463
464
465def _CheckUmaHistogramChanges(input_api, output_api):
466 """Check that UMA histogram names in touched lines can still be found in other
467 lines of the patch or in histograms.xml. Note that this check would not catch
468 the reverse: changes in histograms.xml not matched in the code itself."""
469 touched_histograms = []
470 histograms_xml_modifications = []
471 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
472 for f in input_api.AffectedFiles():
473 # If histograms.xml itself is modified, keep the modified lines for later.
474 if f.LocalPath().endswith(('histograms.xml')):
475 histograms_xml_modifications = f.ChangedContents()
476 continue
477 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
478 continue
479 for line_num, line in f.ChangedContents():
480 found = pattern.search(line)
481 if found:
482 touched_histograms.append([found.group(1), f, line_num])
483
484 # Search for the touched histogram names in the local modifications to
485 # histograms.xml, and, if not found, on the base histograms.xml file.
486 unmatched_histograms = []
487 for histogram_info in touched_histograms:
488 histogram_name_found = False
489 for line_num, line in histograms_xml_modifications:
490 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
491 if histogram_name_found:
492 break
493 if not histogram_name_found:
494 unmatched_histograms.append(histogram_info)
495
eromanb90c82e7e32015-04-01 15:13:49496 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19497 problems = []
498 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49499 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19500 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45501 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19502 histogram_name_found = False
503 for line in histograms_xml:
504 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
505 if histogram_name_found:
506 break
507 if not histogram_name_found:
508 problems.append(' [%s:%d] %s' %
509 (f.LocalPath(), line_num, histogram_name))
510
511 if not problems:
512 return []
513 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
514 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49515 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19516
wnwenbdc444e2016-05-25 13:44:15517
yolandyandaabc6d2016-04-18 18:29:39518def _CheckFlakyTestUsage(input_api, output_api):
519 """Check that FlakyTest annotation is our own instead of the android one"""
520 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
521 files = []
522 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
523 if f.LocalPath().endswith('Test.java'):
524 if pattern.search(input_api.ReadFile(f)):
525 files.append(f)
526 if len(files):
527 return [output_api.PresubmitError(
528 'Use org.chromium.base.test.util.FlakyTest instead of '
529 'android.test.FlakyTest',
530 files)]
531 return []
mcasasb7440c282015-02-04 14:52:19532
wnwenbdc444e2016-05-25 13:44:15533
[email protected]8ea5d4b2011-09-13 21:49:22534def _CheckNoNewWStrings(input_api, output_api):
535 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27536 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22537 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20538 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57539 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34540 '/win/' in f.LocalPath() or
541 'chrome_elf' in f.LocalPath() or
542 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20543 continue
[email protected]8ea5d4b2011-09-13 21:49:22544
[email protected]a11dbe9b2012-08-07 01:32:58545 allowWString = False
[email protected]b5c24292011-11-28 14:38:20546 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58547 if 'presubmit: allow wstring' in line:
548 allowWString = True
549 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27550 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58551 allowWString = False
552 else:
553 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22554
[email protected]55463aa62011-10-12 00:48:27555 if not problems:
556 return []
557 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58558 ' If you are calling a cross-platform API that accepts a wstring, '
559 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27560 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22561
562
[email protected]2a8ac9c2011-10-19 17:20:44563def _CheckNoDEPSGIT(input_api, output_api):
564 """Make sure .DEPS.git is never modified manually."""
565 if any(f.LocalPath().endswith('.DEPS.git') for f in
566 input_api.AffectedFiles()):
567 return [output_api.PresubmitError(
568 'Never commit changes to .DEPS.git. This file is maintained by an\n'
569 'automated system based on what\'s in DEPS and your changes will be\n'
570 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34571 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:44572 'for more information')]
573 return []
574
575
tandriief664692014-09-23 14:51:47576def _CheckValidHostsInDEPS(input_api, output_api):
577 """Checks that DEPS file deps are from allowed_hosts."""
578 # Run only if DEPS file has been modified to annoy fewer bystanders.
579 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
580 return []
581 # Outsource work to gclient verify
582 try:
583 input_api.subprocess.check_output(['gclient', 'verify'])
584 return []
585 except input_api.subprocess.CalledProcessError, error:
586 return [output_api.PresubmitError(
587 'DEPS file must have only git dependencies.',
588 long_text=error.output)]
589
590
[email protected]127f18ec2012-06-16 05:05:59591def _CheckNoBannedFunctions(input_api, output_api):
592 """Make sure that banned functions are not used."""
593 warnings = []
594 errors = []
595
wnwenbdc444e2016-05-25 13:44:15596 def IsBlacklisted(affected_file, blacklist):
597 local_path = affected_file.LocalPath()
598 for item in blacklist:
599 if input_api.re.match(item, local_path):
600 return True
601 return False
602
603 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
604 matched = False
605 if func_name[0:1] == '/':
606 regex = func_name[1:]
607 if input_api.re.search(regex, line):
608 matched = True
609 elif func_name in line:
dchenge07de812016-06-20 19:27:17610 matched = True
wnwenbdc444e2016-05-25 13:44:15611 if matched:
dchenge07de812016-06-20 19:27:17612 problems = warnings
wnwenbdc444e2016-05-25 13:44:15613 if error:
dchenge07de812016-06-20 19:27:17614 problems = errors
wnwenbdc444e2016-05-25 13:44:15615 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
616 for message_line in message:
617 problems.append(' %s' % message_line)
618
[email protected]127f18ec2012-06-16 05:05:59619 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
620 for f in input_api.AffectedFiles(file_filter=file_filter):
621 for line_num, line in f.ChangedContents():
622 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:15623 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59624
625 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
626 for f in input_api.AffectedFiles(file_filter=file_filter):
627 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49628 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:49629 if IsBlacklisted(f, excluded_paths):
630 continue
wnwenbdc444e2016-05-25 13:44:15631 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59632
633 result = []
634 if (warnings):
635 result.append(output_api.PresubmitPromptWarning(
636 'Banned functions were used.\n' + '\n'.join(warnings)))
637 if (errors):
638 result.append(output_api.PresubmitError(
639 'Banned functions were used.\n' + '\n'.join(errors)))
640 return result
641
642
[email protected]6c063c62012-07-11 19:11:06643def _CheckNoPragmaOnce(input_api, output_api):
644 """Make sure that banned functions are not used."""
645 files = []
646 pattern = input_api.re.compile(r'^#pragma\s+once',
647 input_api.re.MULTILINE)
648 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
649 if not f.LocalPath().endswith('.h'):
650 continue
651 contents = input_api.ReadFile(f)
652 if pattern.search(contents):
653 files.append(f)
654
655 if files:
656 return [output_api.PresubmitError(
657 'Do not use #pragma once in header files.\n'
658 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
659 files)]
660 return []
661
[email protected]127f18ec2012-06-16 05:05:59662
[email protected]e7479052012-09-19 00:26:12663def _CheckNoTrinaryTrueFalse(input_api, output_api):
664 """Checks to make sure we don't introduce use of foo ? true : false."""
665 problems = []
666 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
667 for f in input_api.AffectedFiles():
668 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
669 continue
670
671 for line_num, line in f.ChangedContents():
672 if pattern.match(line):
673 problems.append(' %s:%d' % (f.LocalPath(), line_num))
674
675 if not problems:
676 return []
677 return [output_api.PresubmitPromptWarning(
678 'Please consider avoiding the "? true : false" pattern if possible.\n' +
679 '\n'.join(problems))]
680
681
[email protected]55f9f382012-07-31 11:02:18682def _CheckUnwantedDependencies(input_api, output_api):
683 """Runs checkdeps on #include statements added in this
684 change. Breaking - rules is an error, breaking ! rules is a
685 warning.
686 """
mohan.reddyf21db962014-10-16 12:26:47687 import sys
[email protected]55f9f382012-07-31 11:02:18688 # We need to wait until we have an input_api object and use this
689 # roundabout construct to import checkdeps because this file is
690 # eval-ed and thus doesn't have __file__.
691 original_sys_path = sys.path
692 try:
693 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47694 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18695 import checkdeps
696 from cpp_checker import CppChecker
697 from rules import Rule
698 finally:
699 # Restore sys.path to what it was before.
700 sys.path = original_sys_path
701
702 added_includes = []
703 for f in input_api.AffectedFiles():
704 if not CppChecker.IsCppFile(f.LocalPath()):
705 continue
706
707 changed_lines = [line for line_num, line in f.ChangedContents()]
708 added_includes.append([f.LocalPath(), changed_lines])
709
[email protected]26385172013-05-09 23:11:35710 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18711
712 error_descriptions = []
713 warning_descriptions = []
714 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
715 added_includes):
716 description_with_path = '%s\n %s' % (path, rule_description)
717 if rule_type == Rule.DISALLOW:
718 error_descriptions.append(description_with_path)
719 else:
720 warning_descriptions.append(description_with_path)
721
722 results = []
723 if error_descriptions:
724 results.append(output_api.PresubmitError(
725 'You added one or more #includes that violate checkdeps rules.',
726 error_descriptions))
727 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42728 results.append(output_api.PresubmitPromptOrNotify(
[email protected]55f9f382012-07-31 11:02:18729 'You added one or more #includes of files that are temporarily\n'
730 'allowed but being removed. Can you avoid introducing the\n'
731 '#include? See relevant DEPS file(s) for details and contacts.',
732 warning_descriptions))
733 return results
734
735
[email protected]fbcafe5a2012-08-08 15:31:22736def _CheckFilePermissions(input_api, output_api):
737 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15738 if input_api.platform == 'win32':
739 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29740 checkperms_tool = input_api.os_path.join(
741 input_api.PresubmitLocalPath(),
742 'tools', 'checkperms', 'checkperms.py')
743 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47744 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22745 for f in input_api.AffectedFiles():
746 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11747 try:
748 input_api.subprocess.check_output(args)
749 return []
750 except input_api.subprocess.CalledProcessError as error:
751 return [output_api.PresubmitError(
752 'checkperms.py failed:',
753 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22754
755
robertocn832f5992017-01-04 19:01:30756def _CheckTeamTags(input_api, output_api):
757 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
758 checkteamtags_tool = input_api.os_path.join(
759 input_api.PresubmitLocalPath(),
760 'tools', 'checkteamtags', 'checkteamtags.py')
761 args = [input_api.python_executable, checkteamtags_tool,
762 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:22763 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:30764 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
765 'OWNERS']
766 try:
767 if files:
768 input_api.subprocess.check_output(args + files)
769 return []
770 except input_api.subprocess.CalledProcessError as error:
771 return [output_api.PresubmitError(
772 'checkteamtags.py failed:',
773 long_text=error.output)]
774
775
[email protected]c8278b32012-10-30 20:35:49776def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
777 """Makes sure we don't include ui/aura/window_property.h
778 in header files.
779 """
780 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
781 errors = []
782 for f in input_api.AffectedFiles():
783 if not f.LocalPath().endswith('.h'):
784 continue
785 for line_num, line in f.ChangedContents():
786 if pattern.match(line):
787 errors.append(' %s:%d' % (f.LocalPath(), line_num))
788
789 results = []
790 if errors:
791 results.append(output_api.PresubmitError(
792 'Header files should not include ui/aura/window_property.h', errors))
793 return results
794
795
[email protected]cf9b78f2012-11-14 11:40:28796def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
797 """Checks that the lines in scope occur in the right order.
798
799 1. C system files in alphabetical order
800 2. C++ system files in alphabetical order
801 3. Project's .h files
802 """
803
804 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
805 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
806 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
807
808 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
809
810 state = C_SYSTEM_INCLUDES
811
812 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57813 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28814 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55815 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28816 for line_num, line in scope:
817 if c_system_include_pattern.match(line):
818 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55819 problem_linenums.append((line_num, previous_line_num,
820 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28821 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55822 problem_linenums.append((line_num, previous_line_num,
823 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28824 elif cpp_system_include_pattern.match(line):
825 if state == C_SYSTEM_INCLUDES:
826 state = CPP_SYSTEM_INCLUDES
827 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55828 problem_linenums.append((line_num, previous_line_num,
829 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28830 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55831 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28832 elif custom_include_pattern.match(line):
833 if state != CUSTOM_INCLUDES:
834 state = CUSTOM_INCLUDES
835 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55836 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28837 else:
brucedawson70fadb02015-06-30 17:47:55838 problem_linenums.append((line_num, previous_line_num,
839 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28840 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57841 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28842
843 warnings = []
brucedawson70fadb02015-06-30 17:47:55844 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57845 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55846 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28847 return warnings
848
849
[email protected]ac294a12012-12-06 16:38:43850def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28851 """Checks the #include order for the given file f."""
852
[email protected]2299dcf2012-11-15 19:56:24853 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30854 # Exclude the following includes from the check:
855 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
856 # specific order.
857 # 2) <atlbase.h>, "build/build_config.h"
858 excluded_include_pattern = input_api.re.compile(
859 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24860 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33861 # Match the final or penultimate token if it is xxxtest so we can ignore it
862 # when considering the special first include.
863 test_file_tag_pattern = input_api.re.compile(
864 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11865 if_pattern = input_api.re.compile(
866 r'\s*#\s*(if|elif|else|endif|define|undef).*')
867 # Some files need specialized order of includes; exclude such files from this
868 # check.
869 uncheckable_includes_pattern = input_api.re.compile(
870 r'\s*#include '
871 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28872
873 contents = f.NewContents()
874 warnings = []
875 line_num = 0
876
[email protected]ac294a12012-12-06 16:38:43877 # Handle the special first include. If the first include file is
878 # some/path/file.h, the corresponding including file can be some/path/file.cc,
879 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
880 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33881 # If the included file is some/path/file_platform.h the including file could
882 # also be some/path/file_xxxtest_platform.h.
883 including_file_base_name = test_file_tag_pattern.sub(
884 '', input_api.os_path.basename(f.LocalPath()))
885
[email protected]ac294a12012-12-06 16:38:43886 for line in contents:
887 line_num += 1
888 if system_include_pattern.match(line):
889 # No special first include -> process the line again along with normal
890 # includes.
891 line_num -= 1
892 break
893 match = custom_include_pattern.match(line)
894 if match:
895 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33896 header_basename = test_file_tag_pattern.sub(
897 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
898
899 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24900 # No special first include -> process the line again along with normal
901 # includes.
902 line_num -= 1
[email protected]ac294a12012-12-06 16:38:43903 break
[email protected]cf9b78f2012-11-14 11:40:28904
905 # Split into scopes: Each region between #if and #endif is its own scope.
906 scopes = []
907 current_scope = []
908 for line in contents[line_num:]:
909 line_num += 1
[email protected]0e5c1852012-12-18 20:17:11910 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:54911 continue
[email protected]2309b0fa02012-11-16 12:18:27912 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:28913 scopes.append(current_scope)
914 current_scope = []
[email protected]962f117e2012-11-22 18:11:56915 elif ((system_include_pattern.match(line) or
916 custom_include_pattern.match(line)) and
917 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:28918 current_scope.append((line_num, line))
919 scopes.append(current_scope)
920
921 for scope in scopes:
922 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
923 changed_linenums))
924 return warnings
925
926
927def _CheckIncludeOrder(input_api, output_api):
928 """Checks that the #include order is correct.
929
930 1. The corresponding header for source files.
931 2. C system files in alphabetical order
932 3. C++ system files in alphabetical order
933 4. Project's .h files in alphabetical order
934
[email protected]ac294a12012-12-06 16:38:43935 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
936 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:28937 """
[email protected]e120b012014-08-15 19:08:35938 def FileFilterIncludeOrder(affected_file):
939 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
940 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:28941
942 warnings = []
[email protected]e120b012014-08-15 19:08:35943 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:08944 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:43945 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
946 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:28947
948 results = []
949 if warnings:
[email protected]f7051d52013-04-02 18:31:42950 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:53951 warnings))
[email protected]cf9b78f2012-11-14 11:40:28952 return results
953
954
[email protected]70ca77752012-11-20 03:45:03955def _CheckForVersionControlConflictsInFile(input_api, f):
956 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
957 errors = []
958 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23959 if f.LocalPath().endswith('.md'):
960 # First-level headers in markdown look a lot like version control
961 # conflict markers. http://daringfireball.net/projects/markdown/basics
962 continue
[email protected]70ca77752012-11-20 03:45:03963 if pattern.match(line):
964 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
965 return errors
966
967
968def _CheckForVersionControlConflicts(input_api, output_api):
969 """Usually this is not intentional and will cause a compile failure."""
970 errors = []
971 for f in input_api.AffectedFiles():
972 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
973
974 results = []
975 if errors:
976 results.append(output_api.PresubmitError(
977 'Version control conflict markers found, please resolve.', errors))
978 return results
979
estadee17314a02017-01-12 16:22:16980def _CheckGoogleSupportAnswerUrl(input_api, output_api):
981 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
982 errors = []
983 for f in input_api.AffectedFiles():
984 for line_num, line in f.ChangedContents():
985 if pattern.search(line):
986 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
987
988 results = []
989 if errors:
990 results.append(output_api.PresubmitPromptWarning(
991 'Found Google support URL addressed by answer number. Please replace with '
992 'a p= identifier instead. See crbug.com/679462\n', errors))
993 return results
994
[email protected]70ca77752012-11-20 03:45:03995
[email protected]06e6d0ff2012-12-11 01:36:44996def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
997 def FilterFile(affected_file):
998 """Filter function for use with input_api.AffectedSourceFiles,
999 below. This filters out everything except non-test files from
1000 top-level directories that generally speaking should not hard-code
1001 service URLs (e.g. src/android_webview/, src/content/ and others).
1002 """
1003 return input_api.FilterSourceFile(
1004 affected_file,
[email protected]78bb39d62012-12-11 15:11:561005 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:441006 black_list=(_EXCLUDED_PATHS +
1007 _TEST_CODE_EXCLUDED_PATHS +
1008 input_api.DEFAULT_BLACK_LIST))
1009
reillyi38965732015-11-16 18:27:331010 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1011 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461012 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1013 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441014 problems = [] # items are (filename, line_number, line)
1015 for f in input_api.AffectedSourceFiles(FilterFile):
1016 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461017 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441018 problems.append((f.LocalPath(), line_num, line))
1019
1020 if problems:
[email protected]f7051d52013-04-02 18:31:421021 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441022 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581023 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441024 [' %s:%d: %s' % (
1025 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031026 else:
1027 return []
[email protected]06e6d0ff2012-12-11 01:36:441028
1029
[email protected]d2530012013-01-25 16:39:271030def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1031 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311032 The native_client_sdk directory is excluded because it has auto-generated PNG
1033 files for documentation.
[email protected]d2530012013-01-25 16:39:271034 """
[email protected]d2530012013-01-25 16:39:271035 errors = []
binji0dcdf342014-12-12 18:32:311036 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
1037 black_list = (r'^native_client_sdk[\\\/]',)
1038 file_filter = lambda f: input_api.FilterSourceFile(
1039 f, white_list=white_list, black_list=black_list)
1040 for f in input_api.AffectedFiles(include_deletes=False,
1041 file_filter=file_filter):
1042 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271043
1044 results = []
1045 if errors:
1046 results.append(output_api.PresubmitError(
1047 'The name of PNG files should not have abbreviations. \n'
1048 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1049 'Contact [email protected] if you have questions.', errors))
1050 return results
1051
1052
ksakamotob89c4322017-03-23 04:39:101053def _FilesToCheckForIncomingDeps(re, changed_lines):
[email protected]f32e2d1e2013-07-26 21:39:081054 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411055 a set of DEPS entries that we should look up.
1056
1057 For a directory (rather than a specific filename) we fake a path to
1058 a specific filename by adding /DEPS. This is chosen as a file that
1059 will seldom or never be subject to per-file include_rules.
1060 """
[email protected]2b438d62013-11-14 17:54:141061 # We ignore deps entries on auto-generated directories.
1062 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081063
ksakamotob89c4322017-03-23 04:39:101064 # This pattern grabs the path without basename in the first
1065 # parentheses, and the basename (if present) in the second. It
1066 # relies on the simple heuristic that if there is a basename it will
1067 # be a header file ending in ".h".
1068 pattern = re.compile(
1069 r"""['"]\+([^'"]+?)(/[a-zA-Z0-9_]+\.h)?['"].*""")
[email protected]2b438d62013-11-14 17:54:141070 results = set()
ksakamotob89c4322017-03-23 04:39:101071 for changed_line in changed_lines:
1072 m = pattern.match(changed_line)
1073 if m:
1074 path = m.group(1)
1075 if path.split('/')[0] not in AUTO_GENERATED_DIRS:
1076 if m.group(2):
1077 results.add('%s%s' % (path, m.group(2)))
1078 else:
1079 results.add('%s/DEPS' % path)
[email protected]f32e2d1e2013-07-26 21:39:081080 return results
1081
1082
[email protected]e871964c2013-05-13 14:14:551083def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1084 """When a dependency prefixed with + is added to a DEPS file, we
1085 want to make sure that the change is reviewed by an OWNER of the
1086 target file or directory, to avoid layering violations from being
1087 introduced. This check verifies that this happens.
1088 """
ksakamotob89c4322017-03-23 04:39:101089 changed_lines = set()
jochen53efcdd2016-01-29 05:09:241090
1091 file_filter = lambda f: not input_api.re.match(
1092 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1093 for f in input_api.AffectedFiles(include_deletes=False,
1094 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551095 filename = input_api.os_path.basename(f.LocalPath())
1096 if filename == 'DEPS':
ksakamotob89c4322017-03-23 04:39:101097 changed_lines |= set(line.strip()
1098 for line_num, line
1099 in f.ChangedContents())
1100 if not changed_lines:
1101 return []
[email protected]e871964c2013-05-13 14:14:551102
ksakamotob89c4322017-03-23 04:39:101103 virtual_depended_on_files = _FilesToCheckForIncomingDeps(input_api.re,
1104 changed_lines)
[email protected]e871964c2013-05-13 14:14:551105 if not virtual_depended_on_files:
1106 return []
1107
1108 if input_api.is_committing:
1109 if input_api.tbr:
1110 return [output_api.PresubmitNotifyResult(
1111 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271112 if input_api.dry_run:
1113 return [output_api.PresubmitNotifyResult(
1114 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551115 if not input_api.change.issue:
1116 return [output_api.PresubmitError(
1117 "DEPS approval by OWNERS check failed: this change has "
1118 "no Rietveld issue number, so we can't check it for approvals.")]
1119 output = output_api.PresubmitError
1120 else:
1121 output = output_api.PresubmitNotifyResult
1122
1123 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501124 owner_email, reviewers = (
1125 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1126 input_api,
1127 owners_db.email_regexp,
1128 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551129
1130 owner_email = owner_email or input_api.change.author_email
1131
[email protected]de4f7d22013-05-23 14:27:461132 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511133 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461134 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551135 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1136 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411137
1138 # We strip the /DEPS part that was added by
1139 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1140 # directory.
1141 def StripDeps(path):
1142 start_deps = path.rfind('/DEPS')
1143 if start_deps != -1:
1144 return path[:start_deps]
1145 else:
1146 return path
1147 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551148 for path in missing_files]
1149
1150 if unapproved_dependencies:
1151 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151152 output('You need LGTM from owners of depends-on paths in DEPS that were '
1153 'modified in this CL:\n %s' %
1154 '\n '.join(sorted(unapproved_dependencies)))]
1155 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1156 output_list.append(output(
1157 'Suggested missing target path OWNERS:\n %s' %
1158 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551159 return output_list
1160
1161 return []
1162
1163
[email protected]85218562013-11-22 07:41:401164def _CheckSpamLogging(input_api, output_api):
1165 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1166 black_list = (_EXCLUDED_PATHS +
1167 _TEST_CODE_EXCLUDED_PATHS +
1168 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501169 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191170 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481171 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461172 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121173 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1174 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581175 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161176 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031177 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151178 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1179 r"^chromecast[\\\/]",
1180 r"^cloud_print[\\\/]",
jochen34415e52015-07-10 08:34:311181 r"^components[\\\/]html_viewer[\\\/]"
1182 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461183 # TODO(peter): Remove this exception. https://crbug.com/534537
1184 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1185 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251186 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1187 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241188 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111189 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151190 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111191 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521192 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501193 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361194 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311195 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131196 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001197 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441198 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451199 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021200 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351201 r"dump_file_system.cc$",
1202 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401203 source_file_filter = lambda x: input_api.FilterSourceFile(
1204 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1205
1206 log_info = []
1207 printf = []
1208
1209 for f in input_api.AffectedSourceFiles(source_file_filter):
1210 contents = input_api.ReadFile(f, 'rb')
mohan.reddyf21db962014-10-16 12:26:471211 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", contents):
[email protected]85218562013-11-22 07:41:401212 log_info.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471213 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", contents):
[email protected]85210652013-11-28 05:50:131214 log_info.append(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371215
mohan.reddyf21db962014-10-16 12:26:471216 if input_api.re.search(r"\bprintf\(", contents):
[email protected]18b466b2013-12-02 22:01:371217 printf.append(f.LocalPath())
mohan.reddyf21db962014-10-16 12:26:471218 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", contents):
[email protected]85218562013-11-22 07:41:401219 printf.append(f.LocalPath())
1220
1221 if log_info:
1222 return [output_api.PresubmitError(
1223 'These files spam the console log with LOG(INFO):',
1224 items=log_info)]
1225 if printf:
1226 return [output_api.PresubmitError(
1227 'These files spam the console log with printf/fprintf:',
1228 items=printf)]
1229 return []
1230
1231
[email protected]49aa76a2013-12-04 06:59:161232def _CheckForAnonymousVariables(input_api, output_api):
1233 """These types are all expected to hold locks while in scope and
1234 so should never be anonymous (which causes them to be immediately
1235 destroyed)."""
1236 they_who_must_be_named = [
1237 'base::AutoLock',
1238 'base::AutoReset',
1239 'base::AutoUnlock',
1240 'SkAutoAlphaRestore',
1241 'SkAutoBitmapShaderInstall',
1242 'SkAutoBlitterChoose',
1243 'SkAutoBounderCommit',
1244 'SkAutoCallProc',
1245 'SkAutoCanvasRestore',
1246 'SkAutoCommentBlock',
1247 'SkAutoDescriptor',
1248 'SkAutoDisableDirectionCheck',
1249 'SkAutoDisableOvalCheck',
1250 'SkAutoFree',
1251 'SkAutoGlyphCache',
1252 'SkAutoHDC',
1253 'SkAutoLockColors',
1254 'SkAutoLockPixels',
1255 'SkAutoMalloc',
1256 'SkAutoMaskFreeImage',
1257 'SkAutoMutexAcquire',
1258 'SkAutoPathBoundsUpdate',
1259 'SkAutoPDFRelease',
1260 'SkAutoRasterClipValidate',
1261 'SkAutoRef',
1262 'SkAutoTime',
1263 'SkAutoTrace',
1264 'SkAutoUnref',
1265 ]
1266 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1267 # bad: base::AutoLock(lock.get());
1268 # not bad: base::AutoLock lock(lock.get());
1269 bad_pattern = input_api.re.compile(anonymous)
1270 # good: new base::AutoLock(lock.get())
1271 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1272 errors = []
1273
1274 for f in input_api.AffectedFiles():
1275 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1276 continue
1277 for linenum, line in f.ChangedContents():
1278 if bad_pattern.search(line) and not good_pattern.search(line):
1279 errors.append('%s:%d' % (f.LocalPath(), linenum))
1280
1281 if errors:
1282 return [output_api.PresubmitError(
1283 'These lines create anonymous variables that need to be named:',
1284 items=errors)]
1285 return []
1286
1287
[email protected]5fe0f8742013-11-29 01:04:591288def _CheckCygwinShell(input_api, output_api):
1289 source_file_filter = lambda x: input_api.FilterSourceFile(
1290 x, white_list=(r'.+\.(gyp|gypi)$',))
1291 cygwin_shell = []
1292
1293 for f in input_api.AffectedSourceFiles(source_file_filter):
1294 for linenum, line in f.ChangedContents():
1295 if 'msvs_cygwin_shell' in line:
1296 cygwin_shell.append(f.LocalPath())
1297 break
1298
1299 if cygwin_shell:
1300 return [output_api.PresubmitError(
1301 'These files should not use msvs_cygwin_shell (the default is 0):',
1302 items=cygwin_shell)]
1303 return []
1304
[email protected]85218562013-11-22 07:41:401305
[email protected]999261d2014-03-03 20:08:081306def _CheckUserActionUpdate(input_api, output_api):
1307 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521308 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081309 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521310 # If actions.xml is already included in the changelist, the PRESUBMIT
1311 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081312 return []
1313
[email protected]999261d2014-03-03 20:08:081314 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1315 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521316 current_actions = None
[email protected]999261d2014-03-03 20:08:081317 for f in input_api.AffectedFiles(file_filter=file_filter):
1318 for line_num, line in f.ChangedContents():
1319 match = input_api.re.search(action_re, line)
1320 if match:
[email protected]2f92dec2014-03-07 19:21:521321 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1322 # loaded only once.
1323 if not current_actions:
1324 with open('tools/metrics/actions/actions.xml') as actions_f:
1325 current_actions = actions_f.read()
1326 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081327 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521328 action = 'name="{0}"'.format(action_name)
1329 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081330 return [output_api.PresubmitPromptWarning(
1331 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521332 'tools/metrics/actions/actions.xml. Please run '
1333 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081334 % (f.LocalPath(), line_num, action_name))]
1335 return []
1336
1337
[email protected]99171a92014-06-03 08:44:471338def _GetJSONParseError(input_api, filename, eat_comments=True):
1339 try:
1340 contents = input_api.ReadFile(filename)
1341 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131342 import sys
1343 original_sys_path = sys.path
1344 try:
1345 sys.path = sys.path + [input_api.os_path.join(
1346 input_api.PresubmitLocalPath(),
1347 'tools', 'json_comment_eater')]
1348 import json_comment_eater
1349 finally:
1350 sys.path = original_sys_path
1351 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471352
1353 input_api.json.loads(contents)
1354 except ValueError as e:
1355 return e
1356 return None
1357
1358
1359def _GetIDLParseError(input_api, filename):
1360 try:
1361 contents = input_api.ReadFile(filename)
1362 idl_schema = input_api.os_path.join(
1363 input_api.PresubmitLocalPath(),
1364 'tools', 'json_schema_compiler', 'idl_schema.py')
1365 process = input_api.subprocess.Popen(
1366 [input_api.python_executable, idl_schema],
1367 stdin=input_api.subprocess.PIPE,
1368 stdout=input_api.subprocess.PIPE,
1369 stderr=input_api.subprocess.PIPE,
1370 universal_newlines=True)
1371 (_, error) = process.communicate(input=contents)
1372 return error or None
1373 except ValueError as e:
1374 return e
1375
1376
1377def _CheckParseErrors(input_api, output_api):
1378 """Check that IDL and JSON files do not contain syntax errors."""
1379 actions = {
1380 '.idl': _GetIDLParseError,
1381 '.json': _GetJSONParseError,
1382 }
1383 # These paths contain test data and other known invalid JSON files.
1384 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491385 r'test[\\\/]data[\\\/]',
1386 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471387 ]
1388 # Most JSON files are preprocessed and support comments, but these do not.
1389 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491390 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471391 ]
1392 # Only run IDL checker on files in these directories.
1393 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491394 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1395 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471396 ]
1397
1398 def get_action(affected_file):
1399 filename = affected_file.LocalPath()
1400 return actions.get(input_api.os_path.splitext(filename)[1])
1401
1402 def MatchesFile(patterns, path):
1403 for pattern in patterns:
1404 if input_api.re.search(pattern, path):
1405 return True
1406 return False
1407
1408 def FilterFile(affected_file):
1409 action = get_action(affected_file)
1410 if not action:
1411 return False
1412 path = affected_file.LocalPath()
1413
1414 if MatchesFile(excluded_patterns, path):
1415 return False
1416
1417 if (action == _GetIDLParseError and
1418 not MatchesFile(idl_included_patterns, path)):
1419 return False
1420 return True
1421
1422 results = []
1423 for affected_file in input_api.AffectedFiles(
1424 file_filter=FilterFile, include_deletes=False):
1425 action = get_action(affected_file)
1426 kwargs = {}
1427 if (action == _GetJSONParseError and
1428 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1429 kwargs['eat_comments'] = False
1430 parse_error = action(input_api,
1431 affected_file.AbsoluteLocalPath(),
1432 **kwargs)
1433 if parse_error:
1434 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1435 (affected_file.LocalPath(), parse_error)))
1436 return results
1437
1438
[email protected]760deea2013-12-10 19:33:491439def _CheckJavaStyle(input_api, output_api):
1440 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471441 import sys
[email protected]760deea2013-12-10 19:33:491442 original_sys_path = sys.path
1443 try:
1444 sys.path = sys.path + [input_api.os_path.join(
1445 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1446 import checkstyle
1447 finally:
1448 # Restore sys.path to what it was before.
1449 sys.path = original_sys_path
1450
1451 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091452 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511453 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491454
1455
dchenge07de812016-06-20 19:27:171456def _CheckIpcOwners(input_api, output_api):
1457 """Checks that affected files involving IPC have an IPC OWNERS rule.
1458
1459 Whether or not a file affects IPC is determined by a simple whitelist of
1460 filename patterns."""
1461 file_patterns = [
palmerb19a0932017-01-24 04:00:311462 # Legacy IPC:
dchenge07de812016-06-20 19:27:171463 '*_messages.cc',
1464 '*_messages*.h',
1465 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311466 # Mojo IPC:
dchenge07de812016-06-20 19:27:171467 '*.mojom',
1468 '*_struct_traits*.*',
1469 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311470 '*.typemap',
1471 # Android native IPC:
1472 '*.aidl',
1473 # Blink uses a different file naming convention:
1474 '*EnumTraits*.*',
dchenge07de812016-06-20 19:27:171475 '*StructTraits*.*',
1476 '*TypeConverter*.*',
1477 ]
1478
scottmg7a6ed5ba2016-11-04 18:22:041479 # These third_party directories do not contain IPCs, but contain files
1480 # matching the above patterns, which trigger false positives.
1481 exclude_paths = [
1482 'third_party/crashpad/*',
1483 ]
1484
dchenge07de812016-06-20 19:27:171485 # Dictionary mapping an OWNERS file path to Patterns.
1486 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1487 # rules ) to a PatternEntry.
1488 # PatternEntry is a dictionary with two keys:
1489 # - 'files': the files that are matched by this pattern
1490 # - 'rules': the per-file rules needed for this pattern
1491 # For example, if we expect OWNERS file to contain rules for *.mojom and
1492 # *_struct_traits*.*, Patterns might look like this:
1493 # {
1494 # '*.mojom': {
1495 # 'files': ...,
1496 # 'rules': [
1497 # 'per-file *.mojom=set noparent',
1498 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1499 # ],
1500 # },
1501 # '*_struct_traits*.*': {
1502 # 'files': ...,
1503 # 'rules': [
1504 # 'per-file *_struct_traits*.*=set noparent',
1505 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1506 # ],
1507 # },
1508 # }
1509 to_check = {}
1510
1511 # Iterate through the affected files to see what we actually need to check
1512 # for. We should only nag patch authors about per-file rules if a file in that
1513 # directory would match that pattern. If a directory only contains *.mojom
1514 # files and no *_messages*.h files, we should only nag about rules for
1515 # *.mojom files.
rockot51249332016-06-23 16:32:251516 for f in input_api.change.AffectedFiles(include_deletes=False):
dchenge07de812016-06-20 19:27:171517 for pattern in file_patterns:
1518 if input_api.fnmatch.fnmatch(
1519 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041520 skip = False
1521 for exclude in exclude_paths:
1522 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1523 skip = True
1524 break
1525 if skip:
1526 continue
dchenge07de812016-06-20 19:27:171527 owners_file = input_api.os_path.join(
1528 input_api.os_path.dirname(f.LocalPath()), 'OWNERS')
1529 if owners_file not in to_check:
1530 to_check[owners_file] = {}
1531 if pattern not in to_check[owners_file]:
1532 to_check[owners_file][pattern] = {
1533 'files': [],
1534 'rules': [
1535 'per-file %s=set noparent' % pattern,
1536 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1537 ]
1538 }
1539 to_check[owners_file][pattern]['files'].append(f)
1540 break
1541
1542 # Now go through the OWNERS files we collected, filtering out rules that are
1543 # already present in that OWNERS file.
1544 for owners_file, patterns in to_check.iteritems():
1545 try:
1546 with file(owners_file) as f:
1547 lines = set(f.read().splitlines())
1548 for entry in patterns.itervalues():
1549 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1550 ]
1551 except IOError:
1552 # No OWNERS file, so all the rules are definitely missing.
1553 continue
1554
1555 # All the remaining lines weren't found in OWNERS files, so emit an error.
1556 errors = []
1557 for owners_file, patterns in to_check.iteritems():
1558 missing_lines = []
1559 files = []
1560 for pattern, entry in patterns.iteritems():
1561 missing_lines.extend(entry['rules'])
1562 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1563 if missing_lines:
1564 errors.append(
1565 '%s is missing the following lines:\n\n%s\n\nfor changed files:\n%s' %
1566 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1567
1568 results = []
1569 if errors:
vabrf5ce3bf92016-07-11 14:52:411570 if input_api.is_committing:
1571 output = output_api.PresubmitError
1572 else:
1573 output = output_api.PresubmitPromptWarning
1574 results.append(output(
dchenge07de812016-06-20 19:27:171575 'Found changes to IPC files without a security OWNER!',
1576 long_text='\n\n'.join(errors)))
1577
1578 return results
1579
1580
jbriance9e12f162016-11-25 07:57:501581def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311582 """Checks that added or removed lines in non third party affected
1583 header files do not lead to new useless class or struct forward
1584 declaration.
jbriance9e12f162016-11-25 07:57:501585 """
1586 results = []
1587 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1588 input_api.re.MULTILINE)
1589 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1590 input_api.re.MULTILINE)
1591 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311592 if (f.LocalPath().startswith('third_party') and
1593 not f.LocalPath().startswith('third_party/WebKit') and
1594 not f.LocalPath().startswith('third_party\\WebKit')):
1595 continue
1596
jbriance9e12f162016-11-25 07:57:501597 if not f.LocalPath().endswith('.h'):
1598 continue
1599
1600 contents = input_api.ReadFile(f)
1601 fwd_decls = input_api.re.findall(class_pattern, contents)
1602 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1603
1604 useless_fwd_decls = []
1605 for decl in fwd_decls:
1606 count = sum(1 for _ in input_api.re.finditer(
1607 r'\b%s\b' % input_api.re.escape(decl), contents))
1608 if count == 1:
1609 useless_fwd_decls.append(decl)
1610
1611 if not useless_fwd_decls:
1612 continue
1613
1614 for line in f.GenerateScmDiff().splitlines():
1615 if (line.startswith('-') and not line.startswith('--') or
1616 line.startswith('+') and not line.startswith('++')):
1617 for decl in useless_fwd_decls:
1618 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1619 results.append(output_api.PresubmitPromptWarning(
1620 '%s: %s forward declaration is becoming useless' %
1621 (f.LocalPath(), decl)))
1622 useless_fwd_decls.remove(decl)
1623
1624 return results
1625
1626
dskiba88634f4e2015-08-14 23:03:291627def _CheckAndroidToastUsage(input_api, output_api):
1628 """Checks that code uses org.chromium.ui.widget.Toast instead of
1629 android.widget.Toast (Chromium Toast doesn't force hardware
1630 acceleration on low-end devices, saving memory).
1631 """
1632 toast_import_pattern = input_api.re.compile(
1633 r'^import android\.widget\.Toast;$')
1634
1635 errors = []
1636
1637 sources = lambda affected_file: input_api.FilterSourceFile(
1638 affected_file,
1639 black_list=(_EXCLUDED_PATHS +
1640 _TEST_CODE_EXCLUDED_PATHS +
1641 input_api.DEFAULT_BLACK_LIST +
1642 (r'^chromecast[\\\/].*',
1643 r'^remoting[\\\/].*')),
1644 white_list=(r'.*\.java$',))
1645
1646 for f in input_api.AffectedSourceFiles(sources):
1647 for line_num, line in f.ChangedContents():
1648 if toast_import_pattern.search(line):
1649 errors.append("%s:%d" % (f.LocalPath(), line_num))
1650
1651 results = []
1652
1653 if errors:
1654 results.append(output_api.PresubmitError(
1655 'android.widget.Toast usage is detected. Android toasts use hardware'
1656 ' acceleration, and can be\ncostly on low-end devices. Please use'
1657 ' org.chromium.ui.widget.Toast instead.\n'
1658 'Contact [email protected] if you have any questions.',
1659 errors))
1660
1661 return results
1662
1663
dgnaa68d5e2015-06-10 10:08:221664def _CheckAndroidCrLogUsage(input_api, output_api):
1665 """Checks that new logs using org.chromium.base.Log:
1666 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511667 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221668 """
pkotwicza1dd0b002016-05-16 14:41:041669
torne89540622017-03-24 19:41:301670 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:041671 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:301672 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:041673 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:301674 # WebView license viewer code cannot depend on //base; used in stub APK.
1675 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
1676 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:041677 ]
1678
dgnaa68d5e2015-06-10 10:08:221679 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121680 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1681 class_in_base_pattern = input_api.re.compile(
1682 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1683 has_some_log_import_pattern = input_api.re.compile(
1684 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221685 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121686 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221687 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511688 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221689 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221690
Vincent Scheib16d7b272015-09-15 18:09:071691 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221692 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041693 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1694 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121695
dgnaa68d5e2015-06-10 10:08:221696 tag_decl_errors = []
1697 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121698 tag_errors = []
dgn38736db2015-09-18 19:20:511699 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121700 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221701
1702 for f in input_api.AffectedSourceFiles(sources):
1703 file_content = input_api.ReadFile(f)
1704 has_modified_logs = False
1705
1706 # Per line checks
dgn87d9fb62015-06-12 09:15:121707 if (cr_log_import_pattern.search(file_content) or
1708 (class_in_base_pattern.search(file_content) and
1709 not has_some_log_import_pattern.search(file_content))):
1710 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221711 for line_num, line in f.ChangedContents():
1712
1713 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121714 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221715 if match:
1716 has_modified_logs = True
1717
1718 # Make sure it uses "TAG"
1719 if not match.group('tag') == 'TAG':
1720 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121721 else:
1722 # Report non cr Log function calls in changed lines
1723 for line_num, line in f.ChangedContents():
1724 if log_call_pattern.search(line):
1725 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221726
1727 # Per file checks
1728 if has_modified_logs:
1729 # Make sure the tag is using the "cr" prefix and is not too long
1730 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511731 tag_name = match.group('name') if match else None
1732 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221733 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511734 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221735 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511736 elif '.' in tag_name:
1737 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221738
1739 results = []
1740 if tag_decl_errors:
1741 results.append(output_api.PresubmitPromptWarning(
1742 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511743 '"private static final String TAG = "<package tag>".\n'
1744 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221745 tag_decl_errors))
1746
1747 if tag_length_errors:
1748 results.append(output_api.PresubmitError(
1749 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511750 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221751 tag_length_errors))
1752
1753 if tag_errors:
1754 results.append(output_api.PresubmitPromptWarning(
1755 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1756 tag_errors))
1757
dgn87d9fb62015-06-12 09:15:121758 if util_log_errors:
dgn4401aa52015-04-29 16:26:171759 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121760 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1761 util_log_errors))
1762
dgn38736db2015-09-18 19:20:511763 if tag_with_dot_errors:
1764 results.append(output_api.PresubmitPromptWarning(
1765 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1766 tag_with_dot_errors))
1767
dgn4401aa52015-04-29 16:26:171768 return results
1769
1770
yolandyan45001472016-12-21 21:12:421771def _CheckAndroidTestAnnotationUsage(input_api, output_api):
1772 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
1773 deprecated_annotation_import_pattern = input_api.re.compile(
1774 r'^import android\.test\.suitebuilder\.annotation\..*;',
1775 input_api.re.MULTILINE)
1776 sources = lambda x: input_api.FilterSourceFile(
1777 x, white_list=(r'.*\.java$',), black_list=None)
1778 errors = []
1779 for f in input_api.AffectedFiles(sources):
1780 for line_num, line in f.ChangedContents():
1781 if deprecated_annotation_import_pattern.search(line):
1782 errors.append("%s:%d" % (f.LocalPath(), line_num))
1783
1784 results = []
1785 if errors:
1786 results.append(output_api.PresubmitError(
1787 'Annotations in android.test.suitebuilder.annotation have been'
1788 ' deprecated since API level 24. Please use android.support.test.filters'
1789 ' from //third_party/android_support_test_runner:runner_java instead.'
1790 ' Contact [email protected] if you have any questions.', errors))
1791 return results
1792
1793
agrieve7b6479d82015-10-07 14:24:221794def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1795 """Checks if MDPI assets are placed in a correct directory."""
1796 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1797 ('/res/drawable/' in f.LocalPath() or
1798 '/res/drawable-ldrtl/' in f.LocalPath()))
1799 errors = []
1800 for f in input_api.AffectedFiles(include_deletes=False,
1801 file_filter=file_filter):
1802 errors.append(' %s' % f.LocalPath())
1803
1804 results = []
1805 if errors:
1806 results.append(output_api.PresubmitError(
1807 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1808 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1809 '/res/drawable-ldrtl/.\n'
1810 'Contact [email protected] if you have questions.', errors))
1811 return results
1812
1813
agrievef32bcc72016-04-04 14:57:401814class PydepsChecker(object):
1815 def __init__(self, input_api, pydeps_files):
1816 self._file_cache = {}
1817 self._input_api = input_api
1818 self._pydeps_files = pydeps_files
1819
1820 def _LoadFile(self, path):
1821 """Returns the list of paths within a .pydeps file relative to //."""
1822 if path not in self._file_cache:
1823 with open(path) as f:
1824 self._file_cache[path] = f.read()
1825 return self._file_cache[path]
1826
1827 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1828 """Returns an interable of paths within the .pydep, relativized to //."""
1829 os_path = self._input_api.os_path
1830 pydeps_dir = os_path.dirname(pydeps_path)
1831 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1832 if not l.startswith('*'))
1833 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1834
1835 def _CreateFilesToPydepsMap(self):
1836 """Returns a map of local_path -> list_of_pydeps."""
1837 ret = {}
1838 for pydep_local_path in self._pydeps_files:
1839 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1840 ret.setdefault(path, []).append(pydep_local_path)
1841 return ret
1842
1843 def ComputeAffectedPydeps(self):
1844 """Returns an iterable of .pydeps files that might need regenerating."""
1845 affected_pydeps = set()
1846 file_to_pydeps_map = None
1847 for f in self._input_api.AffectedFiles(include_deletes=True):
1848 local_path = f.LocalPath()
1849 if local_path == 'DEPS':
1850 return self._pydeps_files
1851 elif local_path.endswith('.pydeps'):
1852 if local_path in self._pydeps_files:
1853 affected_pydeps.add(local_path)
1854 elif local_path.endswith('.py'):
1855 if file_to_pydeps_map is None:
1856 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1857 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1858 return affected_pydeps
1859
1860 def DetermineIfStale(self, pydeps_path):
1861 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:411862 import difflib
agrievef32bcc72016-04-04 14:57:401863 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1864 cmd = old_pydeps_data[1][1:].strip()
1865 new_pydeps_data = self._input_api.subprocess.check_output(
1866 cmd + ' --output ""', shell=True)
phajdan.jr0d9878552016-11-04 10:49:411867 old_contents = old_pydeps_data[2:]
1868 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:401869 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:411870 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:401871
1872
1873def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1874 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001875 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281876 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1877 # Mac, so skip it on other platforms.
1878 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001879 return []
agrievef32bcc72016-04-04 14:57:401880 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1881 is_android = input_api.os_path.exists('third_party/android_tools')
1882 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1883 results = []
1884 # First, check for new / deleted .pydeps.
1885 for f in input_api.AffectedFiles(include_deletes=True):
1886 if f.LocalPath().endswith('.pydeps'):
1887 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1888 results.append(output_api.PresubmitError(
1889 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1890 'remove %s' % f.LocalPath()))
1891 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1892 results.append(output_api.PresubmitError(
1893 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1894 'include %s' % f.LocalPath()))
1895
1896 if results:
1897 return results
1898
1899 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1900
1901 for pydep_path in checker.ComputeAffectedPydeps():
1902 try:
phajdan.jr0d9878552016-11-04 10:49:411903 result = checker.DetermineIfStale(pydep_path)
1904 if result:
1905 cmd, diff = result
agrievef32bcc72016-04-04 14:57:401906 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:411907 'File is stale: %s\nDiff (apply to fix):\n%s\n'
1908 'To regenerate, run:\n\n %s' %
1909 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:401910 except input_api.subprocess.CalledProcessError as error:
1911 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1912 long_text=error.output)]
1913
1914 return results
1915
1916
glidere61efad2015-02-18 17:39:431917def _CheckSingletonInHeaders(input_api, output_api):
1918 """Checks to make sure no header files have |Singleton<|."""
1919 def FileFilter(affected_file):
1920 # It's ok for base/memory/singleton.h to have |Singleton<|.
1921 black_list = (_EXCLUDED_PATHS +
1922 input_api.DEFAULT_BLACK_LIST +
1923 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1924 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1925
sergeyu34d21222015-09-16 00:11:441926 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431927 files = []
1928 for f in input_api.AffectedSourceFiles(FileFilter):
1929 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1930 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1931 contents = input_api.ReadFile(f)
1932 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241933 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431934 pattern.search(line)):
1935 files.append(f)
1936 break
1937
1938 if files:
yolandyandaabc6d2016-04-18 18:29:391939 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441940 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431941 'Please move them to an appropriate source file so that the ' +
1942 'template gets instantiated in a single compilation unit.',
1943 files) ]
1944 return []
1945
1946
dbeam1ec68ac2016-12-15 05:22:241947def _CheckNoDeprecatedCompiledResourcesGyp(input_api, output_api):
dbeam37e8e7402016-02-10 22:58:201948 """Checks for old style compiled_resources.gyp files."""
1949 is_compiled_resource = lambda fp: fp.endswith('compiled_resources.gyp')
1950
1951 added_compiled_resources = filter(is_compiled_resource, [
1952 f.LocalPath() for f in input_api.AffectedFiles() if f.Action() == 'A'
1953 ])
1954
1955 if not added_compiled_resources:
1956 return []
1957
1958 return [output_api.PresubmitError(
1959 "Found new compiled_resources.gyp files:\n%s\n\n"
1960 "compiled_resources.gyp files are deprecated,\n"
michaelpgdb9985072016-02-24 19:13:551961 "please use compiled_resources2.gyp instead:\n"
1962 "https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md"
1963 %
dbeam37e8e7402016-02-10 22:58:201964 "\n".join(added_compiled_resources))]
1965
1966
[email protected]fd20b902014-05-09 02:14:531967_DEPRECATED_CSS = [
1968 # Values
1969 ( "-webkit-box", "flex" ),
1970 ( "-webkit-inline-box", "inline-flex" ),
1971 ( "-webkit-flex", "flex" ),
1972 ( "-webkit-inline-flex", "inline-flex" ),
1973 ( "-webkit-min-content", "min-content" ),
1974 ( "-webkit-max-content", "max-content" ),
1975
1976 # Properties
1977 ( "-webkit-background-clip", "background-clip" ),
1978 ( "-webkit-background-origin", "background-origin" ),
1979 ( "-webkit-background-size", "background-size" ),
1980 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:441981 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:531982
1983 # Functions
1984 ( "-webkit-gradient", "gradient" ),
1985 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1986 ( "-webkit-linear-gradient", "linear-gradient" ),
1987 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1988 ( "-webkit-radial-gradient", "radial-gradient" ),
1989 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1990]
1991
dbeam1ec68ac2016-12-15 05:22:241992def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:531993 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251994 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341995 documentation and iOS CSS for dom distiller
1996 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251997 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531998 results = []
dbeam070cfe62014-10-22 06:44:021999 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:252000 black_list = (_EXCLUDED_PATHS +
2001 _TEST_CODE_EXCLUDED_PATHS +
2002 input_api.DEFAULT_BLACK_LIST +
2003 (r"^chrome/common/extensions/docs",
2004 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342005 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:052006 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:442007 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252008 r"^native_client_sdk"))
2009 file_filter = lambda f: input_api.FilterSourceFile(
2010 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532011 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2012 for line_num, line in fpath.ChangedContents():
2013 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022014 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532015 results.append(output_api.PresubmitError(
2016 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2017 (fpath.LocalPath(), line_num, deprecated_value, value)))
2018 return results
2019
mohan.reddyf21db962014-10-16 12:26:472020
dbeam070cfe62014-10-22 06:44:022021_DEPRECATED_JS = [
2022 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2023 ( "__defineGetter__", "Object.defineProperty" ),
2024 ( "__defineSetter__", "Object.defineProperty" ),
2025]
2026
dbeam1ec68ac2016-12-15 05:22:242027def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022028 """Make sure that we don't use deprecated JS in Chrome code."""
2029 results = []
2030 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2031 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2032 input_api.DEFAULT_BLACK_LIST)
2033 file_filter = lambda f: input_api.FilterSourceFile(
2034 f, white_list=file_inclusion_pattern, black_list=black_list)
2035 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2036 for lnum, line in fpath.ChangedContents():
2037 for (deprecated, replacement) in _DEPRECATED_JS:
2038 if deprecated in line:
2039 results.append(output_api.PresubmitError(
2040 "%s:%d: Use of deprecated JS %s, use %s instead" %
2041 (fpath.LocalPath(), lnum, deprecated, replacement)))
2042 return results
2043
2044
dbeam1ec68ac2016-12-15 05:22:242045def _CheckForRiskyJsFeatures(input_api, output_api):
2046 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
2047 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js)
2048
2049 arrow_lines = []
2050 for f in input_api.AffectedFiles(file_filter=file_filter):
2051 for lnum, line in f.ChangedContents():
2052 if ' => ' in line:
2053 arrow_lines.append((f.LocalPath(), lnum))
2054
2055 if not arrow_lines:
2056 return []
2057
2058 return [output_api.PresubmitPromptWarning("""
2059Use of => operator detected in:
2060%s
2061Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2062https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
2063""" % "\n".join(" %s:%d\n" % line for line in arrow_lines))]
2064
2065
dgnaa68d5e2015-06-10 10:08:222066def _AndroidSpecificOnUploadChecks(input_api, output_api):
2067 """Groups checks that target android code."""
2068 results = []
dgnaa68d5e2015-06-10 10:08:222069 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222070 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292071 results.extend(_CheckAndroidToastUsage(input_api, output_api))
yolandyan45001472016-12-21 21:12:422072 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222073 return results
2074
2075
[email protected]22c9bd72011-03-27 16:47:392076def _CommonChecks(input_api, output_api):
2077 """Checks common to both upload and commit."""
2078 results = []
2079 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382080 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542081 excluded_paths=_EXCLUDED_PATHS))
machenbachfbda9b72016-12-06 13:13:582082 results.extend(
2083 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:192084 results.extend(
[email protected]760deea2013-12-10 19:33:492085 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542086 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182087 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522088 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222089 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442090 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592091 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062092 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122093 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182094 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222095 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302096 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492097 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:272098 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032099 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492100 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442101 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272102 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542103 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442104 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392105 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552106 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042107 results.extend(
2108 input_api.canned_checks.CheckChangeHasNoTabs(
2109 input_api,
2110 output_api,
2111 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402112 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162113 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:592114 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082115 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242116 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2117 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472118 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042119 results.extend(_CheckForIPCRules(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232120 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432121 results.extend(_CheckSingletonInHeaders(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242122 results.extend(_CheckNoDeprecatedCompiledResourcesGyp(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402123 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152124 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172125 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502126 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242127 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242128
2129 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
2130 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2131 input_api, output_api,
2132 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:382133 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392134 return results
[email protected]1f7b4172010-01-28 01:17:342135
[email protected]b337cb5b2011-01-23 21:24:052136
[email protected]b8079ae4a2012-12-05 19:56:492137def _CheckPatchFiles(input_api, output_api):
2138 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2139 if f.LocalPath().endswith(('.orig', '.rej'))]
2140 if problems:
2141 return [output_api.PresubmitError(
2142 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032143 else:
2144 return []
[email protected]b8079ae4a2012-12-05 19:56:492145
2146
[email protected]b00342e7f2013-03-26 16:21:542147def _DidYouMeanOSMacro(bad_macro):
2148 try:
2149 return {'A': 'OS_ANDROID',
2150 'B': 'OS_BSD',
2151 'C': 'OS_CHROMEOS',
2152 'F': 'OS_FREEBSD',
2153 'L': 'OS_LINUX',
2154 'M': 'OS_MACOSX',
2155 'N': 'OS_NACL',
2156 'O': 'OS_OPENBSD',
2157 'P': 'OS_POSIX',
2158 'S': 'OS_SOLARIS',
2159 'W': 'OS_WIN'}[bad_macro[3].upper()]
2160 except KeyError:
2161 return ''
2162
2163
2164def _CheckForInvalidOSMacrosInFile(input_api, f):
2165 """Check for sensible looking, totally invalid OS macros."""
2166 preprocessor_statement = input_api.re.compile(r'^\s*#')
2167 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2168 results = []
2169 for lnum, line in f.ChangedContents():
2170 if preprocessor_statement.search(line):
2171 for match in os_macro.finditer(line):
2172 if not match.group(1) in _VALID_OS_MACROS:
2173 good = _DidYouMeanOSMacro(match.group(1))
2174 did_you_mean = ' (did you mean %s?)' % good if good else ''
2175 results.append(' %s:%d %s%s' % (f.LocalPath(),
2176 lnum,
2177 match.group(1),
2178 did_you_mean))
2179 return results
2180
2181
2182def _CheckForInvalidOSMacros(input_api, output_api):
2183 """Check all affected files for invalid OS macros."""
2184 bad_macros = []
2185 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472186 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542187 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2188
2189 if not bad_macros:
2190 return []
2191
2192 return [output_api.PresubmitError(
2193 'Possibly invalid OS macro[s] found. Please fix your code\n'
2194 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2195
lliabraa35bab3932014-10-01 12:16:442196
2197def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2198 """Check all affected files for invalid "if defined" macros."""
2199 ALWAYS_DEFINED_MACROS = (
2200 "TARGET_CPU_PPC",
2201 "TARGET_CPU_PPC64",
2202 "TARGET_CPU_68K",
2203 "TARGET_CPU_X86",
2204 "TARGET_CPU_ARM",
2205 "TARGET_CPU_MIPS",
2206 "TARGET_CPU_SPARC",
2207 "TARGET_CPU_ALPHA",
2208 "TARGET_IPHONE_SIMULATOR",
2209 "TARGET_OS_EMBEDDED",
2210 "TARGET_OS_IPHONE",
2211 "TARGET_OS_MAC",
2212 "TARGET_OS_UNIX",
2213 "TARGET_OS_WIN32",
2214 )
2215 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2216 results = []
2217 for lnum, line in f.ChangedContents():
2218 for match in ifdef_macro.finditer(line):
2219 if match.group(1) in ALWAYS_DEFINED_MACROS:
2220 always_defined = ' %s is always defined. ' % match.group(1)
2221 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2222 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2223 lnum,
2224 always_defined,
2225 did_you_mean))
2226 return results
2227
2228
2229def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2230 """Check all affected files for invalid "if defined" macros."""
2231 bad_macros = []
2232 for f in input_api.AffectedFiles():
2233 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2234 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2235
2236 if not bad_macros:
2237 return []
2238
2239 return [output_api.PresubmitError(
2240 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2241 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2242 bad_macros)]
2243
2244
mlamouria82272622014-09-16 18:45:042245def _CheckForIPCRules(input_api, output_api):
2246 """Check for same IPC rules described in
2247 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2248 """
2249 base_pattern = r'IPC_ENUM_TRAITS\('
2250 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2251 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2252
2253 problems = []
2254 for f in input_api.AffectedSourceFiles(None):
2255 local_path = f.LocalPath()
2256 if not local_path.endswith('.h'):
2257 continue
2258 for line_number, line in f.ChangedContents():
2259 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2260 problems.append(
2261 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2262
2263 if problems:
2264 return [output_api.PresubmitPromptWarning(
2265 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2266 else:
2267 return []
2268
[email protected]b00342e7f2013-03-26 16:21:542269
mostynbb639aca52015-01-07 20:31:232270def _CheckForWindowsLineEndings(input_api, output_api):
2271 """Check source code and known ascii text files for Windows style line
2272 endings.
2273 """
earthdok1b5e0ee2015-03-10 15:19:102274 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232275
2276 file_inclusion_pattern = (
2277 known_text_files,
2278 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2279 )
2280
2281 filter = lambda f: input_api.FilterSourceFile(
2282 f, white_list=file_inclusion_pattern, black_list=None)
2283 files = [f.LocalPath() for f in
2284 input_api.AffectedSourceFiles(filter)]
2285
2286 problems = []
2287
2288 for file in files:
2289 fp = open(file, 'r')
2290 for line in fp:
2291 if line.endswith('\r\n'):
2292 problems.append(file)
2293 break
2294 fp.close()
2295
2296 if problems:
2297 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2298 'these files to contain Windows style line endings?\n' +
2299 '\n'.join(problems))]
2300
2301 return []
2302
2303
pastarmovj89f7ee12016-09-20 14:58:132304def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None,
2305 lint_filters=None, verbose_level=None):
2306 """Checks that all source files use SYSLOG properly."""
2307 syslog_files = []
2308 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:562309 for line_number, line in f.ChangedContents():
2310 if 'SYSLOG' in line:
2311 syslog_files.append(f.LocalPath() + ':' + str(line_number))
2312
pastarmovj89f7ee12016-09-20 14:58:132313 if syslog_files:
2314 return [output_api.PresubmitPromptWarning(
2315 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
2316 ' calls.\nFiles to check:\n', items=syslog_files)]
2317 return []
2318
2319
[email protected]1f7b4172010-01-28 01:17:342320def CheckChangeOnUpload(input_api, output_api):
2321 results = []
2322 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472323 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282324 results.extend(
jam93a6ee792017-02-08 23:59:222325 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192326 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222327 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:132328 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:162329 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542330 return results
[email protected]ca8d19842009-02-19 16:33:122331
2332
[email protected]1bfb8322014-04-23 01:02:412333def GetTryServerMasterForBot(bot):
2334 """Returns the Try Server master for the given bot.
2335
[email protected]0bb112362014-07-26 04:38:322336 It tries to guess the master from the bot name, but may still fail
2337 and return None. There is no longer a default master.
2338 """
2339 # Potentially ambiguous bot names are listed explicitly.
2340 master_map = {
tandriie5587792016-07-14 00:34:502341 'chromium_presubmit': 'master.tryserver.chromium.linux',
2342 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412343 }
[email protected]0bb112362014-07-26 04:38:322344 master = master_map.get(bot)
2345 if not master:
wnwen4fbaab82016-05-25 12:54:362346 if 'android' in bot:
tandriie5587792016-07-14 00:34:502347 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:362348 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:502349 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:322350 elif 'win' in bot:
tandriie5587792016-07-14 00:34:502351 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:322352 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:502353 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:322354 return master
[email protected]1bfb8322014-04-23 01:02:412355
2356
Paweł Hajdan, Jr55083782014-12-19 20:32:562357def GetDefaultTryConfigs(bots):
2358 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012359 """
2360
Paweł Hajdan, Jr55083782014-12-19 20:32:562361 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412362
2363 # Build up the mapping from tryserver master to bot/test.
2364 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562365 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412366 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2367 return out
[email protected]38c6a512013-12-18 23:48:012368
2369
[email protected]ca8d19842009-02-19 16:33:122370def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542371 results = []
[email protected]1f7b4172010-01-28 01:17:342372 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542373 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272374 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342375 input_api,
2376 output_api,
[email protected]2fdd1f362013-01-16 03:56:032377 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272378
jam93a6ee792017-02-08 23:59:222379 results.extend(
2380 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:542381 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2382 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412383 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2384 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542385 return results