blob: 144c5ccc855c14be1831ee20484a0752f90a9a6c [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-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]ca8d1982009-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]ca8d1982009-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]ca8d1982009-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
Sean Kau46e29bc2017-08-28 16:31:16445# These paths contain test data and other known invalid JSON files.
446_KNOWN_INVALID_JSON_FILE_PATTERNS = [
447 r'test[\\\/]data[\\\/]',
448 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
449 r'^third_party[\\\/]protobuf[\\\/]',
450]
451
452
[email protected]b00342e7f2013-03-26 16:21:54453_VALID_OS_MACROS = (
454 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08455 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54456 'OS_ANDROID',
457 'OS_BSD',
458 'OS_CAT', # For testing.
459 'OS_CHROMEOS',
460 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37461 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54462 'OS_IOS',
463 'OS_LINUX',
464 'OS_MACOSX',
465 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21466 'OS_NACL_NONSFI',
467 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12468 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54469 'OS_OPENBSD',
470 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37471 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54472 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54473 'OS_WIN',
474)
475
476
agrievef32bcc72016-04-04 14:57:40477_ANDROID_SPECIFIC_PYDEPS_FILES = [
478 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04479 'build/android/test_wrapper/logdog_wrapper.pydeps',
jbudorick276cc562017-04-29 01:34:58480 'build/secondary/third_party/android_platform/'
481 'development/scripts/stack.pydeps',
agrieve732db3a2016-04-26 19:18:19482 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40483]
484
wnwenbdc444e2016-05-25 13:44:15485
agrievef32bcc72016-04-04 14:57:40486_GENERIC_PYDEPS_FILES = [
agrievef32bcc72016-04-04 14:57:40487]
488
wnwenbdc444e2016-05-25 13:44:15489
agrievef32bcc72016-04-04 14:57:40490_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
491
492
[email protected]55459852011-08-10 15:17:19493def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
494 """Attempts to prevent use of functions intended only for testing in
495 non-testing code. For now this is just a best-effort implementation
496 that ignores header files and may have some false positives. A
497 better implementation would probably need a proper C++ parser.
498 """
499 # We only scan .cc files and the like, as the declaration of
500 # for-testing functions in header files are hard to distinguish from
501 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44502 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19503
jochenc0d4808c2015-07-27 09:25:42504 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19505 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09506 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19507 exclusion_pattern = input_api.re.compile(
508 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
509 base_function_pattern, base_function_pattern))
510
511 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44512 black_list = (_EXCLUDED_PATHS +
513 _TEST_CODE_EXCLUDED_PATHS +
514 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19515 return input_api.FilterSourceFile(
516 affected_file,
517 white_list=(file_inclusion_pattern, ),
518 black_list=black_list)
519
520 problems = []
521 for f in input_api.AffectedSourceFiles(FilterFile):
522 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24523 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03524 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46525 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03526 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19527 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03528 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19529
530 if problems:
[email protected]f7051d52013-04-02 18:31:42531 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03532 else:
533 return []
[email protected]55459852011-08-10 15:17:19534
535
[email protected]10689ca2011-09-02 02:31:54536def _CheckNoIOStreamInHeaders(input_api, output_api):
537 """Checks to make sure no .h files include <iostream>."""
538 files = []
539 pattern = input_api.re.compile(r'^#include\s*<iostream>',
540 input_api.re.MULTILINE)
541 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
542 if not f.LocalPath().endswith('.h'):
543 continue
544 contents = input_api.ReadFile(f)
545 if pattern.search(contents):
546 files.append(f)
547
548 if len(files):
yolandyandaabc6d2016-04-18 18:29:39549 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06550 'Do not #include <iostream> in header files, since it inserts static '
551 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54552 '#include <ostream>. See http://crbug.com/94794',
553 files) ]
554 return []
555
556
[email protected]72df4e782012-06-21 16:28:18557def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52558 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18559 problems = []
560 for f in input_api.AffectedFiles():
561 if (not f.LocalPath().endswith(('.cc', '.mm'))):
562 continue
563
564 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04565 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18566 problems.append(' %s:%d' % (f.LocalPath(), line_num))
567
568 if not problems:
569 return []
570 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
571 '\n'.join(problems))]
572
573
danakj61c1aa22015-10-26 19:55:52574def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57575 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52576 errors = []
577 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
578 input_api.re.MULTILINE)
579 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
580 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
581 continue
582 for lnum, line in f.ChangedContents():
583 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17584 errors.append(output_api.PresubmitError(
585 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57586 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17587 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52588 return errors
589
590
mcasasb7440c282015-02-04 14:52:19591def _FindHistogramNameInLine(histogram_name, line):
592 """Tries to find a histogram name or prefix in a line."""
593 if not "affected-histogram" in line:
594 return histogram_name in line
595 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
596 # the histogram_name.
597 if not '"' in line:
598 return False
599 histogram_prefix = line.split('\"')[1]
600 return histogram_prefix in histogram_name
601
602
603def _CheckUmaHistogramChanges(input_api, output_api):
604 """Check that UMA histogram names in touched lines can still be found in other
605 lines of the patch or in histograms.xml. Note that this check would not catch
606 the reverse: changes in histograms.xml not matched in the code itself."""
607 touched_histograms = []
608 histograms_xml_modifications = []
609 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
610 for f in input_api.AffectedFiles():
611 # If histograms.xml itself is modified, keep the modified lines for later.
612 if f.LocalPath().endswith(('histograms.xml')):
613 histograms_xml_modifications = f.ChangedContents()
614 continue
615 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
616 continue
617 for line_num, line in f.ChangedContents():
618 found = pattern.search(line)
619 if found:
620 touched_histograms.append([found.group(1), f, line_num])
621
622 # Search for the touched histogram names in the local modifications to
623 # histograms.xml, and, if not found, on the base histograms.xml file.
624 unmatched_histograms = []
625 for histogram_info in touched_histograms:
626 histogram_name_found = False
627 for line_num, line in histograms_xml_modifications:
628 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
629 if histogram_name_found:
630 break
631 if not histogram_name_found:
632 unmatched_histograms.append(histogram_info)
633
eromanb90c82e7e32015-04-01 15:13:49634 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19635 problems = []
636 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49637 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19638 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45639 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19640 histogram_name_found = False
641 for line in histograms_xml:
642 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
643 if histogram_name_found:
644 break
645 if not histogram_name_found:
646 problems.append(' [%s:%d] %s' %
647 (f.LocalPath(), line_num, histogram_name))
648
649 if not problems:
650 return []
651 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
652 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49653 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19654
wnwenbdc444e2016-05-25 13:44:15655
yolandyandaabc6d2016-04-18 18:29:39656def _CheckFlakyTestUsage(input_api, output_api):
657 """Check that FlakyTest annotation is our own instead of the android one"""
658 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
659 files = []
660 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
661 if f.LocalPath().endswith('Test.java'):
662 if pattern.search(input_api.ReadFile(f)):
663 files.append(f)
664 if len(files):
665 return [output_api.PresubmitError(
666 'Use org.chromium.base.test.util.FlakyTest instead of '
667 'android.test.FlakyTest',
668 files)]
669 return []
mcasasb7440c282015-02-04 14:52:19670
wnwenbdc444e2016-05-25 13:44:15671
[email protected]8ea5d4b2011-09-13 21:49:22672def _CheckNoNewWStrings(input_api, output_api):
673 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27674 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22675 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20676 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57677 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34678 '/win/' in f.LocalPath() or
679 'chrome_elf' in f.LocalPath() or
680 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20681 continue
[email protected]8ea5d4b2011-09-13 21:49:22682
[email protected]a11dbe9b2012-08-07 01:32:58683 allowWString = False
[email protected]b5c24292011-11-28 14:38:20684 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58685 if 'presubmit: allow wstring' in line:
686 allowWString = True
687 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27688 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58689 allowWString = False
690 else:
691 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22692
[email protected]55463aa62011-10-12 00:48:27693 if not problems:
694 return []
695 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58696 ' If you are calling a cross-platform API that accepts a wstring, '
697 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27698 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22699
700
[email protected]2a8ac9c2011-10-19 17:20:44701def _CheckNoDEPSGIT(input_api, output_api):
702 """Make sure .DEPS.git is never modified manually."""
703 if any(f.LocalPath().endswith('.DEPS.git') for f in
704 input_api.AffectedFiles()):
705 return [output_api.PresubmitError(
706 'Never commit changes to .DEPS.git. This file is maintained by an\n'
707 'automated system based on what\'s in DEPS and your changes will be\n'
708 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34709 '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:44710 'for more information')]
711 return []
712
713
tandriief664692014-09-23 14:51:47714def _CheckValidHostsInDEPS(input_api, output_api):
715 """Checks that DEPS file deps are from allowed_hosts."""
716 # Run only if DEPS file has been modified to annoy fewer bystanders.
717 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
718 return []
719 # Outsource work to gclient verify
720 try:
721 input_api.subprocess.check_output(['gclient', 'verify'])
722 return []
723 except input_api.subprocess.CalledProcessError, error:
724 return [output_api.PresubmitError(
725 'DEPS file must have only git dependencies.',
726 long_text=error.output)]
727
728
[email protected]127f18ec2012-06-16 05:05:59729def _CheckNoBannedFunctions(input_api, output_api):
730 """Make sure that banned functions are not used."""
731 warnings = []
732 errors = []
733
wnwenbdc444e2016-05-25 13:44:15734 def IsBlacklisted(affected_file, blacklist):
735 local_path = affected_file.LocalPath()
736 for item in blacklist:
737 if input_api.re.match(item, local_path):
738 return True
739 return False
740
741 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
742 matched = False
743 if func_name[0:1] == '/':
744 regex = func_name[1:]
745 if input_api.re.search(regex, line):
746 matched = True
747 elif func_name in line:
dchenge07de812016-06-20 19:27:17748 matched = True
wnwenbdc444e2016-05-25 13:44:15749 if matched:
dchenge07de812016-06-20 19:27:17750 problems = warnings
wnwenbdc444e2016-05-25 13:44:15751 if error:
dchenge07de812016-06-20 19:27:17752 problems = errors
wnwenbdc444e2016-05-25 13:44:15753 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
754 for message_line in message:
755 problems.append(' %s' % message_line)
756
[email protected]127f18ec2012-06-16 05:05:59757 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
758 for f in input_api.AffectedFiles(file_filter=file_filter):
759 for line_num, line in f.ChangedContents():
760 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:15761 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59762
763 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
764 for f in input_api.AffectedFiles(file_filter=file_filter):
765 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49766 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:49767 if IsBlacklisted(f, excluded_paths):
768 continue
wnwenbdc444e2016-05-25 13:44:15769 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59770
771 result = []
772 if (warnings):
773 result.append(output_api.PresubmitPromptWarning(
774 'Banned functions were used.\n' + '\n'.join(warnings)))
775 if (errors):
776 result.append(output_api.PresubmitError(
777 'Banned functions were used.\n' + '\n'.join(errors)))
778 return result
779
780
[email protected]6c063c62012-07-11 19:11:06781def _CheckNoPragmaOnce(input_api, output_api):
782 """Make sure that banned functions are not used."""
783 files = []
784 pattern = input_api.re.compile(r'^#pragma\s+once',
785 input_api.re.MULTILINE)
786 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
787 if not f.LocalPath().endswith('.h'):
788 continue
789 contents = input_api.ReadFile(f)
790 if pattern.search(contents):
791 files.append(f)
792
793 if files:
794 return [output_api.PresubmitError(
795 'Do not use #pragma once in header files.\n'
796 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
797 files)]
798 return []
799
[email protected]127f18ec2012-06-16 05:05:59800
[email protected]e7479052012-09-19 00:26:12801def _CheckNoTrinaryTrueFalse(input_api, output_api):
802 """Checks to make sure we don't introduce use of foo ? true : false."""
803 problems = []
804 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
805 for f in input_api.AffectedFiles():
806 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
807 continue
808
809 for line_num, line in f.ChangedContents():
810 if pattern.match(line):
811 problems.append(' %s:%d' % (f.LocalPath(), line_num))
812
813 if not problems:
814 return []
815 return [output_api.PresubmitPromptWarning(
816 'Please consider avoiding the "? true : false" pattern if possible.\n' +
817 '\n'.join(problems))]
818
819
[email protected]55f9f382012-07-31 11:02:18820def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:28821 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:18822 change. Breaking - rules is an error, breaking ! rules is a
823 warning.
824 """
mohan.reddyf21db962014-10-16 12:26:47825 import sys
[email protected]55f9f382012-07-31 11:02:18826 # We need to wait until we have an input_api object and use this
827 # roundabout construct to import checkdeps because this file is
828 # eval-ed and thus doesn't have __file__.
829 original_sys_path = sys.path
830 try:
831 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47832 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18833 import checkdeps
834 from cpp_checker import CppChecker
rhalavati08acd232017-04-03 07:23:28835 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:18836 from rules import Rule
837 finally:
838 # Restore sys.path to what it was before.
839 sys.path = original_sys_path
840
841 added_includes = []
rhalavati08acd232017-04-03 07:23:28842 added_imports = []
[email protected]55f9f382012-07-31 11:02:18843 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:28844 if CppChecker.IsCppFile(f.LocalPath()):
845 changed_lines = [line for line_num, line in f.ChangedContents()]
846 added_includes.append([f.LocalPath(), changed_lines])
847 elif ProtoChecker.IsProtoFile(f.LocalPath()):
848 changed_lines = [line for line_num, line in f.ChangedContents()]
849 added_imports.append([f.LocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:18850
[email protected]26385172013-05-09 23:11:35851 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18852
853 error_descriptions = []
854 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:28855 error_subjects = set()
856 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:18857 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
858 added_includes):
859 description_with_path = '%s\n %s' % (path, rule_description)
860 if rule_type == Rule.DISALLOW:
861 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28862 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:18863 else:
864 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28865 warning_subjects.add("#includes")
866
867 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
868 added_imports):
869 description_with_path = '%s\n %s' % (path, rule_description)
870 if rule_type == Rule.DISALLOW:
871 error_descriptions.append(description_with_path)
872 error_subjects.add("imports")
873 else:
874 warning_descriptions.append(description_with_path)
875 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:18876
877 results = []
878 if error_descriptions:
879 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:28880 'You added one or more %s that violate checkdeps rules.'
881 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:18882 error_descriptions))
883 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42884 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:28885 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:18886 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:28887 '%s? See relevant DEPS file(s) for details and contacts.' %
888 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:18889 warning_descriptions))
890 return results
891
892
[email protected]fbcafe5a2012-08-08 15:31:22893def _CheckFilePermissions(input_api, output_api):
894 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15895 if input_api.platform == 'win32':
896 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29897 checkperms_tool = input_api.os_path.join(
898 input_api.PresubmitLocalPath(),
899 'tools', 'checkperms', 'checkperms.py')
900 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47901 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22902 for f in input_api.AffectedFiles():
903 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11904 try:
905 input_api.subprocess.check_output(args)
906 return []
907 except input_api.subprocess.CalledProcessError as error:
908 return [output_api.PresubmitError(
909 'checkperms.py failed:',
910 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22911
912
robertocn832f5992017-01-04 19:01:30913def _CheckTeamTags(input_api, output_api):
914 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
915 checkteamtags_tool = input_api.os_path.join(
916 input_api.PresubmitLocalPath(),
917 'tools', 'checkteamtags', 'checkteamtags.py')
918 args = [input_api.python_executable, checkteamtags_tool,
919 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:22920 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:30921 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
922 'OWNERS']
923 try:
924 if files:
925 input_api.subprocess.check_output(args + files)
926 return []
927 except input_api.subprocess.CalledProcessError as error:
928 return [output_api.PresubmitError(
929 'checkteamtags.py failed:',
930 long_text=error.output)]
931
932
[email protected]c8278b32012-10-30 20:35:49933def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
934 """Makes sure we don't include ui/aura/window_property.h
935 in header files.
936 """
937 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
938 errors = []
939 for f in input_api.AffectedFiles():
940 if not f.LocalPath().endswith('.h'):
941 continue
942 for line_num, line in f.ChangedContents():
943 if pattern.match(line):
944 errors.append(' %s:%d' % (f.LocalPath(), line_num))
945
946 results = []
947 if errors:
948 results.append(output_api.PresubmitError(
949 'Header files should not include ui/aura/window_property.h', errors))
950 return results
951
952
[email protected]70ca77752012-11-20 03:45:03953def _CheckForVersionControlConflictsInFile(input_api, f):
954 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
955 errors = []
956 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23957 if f.LocalPath().endswith('.md'):
958 # First-level headers in markdown look a lot like version control
959 # conflict markers. http://daringfireball.net/projects/markdown/basics
960 continue
[email protected]70ca77752012-11-20 03:45:03961 if pattern.match(line):
962 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
963 return errors
964
965
966def _CheckForVersionControlConflicts(input_api, output_api):
967 """Usually this is not intentional and will cause a compile failure."""
968 errors = []
969 for f in input_api.AffectedFiles():
970 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
971
972 results = []
973 if errors:
974 results.append(output_api.PresubmitError(
975 'Version control conflict markers found, please resolve.', errors))
976 return results
977
estadee17314a02017-01-12 16:22:16978def _CheckGoogleSupportAnswerUrl(input_api, output_api):
979 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
980 errors = []
981 for f in input_api.AffectedFiles():
982 for line_num, line in f.ChangedContents():
983 if pattern.search(line):
984 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
985
986 results = []
987 if errors:
988 results.append(output_api.PresubmitPromptWarning(
989 'Found Google support URL addressed by answer number. Please replace with '
990 'a p= identifier instead. See crbug.com/679462\n', errors))
991 return results
992
[email protected]70ca77752012-11-20 03:45:03993
[email protected]06e6d0ff2012-12-11 01:36:44994def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
995 def FilterFile(affected_file):
996 """Filter function for use with input_api.AffectedSourceFiles,
997 below. This filters out everything except non-test files from
998 top-level directories that generally speaking should not hard-code
999 service URLs (e.g. src/android_webview/, src/content/ and others).
1000 """
1001 return input_api.FilterSourceFile(
1002 affected_file,
[email protected]78bb39d62012-12-11 15:11:561003 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:441004 black_list=(_EXCLUDED_PATHS +
1005 _TEST_CODE_EXCLUDED_PATHS +
1006 input_api.DEFAULT_BLACK_LIST))
1007
reillyi38965732015-11-16 18:27:331008 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1009 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461010 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1011 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441012 problems = [] # items are (filename, line_number, line)
1013 for f in input_api.AffectedSourceFiles(FilterFile):
1014 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461015 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441016 problems.append((f.LocalPath(), line_num, line))
1017
1018 if problems:
[email protected]f7051d52013-04-02 18:31:421019 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441020 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581021 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441022 [' %s:%d: %s' % (
1023 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031024 else:
1025 return []
[email protected]06e6d0ff2012-12-11 01:36:441026
1027
[email protected]d2530012013-01-25 16:39:271028def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1029 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311030 The native_client_sdk directory is excluded because it has auto-generated PNG
1031 files for documentation.
[email protected]d2530012013-01-25 16:39:271032 """
[email protected]d2530012013-01-25 16:39:271033 errors = []
binji0dcdf342014-12-12 18:32:311034 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
1035 black_list = (r'^native_client_sdk[\\\/]',)
1036 file_filter = lambda f: input_api.FilterSourceFile(
1037 f, white_list=white_list, black_list=black_list)
1038 for f in input_api.AffectedFiles(include_deletes=False,
1039 file_filter=file_filter):
1040 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271041
1042 results = []
1043 if errors:
1044 results.append(output_api.PresubmitError(
1045 'The name of PNG files should not have abbreviations. \n'
1046 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1047 'Contact [email protected] if you have questions.', errors))
1048 return results
1049
1050
Daniel Cheng4dcdb6b2017-04-13 08:30:171051def _ExtractAddRulesFromParsedDeps(parsed_deps):
1052 """Extract the rules that add dependencies from a parsed DEPS file.
1053
1054 Args:
1055 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1056 add_rules = set()
1057 add_rules.update([
1058 rule[1:] for rule in parsed_deps.get('include_rules', [])
1059 if rule.startswith('+') or rule.startswith('!')
1060 ])
1061 for specific_file, rules in parsed_deps.get('specific_include_rules',
1062 {}).iteritems():
1063 add_rules.update([
1064 rule[1:] for rule in rules
1065 if rule.startswith('+') or rule.startswith('!')
1066 ])
1067 return add_rules
1068
1069
1070def _ParseDeps(contents):
1071 """Simple helper for parsing DEPS files."""
1072 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171073 class _VarImpl:
1074
1075 def __init__(self, local_scope):
1076 self._local_scope = local_scope
1077
1078 def Lookup(self, var_name):
1079 """Implements the Var syntax."""
1080 try:
1081 return self._local_scope['vars'][var_name]
1082 except KeyError:
1083 raise Exception('Var is not defined: %s' % var_name)
1084
1085 local_scope = {}
1086 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171087 'Var': _VarImpl(local_scope).Lookup,
1088 }
1089 exec contents in global_scope, local_scope
1090 return local_scope
1091
1092
1093def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081094 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411095 a set of DEPS entries that we should look up.
1096
1097 For a directory (rather than a specific filename) we fake a path to
1098 a specific filename by adding /DEPS. This is chosen as a file that
1099 will seldom or never be subject to per-file include_rules.
1100 """
[email protected]2b438d62013-11-14 17:54:141101 # We ignore deps entries on auto-generated directories.
1102 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081103
Daniel Cheng4dcdb6b2017-04-13 08:30:171104 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1105 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1106
1107 added_deps = new_deps.difference(old_deps)
1108
[email protected]2b438d62013-11-14 17:54:141109 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171110 for added_dep in added_deps:
1111 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1112 continue
1113 # Assume that a rule that ends in .h is a rule for a specific file.
1114 if added_dep.endswith('.h'):
1115 results.add(added_dep)
1116 else:
1117 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081118 return results
1119
1120
[email protected]e871964c2013-05-13 14:14:551121def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1122 """When a dependency prefixed with + is added to a DEPS file, we
1123 want to make sure that the change is reviewed by an OWNER of the
1124 target file or directory, to avoid layering violations from being
1125 introduced. This check verifies that this happens.
1126 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171127 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241128
1129 file_filter = lambda f: not input_api.re.match(
1130 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1131 for f in input_api.AffectedFiles(include_deletes=False,
1132 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551133 filename = input_api.os_path.basename(f.LocalPath())
1134 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171135 virtual_depended_on_files.update(_CalculateAddedDeps(
1136 input_api.os_path,
1137 '\n'.join(f.OldContents()),
1138 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551139
[email protected]e871964c2013-05-13 14:14:551140 if not virtual_depended_on_files:
1141 return []
1142
1143 if input_api.is_committing:
1144 if input_api.tbr:
1145 return [output_api.PresubmitNotifyResult(
1146 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271147 if input_api.dry_run:
1148 return [output_api.PresubmitNotifyResult(
1149 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551150 if not input_api.change.issue:
1151 return [output_api.PresubmitError(
1152 "DEPS approval by OWNERS check failed: this change has "
1153 "no Rietveld issue number, so we can't check it for approvals.")]
1154 output = output_api.PresubmitError
1155 else:
1156 output = output_api.PresubmitNotifyResult
1157
1158 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501159 owner_email, reviewers = (
1160 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1161 input_api,
1162 owners_db.email_regexp,
1163 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551164
1165 owner_email = owner_email or input_api.change.author_email
1166
[email protected]de4f7d22013-05-23 14:27:461167 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511168 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461169 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551170 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1171 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411172
1173 # We strip the /DEPS part that was added by
1174 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1175 # directory.
1176 def StripDeps(path):
1177 start_deps = path.rfind('/DEPS')
1178 if start_deps != -1:
1179 return path[:start_deps]
1180 else:
1181 return path
1182 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551183 for path in missing_files]
1184
1185 if unapproved_dependencies:
1186 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151187 output('You need LGTM from owners of depends-on paths in DEPS that were '
1188 'modified in this CL:\n %s' %
1189 '\n '.join(sorted(unapproved_dependencies)))]
1190 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1191 output_list.append(output(
1192 'Suggested missing target path OWNERS:\n %s' %
1193 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551194 return output_list
1195
1196 return []
1197
1198
[email protected]85218562013-11-22 07:41:401199def _CheckSpamLogging(input_api, output_api):
1200 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1201 black_list = (_EXCLUDED_PATHS +
1202 _TEST_CODE_EXCLUDED_PATHS +
1203 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501204 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191205 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481206 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461207 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121208 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1209 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581210 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
huangsa13b5a02017-07-14 15:17:591211 r"^chrome[\\\/]installer[\\\/]zucchini[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161212 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031213 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151214 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1215 r"^chromecast[\\\/]",
1216 r"^cloud_print[\\\/]",
manzagop85e629e2017-05-09 22:11:481217 r"^components[\\\/]browser_watcher[\\\/]"
1218 r"dump_stability_report_main_win.cc$",
jochen34415e52015-07-10 08:34:311219 r"^components[\\\/]html_viewer[\\\/]"
1220 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461221 # TODO(peter): Remove this exception. https://crbug.com/534537
1222 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1223 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251224 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1225 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241226 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111227 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151228 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111229 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521230 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501231 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361232 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311233 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131234 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001235 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441236 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451237 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021238 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351239 r"dump_file_system.cc$",
1240 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401241 source_file_filter = lambda x: input_api.FilterSourceFile(
1242 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1243
thomasanderson625d3932017-03-29 07:16:581244 log_info = set([])
1245 printf = set([])
[email protected]85218562013-11-22 07:41:401246
1247 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581248 for _, line in f.ChangedContents():
1249 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1250 log_info.add(f.LocalPath())
1251 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1252 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371253
thomasanderson625d3932017-03-29 07:16:581254 if input_api.re.search(r"\bprintf\(", line):
1255 printf.add(f.LocalPath())
1256 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1257 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401258
1259 if log_info:
1260 return [output_api.PresubmitError(
1261 'These files spam the console log with LOG(INFO):',
1262 items=log_info)]
1263 if printf:
1264 return [output_api.PresubmitError(
1265 'These files spam the console log with printf/fprintf:',
1266 items=printf)]
1267 return []
1268
1269
[email protected]49aa76a2013-12-04 06:59:161270def _CheckForAnonymousVariables(input_api, output_api):
1271 """These types are all expected to hold locks while in scope and
1272 so should never be anonymous (which causes them to be immediately
1273 destroyed)."""
1274 they_who_must_be_named = [
1275 'base::AutoLock',
1276 'base::AutoReset',
1277 'base::AutoUnlock',
1278 'SkAutoAlphaRestore',
1279 'SkAutoBitmapShaderInstall',
1280 'SkAutoBlitterChoose',
1281 'SkAutoBounderCommit',
1282 'SkAutoCallProc',
1283 'SkAutoCanvasRestore',
1284 'SkAutoCommentBlock',
1285 'SkAutoDescriptor',
1286 'SkAutoDisableDirectionCheck',
1287 'SkAutoDisableOvalCheck',
1288 'SkAutoFree',
1289 'SkAutoGlyphCache',
1290 'SkAutoHDC',
1291 'SkAutoLockColors',
1292 'SkAutoLockPixels',
1293 'SkAutoMalloc',
1294 'SkAutoMaskFreeImage',
1295 'SkAutoMutexAcquire',
1296 'SkAutoPathBoundsUpdate',
1297 'SkAutoPDFRelease',
1298 'SkAutoRasterClipValidate',
1299 'SkAutoRef',
1300 'SkAutoTime',
1301 'SkAutoTrace',
1302 'SkAutoUnref',
1303 ]
1304 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1305 # bad: base::AutoLock(lock.get());
1306 # not bad: base::AutoLock lock(lock.get());
1307 bad_pattern = input_api.re.compile(anonymous)
1308 # good: new base::AutoLock(lock.get())
1309 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1310 errors = []
1311
1312 for f in input_api.AffectedFiles():
1313 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1314 continue
1315 for linenum, line in f.ChangedContents():
1316 if bad_pattern.search(line) and not good_pattern.search(line):
1317 errors.append('%s:%d' % (f.LocalPath(), linenum))
1318
1319 if errors:
1320 return [output_api.PresubmitError(
1321 'These lines create anonymous variables that need to be named:',
1322 items=errors)]
1323 return []
1324
1325
[email protected]999261d2014-03-03 20:08:081326def _CheckUserActionUpdate(input_api, output_api):
1327 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521328 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081329 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521330 # If actions.xml is already included in the changelist, the PRESUBMIT
1331 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081332 return []
1333
[email protected]999261d2014-03-03 20:08:081334 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1335 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521336 current_actions = None
[email protected]999261d2014-03-03 20:08:081337 for f in input_api.AffectedFiles(file_filter=file_filter):
1338 for line_num, line in f.ChangedContents():
1339 match = input_api.re.search(action_re, line)
1340 if match:
[email protected]2f92dec2014-03-07 19:21:521341 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1342 # loaded only once.
1343 if not current_actions:
1344 with open('tools/metrics/actions/actions.xml') as actions_f:
1345 current_actions = actions_f.read()
1346 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081347 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521348 action = 'name="{0}"'.format(action_name)
1349 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081350 return [output_api.PresubmitPromptWarning(
1351 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521352 'tools/metrics/actions/actions.xml. Please run '
1353 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081354 % (f.LocalPath(), line_num, action_name))]
1355 return []
1356
1357
Daniel Cheng13ca61a882017-08-25 15:11:251358def _ImportJSONCommentEater(input_api):
1359 import sys
1360 sys.path = sys.path + [input_api.os_path.join(
1361 input_api.PresubmitLocalPath(),
1362 'tools', 'json_comment_eater')]
1363 import json_comment_eater
1364 return json_comment_eater
1365
1366
[email protected]99171a92014-06-03 08:44:471367def _GetJSONParseError(input_api, filename, eat_comments=True):
1368 try:
1369 contents = input_api.ReadFile(filename)
1370 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:251371 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:131372 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471373
1374 input_api.json.loads(contents)
1375 except ValueError as e:
1376 return e
1377 return None
1378
1379
1380def _GetIDLParseError(input_api, filename):
1381 try:
1382 contents = input_api.ReadFile(filename)
1383 idl_schema = input_api.os_path.join(
1384 input_api.PresubmitLocalPath(),
1385 'tools', 'json_schema_compiler', 'idl_schema.py')
1386 process = input_api.subprocess.Popen(
1387 [input_api.python_executable, idl_schema],
1388 stdin=input_api.subprocess.PIPE,
1389 stdout=input_api.subprocess.PIPE,
1390 stderr=input_api.subprocess.PIPE,
1391 universal_newlines=True)
1392 (_, error) = process.communicate(input=contents)
1393 return error or None
1394 except ValueError as e:
1395 return e
1396
1397
1398def _CheckParseErrors(input_api, output_api):
1399 """Check that IDL and JSON files do not contain syntax errors."""
1400 actions = {
1401 '.idl': _GetIDLParseError,
1402 '.json': _GetJSONParseError,
1403 }
[email protected]99171a92014-06-03 08:44:471404 # Most JSON files are preprocessed and support comments, but these do not.
1405 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491406 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471407 ]
1408 # Only run IDL checker on files in these directories.
1409 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491410 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1411 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471412 ]
1413
1414 def get_action(affected_file):
1415 filename = affected_file.LocalPath()
1416 return actions.get(input_api.os_path.splitext(filename)[1])
1417
[email protected]99171a92014-06-03 08:44:471418 def FilterFile(affected_file):
1419 action = get_action(affected_file)
1420 if not action:
1421 return False
1422 path = affected_file.LocalPath()
1423
Sean Kau46e29bc2017-08-28 16:31:161424 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:471425 return False
1426
1427 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:161428 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:471429 return False
1430 return True
1431
1432 results = []
1433 for affected_file in input_api.AffectedFiles(
1434 file_filter=FilterFile, include_deletes=False):
1435 action = get_action(affected_file)
1436 kwargs = {}
1437 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:161438 _MatchesFile(input_api, json_no_comments_patterns,
1439 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:471440 kwargs['eat_comments'] = False
1441 parse_error = action(input_api,
1442 affected_file.AbsoluteLocalPath(),
1443 **kwargs)
1444 if parse_error:
1445 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1446 (affected_file.LocalPath(), parse_error)))
1447 return results
1448
1449
[email protected]760deea2013-12-10 19:33:491450def _CheckJavaStyle(input_api, output_api):
1451 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471452 import sys
[email protected]760deea2013-12-10 19:33:491453 original_sys_path = sys.path
1454 try:
1455 sys.path = sys.path + [input_api.os_path.join(
1456 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1457 import checkstyle
1458 finally:
1459 # Restore sys.path to what it was before.
1460 sys.path = original_sys_path
1461
1462 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091463 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511464 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491465
1466
Sean Kau46e29bc2017-08-28 16:31:161467def _MatchesFile(input_api, patterns, path):
1468 for pattern in patterns:
1469 if input_api.re.search(pattern, path):
1470 return True
1471 return False
1472
1473
dchenge07de812016-06-20 19:27:171474def _CheckIpcOwners(input_api, output_api):
1475 """Checks that affected files involving IPC have an IPC OWNERS rule.
1476
1477 Whether or not a file affects IPC is determined by a simple whitelist of
1478 filename patterns."""
1479 file_patterns = [
palmerb19a0932017-01-24 04:00:311480 # Legacy IPC:
dchenge07de812016-06-20 19:27:171481 '*_messages.cc',
1482 '*_messages*.h',
1483 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311484 # Mojo IPC:
dchenge07de812016-06-20 19:27:171485 '*.mojom',
1486 '*_struct_traits*.*',
1487 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311488 '*.typemap',
1489 # Android native IPC:
1490 '*.aidl',
1491 # Blink uses a different file naming convention:
1492 '*EnumTraits*.*',
dchenge07de812016-06-20 19:27:171493 '*StructTraits*.*',
1494 '*TypeConverter*.*',
1495 ]
1496
scottmg7a6ed5ba2016-11-04 18:22:041497 # These third_party directories do not contain IPCs, but contain files
1498 # matching the above patterns, which trigger false positives.
1499 exclude_paths = [
1500 'third_party/crashpad/*',
1501 ]
1502
dchenge07de812016-06-20 19:27:171503 # Dictionary mapping an OWNERS file path to Patterns.
1504 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1505 # rules ) to a PatternEntry.
1506 # PatternEntry is a dictionary with two keys:
1507 # - 'files': the files that are matched by this pattern
1508 # - 'rules': the per-file rules needed for this pattern
1509 # For example, if we expect OWNERS file to contain rules for *.mojom and
1510 # *_struct_traits*.*, Patterns might look like this:
1511 # {
1512 # '*.mojom': {
1513 # 'files': ...,
1514 # 'rules': [
1515 # 'per-file *.mojom=set noparent',
1516 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1517 # ],
1518 # },
1519 # '*_struct_traits*.*': {
1520 # 'files': ...,
1521 # 'rules': [
1522 # 'per-file *_struct_traits*.*=set noparent',
1523 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1524 # ],
1525 # },
1526 # }
1527 to_check = {}
1528
Daniel Cheng13ca61a882017-08-25 15:11:251529 def AddPatternToCheck(input_file, pattern):
1530 owners_file = input_api.os_path.join(
1531 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
1532 if owners_file not in to_check:
1533 to_check[owners_file] = {}
1534 if pattern not in to_check[owners_file]:
1535 to_check[owners_file][pattern] = {
1536 'files': [],
1537 'rules': [
1538 'per-file %s=set noparent' % pattern,
1539 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1540 ]
1541 }
1542 to_check[owners_file][pattern]['files'].append(f)
1543
dchenge07de812016-06-20 19:27:171544 # Iterate through the affected files to see what we actually need to check
1545 # for. We should only nag patch authors about per-file rules if a file in that
1546 # directory would match that pattern. If a directory only contains *.mojom
1547 # files and no *_messages*.h files, we should only nag about rules for
1548 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:251549 for f in input_api.AffectedFiles(include_deletes=False):
1550 # Manifest files don't have a strong naming convention. Instead, scan
1551 # affected files for .json files and see if they look like a manifest.
Sean Kau46e29bc2017-08-28 16:31:161552 if (f.LocalPath().endswith('.json') and
1553 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
1554 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:251555 json_comment_eater = _ImportJSONCommentEater(input_api)
1556 mostly_json_lines = '\n'.join(f.NewContents())
1557 # Comments aren't allowed in strict JSON, so filter them out.
1558 json_lines = json_comment_eater.Nom(mostly_json_lines)
1559 json_content = input_api.json.loads(json_lines)
1560 if 'interface_provider_specs' in json_content:
1561 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:171562 for pattern in file_patterns:
1563 if input_api.fnmatch.fnmatch(
1564 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041565 skip = False
1566 for exclude in exclude_paths:
1567 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1568 skip = True
1569 break
1570 if skip:
1571 continue
Daniel Cheng13ca61a882017-08-25 15:11:251572 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:171573 break
1574
1575 # Now go through the OWNERS files we collected, filtering out rules that are
1576 # already present in that OWNERS file.
1577 for owners_file, patterns in to_check.iteritems():
1578 try:
1579 with file(owners_file) as f:
1580 lines = set(f.read().splitlines())
1581 for entry in patterns.itervalues():
1582 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1583 ]
1584 except IOError:
1585 # No OWNERS file, so all the rules are definitely missing.
1586 continue
1587
1588 # All the remaining lines weren't found in OWNERS files, so emit an error.
1589 errors = []
1590 for owners_file, patterns in to_check.iteritems():
1591 missing_lines = []
1592 files = []
1593 for pattern, entry in patterns.iteritems():
1594 missing_lines.extend(entry['rules'])
1595 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1596 if missing_lines:
1597 errors.append(
Daniel Cheng52111692017-06-14 08:00:591598 '%s needs the following lines added:\n\n%s\n\nfor files:\n%s' %
dchenge07de812016-06-20 19:27:171599 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1600
1601 results = []
1602 if errors:
vabrf5ce3bf92016-07-11 14:52:411603 if input_api.is_committing:
1604 output = output_api.PresubmitError
1605 else:
1606 output = output_api.PresubmitPromptWarning
1607 results.append(output(
Daniel Cheng52111692017-06-14 08:00:591608 'Found OWNERS files that need to be updated for IPC security ' +
1609 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:171610 long_text='\n\n'.join(errors)))
1611
1612 return results
1613
1614
jbriance9e12f162016-11-25 07:57:501615def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311616 """Checks that added or removed lines in non third party affected
1617 header files do not lead to new useless class or struct forward
1618 declaration.
jbriance9e12f162016-11-25 07:57:501619 """
1620 results = []
1621 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1622 input_api.re.MULTILINE)
1623 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1624 input_api.re.MULTILINE)
1625 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311626 if (f.LocalPath().startswith('third_party') and
1627 not f.LocalPath().startswith('third_party/WebKit') and
1628 not f.LocalPath().startswith('third_party\\WebKit')):
1629 continue
1630
jbriance9e12f162016-11-25 07:57:501631 if not f.LocalPath().endswith('.h'):
1632 continue
1633
1634 contents = input_api.ReadFile(f)
1635 fwd_decls = input_api.re.findall(class_pattern, contents)
1636 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1637
1638 useless_fwd_decls = []
1639 for decl in fwd_decls:
1640 count = sum(1 for _ in input_api.re.finditer(
1641 r'\b%s\b' % input_api.re.escape(decl), contents))
1642 if count == 1:
1643 useless_fwd_decls.append(decl)
1644
1645 if not useless_fwd_decls:
1646 continue
1647
1648 for line in f.GenerateScmDiff().splitlines():
1649 if (line.startswith('-') and not line.startswith('--') or
1650 line.startswith('+') and not line.startswith('++')):
1651 for decl in useless_fwd_decls:
1652 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1653 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:241654 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:501655 (f.LocalPath(), decl)))
1656 useless_fwd_decls.remove(decl)
1657
1658 return results
1659
1660
dskiba88634f4e2015-08-14 23:03:291661def _CheckAndroidToastUsage(input_api, output_api):
1662 """Checks that code uses org.chromium.ui.widget.Toast instead of
1663 android.widget.Toast (Chromium Toast doesn't force hardware
1664 acceleration on low-end devices, saving memory).
1665 """
1666 toast_import_pattern = input_api.re.compile(
1667 r'^import android\.widget\.Toast;$')
1668
1669 errors = []
1670
1671 sources = lambda affected_file: input_api.FilterSourceFile(
1672 affected_file,
1673 black_list=(_EXCLUDED_PATHS +
1674 _TEST_CODE_EXCLUDED_PATHS +
1675 input_api.DEFAULT_BLACK_LIST +
1676 (r'^chromecast[\\\/].*',
1677 r'^remoting[\\\/].*')),
1678 white_list=(r'.*\.java$',))
1679
1680 for f in input_api.AffectedSourceFiles(sources):
1681 for line_num, line in f.ChangedContents():
1682 if toast_import_pattern.search(line):
1683 errors.append("%s:%d" % (f.LocalPath(), line_num))
1684
1685 results = []
1686
1687 if errors:
1688 results.append(output_api.PresubmitError(
1689 'android.widget.Toast usage is detected. Android toasts use hardware'
1690 ' acceleration, and can be\ncostly on low-end devices. Please use'
1691 ' org.chromium.ui.widget.Toast instead.\n'
1692 'Contact [email protected] if you have any questions.',
1693 errors))
1694
1695 return results
1696
1697
dgnaa68d5e2015-06-10 10:08:221698def _CheckAndroidCrLogUsage(input_api, output_api):
1699 """Checks that new logs using org.chromium.base.Log:
1700 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511701 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221702 """
pkotwicza1dd0b002016-05-16 14:41:041703
torne89540622017-03-24 19:41:301704 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:041705 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:301706 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:041707 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:301708 # WebView license viewer code cannot depend on //base; used in stub APK.
1709 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
1710 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:041711 ]
1712
dgnaa68d5e2015-06-10 10:08:221713 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121714 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1715 class_in_base_pattern = input_api.re.compile(
1716 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1717 has_some_log_import_pattern = input_api.re.compile(
1718 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221719 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121720 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221721 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511722 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221723 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221724
Vincent Scheib16d7b272015-09-15 18:09:071725 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221726 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041727 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1728 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121729
dgnaa68d5e2015-06-10 10:08:221730 tag_decl_errors = []
1731 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121732 tag_errors = []
dgn38736db2015-09-18 19:20:511733 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121734 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221735
1736 for f in input_api.AffectedSourceFiles(sources):
1737 file_content = input_api.ReadFile(f)
1738 has_modified_logs = False
1739
1740 # Per line checks
dgn87d9fb62015-06-12 09:15:121741 if (cr_log_import_pattern.search(file_content) or
1742 (class_in_base_pattern.search(file_content) and
1743 not has_some_log_import_pattern.search(file_content))):
1744 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221745 for line_num, line in f.ChangedContents():
1746
1747 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121748 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221749 if match:
1750 has_modified_logs = True
1751
1752 # Make sure it uses "TAG"
1753 if not match.group('tag') == 'TAG':
1754 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121755 else:
1756 # Report non cr Log function calls in changed lines
1757 for line_num, line in f.ChangedContents():
1758 if log_call_pattern.search(line):
1759 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221760
1761 # Per file checks
1762 if has_modified_logs:
1763 # Make sure the tag is using the "cr" prefix and is not too long
1764 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511765 tag_name = match.group('name') if match else None
1766 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221767 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511768 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221769 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511770 elif '.' in tag_name:
1771 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221772
1773 results = []
1774 if tag_decl_errors:
1775 results.append(output_api.PresubmitPromptWarning(
1776 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511777 '"private static final String TAG = "<package tag>".\n'
1778 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221779 tag_decl_errors))
1780
1781 if tag_length_errors:
1782 results.append(output_api.PresubmitError(
1783 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511784 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221785 tag_length_errors))
1786
1787 if tag_errors:
1788 results.append(output_api.PresubmitPromptWarning(
1789 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1790 tag_errors))
1791
dgn87d9fb62015-06-12 09:15:121792 if util_log_errors:
dgn4401aa52015-04-29 16:26:171793 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121794 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1795 util_log_errors))
1796
dgn38736db2015-09-18 19:20:511797 if tag_with_dot_errors:
1798 results.append(output_api.PresubmitPromptWarning(
1799 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1800 tag_with_dot_errors))
1801
dgn4401aa52015-04-29 16:26:171802 return results
1803
1804
yolandyan45001472016-12-21 21:12:421805def _CheckAndroidTestAnnotationUsage(input_api, output_api):
1806 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
1807 deprecated_annotation_import_pattern = input_api.re.compile(
1808 r'^import android\.test\.suitebuilder\.annotation\..*;',
1809 input_api.re.MULTILINE)
1810 sources = lambda x: input_api.FilterSourceFile(
1811 x, white_list=(r'.*\.java$',), black_list=None)
1812 errors = []
1813 for f in input_api.AffectedFiles(sources):
1814 for line_num, line in f.ChangedContents():
1815 if deprecated_annotation_import_pattern.search(line):
1816 errors.append("%s:%d" % (f.LocalPath(), line_num))
1817
1818 results = []
1819 if errors:
1820 results.append(output_api.PresubmitError(
1821 'Annotations in android.test.suitebuilder.annotation have been'
1822 ' deprecated since API level 24. Please use android.support.test.filters'
1823 ' from //third_party/android_support_test_runner:runner_java instead.'
1824 ' Contact [email protected] if you have any questions.', errors))
1825 return results
1826
1827
agrieve7b6479d82015-10-07 14:24:221828def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1829 """Checks if MDPI assets are placed in a correct directory."""
1830 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1831 ('/res/drawable/' in f.LocalPath() or
1832 '/res/drawable-ldrtl/' in f.LocalPath()))
1833 errors = []
1834 for f in input_api.AffectedFiles(include_deletes=False,
1835 file_filter=file_filter):
1836 errors.append(' %s' % f.LocalPath())
1837
1838 results = []
1839 if errors:
1840 results.append(output_api.PresubmitError(
1841 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1842 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1843 '/res/drawable-ldrtl/.\n'
1844 'Contact [email protected] if you have questions.', errors))
1845 return results
1846
1847
agrievef32bcc72016-04-04 14:57:401848class PydepsChecker(object):
1849 def __init__(self, input_api, pydeps_files):
1850 self._file_cache = {}
1851 self._input_api = input_api
1852 self._pydeps_files = pydeps_files
1853
1854 def _LoadFile(self, path):
1855 """Returns the list of paths within a .pydeps file relative to //."""
1856 if path not in self._file_cache:
1857 with open(path) as f:
1858 self._file_cache[path] = f.read()
1859 return self._file_cache[path]
1860
1861 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1862 """Returns an interable of paths within the .pydep, relativized to //."""
1863 os_path = self._input_api.os_path
1864 pydeps_dir = os_path.dirname(pydeps_path)
1865 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1866 if not l.startswith('*'))
1867 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1868
1869 def _CreateFilesToPydepsMap(self):
1870 """Returns a map of local_path -> list_of_pydeps."""
1871 ret = {}
1872 for pydep_local_path in self._pydeps_files:
1873 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1874 ret.setdefault(path, []).append(pydep_local_path)
1875 return ret
1876
1877 def ComputeAffectedPydeps(self):
1878 """Returns an iterable of .pydeps files that might need regenerating."""
1879 affected_pydeps = set()
1880 file_to_pydeps_map = None
1881 for f in self._input_api.AffectedFiles(include_deletes=True):
1882 local_path = f.LocalPath()
1883 if local_path == 'DEPS':
1884 return self._pydeps_files
1885 elif local_path.endswith('.pydeps'):
1886 if local_path in self._pydeps_files:
1887 affected_pydeps.add(local_path)
1888 elif local_path.endswith('.py'):
1889 if file_to_pydeps_map is None:
1890 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1891 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1892 return affected_pydeps
1893
1894 def DetermineIfStale(self, pydeps_path):
1895 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:411896 import difflib
agrievef32bcc72016-04-04 14:57:401897 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1898 cmd = old_pydeps_data[1][1:].strip()
1899 new_pydeps_data = self._input_api.subprocess.check_output(
1900 cmd + ' --output ""', shell=True)
phajdan.jr0d9878552016-11-04 10:49:411901 old_contents = old_pydeps_data[2:]
1902 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:401903 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:411904 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:401905
1906
1907def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1908 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001909 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281910 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1911 # Mac, so skip it on other platforms.
1912 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001913 return []
agrievef32bcc72016-04-04 14:57:401914 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1915 is_android = input_api.os_path.exists('third_party/android_tools')
1916 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1917 results = []
1918 # First, check for new / deleted .pydeps.
1919 for f in input_api.AffectedFiles(include_deletes=True):
1920 if f.LocalPath().endswith('.pydeps'):
1921 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1922 results.append(output_api.PresubmitError(
1923 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1924 'remove %s' % f.LocalPath()))
1925 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1926 results.append(output_api.PresubmitError(
1927 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1928 'include %s' % f.LocalPath()))
1929
1930 if results:
1931 return results
1932
1933 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1934
1935 for pydep_path in checker.ComputeAffectedPydeps():
1936 try:
phajdan.jr0d9878552016-11-04 10:49:411937 result = checker.DetermineIfStale(pydep_path)
1938 if result:
1939 cmd, diff = result
agrievef32bcc72016-04-04 14:57:401940 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:411941 'File is stale: %s\nDiff (apply to fix):\n%s\n'
1942 'To regenerate, run:\n\n %s' %
1943 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:401944 except input_api.subprocess.CalledProcessError as error:
1945 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1946 long_text=error.output)]
1947
1948 return results
1949
1950
glidere61efad2015-02-18 17:39:431951def _CheckSingletonInHeaders(input_api, output_api):
1952 """Checks to make sure no header files have |Singleton<|."""
1953 def FileFilter(affected_file):
1954 # It's ok for base/memory/singleton.h to have |Singleton<|.
1955 black_list = (_EXCLUDED_PATHS +
1956 input_api.DEFAULT_BLACK_LIST +
1957 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1958 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1959
sergeyu34d21222015-09-16 00:11:441960 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431961 files = []
1962 for f in input_api.AffectedSourceFiles(FileFilter):
1963 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1964 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1965 contents = input_api.ReadFile(f)
1966 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241967 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431968 pattern.search(line)):
1969 files.append(f)
1970 break
1971
1972 if files:
yolandyandaabc6d2016-04-18 18:29:391973 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441974 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431975 'Please move them to an appropriate source file so that the ' +
1976 'template gets instantiated in a single compilation unit.',
1977 files) ]
1978 return []
1979
1980
[email protected]fd20b902014-05-09 02:14:531981_DEPRECATED_CSS = [
1982 # Values
1983 ( "-webkit-box", "flex" ),
1984 ( "-webkit-inline-box", "inline-flex" ),
1985 ( "-webkit-flex", "flex" ),
1986 ( "-webkit-inline-flex", "inline-flex" ),
1987 ( "-webkit-min-content", "min-content" ),
1988 ( "-webkit-max-content", "max-content" ),
1989
1990 # Properties
1991 ( "-webkit-background-clip", "background-clip" ),
1992 ( "-webkit-background-origin", "background-origin" ),
1993 ( "-webkit-background-size", "background-size" ),
1994 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:441995 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:531996
1997 # Functions
1998 ( "-webkit-gradient", "gradient" ),
1999 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2000 ( "-webkit-linear-gradient", "linear-gradient" ),
2001 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2002 ( "-webkit-radial-gradient", "radial-gradient" ),
2003 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2004]
2005
dbeam1ec68ac2016-12-15 05:22:242006def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532007 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252008 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342009 documentation and iOS CSS for dom distiller
2010 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252011 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532012 results = []
dbeam070cfe62014-10-22 06:44:022013 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:252014 black_list = (_EXCLUDED_PATHS +
2015 _TEST_CODE_EXCLUDED_PATHS +
2016 input_api.DEFAULT_BLACK_LIST +
2017 (r"^chrome/common/extensions/docs",
2018 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342019 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442020 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252021 r"^native_client_sdk"))
2022 file_filter = lambda f: input_api.FilterSourceFile(
2023 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532024 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2025 for line_num, line in fpath.ChangedContents():
2026 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022027 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532028 results.append(output_api.PresubmitError(
2029 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2030 (fpath.LocalPath(), line_num, deprecated_value, value)))
2031 return results
2032
mohan.reddyf21db962014-10-16 12:26:472033
dbeam070cfe62014-10-22 06:44:022034_DEPRECATED_JS = [
2035 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2036 ( "__defineGetter__", "Object.defineProperty" ),
2037 ( "__defineSetter__", "Object.defineProperty" ),
2038]
2039
dbeam1ec68ac2016-12-15 05:22:242040def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022041 """Make sure that we don't use deprecated JS in Chrome code."""
2042 results = []
2043 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2044 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2045 input_api.DEFAULT_BLACK_LIST)
2046 file_filter = lambda f: input_api.FilterSourceFile(
2047 f, white_list=file_inclusion_pattern, black_list=black_list)
2048 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2049 for lnum, line in fpath.ChangedContents():
2050 for (deprecated, replacement) in _DEPRECATED_JS:
2051 if deprecated in line:
2052 results.append(output_api.PresubmitError(
2053 "%s:%d: Use of deprecated JS %s, use %s instead" %
2054 (fpath.LocalPath(), lnum, deprecated, replacement)))
2055 return results
2056
dpapadd651231d82017-07-21 02:44:472057def _CheckForRiskyJsArrowFunction(line_number, line):
2058 if ' => ' in line:
2059 return "line %d, is using an => (arrow) function\n %s\n" % (
2060 line_number, line)
2061 return ''
2062
2063def _CheckForRiskyJsConstLet(input_api, line_number, line):
2064 if input_api.re.match('^\s*(const|let)\s', line):
2065 return "line %d, is using const/let keyword\n %s\n" % (
2066 line_number, line)
2067 return ''
dbeam070cfe62014-10-22 06:44:022068
dbeam1ec68ac2016-12-15 05:22:242069def _CheckForRiskyJsFeatures(input_api, output_api):
2070 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
Steven Bennetts90545f3cb2017-08-14 18:11:002071 # 'ui/webui/resources/cr_components are not allowed on ios'
2072 not_ios_filter = (r".*ui\/webui\/resources\/cr_components.*", )
Steven Bennetts9c7e3c22017-08-02 19:10:572073 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js,
Steven Bennetts90545f3cb2017-08-14 18:11:002074 black_list=not_ios_filter)
dpapadd651231d82017-07-21 02:44:472075 results = []
dbeam1ec68ac2016-12-15 05:22:242076 for f in input_api.AffectedFiles(file_filter=file_filter):
dpapadd651231d82017-07-21 02:44:472077 arrow_error_lines = []
2078 const_let_error_lines = []
dbeam1ec68ac2016-12-15 05:22:242079 for lnum, line in f.ChangedContents():
dpapadd651231d82017-07-21 02:44:472080 arrow_error_lines += filter(None, [
2081 _CheckForRiskyJsArrowFunction(lnum, line),
2082 ])
dbeam1ec68ac2016-12-15 05:22:242083
dpapadd651231d82017-07-21 02:44:472084 const_let_error_lines += filter(None, [
2085 _CheckForRiskyJsConstLet(input_api, lnum, line),
2086 ])
dbeam1ec68ac2016-12-15 05:22:242087
dpapadd651231d82017-07-21 02:44:472088 if arrow_error_lines:
2089 arrow_error_lines = map(
2090 lambda e: "%s:%s" % (f.LocalPath(), e), arrow_error_lines)
2091 results.append(
2092 output_api.PresubmitPromptWarning('\n'.join(arrow_error_lines + [
2093"""
2094Use of => (arrow) operator detected in:
dbeam1ec68ac2016-12-15 05:22:242095%s
2096Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2097https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
dpapadd651231d82017-07-21 02:44:472098""" % f.LocalPath()
2099 ])))
dbeam1ec68ac2016-12-15 05:22:242100
dpapadd651231d82017-07-21 02:44:472101 if const_let_error_lines:
2102 const_let_error_lines = map(
2103 lambda e: "%s:%s" % (f.LocalPath(), e), const_let_error_lines)
2104 results.append(
2105 output_api.PresubmitPromptWarning('\n'.join(const_let_error_lines + [
2106"""
2107Use of const/let keywords detected in:
2108%s
2109Please ensure your code does not run on iOS9 because const/let is not fully
2110supported.
2111https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#let-Block_Scoped-Variables
2112https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#const-Block_Scoped-Constants
2113""" % f.LocalPath()
2114 ])))
2115
2116 return results
dbeam1ec68ac2016-12-15 05:22:242117
rlanday6802cf632017-05-30 17:48:362118def _CheckForRelativeIncludes(input_api, output_api):
2119 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2120 import sys
2121 original_sys_path = sys.path
2122 try:
2123 sys.path = sys.path + [input_api.os_path.join(
2124 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2125 from cpp_checker import CppChecker
2126 finally:
2127 # Restore sys.path to what it was before.
2128 sys.path = original_sys_path
2129
2130 bad_files = {}
2131 for f in input_api.AffectedFiles(include_deletes=False):
2132 if (f.LocalPath().startswith('third_party') and
2133 not f.LocalPath().startswith('third_party/WebKit') and
2134 not f.LocalPath().startswith('third_party\\WebKit')):
2135 continue
2136
2137 if not CppChecker.IsCppFile(f.LocalPath()):
2138 continue
2139
2140 relative_includes = [line for line_num, line in f.ChangedContents()
2141 if "#include" in line and "../" in line]
2142 if not relative_includes:
2143 continue
2144 bad_files[f.LocalPath()] = relative_includes
2145
2146 if not bad_files:
2147 return []
2148
2149 error_descriptions = []
2150 for file_path, bad_lines in bad_files.iteritems():
2151 error_description = file_path
2152 for line in bad_lines:
2153 error_description += '\n ' + line
2154 error_descriptions.append(error_description)
2155
2156 results = []
2157 results.append(output_api.PresubmitError(
2158 'You added one or more relative #include paths (including "../").\n'
2159 'These shouldn\'t be used because they can be used to include headers\n'
2160 'from code that\'s not correctly specified as a dependency in the\n'
2161 'relevant BUILD.gn file(s).',
2162 error_descriptions))
2163
2164 return results
2165
Takeshi Yoshinoe387aa32017-08-02 13:16:132166
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202167def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2168 if not isinstance(key, ast.Str):
2169 return 'Key at line %d must be a string literal' % key.lineno
2170 if not isinstance(value, ast.Dict):
2171 return 'Value at line %d must be a dict' % value.lineno
2172 if len(value.keys) != 1:
2173 return 'Dict at line %d must have single entry' % value.lineno
2174 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2175 return (
2176 'Entry at line %d must have a string literal \'filepath\' as key' %
2177 value.lineno)
2178 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132179
Takeshi Yoshinoe387aa32017-08-02 13:16:132180
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202181def _CheckWatchlistsEntrySyntax(key, value, ast):
2182 if not isinstance(key, ast.Str):
2183 return 'Key at line %d must be a string literal' % key.lineno
2184 if not isinstance(value, ast.List):
2185 return 'Value at line %d must be a list' % value.lineno
2186 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132187
Takeshi Yoshinoe387aa32017-08-02 13:16:132188
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202189def _CheckWATCHLISTSEntries(wd_dict, w_dict, ast):
2190 mismatch_template = (
2191 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2192 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132193
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202194 i = 0
2195 last_key = ''
2196 while True:
2197 if i >= len(wd_dict.keys):
2198 if i >= len(w_dict.keys):
2199 return None
2200 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2201 elif i >= len(w_dict.keys):
2202 return (
2203 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132204
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202205 wd_key = wd_dict.keys[i]
2206 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132207
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202208 result = _CheckWatchlistDefinitionsEntrySyntax(
2209 wd_key, wd_dict.values[i], ast)
2210 if result is not None:
2211 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132212
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202213 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast)
2214 if result is not None:
2215 return 'Bad entry in WATCHLISTS dict: %s' % result
2216
2217 if wd_key.s != w_key.s:
2218 return mismatch_template % (
2219 '%s at line %d' % (wd_key.s, wd_key.lineno),
2220 '%s at line %d' % (w_key.s, w_key.lineno))
2221
2222 if wd_key.s < last_key:
2223 return (
2224 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2225 (wd_key.lineno, w_key.lineno))
2226 last_key = wd_key.s
2227
2228 i = i + 1
2229
2230
2231def _CheckWATCHLISTSSyntax(expression, ast):
2232 if not isinstance(expression, ast.Expression):
2233 return 'WATCHLISTS file must contain a valid expression'
2234 dictionary = expression.body
2235 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2236 return 'WATCHLISTS file must have single dict with exactly two entries'
2237
2238 first_key = dictionary.keys[0]
2239 first_value = dictionary.values[0]
2240 second_key = dictionary.keys[1]
2241 second_value = dictionary.values[1]
2242
2243 if (not isinstance(first_key, ast.Str) or
2244 first_key.s != 'WATCHLIST_DEFINITIONS' or
2245 not isinstance(first_value, ast.Dict)):
2246 return (
2247 'The first entry of the dict in WATCHLISTS file must be '
2248 'WATCHLIST_DEFINITIONS dict')
2249
2250 if (not isinstance(second_key, ast.Str) or
2251 second_key.s != 'WATCHLISTS' or
2252 not isinstance(second_value, ast.Dict)):
2253 return (
2254 'The second entry of the dict in WATCHLISTS file must be '
2255 'WATCHLISTS dict')
2256
2257 return _CheckWATCHLISTSEntries(first_value, second_value, ast)
Takeshi Yoshinoe387aa32017-08-02 13:16:132258
2259
2260def _CheckWATCHLISTS(input_api, output_api):
2261 for f in input_api.AffectedFiles(include_deletes=False):
2262 if f.LocalPath() == 'WATCHLISTS':
2263 contents = input_api.ReadFile(f, 'r')
2264
2265 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202266 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132267 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202268 # Get an AST tree for it and scan the tree for detailed style checking.
2269 expression = input_api.ast.parse(
2270 contents, filename='WATCHLISTS', mode='eval')
2271 except ValueError as e:
2272 return [output_api.PresubmitError(
2273 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2274 except SyntaxError as e:
2275 return [output_api.PresubmitError(
2276 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2277 except TypeError as e:
2278 return [output_api.PresubmitError(
2279 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132280
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202281 result = _CheckWATCHLISTSSyntax(expression, input_api.ast)
2282 if result is not None:
2283 return [output_api.PresubmitError(result)]
2284 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132285
2286 return []
2287
2288
dgnaa68d5e2015-06-10 10:08:222289def _AndroidSpecificOnUploadChecks(input_api, output_api):
2290 """Groups checks that target android code."""
2291 results = []
dgnaa68d5e2015-06-10 10:08:222292 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222293 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292294 results.extend(_CheckAndroidToastUsage(input_api, output_api))
yolandyan45001472016-12-21 21:12:422295 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222296 return results
2297
2298
[email protected]22c9bd72011-03-27 16:47:392299def _CommonChecks(input_api, output_api):
2300 """Checks common to both upload and commit."""
2301 results = []
2302 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382303 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542304 excluded_paths=_EXCLUDED_PATHS))
machenbachfbda9b72016-12-06 13:13:582305 results.extend(
2306 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:192307 results.extend(
[email protected]760deea2013-12-10 19:33:492308 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542309 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182310 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522311 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222312 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442313 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592314 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062315 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122316 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182317 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222318 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302319 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492320 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032321 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492322 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442323 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272324 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:072325 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542326 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442327 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392328 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552329 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042330 results.extend(
2331 input_api.canned_checks.CheckChangeHasNoTabs(
2332 input_api,
2333 output_api,
2334 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402335 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162336 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082337 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242338 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2339 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472340 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042341 results.extend(_CheckForIPCRules(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232342 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432343 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402344 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152345 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172346 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502347 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242348 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:362349 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:132350 results.extend(_CheckWATCHLISTS(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242351
2352 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
2353 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2354 input_api, output_api,
2355 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:382356 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392357 return results
[email protected]1f7b4172010-01-28 01:17:342358
[email protected]b337cb5b2011-01-23 21:24:052359
[email protected]b8079ae4a2012-12-05 19:56:492360def _CheckPatchFiles(input_api, output_api):
2361 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2362 if f.LocalPath().endswith(('.orig', '.rej'))]
2363 if problems:
2364 return [output_api.PresubmitError(
2365 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032366 else:
2367 return []
[email protected]b8079ae4a2012-12-05 19:56:492368
2369
Kent Tamura5a8755d2017-06-29 23:37:072370def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:212371 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
2372 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
2373 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:072374 include_re = input_api.re.compile(
2375 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
2376 extension_re = input_api.re.compile(r'\.[a-z]+$')
2377 errors = []
2378 for f in input_api.AffectedFiles():
2379 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
2380 continue
2381 found_line_number = None
2382 found_macro = None
2383 for line_num, line in f.ChangedContents():
2384 match = macro_re.search(line)
2385 if match:
2386 found_line_number = line_num
2387 found_macro = match.group(2)
2388 break
2389 if not found_line_number:
2390 continue
2391
2392 found_include = False
2393 for line in f.NewContents():
2394 if include_re.search(line):
2395 found_include = True
2396 break
2397 if found_include:
2398 continue
2399
2400 if not f.LocalPath().endswith('.h'):
2401 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
2402 try:
2403 content = input_api.ReadFile(primary_header_path, 'r')
2404 if include_re.search(content):
2405 continue
2406 except IOError:
2407 pass
2408 errors.append('%s:%d %s macro is used without including build/'
2409 'build_config.h.'
2410 % (f.LocalPath(), found_line_number, found_macro))
2411 if errors:
2412 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
2413 return []
2414
2415
[email protected]b00342e7f2013-03-26 16:21:542416def _DidYouMeanOSMacro(bad_macro):
2417 try:
2418 return {'A': 'OS_ANDROID',
2419 'B': 'OS_BSD',
2420 'C': 'OS_CHROMEOS',
2421 'F': 'OS_FREEBSD',
2422 'L': 'OS_LINUX',
2423 'M': 'OS_MACOSX',
2424 'N': 'OS_NACL',
2425 'O': 'OS_OPENBSD',
2426 'P': 'OS_POSIX',
2427 'S': 'OS_SOLARIS',
2428 'W': 'OS_WIN'}[bad_macro[3].upper()]
2429 except KeyError:
2430 return ''
2431
2432
2433def _CheckForInvalidOSMacrosInFile(input_api, f):
2434 """Check for sensible looking, totally invalid OS macros."""
2435 preprocessor_statement = input_api.re.compile(r'^\s*#')
2436 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2437 results = []
2438 for lnum, line in f.ChangedContents():
2439 if preprocessor_statement.search(line):
2440 for match in os_macro.finditer(line):
2441 if not match.group(1) in _VALID_OS_MACROS:
2442 good = _DidYouMeanOSMacro(match.group(1))
2443 did_you_mean = ' (did you mean %s?)' % good if good else ''
2444 results.append(' %s:%d %s%s' % (f.LocalPath(),
2445 lnum,
2446 match.group(1),
2447 did_you_mean))
2448 return results
2449
2450
2451def _CheckForInvalidOSMacros(input_api, output_api):
2452 """Check all affected files for invalid OS macros."""
2453 bad_macros = []
2454 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472455 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542456 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2457
2458 if not bad_macros:
2459 return []
2460
2461 return [output_api.PresubmitError(
2462 'Possibly invalid OS macro[s] found. Please fix your code\n'
2463 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2464
lliabraa35bab3932014-10-01 12:16:442465
2466def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2467 """Check all affected files for invalid "if defined" macros."""
2468 ALWAYS_DEFINED_MACROS = (
2469 "TARGET_CPU_PPC",
2470 "TARGET_CPU_PPC64",
2471 "TARGET_CPU_68K",
2472 "TARGET_CPU_X86",
2473 "TARGET_CPU_ARM",
2474 "TARGET_CPU_MIPS",
2475 "TARGET_CPU_SPARC",
2476 "TARGET_CPU_ALPHA",
2477 "TARGET_IPHONE_SIMULATOR",
2478 "TARGET_OS_EMBEDDED",
2479 "TARGET_OS_IPHONE",
2480 "TARGET_OS_MAC",
2481 "TARGET_OS_UNIX",
2482 "TARGET_OS_WIN32",
2483 )
2484 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2485 results = []
2486 for lnum, line in f.ChangedContents():
2487 for match in ifdef_macro.finditer(line):
2488 if match.group(1) in ALWAYS_DEFINED_MACROS:
2489 always_defined = ' %s is always defined. ' % match.group(1)
2490 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2491 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2492 lnum,
2493 always_defined,
2494 did_you_mean))
2495 return results
2496
2497
2498def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2499 """Check all affected files for invalid "if defined" macros."""
2500 bad_macros = []
2501 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:212502 if f.LocalPath().startswith('third_party/sqlite/'):
2503 continue
lliabraa35bab3932014-10-01 12:16:442504 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2505 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2506
2507 if not bad_macros:
2508 return []
2509
2510 return [output_api.PresubmitError(
2511 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2512 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2513 bad_macros)]
2514
2515
mlamouria82272622014-09-16 18:45:042516def _CheckForIPCRules(input_api, output_api):
2517 """Check for same IPC rules described in
2518 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2519 """
2520 base_pattern = r'IPC_ENUM_TRAITS\('
2521 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2522 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2523
2524 problems = []
2525 for f in input_api.AffectedSourceFiles(None):
2526 local_path = f.LocalPath()
2527 if not local_path.endswith('.h'):
2528 continue
2529 for line_number, line in f.ChangedContents():
2530 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2531 problems.append(
2532 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2533
2534 if problems:
2535 return [output_api.PresubmitPromptWarning(
2536 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2537 else:
2538 return []
2539
[email protected]b00342e7f2013-03-26 16:21:542540
mostynbb639aca52015-01-07 20:31:232541def _CheckForWindowsLineEndings(input_api, output_api):
2542 """Check source code and known ascii text files for Windows style line
2543 endings.
2544 """
earthdok1b5e0ee2015-03-10 15:19:102545 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232546
2547 file_inclusion_pattern = (
2548 known_text_files,
2549 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2550 )
2551
2552 filter = lambda f: input_api.FilterSourceFile(
2553 f, white_list=file_inclusion_pattern, black_list=None)
2554 files = [f.LocalPath() for f in
2555 input_api.AffectedSourceFiles(filter)]
2556
2557 problems = []
2558
2559 for file in files:
2560 fp = open(file, 'r')
2561 for line in fp:
2562 if line.endswith('\r\n'):
2563 problems.append(file)
2564 break
2565 fp.close()
2566
2567 if problems:
2568 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2569 'these files to contain Windows style line endings?\n' +
2570 '\n'.join(problems))]
2571
2572 return []
2573
2574
pastarmovj89f7ee12016-09-20 14:58:132575def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None,
2576 lint_filters=None, verbose_level=None):
2577 """Checks that all source files use SYSLOG properly."""
2578 syslog_files = []
2579 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:562580 for line_number, line in f.ChangedContents():
2581 if 'SYSLOG' in line:
2582 syslog_files.append(f.LocalPath() + ':' + str(line_number))
2583
pastarmovj89f7ee12016-09-20 14:58:132584 if syslog_files:
2585 return [output_api.PresubmitPromptWarning(
2586 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
2587 ' calls.\nFiles to check:\n', items=syslog_files)]
2588 return []
2589
2590
[email protected]1f7b4172010-01-28 01:17:342591def CheckChangeOnUpload(input_api, output_api):
2592 results = []
2593 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472594 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282595 results.extend(
jam93a6ee792017-02-08 23:59:222596 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192597 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222598 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:132599 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:162600 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542601 return results
[email protected]ca8d1982009-02-19 16:33:122602
2603
[email protected]1bfb8322014-04-23 01:02:412604def GetTryServerMasterForBot(bot):
2605 """Returns the Try Server master for the given bot.
2606
[email protected]0bb112362014-07-26 04:38:322607 It tries to guess the master from the bot name, but may still fail
2608 and return None. There is no longer a default master.
2609 """
2610 # Potentially ambiguous bot names are listed explicitly.
2611 master_map = {
tandriie5587792016-07-14 00:34:502612 'chromium_presubmit': 'master.tryserver.chromium.linux',
2613 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412614 }
[email protected]0bb112362014-07-26 04:38:322615 master = master_map.get(bot)
2616 if not master:
wnwen4fbaab82016-05-25 12:54:362617 if 'android' in bot:
tandriie5587792016-07-14 00:34:502618 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:362619 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:502620 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:322621 elif 'win' in bot:
tandriie5587792016-07-14 00:34:502622 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:322623 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:502624 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:322625 return master
[email protected]1bfb8322014-04-23 01:02:412626
2627
[email protected]ca8d1982009-02-19 16:33:122628def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542629 results = []
[email protected]1f7b4172010-01-28 01:17:342630 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542631 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272632 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342633 input_api,
2634 output_api,
[email protected]2fdd1f362013-01-16 03:56:032635 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272636
jam93a6ee792017-02-08 23:59:222637 results.extend(
2638 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:542639 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2640 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412641 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2642 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542643 return results