blob: 285a98d5c47263450813053c867f0677f3a0f8a4 [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
[email protected]99171a92014-06-03 08:44:471350def _GetJSONParseError(input_api, filename, eat_comments=True):
1351 try:
1352 contents = input_api.ReadFile(filename)
1353 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131354 import sys
1355 original_sys_path = sys.path
1356 try:
1357 sys.path = sys.path + [input_api.os_path.join(
1358 input_api.PresubmitLocalPath(),
1359 'tools', 'json_comment_eater')]
1360 import json_comment_eater
1361 finally:
1362 sys.path = original_sys_path
1363 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471364
1365 input_api.json.loads(contents)
1366 except ValueError as e:
1367 return e
1368 return None
1369
1370
1371def _GetIDLParseError(input_api, filename):
1372 try:
1373 contents = input_api.ReadFile(filename)
1374 idl_schema = input_api.os_path.join(
1375 input_api.PresubmitLocalPath(),
1376 'tools', 'json_schema_compiler', 'idl_schema.py')
1377 process = input_api.subprocess.Popen(
1378 [input_api.python_executable, idl_schema],
1379 stdin=input_api.subprocess.PIPE,
1380 stdout=input_api.subprocess.PIPE,
1381 stderr=input_api.subprocess.PIPE,
1382 universal_newlines=True)
1383 (_, error) = process.communicate(input=contents)
1384 return error or None
1385 except ValueError as e:
1386 return e
1387
1388
1389def _CheckParseErrors(input_api, output_api):
1390 """Check that IDL and JSON files do not contain syntax errors."""
1391 actions = {
1392 '.idl': _GetIDLParseError,
1393 '.json': _GetJSONParseError,
1394 }
1395 # These paths contain test data and other known invalid JSON files.
1396 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491397 r'test[\\\/]data[\\\/]',
1398 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
Tom Andersonac47edd2017-07-27 17:23:141399 r'^third_party[\\\/]protobuf[\\\/]',
[email protected]99171a92014-06-03 08:44:471400 ]
1401 # Most JSON files are preprocessed and support comments, but these do not.
1402 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491403 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471404 ]
1405 # Only run IDL checker on files in these directories.
1406 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491407 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1408 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471409 ]
1410
1411 def get_action(affected_file):
1412 filename = affected_file.LocalPath()
1413 return actions.get(input_api.os_path.splitext(filename)[1])
1414
1415 def MatchesFile(patterns, path):
1416 for pattern in patterns:
1417 if input_api.re.search(pattern, path):
1418 return True
1419 return False
1420
1421 def FilterFile(affected_file):
1422 action = get_action(affected_file)
1423 if not action:
1424 return False
1425 path = affected_file.LocalPath()
1426
1427 if MatchesFile(excluded_patterns, path):
1428 return False
1429
1430 if (action == _GetIDLParseError and
1431 not MatchesFile(idl_included_patterns, path)):
1432 return False
1433 return True
1434
1435 results = []
1436 for affected_file in input_api.AffectedFiles(
1437 file_filter=FilterFile, include_deletes=False):
1438 action = get_action(affected_file)
1439 kwargs = {}
1440 if (action == _GetJSONParseError and
1441 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1442 kwargs['eat_comments'] = False
1443 parse_error = action(input_api,
1444 affected_file.AbsoluteLocalPath(),
1445 **kwargs)
1446 if parse_error:
1447 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1448 (affected_file.LocalPath(), parse_error)))
1449 return results
1450
1451
[email protected]760deea2013-12-10 19:33:491452def _CheckJavaStyle(input_api, output_api):
1453 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471454 import sys
[email protected]760deea2013-12-10 19:33:491455 original_sys_path = sys.path
1456 try:
1457 sys.path = sys.path + [input_api.os_path.join(
1458 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1459 import checkstyle
1460 finally:
1461 # Restore sys.path to what it was before.
1462 sys.path = original_sys_path
1463
1464 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091465 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511466 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491467
1468
dchenge07de812016-06-20 19:27:171469def _CheckIpcOwners(input_api, output_api):
1470 """Checks that affected files involving IPC have an IPC OWNERS rule.
1471
1472 Whether or not a file affects IPC is determined by a simple whitelist of
1473 filename patterns."""
1474 file_patterns = [
palmerb19a0932017-01-24 04:00:311475 # Legacy IPC:
dchenge07de812016-06-20 19:27:171476 '*_messages.cc',
1477 '*_messages*.h',
1478 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311479 # Mojo IPC:
dchenge07de812016-06-20 19:27:171480 '*.mojom',
1481 '*_struct_traits*.*',
1482 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311483 '*.typemap',
1484 # Android native IPC:
1485 '*.aidl',
1486 # Blink uses a different file naming convention:
1487 '*EnumTraits*.*',
dchenge07de812016-06-20 19:27:171488 '*StructTraits*.*',
1489 '*TypeConverter*.*',
1490 ]
1491
scottmg7a6ed5ba2016-11-04 18:22:041492 # These third_party directories do not contain IPCs, but contain files
1493 # matching the above patterns, which trigger false positives.
1494 exclude_paths = [
1495 'third_party/crashpad/*',
1496 ]
1497
dchenge07de812016-06-20 19:27:171498 # Dictionary mapping an OWNERS file path to Patterns.
1499 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1500 # rules ) to a PatternEntry.
1501 # PatternEntry is a dictionary with two keys:
1502 # - 'files': the files that are matched by this pattern
1503 # - 'rules': the per-file rules needed for this pattern
1504 # For example, if we expect OWNERS file to contain rules for *.mojom and
1505 # *_struct_traits*.*, Patterns might look like this:
1506 # {
1507 # '*.mojom': {
1508 # 'files': ...,
1509 # 'rules': [
1510 # 'per-file *.mojom=set noparent',
1511 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1512 # ],
1513 # },
1514 # '*_struct_traits*.*': {
1515 # 'files': ...,
1516 # 'rules': [
1517 # 'per-file *_struct_traits*.*=set noparent',
1518 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1519 # ],
1520 # },
1521 # }
1522 to_check = {}
1523
1524 # Iterate through the affected files to see what we actually need to check
1525 # for. We should only nag patch authors about per-file rules if a file in that
1526 # directory would match that pattern. If a directory only contains *.mojom
1527 # files and no *_messages*.h files, we should only nag about rules for
1528 # *.mojom files.
rockot51249332016-06-23 16:32:251529 for f in input_api.change.AffectedFiles(include_deletes=False):
dchenge07de812016-06-20 19:27:171530 for pattern in file_patterns:
1531 if input_api.fnmatch.fnmatch(
1532 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041533 skip = False
1534 for exclude in exclude_paths:
1535 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1536 skip = True
1537 break
1538 if skip:
1539 continue
dchenge07de812016-06-20 19:27:171540 owners_file = input_api.os_path.join(
1541 input_api.os_path.dirname(f.LocalPath()), 'OWNERS')
1542 if owners_file not in to_check:
1543 to_check[owners_file] = {}
1544 if pattern not in to_check[owners_file]:
1545 to_check[owners_file][pattern] = {
1546 'files': [],
1547 'rules': [
1548 'per-file %s=set noparent' % pattern,
1549 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1550 ]
1551 }
1552 to_check[owners_file][pattern]['files'].append(f)
1553 break
1554
1555 # Now go through the OWNERS files we collected, filtering out rules that are
1556 # already present in that OWNERS file.
1557 for owners_file, patterns in to_check.iteritems():
1558 try:
1559 with file(owners_file) as f:
1560 lines = set(f.read().splitlines())
1561 for entry in patterns.itervalues():
1562 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1563 ]
1564 except IOError:
1565 # No OWNERS file, so all the rules are definitely missing.
1566 continue
1567
1568 # All the remaining lines weren't found in OWNERS files, so emit an error.
1569 errors = []
1570 for owners_file, patterns in to_check.iteritems():
1571 missing_lines = []
1572 files = []
1573 for pattern, entry in patterns.iteritems():
1574 missing_lines.extend(entry['rules'])
1575 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1576 if missing_lines:
1577 errors.append(
Daniel Cheng52111692017-06-14 08:00:591578 '%s needs the following lines added:\n\n%s\n\nfor files:\n%s' %
dchenge07de812016-06-20 19:27:171579 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1580
1581 results = []
1582 if errors:
vabrf5ce3bf92016-07-11 14:52:411583 if input_api.is_committing:
1584 output = output_api.PresubmitError
1585 else:
1586 output = output_api.PresubmitPromptWarning
1587 results.append(output(
Daniel Cheng52111692017-06-14 08:00:591588 'Found OWNERS files that need to be updated for IPC security ' +
1589 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:171590 long_text='\n\n'.join(errors)))
1591
1592 return results
1593
1594
jbriance9e12f162016-11-25 07:57:501595def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311596 """Checks that added or removed lines in non third party affected
1597 header files do not lead to new useless class or struct forward
1598 declaration.
jbriance9e12f162016-11-25 07:57:501599 """
1600 results = []
1601 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1602 input_api.re.MULTILINE)
1603 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1604 input_api.re.MULTILINE)
1605 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311606 if (f.LocalPath().startswith('third_party') and
1607 not f.LocalPath().startswith('third_party/WebKit') and
1608 not f.LocalPath().startswith('third_party\\WebKit')):
1609 continue
1610
jbriance9e12f162016-11-25 07:57:501611 if not f.LocalPath().endswith('.h'):
1612 continue
1613
1614 contents = input_api.ReadFile(f)
1615 fwd_decls = input_api.re.findall(class_pattern, contents)
1616 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1617
1618 useless_fwd_decls = []
1619 for decl in fwd_decls:
1620 count = sum(1 for _ in input_api.re.finditer(
1621 r'\b%s\b' % input_api.re.escape(decl), contents))
1622 if count == 1:
1623 useless_fwd_decls.append(decl)
1624
1625 if not useless_fwd_decls:
1626 continue
1627
1628 for line in f.GenerateScmDiff().splitlines():
1629 if (line.startswith('-') and not line.startswith('--') or
1630 line.startswith('+') and not line.startswith('++')):
1631 for decl in useless_fwd_decls:
1632 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1633 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:241634 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:501635 (f.LocalPath(), decl)))
1636 useless_fwd_decls.remove(decl)
1637
1638 return results
1639
1640
dskiba88634f4e2015-08-14 23:03:291641def _CheckAndroidToastUsage(input_api, output_api):
1642 """Checks that code uses org.chromium.ui.widget.Toast instead of
1643 android.widget.Toast (Chromium Toast doesn't force hardware
1644 acceleration on low-end devices, saving memory).
1645 """
1646 toast_import_pattern = input_api.re.compile(
1647 r'^import android\.widget\.Toast;$')
1648
1649 errors = []
1650
1651 sources = lambda affected_file: input_api.FilterSourceFile(
1652 affected_file,
1653 black_list=(_EXCLUDED_PATHS +
1654 _TEST_CODE_EXCLUDED_PATHS +
1655 input_api.DEFAULT_BLACK_LIST +
1656 (r'^chromecast[\\\/].*',
1657 r'^remoting[\\\/].*')),
1658 white_list=(r'.*\.java$',))
1659
1660 for f in input_api.AffectedSourceFiles(sources):
1661 for line_num, line in f.ChangedContents():
1662 if toast_import_pattern.search(line):
1663 errors.append("%s:%d" % (f.LocalPath(), line_num))
1664
1665 results = []
1666
1667 if errors:
1668 results.append(output_api.PresubmitError(
1669 'android.widget.Toast usage is detected. Android toasts use hardware'
1670 ' acceleration, and can be\ncostly on low-end devices. Please use'
1671 ' org.chromium.ui.widget.Toast instead.\n'
1672 'Contact [email protected] if you have any questions.',
1673 errors))
1674
1675 return results
1676
1677
dgnaa68d5e2015-06-10 10:08:221678def _CheckAndroidCrLogUsage(input_api, output_api):
1679 """Checks that new logs using org.chromium.base.Log:
1680 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511681 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221682 """
pkotwicza1dd0b002016-05-16 14:41:041683
torne89540622017-03-24 19:41:301684 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:041685 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:301686 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:041687 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:301688 # WebView license viewer code cannot depend on //base; used in stub APK.
1689 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
1690 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:041691 ]
1692
dgnaa68d5e2015-06-10 10:08:221693 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121694 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1695 class_in_base_pattern = input_api.re.compile(
1696 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1697 has_some_log_import_pattern = input_api.re.compile(
1698 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221699 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121700 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221701 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511702 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221703 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221704
Vincent Scheib16d7b272015-09-15 18:09:071705 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221706 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041707 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1708 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121709
dgnaa68d5e2015-06-10 10:08:221710 tag_decl_errors = []
1711 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121712 tag_errors = []
dgn38736db2015-09-18 19:20:511713 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121714 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221715
1716 for f in input_api.AffectedSourceFiles(sources):
1717 file_content = input_api.ReadFile(f)
1718 has_modified_logs = False
1719
1720 # Per line checks
dgn87d9fb62015-06-12 09:15:121721 if (cr_log_import_pattern.search(file_content) or
1722 (class_in_base_pattern.search(file_content) and
1723 not has_some_log_import_pattern.search(file_content))):
1724 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221725 for line_num, line in f.ChangedContents():
1726
1727 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121728 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221729 if match:
1730 has_modified_logs = True
1731
1732 # Make sure it uses "TAG"
1733 if not match.group('tag') == 'TAG':
1734 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121735 else:
1736 # Report non cr Log function calls in changed lines
1737 for line_num, line in f.ChangedContents():
1738 if log_call_pattern.search(line):
1739 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221740
1741 # Per file checks
1742 if has_modified_logs:
1743 # Make sure the tag is using the "cr" prefix and is not too long
1744 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511745 tag_name = match.group('name') if match else None
1746 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221747 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511748 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221749 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511750 elif '.' in tag_name:
1751 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221752
1753 results = []
1754 if tag_decl_errors:
1755 results.append(output_api.PresubmitPromptWarning(
1756 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511757 '"private static final String TAG = "<package tag>".\n'
1758 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221759 tag_decl_errors))
1760
1761 if tag_length_errors:
1762 results.append(output_api.PresubmitError(
1763 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511764 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221765 tag_length_errors))
1766
1767 if tag_errors:
1768 results.append(output_api.PresubmitPromptWarning(
1769 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1770 tag_errors))
1771
dgn87d9fb62015-06-12 09:15:121772 if util_log_errors:
dgn4401aa52015-04-29 16:26:171773 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121774 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1775 util_log_errors))
1776
dgn38736db2015-09-18 19:20:511777 if tag_with_dot_errors:
1778 results.append(output_api.PresubmitPromptWarning(
1779 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1780 tag_with_dot_errors))
1781
dgn4401aa52015-04-29 16:26:171782 return results
1783
1784
yolandyan45001472016-12-21 21:12:421785def _CheckAndroidTestAnnotationUsage(input_api, output_api):
1786 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
1787 deprecated_annotation_import_pattern = input_api.re.compile(
1788 r'^import android\.test\.suitebuilder\.annotation\..*;',
1789 input_api.re.MULTILINE)
1790 sources = lambda x: input_api.FilterSourceFile(
1791 x, white_list=(r'.*\.java$',), black_list=None)
1792 errors = []
1793 for f in input_api.AffectedFiles(sources):
1794 for line_num, line in f.ChangedContents():
1795 if deprecated_annotation_import_pattern.search(line):
1796 errors.append("%s:%d" % (f.LocalPath(), line_num))
1797
1798 results = []
1799 if errors:
1800 results.append(output_api.PresubmitError(
1801 'Annotations in android.test.suitebuilder.annotation have been'
1802 ' deprecated since API level 24. Please use android.support.test.filters'
1803 ' from //third_party/android_support_test_runner:runner_java instead.'
1804 ' Contact [email protected] if you have any questions.', errors))
1805 return results
1806
1807
agrieve7b6479d82015-10-07 14:24:221808def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1809 """Checks if MDPI assets are placed in a correct directory."""
1810 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1811 ('/res/drawable/' in f.LocalPath() or
1812 '/res/drawable-ldrtl/' in f.LocalPath()))
1813 errors = []
1814 for f in input_api.AffectedFiles(include_deletes=False,
1815 file_filter=file_filter):
1816 errors.append(' %s' % f.LocalPath())
1817
1818 results = []
1819 if errors:
1820 results.append(output_api.PresubmitError(
1821 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1822 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1823 '/res/drawable-ldrtl/.\n'
1824 'Contact [email protected] if you have questions.', errors))
1825 return results
1826
1827
agrievef32bcc72016-04-04 14:57:401828class PydepsChecker(object):
1829 def __init__(self, input_api, pydeps_files):
1830 self._file_cache = {}
1831 self._input_api = input_api
1832 self._pydeps_files = pydeps_files
1833
1834 def _LoadFile(self, path):
1835 """Returns the list of paths within a .pydeps file relative to //."""
1836 if path not in self._file_cache:
1837 with open(path) as f:
1838 self._file_cache[path] = f.read()
1839 return self._file_cache[path]
1840
1841 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1842 """Returns an interable of paths within the .pydep, relativized to //."""
1843 os_path = self._input_api.os_path
1844 pydeps_dir = os_path.dirname(pydeps_path)
1845 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1846 if not l.startswith('*'))
1847 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1848
1849 def _CreateFilesToPydepsMap(self):
1850 """Returns a map of local_path -> list_of_pydeps."""
1851 ret = {}
1852 for pydep_local_path in self._pydeps_files:
1853 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1854 ret.setdefault(path, []).append(pydep_local_path)
1855 return ret
1856
1857 def ComputeAffectedPydeps(self):
1858 """Returns an iterable of .pydeps files that might need regenerating."""
1859 affected_pydeps = set()
1860 file_to_pydeps_map = None
1861 for f in self._input_api.AffectedFiles(include_deletes=True):
1862 local_path = f.LocalPath()
1863 if local_path == 'DEPS':
1864 return self._pydeps_files
1865 elif local_path.endswith('.pydeps'):
1866 if local_path in self._pydeps_files:
1867 affected_pydeps.add(local_path)
1868 elif local_path.endswith('.py'):
1869 if file_to_pydeps_map is None:
1870 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1871 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1872 return affected_pydeps
1873
1874 def DetermineIfStale(self, pydeps_path):
1875 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:411876 import difflib
agrievef32bcc72016-04-04 14:57:401877 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1878 cmd = old_pydeps_data[1][1:].strip()
1879 new_pydeps_data = self._input_api.subprocess.check_output(
1880 cmd + ' --output ""', shell=True)
phajdan.jr0d9878552016-11-04 10:49:411881 old_contents = old_pydeps_data[2:]
1882 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:401883 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:411884 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:401885
1886
1887def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1888 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001889 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281890 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1891 # Mac, so skip it on other platforms.
1892 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001893 return []
agrievef32bcc72016-04-04 14:57:401894 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1895 is_android = input_api.os_path.exists('third_party/android_tools')
1896 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1897 results = []
1898 # First, check for new / deleted .pydeps.
1899 for f in input_api.AffectedFiles(include_deletes=True):
1900 if f.LocalPath().endswith('.pydeps'):
1901 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1902 results.append(output_api.PresubmitError(
1903 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1904 'remove %s' % f.LocalPath()))
1905 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1906 results.append(output_api.PresubmitError(
1907 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1908 'include %s' % f.LocalPath()))
1909
1910 if results:
1911 return results
1912
1913 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1914
1915 for pydep_path in checker.ComputeAffectedPydeps():
1916 try:
phajdan.jr0d9878552016-11-04 10:49:411917 result = checker.DetermineIfStale(pydep_path)
1918 if result:
1919 cmd, diff = result
agrievef32bcc72016-04-04 14:57:401920 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:411921 'File is stale: %s\nDiff (apply to fix):\n%s\n'
1922 'To regenerate, run:\n\n %s' %
1923 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:401924 except input_api.subprocess.CalledProcessError as error:
1925 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1926 long_text=error.output)]
1927
1928 return results
1929
1930
glidere61efad2015-02-18 17:39:431931def _CheckSingletonInHeaders(input_api, output_api):
1932 """Checks to make sure no header files have |Singleton<|."""
1933 def FileFilter(affected_file):
1934 # It's ok for base/memory/singleton.h to have |Singleton<|.
1935 black_list = (_EXCLUDED_PATHS +
1936 input_api.DEFAULT_BLACK_LIST +
1937 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1938 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1939
sergeyu34d21222015-09-16 00:11:441940 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431941 files = []
1942 for f in input_api.AffectedSourceFiles(FileFilter):
1943 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1944 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1945 contents = input_api.ReadFile(f)
1946 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241947 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431948 pattern.search(line)):
1949 files.append(f)
1950 break
1951
1952 if files:
yolandyandaabc6d2016-04-18 18:29:391953 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441954 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431955 'Please move them to an appropriate source file so that the ' +
1956 'template gets instantiated in a single compilation unit.',
1957 files) ]
1958 return []
1959
1960
[email protected]fd20b902014-05-09 02:14:531961_DEPRECATED_CSS = [
1962 # Values
1963 ( "-webkit-box", "flex" ),
1964 ( "-webkit-inline-box", "inline-flex" ),
1965 ( "-webkit-flex", "flex" ),
1966 ( "-webkit-inline-flex", "inline-flex" ),
1967 ( "-webkit-min-content", "min-content" ),
1968 ( "-webkit-max-content", "max-content" ),
1969
1970 # Properties
1971 ( "-webkit-background-clip", "background-clip" ),
1972 ( "-webkit-background-origin", "background-origin" ),
1973 ( "-webkit-background-size", "background-size" ),
1974 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:441975 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:531976
1977 # Functions
1978 ( "-webkit-gradient", "gradient" ),
1979 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1980 ( "-webkit-linear-gradient", "linear-gradient" ),
1981 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1982 ( "-webkit-radial-gradient", "radial-gradient" ),
1983 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1984]
1985
dbeam1ec68ac2016-12-15 05:22:241986def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:531987 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251988 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341989 documentation and iOS CSS for dom distiller
1990 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251991 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531992 results = []
dbeam070cfe62014-10-22 06:44:021993 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251994 black_list = (_EXCLUDED_PATHS +
1995 _TEST_CODE_EXCLUDED_PATHS +
1996 input_api.DEFAULT_BLACK_LIST +
1997 (r"^chrome/common/extensions/docs",
1998 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341999 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442000 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252001 r"^native_client_sdk"))
2002 file_filter = lambda f: input_api.FilterSourceFile(
2003 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532004 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2005 for line_num, line in fpath.ChangedContents():
2006 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022007 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532008 results.append(output_api.PresubmitError(
2009 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2010 (fpath.LocalPath(), line_num, deprecated_value, value)))
2011 return results
2012
mohan.reddyf21db962014-10-16 12:26:472013
dbeam070cfe62014-10-22 06:44:022014_DEPRECATED_JS = [
2015 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2016 ( "__defineGetter__", "Object.defineProperty" ),
2017 ( "__defineSetter__", "Object.defineProperty" ),
2018]
2019
dbeam1ec68ac2016-12-15 05:22:242020def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022021 """Make sure that we don't use deprecated JS in Chrome code."""
2022 results = []
2023 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2024 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2025 input_api.DEFAULT_BLACK_LIST)
2026 file_filter = lambda f: input_api.FilterSourceFile(
2027 f, white_list=file_inclusion_pattern, black_list=black_list)
2028 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2029 for lnum, line in fpath.ChangedContents():
2030 for (deprecated, replacement) in _DEPRECATED_JS:
2031 if deprecated in line:
2032 results.append(output_api.PresubmitError(
2033 "%s:%d: Use of deprecated JS %s, use %s instead" %
2034 (fpath.LocalPath(), lnum, deprecated, replacement)))
2035 return results
2036
dpapadd651231d82017-07-21 02:44:472037def _CheckForRiskyJsArrowFunction(line_number, line):
2038 if ' => ' in line:
2039 return "line %d, is using an => (arrow) function\n %s\n" % (
2040 line_number, line)
2041 return ''
2042
2043def _CheckForRiskyJsConstLet(input_api, line_number, line):
2044 if input_api.re.match('^\s*(const|let)\s', line):
2045 return "line %d, is using const/let keyword\n %s\n" % (
2046 line_number, line)
2047 return ''
dbeam070cfe62014-10-22 06:44:022048
dbeam1ec68ac2016-12-15 05:22:242049def _CheckForRiskyJsFeatures(input_api, output_api):
2050 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
Steven Bennetts90545f3cb2017-08-14 18:11:002051 # 'ui/webui/resources/cr_components are not allowed on ios'
2052 not_ios_filter = (r".*ui\/webui\/resources\/cr_components.*", )
Steven Bennetts9c7e3c22017-08-02 19:10:572053 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js,
Steven Bennetts90545f3cb2017-08-14 18:11:002054 black_list=not_ios_filter)
dpapadd651231d82017-07-21 02:44:472055 results = []
dbeam1ec68ac2016-12-15 05:22:242056 for f in input_api.AffectedFiles(file_filter=file_filter):
dpapadd651231d82017-07-21 02:44:472057 arrow_error_lines = []
2058 const_let_error_lines = []
dbeam1ec68ac2016-12-15 05:22:242059 for lnum, line in f.ChangedContents():
dpapadd651231d82017-07-21 02:44:472060 arrow_error_lines += filter(None, [
2061 _CheckForRiskyJsArrowFunction(lnum, line),
2062 ])
dbeam1ec68ac2016-12-15 05:22:242063
dpapadd651231d82017-07-21 02:44:472064 const_let_error_lines += filter(None, [
2065 _CheckForRiskyJsConstLet(input_api, lnum, line),
2066 ])
dbeam1ec68ac2016-12-15 05:22:242067
dpapadd651231d82017-07-21 02:44:472068 if arrow_error_lines:
2069 arrow_error_lines = map(
2070 lambda e: "%s:%s" % (f.LocalPath(), e), arrow_error_lines)
2071 results.append(
2072 output_api.PresubmitPromptWarning('\n'.join(arrow_error_lines + [
2073"""
2074Use of => (arrow) operator detected in:
dbeam1ec68ac2016-12-15 05:22:242075%s
2076Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2077https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
dpapadd651231d82017-07-21 02:44:472078""" % f.LocalPath()
2079 ])))
dbeam1ec68ac2016-12-15 05:22:242080
dpapadd651231d82017-07-21 02:44:472081 if const_let_error_lines:
2082 const_let_error_lines = map(
2083 lambda e: "%s:%s" % (f.LocalPath(), e), const_let_error_lines)
2084 results.append(
2085 output_api.PresubmitPromptWarning('\n'.join(const_let_error_lines + [
2086"""
2087Use of const/let keywords detected in:
2088%s
2089Please ensure your code does not run on iOS9 because const/let is not fully
2090supported.
2091https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#let-Block_Scoped-Variables
2092https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#const-Block_Scoped-Constants
2093""" % f.LocalPath()
2094 ])))
2095
2096 return results
dbeam1ec68ac2016-12-15 05:22:242097
rlanday6802cf632017-05-30 17:48:362098def _CheckForRelativeIncludes(input_api, output_api):
2099 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2100 import sys
2101 original_sys_path = sys.path
2102 try:
2103 sys.path = sys.path + [input_api.os_path.join(
2104 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2105 from cpp_checker import CppChecker
2106 finally:
2107 # Restore sys.path to what it was before.
2108 sys.path = original_sys_path
2109
2110 bad_files = {}
2111 for f in input_api.AffectedFiles(include_deletes=False):
2112 if (f.LocalPath().startswith('third_party') and
2113 not f.LocalPath().startswith('third_party/WebKit') and
2114 not f.LocalPath().startswith('third_party\\WebKit')):
2115 continue
2116
2117 if not CppChecker.IsCppFile(f.LocalPath()):
2118 continue
2119
2120 relative_includes = [line for line_num, line in f.ChangedContents()
2121 if "#include" in line and "../" in line]
2122 if not relative_includes:
2123 continue
2124 bad_files[f.LocalPath()] = relative_includes
2125
2126 if not bad_files:
2127 return []
2128
2129 error_descriptions = []
2130 for file_path, bad_lines in bad_files.iteritems():
2131 error_description = file_path
2132 for line in bad_lines:
2133 error_description += '\n ' + line
2134 error_descriptions.append(error_description)
2135
2136 results = []
2137 results.append(output_api.PresubmitError(
2138 'You added one or more relative #include paths (including "../").\n'
2139 'These shouldn\'t be used because they can be used to include headers\n'
2140 'from code that\'s not correctly specified as a dependency in the\n'
2141 'relevant BUILD.gn file(s).',
2142 error_descriptions))
2143
2144 return results
2145
Takeshi Yoshinoe387aa32017-08-02 13:16:132146
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202147def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2148 if not isinstance(key, ast.Str):
2149 return 'Key at line %d must be a string literal' % key.lineno
2150 if not isinstance(value, ast.Dict):
2151 return 'Value at line %d must be a dict' % value.lineno
2152 if len(value.keys) != 1:
2153 return 'Dict at line %d must have single entry' % value.lineno
2154 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2155 return (
2156 'Entry at line %d must have a string literal \'filepath\' as key' %
2157 value.lineno)
2158 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132159
Takeshi Yoshinoe387aa32017-08-02 13:16:132160
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202161def _CheckWatchlistsEntrySyntax(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.List):
2165 return 'Value at line %d must be a list' % value.lineno
2166 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132167
Takeshi Yoshinoe387aa32017-08-02 13:16:132168
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202169def _CheckWATCHLISTSEntries(wd_dict, w_dict, ast):
2170 mismatch_template = (
2171 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2172 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132173
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202174 i = 0
2175 last_key = ''
2176 while True:
2177 if i >= len(wd_dict.keys):
2178 if i >= len(w_dict.keys):
2179 return None
2180 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2181 elif i >= len(w_dict.keys):
2182 return (
2183 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132184
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202185 wd_key = wd_dict.keys[i]
2186 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132187
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202188 result = _CheckWatchlistDefinitionsEntrySyntax(
2189 wd_key, wd_dict.values[i], ast)
2190 if result is not None:
2191 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132192
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202193 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast)
2194 if result is not None:
2195 return 'Bad entry in WATCHLISTS dict: %s' % result
2196
2197 if wd_key.s != w_key.s:
2198 return mismatch_template % (
2199 '%s at line %d' % (wd_key.s, wd_key.lineno),
2200 '%s at line %d' % (w_key.s, w_key.lineno))
2201
2202 if wd_key.s < last_key:
2203 return (
2204 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2205 (wd_key.lineno, w_key.lineno))
2206 last_key = wd_key.s
2207
2208 i = i + 1
2209
2210
2211def _CheckWATCHLISTSSyntax(expression, ast):
2212 if not isinstance(expression, ast.Expression):
2213 return 'WATCHLISTS file must contain a valid expression'
2214 dictionary = expression.body
2215 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2216 return 'WATCHLISTS file must have single dict with exactly two entries'
2217
2218 first_key = dictionary.keys[0]
2219 first_value = dictionary.values[0]
2220 second_key = dictionary.keys[1]
2221 second_value = dictionary.values[1]
2222
2223 if (not isinstance(first_key, ast.Str) or
2224 first_key.s != 'WATCHLIST_DEFINITIONS' or
2225 not isinstance(first_value, ast.Dict)):
2226 return (
2227 'The first entry of the dict in WATCHLISTS file must be '
2228 'WATCHLIST_DEFINITIONS dict')
2229
2230 if (not isinstance(second_key, ast.Str) or
2231 second_key.s != 'WATCHLISTS' or
2232 not isinstance(second_value, ast.Dict)):
2233 return (
2234 'The second entry of the dict in WATCHLISTS file must be '
2235 'WATCHLISTS dict')
2236
2237 return _CheckWATCHLISTSEntries(first_value, second_value, ast)
Takeshi Yoshinoe387aa32017-08-02 13:16:132238
2239
2240def _CheckWATCHLISTS(input_api, output_api):
2241 for f in input_api.AffectedFiles(include_deletes=False):
2242 if f.LocalPath() == 'WATCHLISTS':
2243 contents = input_api.ReadFile(f, 'r')
2244
2245 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202246 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132247 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202248 # Get an AST tree for it and scan the tree for detailed style checking.
2249 expression = input_api.ast.parse(
2250 contents, filename='WATCHLISTS', mode='eval')
2251 except ValueError as e:
2252 return [output_api.PresubmitError(
2253 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2254 except SyntaxError as e:
2255 return [output_api.PresubmitError(
2256 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2257 except TypeError as e:
2258 return [output_api.PresubmitError(
2259 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132260
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202261 result = _CheckWATCHLISTSSyntax(expression, input_api.ast)
2262 if result is not None:
2263 return [output_api.PresubmitError(result)]
2264 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132265
2266 return []
2267
2268
dgnaa68d5e2015-06-10 10:08:222269def _AndroidSpecificOnUploadChecks(input_api, output_api):
2270 """Groups checks that target android code."""
2271 results = []
dgnaa68d5e2015-06-10 10:08:222272 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222273 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292274 results.extend(_CheckAndroidToastUsage(input_api, output_api))
yolandyan45001472016-12-21 21:12:422275 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222276 return results
2277
2278
[email protected]22c9bd72011-03-27 16:47:392279def _CommonChecks(input_api, output_api):
2280 """Checks common to both upload and commit."""
2281 results = []
2282 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382283 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542284 excluded_paths=_EXCLUDED_PATHS))
machenbachfbda9b72016-12-06 13:13:582285 results.extend(
2286 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:192287 results.extend(
[email protected]760deea2013-12-10 19:33:492288 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542289 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182290 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522291 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222292 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442293 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592294 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062295 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122296 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182297 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222298 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302299 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492300 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032301 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492302 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442303 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272304 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:072305 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542306 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442307 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392308 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552309 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042310 results.extend(
2311 input_api.canned_checks.CheckChangeHasNoTabs(
2312 input_api,
2313 output_api,
2314 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402315 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162316 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082317 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242318 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2319 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472320 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042321 results.extend(_CheckForIPCRules(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232322 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432323 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402324 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152325 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172326 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502327 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242328 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:362329 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:132330 results.extend(_CheckWATCHLISTS(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242331
2332 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
2333 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2334 input_api, output_api,
2335 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:382336 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392337 return results
[email protected]1f7b4172010-01-28 01:17:342338
[email protected]b337cb5b2011-01-23 21:24:052339
[email protected]b8079ae4a2012-12-05 19:56:492340def _CheckPatchFiles(input_api, output_api):
2341 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2342 if f.LocalPath().endswith(('.orig', '.rej'))]
2343 if problems:
2344 return [output_api.PresubmitError(
2345 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032346 else:
2347 return []
[email protected]b8079ae4a2012-12-05 19:56:492348
2349
Kent Tamura5a8755d2017-06-29 23:37:072350def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:212351 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
2352 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
2353 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:072354 include_re = input_api.re.compile(
2355 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
2356 extension_re = input_api.re.compile(r'\.[a-z]+$')
2357 errors = []
2358 for f in input_api.AffectedFiles():
2359 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
2360 continue
2361 found_line_number = None
2362 found_macro = None
2363 for line_num, line in f.ChangedContents():
2364 match = macro_re.search(line)
2365 if match:
2366 found_line_number = line_num
2367 found_macro = match.group(2)
2368 break
2369 if not found_line_number:
2370 continue
2371
2372 found_include = False
2373 for line in f.NewContents():
2374 if include_re.search(line):
2375 found_include = True
2376 break
2377 if found_include:
2378 continue
2379
2380 if not f.LocalPath().endswith('.h'):
2381 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
2382 try:
2383 content = input_api.ReadFile(primary_header_path, 'r')
2384 if include_re.search(content):
2385 continue
2386 except IOError:
2387 pass
2388 errors.append('%s:%d %s macro is used without including build/'
2389 'build_config.h.'
2390 % (f.LocalPath(), found_line_number, found_macro))
2391 if errors:
2392 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
2393 return []
2394
2395
[email protected]b00342e7f2013-03-26 16:21:542396def _DidYouMeanOSMacro(bad_macro):
2397 try:
2398 return {'A': 'OS_ANDROID',
2399 'B': 'OS_BSD',
2400 'C': 'OS_CHROMEOS',
2401 'F': 'OS_FREEBSD',
2402 'L': 'OS_LINUX',
2403 'M': 'OS_MACOSX',
2404 'N': 'OS_NACL',
2405 'O': 'OS_OPENBSD',
2406 'P': 'OS_POSIX',
2407 'S': 'OS_SOLARIS',
2408 'W': 'OS_WIN'}[bad_macro[3].upper()]
2409 except KeyError:
2410 return ''
2411
2412
2413def _CheckForInvalidOSMacrosInFile(input_api, f):
2414 """Check for sensible looking, totally invalid OS macros."""
2415 preprocessor_statement = input_api.re.compile(r'^\s*#')
2416 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2417 results = []
2418 for lnum, line in f.ChangedContents():
2419 if preprocessor_statement.search(line):
2420 for match in os_macro.finditer(line):
2421 if not match.group(1) in _VALID_OS_MACROS:
2422 good = _DidYouMeanOSMacro(match.group(1))
2423 did_you_mean = ' (did you mean %s?)' % good if good else ''
2424 results.append(' %s:%d %s%s' % (f.LocalPath(),
2425 lnum,
2426 match.group(1),
2427 did_you_mean))
2428 return results
2429
2430
2431def _CheckForInvalidOSMacros(input_api, output_api):
2432 """Check all affected files for invalid OS macros."""
2433 bad_macros = []
2434 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472435 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542436 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2437
2438 if not bad_macros:
2439 return []
2440
2441 return [output_api.PresubmitError(
2442 'Possibly invalid OS macro[s] found. Please fix your code\n'
2443 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2444
lliabraa35bab3932014-10-01 12:16:442445
2446def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2447 """Check all affected files for invalid "if defined" macros."""
2448 ALWAYS_DEFINED_MACROS = (
2449 "TARGET_CPU_PPC",
2450 "TARGET_CPU_PPC64",
2451 "TARGET_CPU_68K",
2452 "TARGET_CPU_X86",
2453 "TARGET_CPU_ARM",
2454 "TARGET_CPU_MIPS",
2455 "TARGET_CPU_SPARC",
2456 "TARGET_CPU_ALPHA",
2457 "TARGET_IPHONE_SIMULATOR",
2458 "TARGET_OS_EMBEDDED",
2459 "TARGET_OS_IPHONE",
2460 "TARGET_OS_MAC",
2461 "TARGET_OS_UNIX",
2462 "TARGET_OS_WIN32",
2463 )
2464 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2465 results = []
2466 for lnum, line in f.ChangedContents():
2467 for match in ifdef_macro.finditer(line):
2468 if match.group(1) in ALWAYS_DEFINED_MACROS:
2469 always_defined = ' %s is always defined. ' % match.group(1)
2470 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2471 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2472 lnum,
2473 always_defined,
2474 did_you_mean))
2475 return results
2476
2477
2478def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2479 """Check all affected files for invalid "if defined" macros."""
2480 bad_macros = []
2481 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:212482 if f.LocalPath().startswith('third_party/sqlite/'):
2483 continue
lliabraa35bab3932014-10-01 12:16:442484 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2485 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2486
2487 if not bad_macros:
2488 return []
2489
2490 return [output_api.PresubmitError(
2491 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2492 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2493 bad_macros)]
2494
2495
mlamouria82272622014-09-16 18:45:042496def _CheckForIPCRules(input_api, output_api):
2497 """Check for same IPC rules described in
2498 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2499 """
2500 base_pattern = r'IPC_ENUM_TRAITS\('
2501 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2502 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2503
2504 problems = []
2505 for f in input_api.AffectedSourceFiles(None):
2506 local_path = f.LocalPath()
2507 if not local_path.endswith('.h'):
2508 continue
2509 for line_number, line in f.ChangedContents():
2510 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2511 problems.append(
2512 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2513
2514 if problems:
2515 return [output_api.PresubmitPromptWarning(
2516 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2517 else:
2518 return []
2519
[email protected]b00342e7f2013-03-26 16:21:542520
mostynbb639aca52015-01-07 20:31:232521def _CheckForWindowsLineEndings(input_api, output_api):
2522 """Check source code and known ascii text files for Windows style line
2523 endings.
2524 """
earthdok1b5e0ee2015-03-10 15:19:102525 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232526
2527 file_inclusion_pattern = (
2528 known_text_files,
2529 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2530 )
2531
2532 filter = lambda f: input_api.FilterSourceFile(
2533 f, white_list=file_inclusion_pattern, black_list=None)
2534 files = [f.LocalPath() for f in
2535 input_api.AffectedSourceFiles(filter)]
2536
2537 problems = []
2538
2539 for file in files:
2540 fp = open(file, 'r')
2541 for line in fp:
2542 if line.endswith('\r\n'):
2543 problems.append(file)
2544 break
2545 fp.close()
2546
2547 if problems:
2548 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2549 'these files to contain Windows style line endings?\n' +
2550 '\n'.join(problems))]
2551
2552 return []
2553
2554
pastarmovj89f7ee12016-09-20 14:58:132555def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None,
2556 lint_filters=None, verbose_level=None):
2557 """Checks that all source files use SYSLOG properly."""
2558 syslog_files = []
2559 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:562560 for line_number, line in f.ChangedContents():
2561 if 'SYSLOG' in line:
2562 syslog_files.append(f.LocalPath() + ':' + str(line_number))
2563
pastarmovj89f7ee12016-09-20 14:58:132564 if syslog_files:
2565 return [output_api.PresubmitPromptWarning(
2566 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
2567 ' calls.\nFiles to check:\n', items=syslog_files)]
2568 return []
2569
2570
[email protected]1f7b4172010-01-28 01:17:342571def CheckChangeOnUpload(input_api, output_api):
2572 results = []
2573 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472574 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282575 results.extend(
jam93a6ee792017-02-08 23:59:222576 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192577 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222578 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:132579 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:162580 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542581 return results
[email protected]ca8d19842009-02-19 16:33:122582
2583
[email protected]1bfb8322014-04-23 01:02:412584def GetTryServerMasterForBot(bot):
2585 """Returns the Try Server master for the given bot.
2586
[email protected]0bb112362014-07-26 04:38:322587 It tries to guess the master from the bot name, but may still fail
2588 and return None. There is no longer a default master.
2589 """
2590 # Potentially ambiguous bot names are listed explicitly.
2591 master_map = {
tandriie5587792016-07-14 00:34:502592 'chromium_presubmit': 'master.tryserver.chromium.linux',
2593 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412594 }
[email protected]0bb112362014-07-26 04:38:322595 master = master_map.get(bot)
2596 if not master:
wnwen4fbaab82016-05-25 12:54:362597 if 'android' in bot:
tandriie5587792016-07-14 00:34:502598 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:362599 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:502600 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:322601 elif 'win' in bot:
tandriie5587792016-07-14 00:34:502602 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:322603 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:502604 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:322605 return master
[email protected]1bfb8322014-04-23 01:02:412606
2607
[email protected]ca8d19842009-02-19 16:33:122608def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542609 results = []
[email protected]1f7b4172010-01-28 01:17:342610 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542611 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272612 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342613 input_api,
2614 output_api,
[email protected]2fdd1f362013-01-16 03:56:032615 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272616
jam93a6ee792017-02-08 23:59:222617 results.extend(
2618 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:542619 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2620 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412621 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2622 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542623 return results