blob: 21c855c56a67cf7bd40ddfe206b0df442e2eeb48 [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",
vapierb2053f542017-03-09 19:46:1026 r"tools[\\\/]md_browser[\\\/].*\.css$",
ehmaldonado78eee2ed2017-03-28 13:16:5427 # Test pages for WebRTC telemetry tests.
28 r"tools[\\\/]perf[\\\/]page_sets[\\\/]webrtc_cases.*",
[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 (
thomasandersone7caaa9b2017-03-29 19:22:53158 r'\bNULL\b',
159 (
160 'New code should not use NULL. Use nullptr instead.',
161 ),
162 True,
163 (),
164 ),
165 (
[email protected]23e6cbc2012-06-16 18:51:20166 'FRIEND_TEST(',
167 (
[email protected]e3c945502012-06-26 20:01:49168 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20169 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
170 ),
171 False,
[email protected]7345da02012-11-27 14:31:49172 (),
[email protected]23e6cbc2012-06-16 18:51:20173 ),
174 (
thomasanderson4b569052016-09-14 20:15:53175 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
176 (
177 'Chrome clients wishing to select events on X windows should use',
178 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
179 'you are selecting events from the GPU process, or if you are using',
180 'an XDisplay other than gfx::GetXDisplay().',
181 ),
182 True,
183 (
184 r"^ui[\\\/]gl[\\\/].*\.cc$",
185 r"^media[\\\/]gpu[\\\/].*\.cc$",
186 r"^gpu[\\\/].*\.cc$",
187 ),
188 ),
189 (
thomasandersone043e3ce2017-06-08 00:43:20190 r'XInternAtom|xcb_intern_atom',
191 (
thomasanderson11aa41d2017-06-08 22:22:38192 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20193 ),
194 True,
195 (
thomasanderson11aa41d2017-06-08 22:22:38196 r"^gpu[\\\/]ipc[\\\/]service[\\\/]gpu_watchdog_thread\.cc$",
197 r"^remoting[\\\/]host[\\\/]linux[\\\/]x_server_clipboard\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20198 r"^ui[\\\/]gfx[\\\/]x[\\\/]x11_atom_cache\.cc$",
199 ),
200 ),
201 (
[email protected]23e6cbc2012-06-16 18:51:20202 'ScopedAllowIO',
203 (
satoruxe1396f8a2017-06-01 06:40:39204 'New production code should not use ScopedAllowIO (using it in',
Marijn Kruisselbrink085ef092017-07-12 23:56:55205 'tests is fine). Post a task to a MayBlock task runner instead.',
[email protected]23e6cbc2012-06-16 18:51:20206 ),
[email protected]e3c945502012-06-26 20:01:49207 True,
[email protected]7345da02012-11-27 14:31:49208 (
Marijn Kruisselbrink085ef092017-07-12 23:56:55209 r"^.*(browser|unit)(|_)test[a-z_]*\.cc$",
hajimehoshi2acea432017-03-08 08:55:37210 r"^base[\\\/]memory[\\\/]shared_memory_posix\.cc$",
rayb0088ee52017-04-26 22:35:08211 r"^base[\\\/]process[\\\/]internal_aix\.cc$",
nyad2c548b2015-12-09 03:22:32212 r"^base[\\\/]process[\\\/]process_linux\.cc$",
thestig75844fdb2014-09-09 19:47:10213 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
tfarina0923ac52015-01-07 03:21:22214 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
rdevlin.cronin62018a12017-06-22 17:34:06215 r"^chrome[\\\/]browser[\\\/]extensions[\\\/]" +
216 r"chrome_test_extension_loader.cc$",
sky0e07a142016-03-25 21:27:31217 r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$",
philipj3f9d5bde2014-08-28 14:09:09218 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49219 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
220 r"test_info_extractor\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41221 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
222 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
lukasza7947ccd2016-07-28 21:56:25223 r"^content[\\\/]test[\\\/]ppapi[\\\/]ppapi_test\.cc$",
miu8e0e80c2017-05-31 03:35:57224 r"^media[\\\/]cast[\\\/]test[\\\/]utility[\\\/]" +
225 r"standalone_cast_environment\.cc$",
jamesra03ae492014-10-03 04:26:48226 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
227 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01228 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
lukasza7947ccd2016-07-28 21:56:25229 r"^net[\\\/]cert[\\\/]test_root_certs\.cc$",
230 r"^net[\\\/]test[\\\/]embedded_test_server[\\\/]" +
231 r"embedded_test_server\.cc$",
232 r"^net[\\\/]test[\\\/]spawned_test_server[\\\/]local_test_server\.cc$",
233 r"^net[\\\/]test[\\\/]test_data_directory\.cc$",
[email protected]1f52a572014-05-12 23:21:54234 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
sergeyu2c41f9842016-12-10 01:45:16235 r"^remoting[\\\/]protocol[\\\/]webrtc_transport\.cc$",
lambroslambrouf6fb94ea2016-06-27 21:21:53236 r"^ui[\\\/]base[\\\/]material_design[\\\/]"
237 "material_design_controller\.cc$",
kylechar16666242016-07-04 20:54:45238 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_mac\.cc$",
239 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_win\.cc$",
240 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_x11\.cc$",
241 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
242 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49243 ),
[email protected]23e6cbc2012-06-16 18:51:20244 ),
[email protected]52657f62013-05-20 05:30:31245 (
tomhudsone2c14d552016-05-26 17:07:46246 'setMatrixClip',
247 (
248 'Overriding setMatrixClip() is prohibited; ',
249 'the base function is deprecated. ',
250 ),
251 True,
252 (),
253 ),
254 (
[email protected]52657f62013-05-20 05:30:31255 'SkRefPtr',
256 (
257 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22258 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31259 ),
260 True,
261 (),
262 ),
263 (
264 'SkAutoRef',
265 (
266 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22267 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31268 ),
269 True,
270 (),
271 ),
272 (
273 'SkAutoTUnref',
274 (
275 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22276 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31277 ),
278 True,
279 (),
280 ),
281 (
282 'SkAutoUnref',
283 (
284 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
285 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22286 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31287 ),
288 True,
289 (),
290 ),
[email protected]d89eec82013-12-03 14:10:59291 (
292 r'/HANDLE_EINTR\(.*close',
293 (
294 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
295 'descriptor will be closed, and it is incorrect to retry the close.',
296 'Either call close directly and ignore its return value, or wrap close',
297 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
298 ),
299 True,
300 (),
301 ),
302 (
303 r'/IGNORE_EINTR\((?!.*close)',
304 (
305 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
306 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
307 ),
308 True,
309 (
310 # Files that #define IGNORE_EINTR.
311 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
312 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
313 ),
314 ),
[email protected]ec5b3f02014-04-04 18:43:43315 (
316 r'/v8::Extension\(',
317 (
318 'Do not introduce new v8::Extensions into the code base, use',
319 'gin::Wrappable instead. See http://crbug.com/334679',
320 ),
321 True,
[email protected]f55c90ee62014-04-12 00:50:03322 (
joaodasilva718f87672014-08-30 09:25:49323 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03324 ),
[email protected]ec5b3f02014-04-04 18:43:43325 ),
skyostilf9469f72015-04-20 10:38:52326 (
jame2d1a952016-04-02 00:27:10327 '#pragma comment(lib,',
328 (
329 'Specify libraries to link with in build files and not in the source.',
330 ),
331 True,
332 (),
333 ),
fdorayc4ac18d2017-05-01 21:39:59334 (
Francois Dorayd7c671722017-08-01 17:31:39335 r'/(WebThread|BrowserThread)::GetBlockingPool',
fdorayc4ac18d2017-05-01 21:39:59336 (
337 'Use base/task_scheduler/post_task.h instead of the blocking pool. See',
338 'mapping between both APIs in content/public/browser/browser_thread.h.',
339 'For questions, contact base/task_scheduler/OWNERS.',
340 ),
341 True,
342 (),
343 ),
gabd52c912a2017-05-11 04:15:59344 (
Kevin Marshall342ddd62017-08-24 17:22:36345 r'/(WebThread|BrowserThread)::(FILE|FILE_USER_BLOCKING|DB|CACHE)',
Gabriel Charette664e4482017-06-13 19:55:29346 (
347 'The non-UI/IO BrowserThreads are deprecated, please migrate this',
348 'code to TaskScheduler. See https://goo.gl/mDSxKl for details.',
349 'For questions, contact base/task_scheduler/OWNERS.',
350 ),
351 True,
352 (),
353 ),
354 (
gabd52c912a2017-05-11 04:15:59355 'base::SequenceChecker',
356 (
357 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
358 ),
359 False,
360 (),
361 ),
362 (
363 'base::ThreadChecker',
364 (
365 'Consider using THREAD_CHECKER macros instead of the class directly.',
366 ),
367 False,
368 (),
369 ),
dbeamb6f4fde2017-06-15 04:03:06370 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06371 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
372 (
373 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
374 'deprecated (http://crbug.com/634507). Please avoid converting away',
375 'from the Time types in Chromium code, especially if any math is',
376 'being done on time values. For interfacing with platform/library',
377 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
378 'type converter methods instead. For faking TimeXXX values (for unit',
379 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
380 'other use cases, please contact base/time/OWNERS.',
381 ),
382 False,
383 (),
384 ),
385 (
dbeamb6f4fde2017-06-15 04:03:06386 'CallJavascriptFunctionUnsafe',
387 (
388 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
389 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
390 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
391 ),
392 False,
393 (
394 r'^content[\\\/]browser[\\\/]webui[\\\/]web_ui_impl\.(cc|h)$',
395 r'^content[\\\/]public[\\\/]browser[\\\/]web_ui\.h$',
396 r'^content[\\\/]public[\\\/]test[\\\/]test_web_ui\.(cc|h)$',
397 ),
398 ),
dskiba1474c2bfd62017-07-20 02:19:24399 (
400 'leveldb::DB::Open',
401 (
402 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
403 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
404 "Chrome's tracing, making their memory usage visible.",
405 ),
406 True,
407 (
408 r'^third_party/leveldatabase/.*\.(cc|h)$',
409 ),
Gabriel Charette0592c3a2017-07-26 12:02:04410 ),
411 (
Gabriel Charetted9839bc2017-07-29 14:17:47412 'MessageLoop::QuitWhenIdleClosure',
Gabriel Charette0592c3a2017-07-26 12:02:04413 (
Robert Liao64b7ab22017-08-04 23:03:43414 'MessageLoop::QuitWhenIdleClosure is deprecated. Please migrate to',
415 'Runloop.',
Gabriel Charette0592c3a2017-07-26 12:02:04416 ),
417 True,
418 (),
Gabriel Charetted9839bc2017-07-29 14:17:47419 ),
420 (
421 'RunLoop::QuitCurrent',
422 (
Robert Liao64b7ab22017-08-04 23:03:43423 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
424 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47425 ),
426 True,
427 (),
Gabriel Charettea44975052017-08-21 23:14:04428 ),
429 (
430 'base::ScopedMockTimeMessageLoopTaskRunner',
431 (
432 'ScopedMockTimeMessageLoopTaskRunner is deprecated.',
433 ),
434 True,
435 (),
dskiba1474c2bfd62017-07-20 02:19:24436 )
[email protected]127f18ec2012-06-16 05:05:59437)
438
wnwenbdc444e2016-05-25 13:44:15439
mlamouria82272622014-09-16 18:45:04440_IPC_ENUM_TRAITS_DEPRECATED = (
441 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
442 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
443
[email protected]127f18ec2012-06-16 05:05:59444
[email protected]b00342e7f2013-03-26 16:21:54445_VALID_OS_MACROS = (
446 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08447 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54448 'OS_ANDROID',
449 'OS_BSD',
450 'OS_CAT', # For testing.
451 'OS_CHROMEOS',
452 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37453 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54454 'OS_IOS',
455 'OS_LINUX',
456 'OS_MACOSX',
457 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21458 'OS_NACL_NONSFI',
459 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12460 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54461 'OS_OPENBSD',
462 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37463 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54464 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54465 'OS_WIN',
466)
467
468
agrievef32bcc72016-04-04 14:57:40469_ANDROID_SPECIFIC_PYDEPS_FILES = [
470 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04471 'build/android/test_wrapper/logdog_wrapper.pydeps',
jbudorick276cc562017-04-29 01:34:58472 'build/secondary/third_party/android_platform/'
473 'development/scripts/stack.pydeps',
agrieve732db3a2016-04-26 19:18:19474 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40475]
476
wnwenbdc444e2016-05-25 13:44:15477
agrievef32bcc72016-04-04 14:57:40478_GENERIC_PYDEPS_FILES = [
agrievef32bcc72016-04-04 14:57:40479]
480
wnwenbdc444e2016-05-25 13:44:15481
agrievef32bcc72016-04-04 14:57:40482_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
483
484
[email protected]55459852011-08-10 15:17:19485def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
486 """Attempts to prevent use of functions intended only for testing in
487 non-testing code. For now this is just a best-effort implementation
488 that ignores header files and may have some false positives. A
489 better implementation would probably need a proper C++ parser.
490 """
491 # We only scan .cc files and the like, as the declaration of
492 # for-testing functions in header files are hard to distinguish from
493 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44494 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19495
jochenc0d4808c2015-07-27 09:25:42496 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19497 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09498 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19499 exclusion_pattern = input_api.re.compile(
500 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
501 base_function_pattern, base_function_pattern))
502
503 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44504 black_list = (_EXCLUDED_PATHS +
505 _TEST_CODE_EXCLUDED_PATHS +
506 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19507 return input_api.FilterSourceFile(
508 affected_file,
509 white_list=(file_inclusion_pattern, ),
510 black_list=black_list)
511
512 problems = []
513 for f in input_api.AffectedSourceFiles(FilterFile):
514 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24515 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03516 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46517 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03518 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19519 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03520 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19521
522 if problems:
[email protected]f7051d52013-04-02 18:31:42523 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03524 else:
525 return []
[email protected]55459852011-08-10 15:17:19526
527
[email protected]10689ca2011-09-02 02:31:54528def _CheckNoIOStreamInHeaders(input_api, output_api):
529 """Checks to make sure no .h files include <iostream>."""
530 files = []
531 pattern = input_api.re.compile(r'^#include\s*<iostream>',
532 input_api.re.MULTILINE)
533 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
534 if not f.LocalPath().endswith('.h'):
535 continue
536 contents = input_api.ReadFile(f)
537 if pattern.search(contents):
538 files.append(f)
539
540 if len(files):
yolandyandaabc6d2016-04-18 18:29:39541 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06542 'Do not #include <iostream> in header files, since it inserts static '
543 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54544 '#include <ostream>. See http://crbug.com/94794',
545 files) ]
546 return []
547
548
[email protected]72df4e782012-06-21 16:28:18549def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52550 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18551 problems = []
552 for f in input_api.AffectedFiles():
553 if (not f.LocalPath().endswith(('.cc', '.mm'))):
554 continue
555
556 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04557 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18558 problems.append(' %s:%d' % (f.LocalPath(), line_num))
559
560 if not problems:
561 return []
562 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
563 '\n'.join(problems))]
564
565
danakj61c1aa22015-10-26 19:55:52566def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57567 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52568 errors = []
569 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
570 input_api.re.MULTILINE)
571 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
572 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
573 continue
574 for lnum, line in f.ChangedContents():
575 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17576 errors.append(output_api.PresubmitError(
577 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57578 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17579 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52580 return errors
581
582
mcasasb7440c282015-02-04 14:52:19583def _FindHistogramNameInLine(histogram_name, line):
584 """Tries to find a histogram name or prefix in a line."""
585 if not "affected-histogram" in line:
586 return histogram_name in line
587 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
588 # the histogram_name.
589 if not '"' in line:
590 return False
591 histogram_prefix = line.split('\"')[1]
592 return histogram_prefix in histogram_name
593
594
595def _CheckUmaHistogramChanges(input_api, output_api):
596 """Check that UMA histogram names in touched lines can still be found in other
597 lines of the patch or in histograms.xml. Note that this check would not catch
598 the reverse: changes in histograms.xml not matched in the code itself."""
599 touched_histograms = []
600 histograms_xml_modifications = []
601 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
602 for f in input_api.AffectedFiles():
603 # If histograms.xml itself is modified, keep the modified lines for later.
604 if f.LocalPath().endswith(('histograms.xml')):
605 histograms_xml_modifications = f.ChangedContents()
606 continue
607 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
608 continue
609 for line_num, line in f.ChangedContents():
610 found = pattern.search(line)
611 if found:
612 touched_histograms.append([found.group(1), f, line_num])
613
614 # Search for the touched histogram names in the local modifications to
615 # histograms.xml, and, if not found, on the base histograms.xml file.
616 unmatched_histograms = []
617 for histogram_info in touched_histograms:
618 histogram_name_found = False
619 for line_num, line in histograms_xml_modifications:
620 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
621 if histogram_name_found:
622 break
623 if not histogram_name_found:
624 unmatched_histograms.append(histogram_info)
625
eromanb90c82e7e32015-04-01 15:13:49626 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19627 problems = []
628 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49629 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19630 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45631 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19632 histogram_name_found = False
633 for line in histograms_xml:
634 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
635 if histogram_name_found:
636 break
637 if not histogram_name_found:
638 problems.append(' [%s:%d] %s' %
639 (f.LocalPath(), line_num, histogram_name))
640
641 if not problems:
642 return []
643 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
644 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49645 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19646
wnwenbdc444e2016-05-25 13:44:15647
yolandyandaabc6d2016-04-18 18:29:39648def _CheckFlakyTestUsage(input_api, output_api):
649 """Check that FlakyTest annotation is our own instead of the android one"""
650 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
651 files = []
652 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
653 if f.LocalPath().endswith('Test.java'):
654 if pattern.search(input_api.ReadFile(f)):
655 files.append(f)
656 if len(files):
657 return [output_api.PresubmitError(
658 'Use org.chromium.base.test.util.FlakyTest instead of '
659 'android.test.FlakyTest',
660 files)]
661 return []
mcasasb7440c282015-02-04 14:52:19662
wnwenbdc444e2016-05-25 13:44:15663
[email protected]8ea5d4b2011-09-13 21:49:22664def _CheckNoNewWStrings(input_api, output_api):
665 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27666 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22667 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20668 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57669 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34670 '/win/' in f.LocalPath() or
671 'chrome_elf' in f.LocalPath() or
672 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20673 continue
[email protected]8ea5d4b2011-09-13 21:49:22674
[email protected]a11dbe9b2012-08-07 01:32:58675 allowWString = False
[email protected]b5c24292011-11-28 14:38:20676 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58677 if 'presubmit: allow wstring' in line:
678 allowWString = True
679 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27680 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58681 allowWString = False
682 else:
683 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22684
[email protected]55463aa62011-10-12 00:48:27685 if not problems:
686 return []
687 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58688 ' If you are calling a cross-platform API that accepts a wstring, '
689 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27690 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22691
692
[email protected]2a8ac9c2011-10-19 17:20:44693def _CheckNoDEPSGIT(input_api, output_api):
694 """Make sure .DEPS.git is never modified manually."""
695 if any(f.LocalPath().endswith('.DEPS.git') for f in
696 input_api.AffectedFiles()):
697 return [output_api.PresubmitError(
698 'Never commit changes to .DEPS.git. This file is maintained by an\n'
699 'automated system based on what\'s in DEPS and your changes will be\n'
700 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34701 '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:44702 'for more information')]
703 return []
704
705
tandriief664692014-09-23 14:51:47706def _CheckValidHostsInDEPS(input_api, output_api):
707 """Checks that DEPS file deps are from allowed_hosts."""
708 # Run only if DEPS file has been modified to annoy fewer bystanders.
709 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
710 return []
711 # Outsource work to gclient verify
712 try:
713 input_api.subprocess.check_output(['gclient', 'verify'])
714 return []
715 except input_api.subprocess.CalledProcessError, error:
716 return [output_api.PresubmitError(
717 'DEPS file must have only git dependencies.',
718 long_text=error.output)]
719
720
[email protected]127f18ec2012-06-16 05:05:59721def _CheckNoBannedFunctions(input_api, output_api):
722 """Make sure that banned functions are not used."""
723 warnings = []
724 errors = []
725
wnwenbdc444e2016-05-25 13:44:15726 def IsBlacklisted(affected_file, blacklist):
727 local_path = affected_file.LocalPath()
728 for item in blacklist:
729 if input_api.re.match(item, local_path):
730 return True
731 return False
732
733 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
734 matched = False
735 if func_name[0:1] == '/':
736 regex = func_name[1:]
737 if input_api.re.search(regex, line):
738 matched = True
739 elif func_name in line:
dchenge07de812016-06-20 19:27:17740 matched = True
wnwenbdc444e2016-05-25 13:44:15741 if matched:
dchenge07de812016-06-20 19:27:17742 problems = warnings
wnwenbdc444e2016-05-25 13:44:15743 if error:
dchenge07de812016-06-20 19:27:17744 problems = errors
wnwenbdc444e2016-05-25 13:44:15745 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
746 for message_line in message:
747 problems.append(' %s' % message_line)
748
[email protected]127f18ec2012-06-16 05:05:59749 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
750 for f in input_api.AffectedFiles(file_filter=file_filter):
751 for line_num, line in f.ChangedContents():
752 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:15753 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59754
755 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
756 for f in input_api.AffectedFiles(file_filter=file_filter):
757 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49758 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:49759 if IsBlacklisted(f, excluded_paths):
760 continue
wnwenbdc444e2016-05-25 13:44:15761 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59762
763 result = []
764 if (warnings):
765 result.append(output_api.PresubmitPromptWarning(
766 'Banned functions were used.\n' + '\n'.join(warnings)))
767 if (errors):
768 result.append(output_api.PresubmitError(
769 'Banned functions were used.\n' + '\n'.join(errors)))
770 return result
771
772
[email protected]6c063c62012-07-11 19:11:06773def _CheckNoPragmaOnce(input_api, output_api):
774 """Make sure that banned functions are not used."""
775 files = []
776 pattern = input_api.re.compile(r'^#pragma\s+once',
777 input_api.re.MULTILINE)
778 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
779 if not f.LocalPath().endswith('.h'):
780 continue
781 contents = input_api.ReadFile(f)
782 if pattern.search(contents):
783 files.append(f)
784
785 if files:
786 return [output_api.PresubmitError(
787 'Do not use #pragma once in header files.\n'
788 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
789 files)]
790 return []
791
[email protected]127f18ec2012-06-16 05:05:59792
[email protected]e7479052012-09-19 00:26:12793def _CheckNoTrinaryTrueFalse(input_api, output_api):
794 """Checks to make sure we don't introduce use of foo ? true : false."""
795 problems = []
796 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
797 for f in input_api.AffectedFiles():
798 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
799 continue
800
801 for line_num, line in f.ChangedContents():
802 if pattern.match(line):
803 problems.append(' %s:%d' % (f.LocalPath(), line_num))
804
805 if not problems:
806 return []
807 return [output_api.PresubmitPromptWarning(
808 'Please consider avoiding the "? true : false" pattern if possible.\n' +
809 '\n'.join(problems))]
810
811
[email protected]55f9f382012-07-31 11:02:18812def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:28813 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:18814 change. Breaking - rules is an error, breaking ! rules is a
815 warning.
816 """
mohan.reddyf21db962014-10-16 12:26:47817 import sys
[email protected]55f9f382012-07-31 11:02:18818 # We need to wait until we have an input_api object and use this
819 # roundabout construct to import checkdeps because this file is
820 # eval-ed and thus doesn't have __file__.
821 original_sys_path = sys.path
822 try:
823 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47824 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18825 import checkdeps
826 from cpp_checker import CppChecker
rhalavati08acd232017-04-03 07:23:28827 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:18828 from rules import Rule
829 finally:
830 # Restore sys.path to what it was before.
831 sys.path = original_sys_path
832
833 added_includes = []
rhalavati08acd232017-04-03 07:23:28834 added_imports = []
[email protected]55f9f382012-07-31 11:02:18835 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:28836 if CppChecker.IsCppFile(f.LocalPath()):
837 changed_lines = [line for line_num, line in f.ChangedContents()]
838 added_includes.append([f.LocalPath(), changed_lines])
839 elif ProtoChecker.IsProtoFile(f.LocalPath()):
840 changed_lines = [line for line_num, line in f.ChangedContents()]
841 added_imports.append([f.LocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:18842
[email protected]26385172013-05-09 23:11:35843 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18844
845 error_descriptions = []
846 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:28847 error_subjects = set()
848 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:18849 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
850 added_includes):
851 description_with_path = '%s\n %s' % (path, rule_description)
852 if rule_type == Rule.DISALLOW:
853 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28854 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:18855 else:
856 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28857 warning_subjects.add("#includes")
858
859 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
860 added_imports):
861 description_with_path = '%s\n %s' % (path, rule_description)
862 if rule_type == Rule.DISALLOW:
863 error_descriptions.append(description_with_path)
864 error_subjects.add("imports")
865 else:
866 warning_descriptions.append(description_with_path)
867 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:18868
869 results = []
870 if error_descriptions:
871 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:28872 'You added one or more %s that violate checkdeps rules.'
873 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:18874 error_descriptions))
875 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42876 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:28877 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:18878 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:28879 '%s? See relevant DEPS file(s) for details and contacts.' %
880 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:18881 warning_descriptions))
882 return results
883
884
[email protected]fbcafe5a2012-08-08 15:31:22885def _CheckFilePermissions(input_api, output_api):
886 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15887 if input_api.platform == 'win32':
888 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29889 checkperms_tool = input_api.os_path.join(
890 input_api.PresubmitLocalPath(),
891 'tools', 'checkperms', 'checkperms.py')
892 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47893 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22894 for f in input_api.AffectedFiles():
895 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11896 try:
897 input_api.subprocess.check_output(args)
898 return []
899 except input_api.subprocess.CalledProcessError as error:
900 return [output_api.PresubmitError(
901 'checkperms.py failed:',
902 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22903
904
robertocn832f5992017-01-04 19:01:30905def _CheckTeamTags(input_api, output_api):
906 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
907 checkteamtags_tool = input_api.os_path.join(
908 input_api.PresubmitLocalPath(),
909 'tools', 'checkteamtags', 'checkteamtags.py')
910 args = [input_api.python_executable, checkteamtags_tool,
911 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:22912 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:30913 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
914 'OWNERS']
915 try:
916 if files:
917 input_api.subprocess.check_output(args + files)
918 return []
919 except input_api.subprocess.CalledProcessError as error:
920 return [output_api.PresubmitError(
921 'checkteamtags.py failed:',
922 long_text=error.output)]
923
924
[email protected]c8278b32012-10-30 20:35:49925def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
926 """Makes sure we don't include ui/aura/window_property.h
927 in header files.
928 """
929 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
930 errors = []
931 for f in input_api.AffectedFiles():
932 if not f.LocalPath().endswith('.h'):
933 continue
934 for line_num, line in f.ChangedContents():
935 if pattern.match(line):
936 errors.append(' %s:%d' % (f.LocalPath(), line_num))
937
938 results = []
939 if errors:
940 results.append(output_api.PresubmitError(
941 'Header files should not include ui/aura/window_property.h', errors))
942 return results
943
944
[email protected]70ca77752012-11-20 03:45:03945def _CheckForVersionControlConflictsInFile(input_api, f):
946 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
947 errors = []
948 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23949 if f.LocalPath().endswith('.md'):
950 # First-level headers in markdown look a lot like version control
951 # conflict markers. http://daringfireball.net/projects/markdown/basics
952 continue
[email protected]70ca77752012-11-20 03:45:03953 if pattern.match(line):
954 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
955 return errors
956
957
958def _CheckForVersionControlConflicts(input_api, output_api):
959 """Usually this is not intentional and will cause a compile failure."""
960 errors = []
961 for f in input_api.AffectedFiles():
962 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
963
964 results = []
965 if errors:
966 results.append(output_api.PresubmitError(
967 'Version control conflict markers found, please resolve.', errors))
968 return results
969
estadee17314a02017-01-12 16:22:16970def _CheckGoogleSupportAnswerUrl(input_api, output_api):
971 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
972 errors = []
973 for f in input_api.AffectedFiles():
974 for line_num, line in f.ChangedContents():
975 if pattern.search(line):
976 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
977
978 results = []
979 if errors:
980 results.append(output_api.PresubmitPromptWarning(
981 'Found Google support URL addressed by answer number. Please replace with '
982 'a p= identifier instead. See crbug.com/679462\n', errors))
983 return results
984
[email protected]70ca77752012-11-20 03:45:03985
[email protected]06e6d0ff2012-12-11 01:36:44986def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
987 def FilterFile(affected_file):
988 """Filter function for use with input_api.AffectedSourceFiles,
989 below. This filters out everything except non-test files from
990 top-level directories that generally speaking should not hard-code
991 service URLs (e.g. src/android_webview/, src/content/ and others).
992 """
993 return input_api.FilterSourceFile(
994 affected_file,
[email protected]78bb39d62012-12-11 15:11:56995 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44996 black_list=(_EXCLUDED_PATHS +
997 _TEST_CODE_EXCLUDED_PATHS +
998 input_api.DEFAULT_BLACK_LIST))
999
reillyi38965732015-11-16 18:27:331000 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1001 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461002 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1003 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441004 problems = [] # items are (filename, line_number, line)
1005 for f in input_api.AffectedSourceFiles(FilterFile):
1006 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461007 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441008 problems.append((f.LocalPath(), line_num, line))
1009
1010 if problems:
[email protected]f7051d52013-04-02 18:31:421011 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441012 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581013 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441014 [' %s:%d: %s' % (
1015 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031016 else:
1017 return []
[email protected]06e6d0ff2012-12-11 01:36:441018
1019
[email protected]d2530012013-01-25 16:39:271020def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1021 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311022 The native_client_sdk directory is excluded because it has auto-generated PNG
1023 files for documentation.
[email protected]d2530012013-01-25 16:39:271024 """
[email protected]d2530012013-01-25 16:39:271025 errors = []
binji0dcdf342014-12-12 18:32:311026 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
1027 black_list = (r'^native_client_sdk[\\\/]',)
1028 file_filter = lambda f: input_api.FilterSourceFile(
1029 f, white_list=white_list, black_list=black_list)
1030 for f in input_api.AffectedFiles(include_deletes=False,
1031 file_filter=file_filter):
1032 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271033
1034 results = []
1035 if errors:
1036 results.append(output_api.PresubmitError(
1037 'The name of PNG files should not have abbreviations. \n'
1038 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1039 'Contact [email protected] if you have questions.', errors))
1040 return results
1041
1042
Daniel Cheng4dcdb6b2017-04-13 08:30:171043def _ExtractAddRulesFromParsedDeps(parsed_deps):
1044 """Extract the rules that add dependencies from a parsed DEPS file.
1045
1046 Args:
1047 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1048 add_rules = set()
1049 add_rules.update([
1050 rule[1:] for rule in parsed_deps.get('include_rules', [])
1051 if rule.startswith('+') or rule.startswith('!')
1052 ])
1053 for specific_file, rules in parsed_deps.get('specific_include_rules',
1054 {}).iteritems():
1055 add_rules.update([
1056 rule[1:] for rule in rules
1057 if rule.startswith('+') or rule.startswith('!')
1058 ])
1059 return add_rules
1060
1061
1062def _ParseDeps(contents):
1063 """Simple helper for parsing DEPS files."""
1064 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171065 class _VarImpl:
1066
1067 def __init__(self, local_scope):
1068 self._local_scope = local_scope
1069
1070 def Lookup(self, var_name):
1071 """Implements the Var syntax."""
1072 try:
1073 return self._local_scope['vars'][var_name]
1074 except KeyError:
1075 raise Exception('Var is not defined: %s' % var_name)
1076
1077 local_scope = {}
1078 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171079 'Var': _VarImpl(local_scope).Lookup,
1080 }
1081 exec contents in global_scope, local_scope
1082 return local_scope
1083
1084
1085def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081086 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411087 a set of DEPS entries that we should look up.
1088
1089 For a directory (rather than a specific filename) we fake a path to
1090 a specific filename by adding /DEPS. This is chosen as a file that
1091 will seldom or never be subject to per-file include_rules.
1092 """
[email protected]2b438d62013-11-14 17:54:141093 # We ignore deps entries on auto-generated directories.
1094 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081095
Daniel Cheng4dcdb6b2017-04-13 08:30:171096 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1097 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1098
1099 added_deps = new_deps.difference(old_deps)
1100
[email protected]2b438d62013-11-14 17:54:141101 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171102 for added_dep in added_deps:
1103 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1104 continue
1105 # Assume that a rule that ends in .h is a rule for a specific file.
1106 if added_dep.endswith('.h'):
1107 results.add(added_dep)
1108 else:
1109 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081110 return results
1111
1112
[email protected]e871964c2013-05-13 14:14:551113def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1114 """When a dependency prefixed with + is added to a DEPS file, we
1115 want to make sure that the change is reviewed by an OWNER of the
1116 target file or directory, to avoid layering violations from being
1117 introduced. This check verifies that this happens.
1118 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171119 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241120
1121 file_filter = lambda f: not input_api.re.match(
1122 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1123 for f in input_api.AffectedFiles(include_deletes=False,
1124 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551125 filename = input_api.os_path.basename(f.LocalPath())
1126 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171127 virtual_depended_on_files.update(_CalculateAddedDeps(
1128 input_api.os_path,
1129 '\n'.join(f.OldContents()),
1130 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551131
[email protected]e871964c2013-05-13 14:14:551132 if not virtual_depended_on_files:
1133 return []
1134
1135 if input_api.is_committing:
1136 if input_api.tbr:
1137 return [output_api.PresubmitNotifyResult(
1138 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271139 if input_api.dry_run:
1140 return [output_api.PresubmitNotifyResult(
1141 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551142 if not input_api.change.issue:
1143 return [output_api.PresubmitError(
1144 "DEPS approval by OWNERS check failed: this change has "
1145 "no Rietveld issue number, so we can't check it for approvals.")]
1146 output = output_api.PresubmitError
1147 else:
1148 output = output_api.PresubmitNotifyResult
1149
1150 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501151 owner_email, reviewers = (
1152 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1153 input_api,
1154 owners_db.email_regexp,
1155 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551156
1157 owner_email = owner_email or input_api.change.author_email
1158
[email protected]de4f7d22013-05-23 14:27:461159 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511160 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461161 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551162 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1163 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411164
1165 # We strip the /DEPS part that was added by
1166 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1167 # directory.
1168 def StripDeps(path):
1169 start_deps = path.rfind('/DEPS')
1170 if start_deps != -1:
1171 return path[:start_deps]
1172 else:
1173 return path
1174 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551175 for path in missing_files]
1176
1177 if unapproved_dependencies:
1178 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151179 output('You need LGTM from owners of depends-on paths in DEPS that were '
1180 'modified in this CL:\n %s' %
1181 '\n '.join(sorted(unapproved_dependencies)))]
1182 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1183 output_list.append(output(
1184 'Suggested missing target path OWNERS:\n %s' %
1185 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551186 return output_list
1187
1188 return []
1189
1190
[email protected]85218562013-11-22 07:41:401191def _CheckSpamLogging(input_api, output_api):
1192 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1193 black_list = (_EXCLUDED_PATHS +
1194 _TEST_CODE_EXCLUDED_PATHS +
1195 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501196 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191197 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481198 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461199 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121200 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1201 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581202 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
huangsa13b5a02017-07-14 15:17:591203 r"^chrome[\\\/]installer[\\\/]zucchini[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161204 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031205 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151206 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1207 r"^chromecast[\\\/]",
1208 r"^cloud_print[\\\/]",
manzagop85e629e2017-05-09 22:11:481209 r"^components[\\\/]browser_watcher[\\\/]"
1210 r"dump_stability_report_main_win.cc$",
jochen34415e52015-07-10 08:34:311211 r"^components[\\\/]html_viewer[\\\/]"
1212 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461213 # TODO(peter): Remove this exception. https://crbug.com/534537
1214 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1215 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251216 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1217 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241218 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111219 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151220 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111221 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521222 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501223 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361224 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311225 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131226 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001227 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441228 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451229 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021230 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351231 r"dump_file_system.cc$",
1232 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401233 source_file_filter = lambda x: input_api.FilterSourceFile(
1234 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1235
thomasanderson625d3932017-03-29 07:16:581236 log_info = set([])
1237 printf = set([])
[email protected]85218562013-11-22 07:41:401238
1239 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581240 for _, line in f.ChangedContents():
1241 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1242 log_info.add(f.LocalPath())
1243 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1244 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371245
thomasanderson625d3932017-03-29 07:16:581246 if input_api.re.search(r"\bprintf\(", line):
1247 printf.add(f.LocalPath())
1248 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1249 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401250
1251 if log_info:
1252 return [output_api.PresubmitError(
1253 'These files spam the console log with LOG(INFO):',
1254 items=log_info)]
1255 if printf:
1256 return [output_api.PresubmitError(
1257 'These files spam the console log with printf/fprintf:',
1258 items=printf)]
1259 return []
1260
1261
[email protected]49aa76a2013-12-04 06:59:161262def _CheckForAnonymousVariables(input_api, output_api):
1263 """These types are all expected to hold locks while in scope and
1264 so should never be anonymous (which causes them to be immediately
1265 destroyed)."""
1266 they_who_must_be_named = [
1267 'base::AutoLock',
1268 'base::AutoReset',
1269 'base::AutoUnlock',
1270 'SkAutoAlphaRestore',
1271 'SkAutoBitmapShaderInstall',
1272 'SkAutoBlitterChoose',
1273 'SkAutoBounderCommit',
1274 'SkAutoCallProc',
1275 'SkAutoCanvasRestore',
1276 'SkAutoCommentBlock',
1277 'SkAutoDescriptor',
1278 'SkAutoDisableDirectionCheck',
1279 'SkAutoDisableOvalCheck',
1280 'SkAutoFree',
1281 'SkAutoGlyphCache',
1282 'SkAutoHDC',
1283 'SkAutoLockColors',
1284 'SkAutoLockPixels',
1285 'SkAutoMalloc',
1286 'SkAutoMaskFreeImage',
1287 'SkAutoMutexAcquire',
1288 'SkAutoPathBoundsUpdate',
1289 'SkAutoPDFRelease',
1290 'SkAutoRasterClipValidate',
1291 'SkAutoRef',
1292 'SkAutoTime',
1293 'SkAutoTrace',
1294 'SkAutoUnref',
1295 ]
1296 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1297 # bad: base::AutoLock(lock.get());
1298 # not bad: base::AutoLock lock(lock.get());
1299 bad_pattern = input_api.re.compile(anonymous)
1300 # good: new base::AutoLock(lock.get())
1301 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1302 errors = []
1303
1304 for f in input_api.AffectedFiles():
1305 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1306 continue
1307 for linenum, line in f.ChangedContents():
1308 if bad_pattern.search(line) and not good_pattern.search(line):
1309 errors.append('%s:%d' % (f.LocalPath(), linenum))
1310
1311 if errors:
1312 return [output_api.PresubmitError(
1313 'These lines create anonymous variables that need to be named:',
1314 items=errors)]
1315 return []
1316
1317
[email protected]999261d2014-03-03 20:08:081318def _CheckUserActionUpdate(input_api, output_api):
1319 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521320 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081321 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521322 # If actions.xml is already included in the changelist, the PRESUBMIT
1323 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081324 return []
1325
[email protected]999261d2014-03-03 20:08:081326 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1327 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521328 current_actions = None
[email protected]999261d2014-03-03 20:08:081329 for f in input_api.AffectedFiles(file_filter=file_filter):
1330 for line_num, line in f.ChangedContents():
1331 match = input_api.re.search(action_re, line)
1332 if match:
[email protected]2f92dec2014-03-07 19:21:521333 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1334 # loaded only once.
1335 if not current_actions:
1336 with open('tools/metrics/actions/actions.xml') as actions_f:
1337 current_actions = actions_f.read()
1338 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081339 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521340 action = 'name="{0}"'.format(action_name)
1341 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081342 return [output_api.PresubmitPromptWarning(
1343 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521344 'tools/metrics/actions/actions.xml. Please run '
1345 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081346 % (f.LocalPath(), line_num, action_name))]
1347 return []
1348
1349
Daniel Cheng13ca61a882017-08-25 15:11:251350def _ImportJSONCommentEater(input_api):
1351 import sys
1352 sys.path = sys.path + [input_api.os_path.join(
1353 input_api.PresubmitLocalPath(),
1354 'tools', 'json_comment_eater')]
1355 import json_comment_eater
1356 return json_comment_eater
1357
1358
[email protected]99171a92014-06-03 08:44:471359def _GetJSONParseError(input_api, filename, eat_comments=True):
1360 try:
1361 contents = input_api.ReadFile(filename)
1362 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:251363 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:131364 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471365
1366 input_api.json.loads(contents)
1367 except ValueError as e:
1368 return e
1369 return None
1370
1371
1372def _GetIDLParseError(input_api, filename):
1373 try:
1374 contents = input_api.ReadFile(filename)
1375 idl_schema = input_api.os_path.join(
1376 input_api.PresubmitLocalPath(),
1377 'tools', 'json_schema_compiler', 'idl_schema.py')
1378 process = input_api.subprocess.Popen(
1379 [input_api.python_executable, idl_schema],
1380 stdin=input_api.subprocess.PIPE,
1381 stdout=input_api.subprocess.PIPE,
1382 stderr=input_api.subprocess.PIPE,
1383 universal_newlines=True)
1384 (_, error) = process.communicate(input=contents)
1385 return error or None
1386 except ValueError as e:
1387 return e
1388
1389
1390def _CheckParseErrors(input_api, output_api):
1391 """Check that IDL and JSON files do not contain syntax errors."""
1392 actions = {
1393 '.idl': _GetIDLParseError,
1394 '.json': _GetJSONParseError,
1395 }
1396 # These paths contain test data and other known invalid JSON files.
1397 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491398 r'test[\\\/]data[\\\/]',
1399 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
Tom Andersonac47edd2017-07-27 17:23:141400 r'^third_party[\\\/]protobuf[\\\/]',
[email protected]99171a92014-06-03 08:44:471401 ]
1402 # Most JSON files are preprocessed and support comments, but these do not.
1403 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491404 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471405 ]
1406 # Only run IDL checker on files in these directories.
1407 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491408 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1409 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471410 ]
1411
1412 def get_action(affected_file):
1413 filename = affected_file.LocalPath()
1414 return actions.get(input_api.os_path.splitext(filename)[1])
1415
1416 def MatchesFile(patterns, path):
1417 for pattern in patterns:
1418 if input_api.re.search(pattern, path):
1419 return True
1420 return False
1421
1422 def FilterFile(affected_file):
1423 action = get_action(affected_file)
1424 if not action:
1425 return False
1426 path = affected_file.LocalPath()
1427
1428 if MatchesFile(excluded_patterns, path):
1429 return False
1430
1431 if (action == _GetIDLParseError and
1432 not MatchesFile(idl_included_patterns, path)):
1433 return False
1434 return True
1435
1436 results = []
1437 for affected_file in input_api.AffectedFiles(
1438 file_filter=FilterFile, include_deletes=False):
1439 action = get_action(affected_file)
1440 kwargs = {}
1441 if (action == _GetJSONParseError and
1442 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1443 kwargs['eat_comments'] = False
1444 parse_error = action(input_api,
1445 affected_file.AbsoluteLocalPath(),
1446 **kwargs)
1447 if parse_error:
1448 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1449 (affected_file.LocalPath(), parse_error)))
1450 return results
1451
1452
[email protected]760deea2013-12-10 19:33:491453def _CheckJavaStyle(input_api, output_api):
1454 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471455 import sys
[email protected]760deea2013-12-10 19:33:491456 original_sys_path = sys.path
1457 try:
1458 sys.path = sys.path + [input_api.os_path.join(
1459 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1460 import checkstyle
1461 finally:
1462 # Restore sys.path to what it was before.
1463 sys.path = original_sys_path
1464
1465 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091466 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511467 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491468
1469
dchenge07de812016-06-20 19:27:171470def _CheckIpcOwners(input_api, output_api):
1471 """Checks that affected files involving IPC have an IPC OWNERS rule.
1472
1473 Whether or not a file affects IPC is determined by a simple whitelist of
1474 filename patterns."""
1475 file_patterns = [
palmerb19a0932017-01-24 04:00:311476 # Legacy IPC:
dchenge07de812016-06-20 19:27:171477 '*_messages.cc',
1478 '*_messages*.h',
1479 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311480 # Mojo IPC:
dchenge07de812016-06-20 19:27:171481 '*.mojom',
1482 '*_struct_traits*.*',
1483 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311484 '*.typemap',
1485 # Android native IPC:
1486 '*.aidl',
1487 # Blink uses a different file naming convention:
1488 '*EnumTraits*.*',
dchenge07de812016-06-20 19:27:171489 '*StructTraits*.*',
1490 '*TypeConverter*.*',
1491 ]
1492
scottmg7a6ed5ba2016-11-04 18:22:041493 # These third_party directories do not contain IPCs, but contain files
1494 # matching the above patterns, which trigger false positives.
1495 exclude_paths = [
1496 'third_party/crashpad/*',
1497 ]
1498
dchenge07de812016-06-20 19:27:171499 # Dictionary mapping an OWNERS file path to Patterns.
1500 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1501 # rules ) to a PatternEntry.
1502 # PatternEntry is a dictionary with two keys:
1503 # - 'files': the files that are matched by this pattern
1504 # - 'rules': the per-file rules needed for this pattern
1505 # For example, if we expect OWNERS file to contain rules for *.mojom and
1506 # *_struct_traits*.*, Patterns might look like this:
1507 # {
1508 # '*.mojom': {
1509 # 'files': ...,
1510 # 'rules': [
1511 # 'per-file *.mojom=set noparent',
1512 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1513 # ],
1514 # },
1515 # '*_struct_traits*.*': {
1516 # 'files': ...,
1517 # 'rules': [
1518 # 'per-file *_struct_traits*.*=set noparent',
1519 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1520 # ],
1521 # },
1522 # }
1523 to_check = {}
1524
Daniel Cheng13ca61a882017-08-25 15:11:251525 def AddPatternToCheck(input_file, pattern):
1526 owners_file = input_api.os_path.join(
1527 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
1528 if owners_file not in to_check:
1529 to_check[owners_file] = {}
1530 if pattern not in to_check[owners_file]:
1531 to_check[owners_file][pattern] = {
1532 'files': [],
1533 'rules': [
1534 'per-file %s=set noparent' % pattern,
1535 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1536 ]
1537 }
1538 to_check[owners_file][pattern]['files'].append(f)
1539
dchenge07de812016-06-20 19:27:171540 # Iterate through the affected files to see what we actually need to check
1541 # for. We should only nag patch authors about per-file rules if a file in that
1542 # directory would match that pattern. If a directory only contains *.mojom
1543 # files and no *_messages*.h files, we should only nag about rules for
1544 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:251545 for f in input_api.AffectedFiles(include_deletes=False):
1546 # Manifest files don't have a strong naming convention. Instead, scan
1547 # affected files for .json files and see if they look like a manifest.
1548 if f.LocalPath().endswith('.json'):
1549 json_comment_eater = _ImportJSONCommentEater(input_api)
1550 mostly_json_lines = '\n'.join(f.NewContents())
1551 # Comments aren't allowed in strict JSON, so filter them out.
1552 json_lines = json_comment_eater.Nom(mostly_json_lines)
1553 json_content = input_api.json.loads(json_lines)
1554 if 'interface_provider_specs' in json_content:
1555 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:171556 for pattern in file_patterns:
1557 if input_api.fnmatch.fnmatch(
1558 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041559 skip = False
1560 for exclude in exclude_paths:
1561 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1562 skip = True
1563 break
1564 if skip:
1565 continue
Daniel Cheng13ca61a882017-08-25 15:11:251566 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:171567 break
1568
1569 # Now go through the OWNERS files we collected, filtering out rules that are
1570 # already present in that OWNERS file.
1571 for owners_file, patterns in to_check.iteritems():
1572 try:
1573 with file(owners_file) as f:
1574 lines = set(f.read().splitlines())
1575 for entry in patterns.itervalues():
1576 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1577 ]
1578 except IOError:
1579 # No OWNERS file, so all the rules are definitely missing.
1580 continue
1581
1582 # All the remaining lines weren't found in OWNERS files, so emit an error.
1583 errors = []
1584 for owners_file, patterns in to_check.iteritems():
1585 missing_lines = []
1586 files = []
1587 for pattern, entry in patterns.iteritems():
1588 missing_lines.extend(entry['rules'])
1589 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1590 if missing_lines:
1591 errors.append(
Daniel Cheng52111692017-06-14 08:00:591592 '%s needs the following lines added:\n\n%s\n\nfor files:\n%s' %
dchenge07de812016-06-20 19:27:171593 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1594
1595 results = []
1596 if errors:
vabrf5ce3bf92016-07-11 14:52:411597 if input_api.is_committing:
1598 output = output_api.PresubmitError
1599 else:
1600 output = output_api.PresubmitPromptWarning
1601 results.append(output(
Daniel Cheng52111692017-06-14 08:00:591602 'Found OWNERS files that need to be updated for IPC security ' +
1603 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:171604 long_text='\n\n'.join(errors)))
1605
1606 return results
1607
1608
jbriance9e12f162016-11-25 07:57:501609def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311610 """Checks that added or removed lines in non third party affected
1611 header files do not lead to new useless class or struct forward
1612 declaration.
jbriance9e12f162016-11-25 07:57:501613 """
1614 results = []
1615 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1616 input_api.re.MULTILINE)
1617 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1618 input_api.re.MULTILINE)
1619 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311620 if (f.LocalPath().startswith('third_party') and
1621 not f.LocalPath().startswith('third_party/WebKit') and
1622 not f.LocalPath().startswith('third_party\\WebKit')):
1623 continue
1624
jbriance9e12f162016-11-25 07:57:501625 if not f.LocalPath().endswith('.h'):
1626 continue
1627
1628 contents = input_api.ReadFile(f)
1629 fwd_decls = input_api.re.findall(class_pattern, contents)
1630 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1631
1632 useless_fwd_decls = []
1633 for decl in fwd_decls:
1634 count = sum(1 for _ in input_api.re.finditer(
1635 r'\b%s\b' % input_api.re.escape(decl), contents))
1636 if count == 1:
1637 useless_fwd_decls.append(decl)
1638
1639 if not useless_fwd_decls:
1640 continue
1641
1642 for line in f.GenerateScmDiff().splitlines():
1643 if (line.startswith('-') and not line.startswith('--') or
1644 line.startswith('+') and not line.startswith('++')):
1645 for decl in useless_fwd_decls:
1646 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1647 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:241648 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:501649 (f.LocalPath(), decl)))
1650 useless_fwd_decls.remove(decl)
1651
1652 return results
1653
1654
dskiba88634f4e2015-08-14 23:03:291655def _CheckAndroidToastUsage(input_api, output_api):
1656 """Checks that code uses org.chromium.ui.widget.Toast instead of
1657 android.widget.Toast (Chromium Toast doesn't force hardware
1658 acceleration on low-end devices, saving memory).
1659 """
1660 toast_import_pattern = input_api.re.compile(
1661 r'^import android\.widget\.Toast;$')
1662
1663 errors = []
1664
1665 sources = lambda affected_file: input_api.FilterSourceFile(
1666 affected_file,
1667 black_list=(_EXCLUDED_PATHS +
1668 _TEST_CODE_EXCLUDED_PATHS +
1669 input_api.DEFAULT_BLACK_LIST +
1670 (r'^chromecast[\\\/].*',
1671 r'^remoting[\\\/].*')),
1672 white_list=(r'.*\.java$',))
1673
1674 for f in input_api.AffectedSourceFiles(sources):
1675 for line_num, line in f.ChangedContents():
1676 if toast_import_pattern.search(line):
1677 errors.append("%s:%d" % (f.LocalPath(), line_num))
1678
1679 results = []
1680
1681 if errors:
1682 results.append(output_api.PresubmitError(
1683 'android.widget.Toast usage is detected. Android toasts use hardware'
1684 ' acceleration, and can be\ncostly on low-end devices. Please use'
1685 ' org.chromium.ui.widget.Toast instead.\n'
1686 'Contact [email protected] if you have any questions.',
1687 errors))
1688
1689 return results
1690
1691
dgnaa68d5e2015-06-10 10:08:221692def _CheckAndroidCrLogUsage(input_api, output_api):
1693 """Checks that new logs using org.chromium.base.Log:
1694 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511695 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221696 """
pkotwicza1dd0b002016-05-16 14:41:041697
torne89540622017-03-24 19:41:301698 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:041699 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:301700 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:041701 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:301702 # WebView license viewer code cannot depend on //base; used in stub APK.
1703 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
1704 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:041705 ]
1706
dgnaa68d5e2015-06-10 10:08:221707 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121708 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1709 class_in_base_pattern = input_api.re.compile(
1710 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1711 has_some_log_import_pattern = input_api.re.compile(
1712 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221713 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121714 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221715 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511716 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221717 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221718
Vincent Scheib16d7b272015-09-15 18:09:071719 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221720 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041721 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1722 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121723
dgnaa68d5e2015-06-10 10:08:221724 tag_decl_errors = []
1725 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121726 tag_errors = []
dgn38736db2015-09-18 19:20:511727 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121728 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221729
1730 for f in input_api.AffectedSourceFiles(sources):
1731 file_content = input_api.ReadFile(f)
1732 has_modified_logs = False
1733
1734 # Per line checks
dgn87d9fb62015-06-12 09:15:121735 if (cr_log_import_pattern.search(file_content) or
1736 (class_in_base_pattern.search(file_content) and
1737 not has_some_log_import_pattern.search(file_content))):
1738 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221739 for line_num, line in f.ChangedContents():
1740
1741 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121742 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221743 if match:
1744 has_modified_logs = True
1745
1746 # Make sure it uses "TAG"
1747 if not match.group('tag') == 'TAG':
1748 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121749 else:
1750 # Report non cr Log function calls in changed lines
1751 for line_num, line in f.ChangedContents():
1752 if log_call_pattern.search(line):
1753 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221754
1755 # Per file checks
1756 if has_modified_logs:
1757 # Make sure the tag is using the "cr" prefix and is not too long
1758 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511759 tag_name = match.group('name') if match else None
1760 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221761 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511762 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221763 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511764 elif '.' in tag_name:
1765 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221766
1767 results = []
1768 if tag_decl_errors:
1769 results.append(output_api.PresubmitPromptWarning(
1770 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511771 '"private static final String TAG = "<package tag>".\n'
1772 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221773 tag_decl_errors))
1774
1775 if tag_length_errors:
1776 results.append(output_api.PresubmitError(
1777 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511778 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221779 tag_length_errors))
1780
1781 if tag_errors:
1782 results.append(output_api.PresubmitPromptWarning(
1783 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1784 tag_errors))
1785
dgn87d9fb62015-06-12 09:15:121786 if util_log_errors:
dgn4401aa52015-04-29 16:26:171787 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121788 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1789 util_log_errors))
1790
dgn38736db2015-09-18 19:20:511791 if tag_with_dot_errors:
1792 results.append(output_api.PresubmitPromptWarning(
1793 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1794 tag_with_dot_errors))
1795
dgn4401aa52015-04-29 16:26:171796 return results
1797
1798
yolandyan45001472016-12-21 21:12:421799def _CheckAndroidTestAnnotationUsage(input_api, output_api):
1800 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
1801 deprecated_annotation_import_pattern = input_api.re.compile(
1802 r'^import android\.test\.suitebuilder\.annotation\..*;',
1803 input_api.re.MULTILINE)
1804 sources = lambda x: input_api.FilterSourceFile(
1805 x, white_list=(r'.*\.java$',), black_list=None)
1806 errors = []
1807 for f in input_api.AffectedFiles(sources):
1808 for line_num, line in f.ChangedContents():
1809 if deprecated_annotation_import_pattern.search(line):
1810 errors.append("%s:%d" % (f.LocalPath(), line_num))
1811
1812 results = []
1813 if errors:
1814 results.append(output_api.PresubmitError(
1815 'Annotations in android.test.suitebuilder.annotation have been'
1816 ' deprecated since API level 24. Please use android.support.test.filters'
1817 ' from //third_party/android_support_test_runner:runner_java instead.'
1818 ' Contact [email protected] if you have any questions.', errors))
1819 return results
1820
1821
agrieve7b6479d82015-10-07 14:24:221822def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1823 """Checks if MDPI assets are placed in a correct directory."""
1824 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1825 ('/res/drawable/' in f.LocalPath() or
1826 '/res/drawable-ldrtl/' in f.LocalPath()))
1827 errors = []
1828 for f in input_api.AffectedFiles(include_deletes=False,
1829 file_filter=file_filter):
1830 errors.append(' %s' % f.LocalPath())
1831
1832 results = []
1833 if errors:
1834 results.append(output_api.PresubmitError(
1835 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1836 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1837 '/res/drawable-ldrtl/.\n'
1838 'Contact [email protected] if you have questions.', errors))
1839 return results
1840
1841
agrievef32bcc72016-04-04 14:57:401842class PydepsChecker(object):
1843 def __init__(self, input_api, pydeps_files):
1844 self._file_cache = {}
1845 self._input_api = input_api
1846 self._pydeps_files = pydeps_files
1847
1848 def _LoadFile(self, path):
1849 """Returns the list of paths within a .pydeps file relative to //."""
1850 if path not in self._file_cache:
1851 with open(path) as f:
1852 self._file_cache[path] = f.read()
1853 return self._file_cache[path]
1854
1855 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1856 """Returns an interable of paths within the .pydep, relativized to //."""
1857 os_path = self._input_api.os_path
1858 pydeps_dir = os_path.dirname(pydeps_path)
1859 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1860 if not l.startswith('*'))
1861 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1862
1863 def _CreateFilesToPydepsMap(self):
1864 """Returns a map of local_path -> list_of_pydeps."""
1865 ret = {}
1866 for pydep_local_path in self._pydeps_files:
1867 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1868 ret.setdefault(path, []).append(pydep_local_path)
1869 return ret
1870
1871 def ComputeAffectedPydeps(self):
1872 """Returns an iterable of .pydeps files that might need regenerating."""
1873 affected_pydeps = set()
1874 file_to_pydeps_map = None
1875 for f in self._input_api.AffectedFiles(include_deletes=True):
1876 local_path = f.LocalPath()
1877 if local_path == 'DEPS':
1878 return self._pydeps_files
1879 elif local_path.endswith('.pydeps'):
1880 if local_path in self._pydeps_files:
1881 affected_pydeps.add(local_path)
1882 elif local_path.endswith('.py'):
1883 if file_to_pydeps_map is None:
1884 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1885 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1886 return affected_pydeps
1887
1888 def DetermineIfStale(self, pydeps_path):
1889 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:411890 import difflib
agrievef32bcc72016-04-04 14:57:401891 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1892 cmd = old_pydeps_data[1][1:].strip()
1893 new_pydeps_data = self._input_api.subprocess.check_output(
1894 cmd + ' --output ""', shell=True)
phajdan.jr0d9878552016-11-04 10:49:411895 old_contents = old_pydeps_data[2:]
1896 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:401897 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:411898 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:401899
1900
1901def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1902 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001903 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281904 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1905 # Mac, so skip it on other platforms.
1906 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001907 return []
agrievef32bcc72016-04-04 14:57:401908 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1909 is_android = input_api.os_path.exists('third_party/android_tools')
1910 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1911 results = []
1912 # First, check for new / deleted .pydeps.
1913 for f in input_api.AffectedFiles(include_deletes=True):
1914 if f.LocalPath().endswith('.pydeps'):
1915 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1916 results.append(output_api.PresubmitError(
1917 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1918 'remove %s' % f.LocalPath()))
1919 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1920 results.append(output_api.PresubmitError(
1921 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1922 'include %s' % f.LocalPath()))
1923
1924 if results:
1925 return results
1926
1927 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1928
1929 for pydep_path in checker.ComputeAffectedPydeps():
1930 try:
phajdan.jr0d9878552016-11-04 10:49:411931 result = checker.DetermineIfStale(pydep_path)
1932 if result:
1933 cmd, diff = result
agrievef32bcc72016-04-04 14:57:401934 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:411935 'File is stale: %s\nDiff (apply to fix):\n%s\n'
1936 'To regenerate, run:\n\n %s' %
1937 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:401938 except input_api.subprocess.CalledProcessError as error:
1939 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1940 long_text=error.output)]
1941
1942 return results
1943
1944
glidere61efad2015-02-18 17:39:431945def _CheckSingletonInHeaders(input_api, output_api):
1946 """Checks to make sure no header files have |Singleton<|."""
1947 def FileFilter(affected_file):
1948 # It's ok for base/memory/singleton.h to have |Singleton<|.
1949 black_list = (_EXCLUDED_PATHS +
1950 input_api.DEFAULT_BLACK_LIST +
1951 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1952 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1953
sergeyu34d21222015-09-16 00:11:441954 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431955 files = []
1956 for f in input_api.AffectedSourceFiles(FileFilter):
1957 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1958 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1959 contents = input_api.ReadFile(f)
1960 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241961 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431962 pattern.search(line)):
1963 files.append(f)
1964 break
1965
1966 if files:
yolandyandaabc6d2016-04-18 18:29:391967 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441968 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431969 'Please move them to an appropriate source file so that the ' +
1970 'template gets instantiated in a single compilation unit.',
1971 files) ]
1972 return []
1973
1974
[email protected]fd20b902014-05-09 02:14:531975_DEPRECATED_CSS = [
1976 # Values
1977 ( "-webkit-box", "flex" ),
1978 ( "-webkit-inline-box", "inline-flex" ),
1979 ( "-webkit-flex", "flex" ),
1980 ( "-webkit-inline-flex", "inline-flex" ),
1981 ( "-webkit-min-content", "min-content" ),
1982 ( "-webkit-max-content", "max-content" ),
1983
1984 # Properties
1985 ( "-webkit-background-clip", "background-clip" ),
1986 ( "-webkit-background-origin", "background-origin" ),
1987 ( "-webkit-background-size", "background-size" ),
1988 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:441989 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:531990
1991 # Functions
1992 ( "-webkit-gradient", "gradient" ),
1993 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1994 ( "-webkit-linear-gradient", "linear-gradient" ),
1995 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1996 ( "-webkit-radial-gradient", "radial-gradient" ),
1997 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1998]
1999
dbeam1ec68ac2016-12-15 05:22:242000def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532001 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252002 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342003 documentation and iOS CSS for dom distiller
2004 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252005 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532006 results = []
dbeam070cfe62014-10-22 06:44:022007 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:252008 black_list = (_EXCLUDED_PATHS +
2009 _TEST_CODE_EXCLUDED_PATHS +
2010 input_api.DEFAULT_BLACK_LIST +
2011 (r"^chrome/common/extensions/docs",
2012 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342013 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442014 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252015 r"^native_client_sdk"))
2016 file_filter = lambda f: input_api.FilterSourceFile(
2017 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532018 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2019 for line_num, line in fpath.ChangedContents():
2020 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022021 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532022 results.append(output_api.PresubmitError(
2023 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2024 (fpath.LocalPath(), line_num, deprecated_value, value)))
2025 return results
2026
mohan.reddyf21db962014-10-16 12:26:472027
dbeam070cfe62014-10-22 06:44:022028_DEPRECATED_JS = [
2029 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2030 ( "__defineGetter__", "Object.defineProperty" ),
2031 ( "__defineSetter__", "Object.defineProperty" ),
2032]
2033
dbeam1ec68ac2016-12-15 05:22:242034def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022035 """Make sure that we don't use deprecated JS in Chrome code."""
2036 results = []
2037 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2038 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2039 input_api.DEFAULT_BLACK_LIST)
2040 file_filter = lambda f: input_api.FilterSourceFile(
2041 f, white_list=file_inclusion_pattern, black_list=black_list)
2042 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2043 for lnum, line in fpath.ChangedContents():
2044 for (deprecated, replacement) in _DEPRECATED_JS:
2045 if deprecated in line:
2046 results.append(output_api.PresubmitError(
2047 "%s:%d: Use of deprecated JS %s, use %s instead" %
2048 (fpath.LocalPath(), lnum, deprecated, replacement)))
2049 return results
2050
dpapadd651231d82017-07-21 02:44:472051def _CheckForRiskyJsArrowFunction(line_number, line):
2052 if ' => ' in line:
2053 return "line %d, is using an => (arrow) function\n %s\n" % (
2054 line_number, line)
2055 return ''
2056
2057def _CheckForRiskyJsConstLet(input_api, line_number, line):
2058 if input_api.re.match('^\s*(const|let)\s', line):
2059 return "line %d, is using const/let keyword\n %s\n" % (
2060 line_number, line)
2061 return ''
dbeam070cfe62014-10-22 06:44:022062
dbeam1ec68ac2016-12-15 05:22:242063def _CheckForRiskyJsFeatures(input_api, output_api):
2064 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
Steven Bennetts90545f3cb2017-08-14 18:11:002065 # 'ui/webui/resources/cr_components are not allowed on ios'
2066 not_ios_filter = (r".*ui\/webui\/resources\/cr_components.*", )
Steven Bennetts9c7e3c22017-08-02 19:10:572067 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js,
Steven Bennetts90545f3cb2017-08-14 18:11:002068 black_list=not_ios_filter)
dpapadd651231d82017-07-21 02:44:472069 results = []
dbeam1ec68ac2016-12-15 05:22:242070 for f in input_api.AffectedFiles(file_filter=file_filter):
dpapadd651231d82017-07-21 02:44:472071 arrow_error_lines = []
2072 const_let_error_lines = []
dbeam1ec68ac2016-12-15 05:22:242073 for lnum, line in f.ChangedContents():
dpapadd651231d82017-07-21 02:44:472074 arrow_error_lines += filter(None, [
2075 _CheckForRiskyJsArrowFunction(lnum, line),
2076 ])
dbeam1ec68ac2016-12-15 05:22:242077
dpapadd651231d82017-07-21 02:44:472078 const_let_error_lines += filter(None, [
2079 _CheckForRiskyJsConstLet(input_api, lnum, line),
2080 ])
dbeam1ec68ac2016-12-15 05:22:242081
dpapadd651231d82017-07-21 02:44:472082 if arrow_error_lines:
2083 arrow_error_lines = map(
2084 lambda e: "%s:%s" % (f.LocalPath(), e), arrow_error_lines)
2085 results.append(
2086 output_api.PresubmitPromptWarning('\n'.join(arrow_error_lines + [
2087"""
2088Use of => (arrow) operator detected in:
dbeam1ec68ac2016-12-15 05:22:242089%s
2090Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2091https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
dpapadd651231d82017-07-21 02:44:472092""" % f.LocalPath()
2093 ])))
dbeam1ec68ac2016-12-15 05:22:242094
dpapadd651231d82017-07-21 02:44:472095 if const_let_error_lines:
2096 const_let_error_lines = map(
2097 lambda e: "%s:%s" % (f.LocalPath(), e), const_let_error_lines)
2098 results.append(
2099 output_api.PresubmitPromptWarning('\n'.join(const_let_error_lines + [
2100"""
2101Use of const/let keywords detected in:
2102%s
2103Please ensure your code does not run on iOS9 because const/let is not fully
2104supported.
2105https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#let-Block_Scoped-Variables
2106https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#const-Block_Scoped-Constants
2107""" % f.LocalPath()
2108 ])))
2109
2110 return results
dbeam1ec68ac2016-12-15 05:22:242111
rlanday6802cf632017-05-30 17:48:362112def _CheckForRelativeIncludes(input_api, output_api):
2113 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2114 import sys
2115 original_sys_path = sys.path
2116 try:
2117 sys.path = sys.path + [input_api.os_path.join(
2118 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2119 from cpp_checker import CppChecker
2120 finally:
2121 # Restore sys.path to what it was before.
2122 sys.path = original_sys_path
2123
2124 bad_files = {}
2125 for f in input_api.AffectedFiles(include_deletes=False):
2126 if (f.LocalPath().startswith('third_party') and
2127 not f.LocalPath().startswith('third_party/WebKit') and
2128 not f.LocalPath().startswith('third_party\\WebKit')):
2129 continue
2130
2131 if not CppChecker.IsCppFile(f.LocalPath()):
2132 continue
2133
2134 relative_includes = [line for line_num, line in f.ChangedContents()
2135 if "#include" in line and "../" in line]
2136 if not relative_includes:
2137 continue
2138 bad_files[f.LocalPath()] = relative_includes
2139
2140 if not bad_files:
2141 return []
2142
2143 error_descriptions = []
2144 for file_path, bad_lines in bad_files.iteritems():
2145 error_description = file_path
2146 for line in bad_lines:
2147 error_description += '\n ' + line
2148 error_descriptions.append(error_description)
2149
2150 results = []
2151 results.append(output_api.PresubmitError(
2152 'You added one or more relative #include paths (including "../").\n'
2153 'These shouldn\'t be used because they can be used to include headers\n'
2154 'from code that\'s not correctly specified as a dependency in the\n'
2155 'relevant BUILD.gn file(s).',
2156 error_descriptions))
2157
2158 return results
2159
Takeshi Yoshinoe387aa32017-08-02 13:16:132160
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202161def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2162 if not isinstance(key, ast.Str):
2163 return 'Key at line %d must be a string literal' % key.lineno
2164 if not isinstance(value, ast.Dict):
2165 return 'Value at line %d must be a dict' % value.lineno
2166 if len(value.keys) != 1:
2167 return 'Dict at line %d must have single entry' % value.lineno
2168 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2169 return (
2170 'Entry at line %d must have a string literal \'filepath\' as key' %
2171 value.lineno)
2172 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132173
Takeshi Yoshinoe387aa32017-08-02 13:16:132174
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202175def _CheckWatchlistsEntrySyntax(key, value, ast):
2176 if not isinstance(key, ast.Str):
2177 return 'Key at line %d must be a string literal' % key.lineno
2178 if not isinstance(value, ast.List):
2179 return 'Value at line %d must be a list' % value.lineno
2180 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132181
Takeshi Yoshinoe387aa32017-08-02 13:16:132182
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202183def _CheckWATCHLISTSEntries(wd_dict, w_dict, ast):
2184 mismatch_template = (
2185 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2186 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132187
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202188 i = 0
2189 last_key = ''
2190 while True:
2191 if i >= len(wd_dict.keys):
2192 if i >= len(w_dict.keys):
2193 return None
2194 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2195 elif i >= len(w_dict.keys):
2196 return (
2197 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132198
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202199 wd_key = wd_dict.keys[i]
2200 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132201
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202202 result = _CheckWatchlistDefinitionsEntrySyntax(
2203 wd_key, wd_dict.values[i], ast)
2204 if result is not None:
2205 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132206
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202207 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast)
2208 if result is not None:
2209 return 'Bad entry in WATCHLISTS dict: %s' % result
2210
2211 if wd_key.s != w_key.s:
2212 return mismatch_template % (
2213 '%s at line %d' % (wd_key.s, wd_key.lineno),
2214 '%s at line %d' % (w_key.s, w_key.lineno))
2215
2216 if wd_key.s < last_key:
2217 return (
2218 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2219 (wd_key.lineno, w_key.lineno))
2220 last_key = wd_key.s
2221
2222 i = i + 1
2223
2224
2225def _CheckWATCHLISTSSyntax(expression, ast):
2226 if not isinstance(expression, ast.Expression):
2227 return 'WATCHLISTS file must contain a valid expression'
2228 dictionary = expression.body
2229 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2230 return 'WATCHLISTS file must have single dict with exactly two entries'
2231
2232 first_key = dictionary.keys[0]
2233 first_value = dictionary.values[0]
2234 second_key = dictionary.keys[1]
2235 second_value = dictionary.values[1]
2236
2237 if (not isinstance(first_key, ast.Str) or
2238 first_key.s != 'WATCHLIST_DEFINITIONS' or
2239 not isinstance(first_value, ast.Dict)):
2240 return (
2241 'The first entry of the dict in WATCHLISTS file must be '
2242 'WATCHLIST_DEFINITIONS dict')
2243
2244 if (not isinstance(second_key, ast.Str) or
2245 second_key.s != 'WATCHLISTS' or
2246 not isinstance(second_value, ast.Dict)):
2247 return (
2248 'The second entry of the dict in WATCHLISTS file must be '
2249 'WATCHLISTS dict')
2250
2251 return _CheckWATCHLISTSEntries(first_value, second_value, ast)
Takeshi Yoshinoe387aa32017-08-02 13:16:132252
2253
2254def _CheckWATCHLISTS(input_api, output_api):
2255 for f in input_api.AffectedFiles(include_deletes=False):
2256 if f.LocalPath() == 'WATCHLISTS':
2257 contents = input_api.ReadFile(f, 'r')
2258
2259 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202260 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132261 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202262 # Get an AST tree for it and scan the tree for detailed style checking.
2263 expression = input_api.ast.parse(
2264 contents, filename='WATCHLISTS', mode='eval')
2265 except ValueError as e:
2266 return [output_api.PresubmitError(
2267 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2268 except SyntaxError as e:
2269 return [output_api.PresubmitError(
2270 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2271 except TypeError as e:
2272 return [output_api.PresubmitError(
2273 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132274
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202275 result = _CheckWATCHLISTSSyntax(expression, input_api.ast)
2276 if result is not None:
2277 return [output_api.PresubmitError(result)]
2278 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132279
2280 return []
2281
2282
dgnaa68d5e2015-06-10 10:08:222283def _AndroidSpecificOnUploadChecks(input_api, output_api):
2284 """Groups checks that target android code."""
2285 results = []
dgnaa68d5e2015-06-10 10:08:222286 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222287 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292288 results.extend(_CheckAndroidToastUsage(input_api, output_api))
yolandyan45001472016-12-21 21:12:422289 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222290 return results
2291
2292
[email protected]22c9bd72011-03-27 16:47:392293def _CommonChecks(input_api, output_api):
2294 """Checks common to both upload and commit."""
2295 results = []
2296 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382297 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542298 excluded_paths=_EXCLUDED_PATHS))
machenbachfbda9b72016-12-06 13:13:582299 results.extend(
2300 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:192301 results.extend(
[email protected]760deea2013-12-10 19:33:492302 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542303 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182304 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522305 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222306 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442307 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592308 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062309 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122310 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182311 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222312 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302313 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492314 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032315 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492316 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442317 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272318 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:072319 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542320 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442321 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392322 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552323 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042324 results.extend(
2325 input_api.canned_checks.CheckChangeHasNoTabs(
2326 input_api,
2327 output_api,
2328 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402329 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162330 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082331 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242332 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2333 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472334 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042335 results.extend(_CheckForIPCRules(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232336 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432337 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402338 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152339 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172340 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502341 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242342 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:362343 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:132344 results.extend(_CheckWATCHLISTS(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242345
2346 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
2347 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2348 input_api, output_api,
2349 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:382350 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392351 return results
[email protected]1f7b4172010-01-28 01:17:342352
[email protected]b337cb5b2011-01-23 21:24:052353
[email protected]b8079ae4a2012-12-05 19:56:492354def _CheckPatchFiles(input_api, output_api):
2355 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2356 if f.LocalPath().endswith(('.orig', '.rej'))]
2357 if problems:
2358 return [output_api.PresubmitError(
2359 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032360 else:
2361 return []
[email protected]b8079ae4a2012-12-05 19:56:492362
2363
Kent Tamura5a8755d2017-06-29 23:37:072364def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:212365 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
2366 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
2367 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:072368 include_re = input_api.re.compile(
2369 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
2370 extension_re = input_api.re.compile(r'\.[a-z]+$')
2371 errors = []
2372 for f in input_api.AffectedFiles():
2373 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
2374 continue
2375 found_line_number = None
2376 found_macro = None
2377 for line_num, line in f.ChangedContents():
2378 match = macro_re.search(line)
2379 if match:
2380 found_line_number = line_num
2381 found_macro = match.group(2)
2382 break
2383 if not found_line_number:
2384 continue
2385
2386 found_include = False
2387 for line in f.NewContents():
2388 if include_re.search(line):
2389 found_include = True
2390 break
2391 if found_include:
2392 continue
2393
2394 if not f.LocalPath().endswith('.h'):
2395 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
2396 try:
2397 content = input_api.ReadFile(primary_header_path, 'r')
2398 if include_re.search(content):
2399 continue
2400 except IOError:
2401 pass
2402 errors.append('%s:%d %s macro is used without including build/'
2403 'build_config.h.'
2404 % (f.LocalPath(), found_line_number, found_macro))
2405 if errors:
2406 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
2407 return []
2408
2409
[email protected]b00342e7f2013-03-26 16:21:542410def _DidYouMeanOSMacro(bad_macro):
2411 try:
2412 return {'A': 'OS_ANDROID',
2413 'B': 'OS_BSD',
2414 'C': 'OS_CHROMEOS',
2415 'F': 'OS_FREEBSD',
2416 'L': 'OS_LINUX',
2417 'M': 'OS_MACOSX',
2418 'N': 'OS_NACL',
2419 'O': 'OS_OPENBSD',
2420 'P': 'OS_POSIX',
2421 'S': 'OS_SOLARIS',
2422 'W': 'OS_WIN'}[bad_macro[3].upper()]
2423 except KeyError:
2424 return ''
2425
2426
2427def _CheckForInvalidOSMacrosInFile(input_api, f):
2428 """Check for sensible looking, totally invalid OS macros."""
2429 preprocessor_statement = input_api.re.compile(r'^\s*#')
2430 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2431 results = []
2432 for lnum, line in f.ChangedContents():
2433 if preprocessor_statement.search(line):
2434 for match in os_macro.finditer(line):
2435 if not match.group(1) in _VALID_OS_MACROS:
2436 good = _DidYouMeanOSMacro(match.group(1))
2437 did_you_mean = ' (did you mean %s?)' % good if good else ''
2438 results.append(' %s:%d %s%s' % (f.LocalPath(),
2439 lnum,
2440 match.group(1),
2441 did_you_mean))
2442 return results
2443
2444
2445def _CheckForInvalidOSMacros(input_api, output_api):
2446 """Check all affected files for invalid OS macros."""
2447 bad_macros = []
2448 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472449 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542450 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2451
2452 if not bad_macros:
2453 return []
2454
2455 return [output_api.PresubmitError(
2456 'Possibly invalid OS macro[s] found. Please fix your code\n'
2457 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2458
lliabraa35bab3932014-10-01 12:16:442459
2460def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2461 """Check all affected files for invalid "if defined" macros."""
2462 ALWAYS_DEFINED_MACROS = (
2463 "TARGET_CPU_PPC",
2464 "TARGET_CPU_PPC64",
2465 "TARGET_CPU_68K",
2466 "TARGET_CPU_X86",
2467 "TARGET_CPU_ARM",
2468 "TARGET_CPU_MIPS",
2469 "TARGET_CPU_SPARC",
2470 "TARGET_CPU_ALPHA",
2471 "TARGET_IPHONE_SIMULATOR",
2472 "TARGET_OS_EMBEDDED",
2473 "TARGET_OS_IPHONE",
2474 "TARGET_OS_MAC",
2475 "TARGET_OS_UNIX",
2476 "TARGET_OS_WIN32",
2477 )
2478 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2479 results = []
2480 for lnum, line in f.ChangedContents():
2481 for match in ifdef_macro.finditer(line):
2482 if match.group(1) in ALWAYS_DEFINED_MACROS:
2483 always_defined = ' %s is always defined. ' % match.group(1)
2484 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2485 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2486 lnum,
2487 always_defined,
2488 did_you_mean))
2489 return results
2490
2491
2492def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2493 """Check all affected files for invalid "if defined" macros."""
2494 bad_macros = []
2495 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:212496 if f.LocalPath().startswith('third_party/sqlite/'):
2497 continue
lliabraa35bab3932014-10-01 12:16:442498 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2499 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2500
2501 if not bad_macros:
2502 return []
2503
2504 return [output_api.PresubmitError(
2505 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2506 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2507 bad_macros)]
2508
2509
mlamouria82272622014-09-16 18:45:042510def _CheckForIPCRules(input_api, output_api):
2511 """Check for same IPC rules described in
2512 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2513 """
2514 base_pattern = r'IPC_ENUM_TRAITS\('
2515 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2516 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2517
2518 problems = []
2519 for f in input_api.AffectedSourceFiles(None):
2520 local_path = f.LocalPath()
2521 if not local_path.endswith('.h'):
2522 continue
2523 for line_number, line in f.ChangedContents():
2524 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2525 problems.append(
2526 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2527
2528 if problems:
2529 return [output_api.PresubmitPromptWarning(
2530 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2531 else:
2532 return []
2533
[email protected]b00342e7f2013-03-26 16:21:542534
mostynbb639aca52015-01-07 20:31:232535def _CheckForWindowsLineEndings(input_api, output_api):
2536 """Check source code and known ascii text files for Windows style line
2537 endings.
2538 """
earthdok1b5e0ee2015-03-10 15:19:102539 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232540
2541 file_inclusion_pattern = (
2542 known_text_files,
2543 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2544 )
2545
2546 filter = lambda f: input_api.FilterSourceFile(
2547 f, white_list=file_inclusion_pattern, black_list=None)
2548 files = [f.LocalPath() for f in
2549 input_api.AffectedSourceFiles(filter)]
2550
2551 problems = []
2552
2553 for file in files:
2554 fp = open(file, 'r')
2555 for line in fp:
2556 if line.endswith('\r\n'):
2557 problems.append(file)
2558 break
2559 fp.close()
2560
2561 if problems:
2562 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2563 'these files to contain Windows style line endings?\n' +
2564 '\n'.join(problems))]
2565
2566 return []
2567
2568
pastarmovj89f7ee12016-09-20 14:58:132569def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None,
2570 lint_filters=None, verbose_level=None):
2571 """Checks that all source files use SYSLOG properly."""
2572 syslog_files = []
2573 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:562574 for line_number, line in f.ChangedContents():
2575 if 'SYSLOG' in line:
2576 syslog_files.append(f.LocalPath() + ':' + str(line_number))
2577
pastarmovj89f7ee12016-09-20 14:58:132578 if syslog_files:
2579 return [output_api.PresubmitPromptWarning(
2580 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
2581 ' calls.\nFiles to check:\n', items=syslog_files)]
2582 return []
2583
2584
[email protected]1f7b4172010-01-28 01:17:342585def CheckChangeOnUpload(input_api, output_api):
2586 results = []
2587 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472588 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282589 results.extend(
jam93a6ee792017-02-08 23:59:222590 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192591 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222592 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:132593 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:162594 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542595 return results
[email protected]ca8d19842009-02-19 16:33:122596
2597
[email protected]1bfb8322014-04-23 01:02:412598def GetTryServerMasterForBot(bot):
2599 """Returns the Try Server master for the given bot.
2600
[email protected]0bb112362014-07-26 04:38:322601 It tries to guess the master from the bot name, but may still fail
2602 and return None. There is no longer a default master.
2603 """
2604 # Potentially ambiguous bot names are listed explicitly.
2605 master_map = {
tandriie5587792016-07-14 00:34:502606 'chromium_presubmit': 'master.tryserver.chromium.linux',
2607 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412608 }
[email protected]0bb112362014-07-26 04:38:322609 master = master_map.get(bot)
2610 if not master:
wnwen4fbaab82016-05-25 12:54:362611 if 'android' in bot:
tandriie5587792016-07-14 00:34:502612 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:362613 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:502614 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:322615 elif 'win' in bot:
tandriie5587792016-07-14 00:34:502616 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:322617 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:502618 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:322619 return master
[email protected]1bfb8322014-04-23 01:02:412620
2621
[email protected]ca8d19842009-02-19 16:33:122622def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542623 results = []
[email protected]1f7b4172010-01-28 01:17:342624 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542625 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272626 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342627 input_api,
2628 output_api,
[email protected]2fdd1f362013-01-16 03:56:032629 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272630
jam93a6ee792017-02-08 23:59:222631 results.extend(
2632 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:542633 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2634 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412635 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2636 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542637 return results