blob: 3ab7802f7a1e48f75b43a2d020e4404164917a88 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d19842009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5413 r"^breakpad[\\\/].*",
[email protected]40d1dbb2012-10-26 07:18:0014 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
15 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2816 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0817 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5418 r"^skia[\\\/].*",
primiano0166ccc82015-10-06 12:12:2819 r"^third_party[\\\/]WebKit[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
calamity8ec9430c2016-08-23 03:56:2926 r".*vulcanized.html$",
27 r".*crisper.js$",
vapierb2053f542017-03-09 19:46:1028 r"tools[\\\/]md_browser[\\\/].*\.css$",
ehmaldonado78eee2ed2017-03-28 13:16:5429 # Test pages for WebRTC telemetry tests.
30 r"tools[\\\/]perf[\\\/]page_sets[\\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4031)
[email protected]ca8d19842009-02-19 16:33:1232
wnwenbdc444e2016-05-25 13:44:1533
[email protected]06e6d0ff2012-12-11 01:36:4434# Fragment of a regular expression that matches C++ and Objective-C++
35# implementation files.
36_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
37
wnwenbdc444e2016-05-25 13:44:1538
[email protected]06e6d0ff2012-12-11 01:36:4439# Regular expression that matches code only used for test binaries
40# (best effort).
41_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4942 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4443 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
sdefresne1fccb0a2016-12-19 08:10:5344 r'.+_(api|browser|eg|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1245 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4446 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4947 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0548 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4949 r'content[\\\/]shell[\\\/].*',
[email protected]7b054982013-11-27 00:44:4750 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4951 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0852 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4953 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4454)
[email protected]ca8d19842009-02-19 16:33:1255
wnwenbdc444e2016-05-25 13:44:1556
[email protected]eea609a2011-11-18 13:10:1257_TEST_ONLY_WARNING = (
58 'You might be calling functions intended only for testing from\n'
59 'production code. It is OK to ignore this warning if you know what\n'
60 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5861 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1262
63
[email protected]cf9b78f2012-11-14 11:40:2864_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4065 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2166 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
67 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2868
wnwenbdc444e2016-05-25 13:44:1569
[email protected]127f18ec2012-06-16 05:05:5970_BANNED_OBJC_FUNCTIONS = (
71 (
72 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2073 (
74 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5975 'prohibited. Please use CrTrackingArea instead.',
76 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
77 ),
78 False,
79 ),
80 (
[email protected]eaae1972014-04-16 04:17:2681 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:2082 (
83 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:5984 'instead.',
85 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
86 ),
87 False,
88 ),
89 (
90 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:2091 (
92 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:5993 'Please use |convertPoint:(point) fromView:nil| instead.',
94 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
95 ),
96 True,
97 ),
98 (
99 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20100 (
101 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59102 'Please use |convertPoint:(point) toView:nil| instead.',
103 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
104 ),
105 True,
106 ),
107 (
108 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20109 (
110 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59111 'Please use |convertRect:(point) fromView:nil| instead.',
112 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
113 ),
114 True,
115 ),
116 (
117 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20118 (
119 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59120 'Please use |convertRect:(point) toView:nil| instead.',
121 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
122 ),
123 True,
124 ),
125 (
126 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20127 (
128 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59129 'Please use |convertSize:(point) fromView:nil| instead.',
130 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
131 ),
132 True,
133 ),
134 (
135 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20136 (
137 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59138 'Please use |convertSize:(point) toView:nil| instead.',
139 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
140 ),
141 True,
142 ),
jif65398702016-10-27 10:19:48143 (
144 r"/\s+UTF8String\s*]",
145 (
146 'The use of -[NSString UTF8String] is dangerous as it can return null',
147 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
148 'Please use |SysNSStringToUTF8| instead.',
149 ),
150 True,
151 ),
[email protected]127f18ec2012-06-16 05:05:59152)
153
154
155_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20156 # Make sure that gtest's FRIEND_TEST() macro is not used; the
157 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30158 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20159 (
thomasandersone7caaa9b2017-03-29 19:22:53160 r'\bNULL\b',
161 (
162 'New code should not use NULL. Use nullptr instead.',
163 ),
164 True,
165 (),
166 ),
167 (
[email protected]23e6cbc2012-06-16 18:51:20168 'FRIEND_TEST(',
169 (
[email protected]e3c945502012-06-26 20:01:49170 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20171 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
172 ),
173 False,
[email protected]7345da02012-11-27 14:31:49174 (),
[email protected]23e6cbc2012-06-16 18:51:20175 ),
176 (
thomasanderson4b569052016-09-14 20:15:53177 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
178 (
179 'Chrome clients wishing to select events on X windows should use',
180 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
181 'you are selecting events from the GPU process, or if you are using',
182 'an XDisplay other than gfx::GetXDisplay().',
183 ),
184 True,
185 (
186 r"^ui[\\\/]gl[\\\/].*\.cc$",
187 r"^media[\\\/]gpu[\\\/].*\.cc$",
188 r"^gpu[\\\/].*\.cc$",
189 ),
190 ),
191 (
thomasandersone043e3ce2017-06-08 00:43:20192 r'XInternAtom|xcb_intern_atom',
193 (
thomasanderson11aa41d2017-06-08 22:22:38194 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20195 ),
196 True,
197 (
thomasanderson11aa41d2017-06-08 22:22:38198 r"^gpu[\\\/]ipc[\\\/]service[\\\/]gpu_watchdog_thread\.cc$",
199 r"^remoting[\\\/]host[\\\/]linux[\\\/]x_server_clipboard\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20200 r"^ui[\\\/]gfx[\\\/]x[\\\/]x11_atom_cache\.cc$",
201 ),
202 ),
203 (
[email protected]23e6cbc2012-06-16 18:51:20204 'ScopedAllowIO',
205 (
satoruxe1396f8a2017-06-01 06:40:39206 'New production code should not use ScopedAllowIO (using it in',
207 'browser tests is fine). Post a task to the blocking pool or the',
208 'FILE thread instead.',
[email protected]23e6cbc2012-06-16 18:51:20209 ),
[email protected]e3c945502012-06-26 20:01:49210 True,
[email protected]7345da02012-11-27 14:31:49211 (
satoruxe1396f8a2017-06-01 06:40:39212 r"^.*browser(|_)test[a-z_]*\.cc$",
hajimehoshi2acea432017-03-08 08:55:37213 r"^base[\\\/]memory[\\\/]shared_memory_posix\.cc$",
rayb0088ee52017-04-26 22:35:08214 r"^base[\\\/]process[\\\/]internal_aix\.cc$",
nyad2c548b2015-12-09 03:22:32215 r"^base[\\\/]process[\\\/]process_linux\.cc$",
thestig75844fdb2014-09-09 19:47:10216 r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$",
tfarina0923ac52015-01-07 03:21:22217 r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$",
rdevlin.cronin62018a12017-06-22 17:34:06218 r"^chrome[\\\/]browser[\\\/]extensions[\\\/]" +
219 r"chrome_test_extension_loader.cc$",
sky0e07a142016-03-25 21:27:31220 r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$",
philipj3f9d5bde2014-08-28 14:09:09221 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49222 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
223 r"test_info_extractor\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41224 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
225 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
lukasza7947ccd2016-07-28 21:56:25226 r"^content[\\\/]test[\\\/]ppapi[\\\/]ppapi_test\.cc$",
miu8e0e80c2017-05-31 03:35:57227 r"^media[\\\/]cast[\\\/]test[\\\/]utility[\\\/]" +
228 r"standalone_cast_environment\.cc$",
jamesra03ae492014-10-03 04:26:48229 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
230 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01231 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
lukasza7947ccd2016-07-28 21:56:25232 r"^net[\\\/]cert[\\\/]test_root_certs\.cc$",
233 r"^net[\\\/]test[\\\/]embedded_test_server[\\\/]" +
234 r"embedded_test_server\.cc$",
235 r"^net[\\\/]test[\\\/]spawned_test_server[\\\/]local_test_server\.cc$",
236 r"^net[\\\/]test[\\\/]test_data_directory\.cc$",
[email protected]1f52a572014-05-12 23:21:54237 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
sergeyu2c41f9842016-12-10 01:45:16238 r"^remoting[\\\/]protocol[\\\/]webrtc_transport\.cc$",
lambroslambrouf6fb94ea2016-06-27 21:21:53239 r"^ui[\\\/]base[\\\/]material_design[\\\/]"
240 "material_design_controller\.cc$",
kylechar16666242016-07-04 20:54:45241 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_mac\.cc$",
242 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_win\.cc$",
243 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_x11\.cc$",
244 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
245 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49246 ),
[email protected]23e6cbc2012-06-16 18:51:20247 ),
[email protected]52657f62013-05-20 05:30:31248 (
tomhudsone2c14d552016-05-26 17:07:46249 'setMatrixClip',
250 (
251 'Overriding setMatrixClip() is prohibited; ',
252 'the base function is deprecated. ',
253 ),
254 True,
255 (),
256 ),
257 (
[email protected]52657f62013-05-20 05:30:31258 'SkRefPtr',
259 (
260 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22261 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31262 ),
263 True,
264 (),
265 ),
266 (
267 'SkAutoRef',
268 (
269 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22270 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31271 ),
272 True,
273 (),
274 ),
275 (
276 'SkAutoTUnref',
277 (
278 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22279 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31280 ),
281 True,
282 (),
283 ),
284 (
285 'SkAutoUnref',
286 (
287 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
288 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22289 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31290 ),
291 True,
292 (),
293 ),
[email protected]d89eec82013-12-03 14:10:59294 (
295 r'/HANDLE_EINTR\(.*close',
296 (
297 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
298 'descriptor will be closed, and it is incorrect to retry the close.',
299 'Either call close directly and ignore its return value, or wrap close',
300 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
301 ),
302 True,
303 (),
304 ),
305 (
306 r'/IGNORE_EINTR\((?!.*close)',
307 (
308 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
309 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
310 ),
311 True,
312 (
313 # Files that #define IGNORE_EINTR.
314 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
315 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
316 ),
317 ),
[email protected]ec5b3f02014-04-04 18:43:43318 (
319 r'/v8::Extension\(',
320 (
321 'Do not introduce new v8::Extensions into the code base, use',
322 'gin::Wrappable instead. See http://crbug.com/334679',
323 ),
324 True,
[email protected]f55c90ee62014-04-12 00:50:03325 (
joaodasilva718f87672014-08-30 09:25:49326 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03327 ),
[email protected]ec5b3f02014-04-04 18:43:43328 ),
skyostilf9469f72015-04-20 10:38:52329 (
jame2d1a952016-04-02 00:27:10330 '#pragma comment(lib,',
331 (
332 'Specify libraries to link with in build files and not in the source.',
333 ),
334 True,
335 (),
336 ),
fdorayc4ac18d2017-05-01 21:39:59337 (
338 'BrowserThread::GetBlockingPool',
339 (
340 'Use base/task_scheduler/post_task.h instead of the blocking pool. See',
341 'mapping between both APIs in content/public/browser/browser_thread.h.',
342 'For questions, contact base/task_scheduler/OWNERS.',
343 ),
344 True,
345 (),
346 ),
gabd52c912a2017-05-11 04:15:59347 (
Gabriel Charette664e4482017-06-13 19:55:29348 'BrowserThread::(FILE|FILE_USER_BLOCKING|DB|PROCESS_LAUNCHER|CACHE)',
349 (
350 'The non-UI/IO BrowserThreads are deprecated, please migrate this',
351 'code to TaskScheduler. See https://goo.gl/mDSxKl for details.',
352 'For questions, contact base/task_scheduler/OWNERS.',
353 ),
354 True,
355 (),
356 ),
357 (
gabd52c912a2017-05-11 04:15:59358 'base::SequenceChecker',
359 (
360 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
361 ),
362 False,
363 (),
364 ),
365 (
366 'base::ThreadChecker',
367 (
368 'Consider using THREAD_CHECKER macros instead of the class directly.',
369 ),
370 False,
371 (),
372 ),
dbeamb6f4fde2017-06-15 04:03:06373 (
374 'CallJavascriptFunctionUnsafe',
375 (
376 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
377 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
378 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
379 ),
380 False,
381 (
382 r'^content[\\\/]browser[\\\/]webui[\\\/]web_ui_impl\.(cc|h)$',
383 r'^content[\\\/]public[\\\/]browser[\\\/]web_ui\.h$',
384 r'^content[\\\/]public[\\\/]test[\\\/]test_web_ui\.(cc|h)$',
385 ),
386 ),
[email protected]127f18ec2012-06-16 05:05:59387)
388
wnwenbdc444e2016-05-25 13:44:15389
mlamouria82272622014-09-16 18:45:04390_IPC_ENUM_TRAITS_DEPRECATED = (
391 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
392 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
393
[email protected]127f18ec2012-06-16 05:05:59394
[email protected]b00342e7f2013-03-26 16:21:54395_VALID_OS_MACROS = (
396 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08397 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54398 'OS_ANDROID',
399 'OS_BSD',
400 'OS_CAT', # For testing.
401 'OS_CHROMEOS',
402 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37403 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54404 'OS_IOS',
405 'OS_LINUX',
406 'OS_MACOSX',
407 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21408 'OS_NACL_NONSFI',
409 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12410 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54411 'OS_OPENBSD',
412 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37413 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54414 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54415 'OS_WIN',
416)
417
418
agrievef32bcc72016-04-04 14:57:40419_ANDROID_SPECIFIC_PYDEPS_FILES = [
420 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04421 'build/android/test_wrapper/logdog_wrapper.pydeps',
jbudorick276cc562017-04-29 01:34:58422 'build/secondary/third_party/android_platform/'
423 'development/scripts/stack.pydeps',
agrieve732db3a2016-04-26 19:18:19424 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40425]
426
wnwenbdc444e2016-05-25 13:44:15427
agrievef32bcc72016-04-04 14:57:40428_GENERIC_PYDEPS_FILES = [
agrievef32bcc72016-04-04 14:57:40429]
430
wnwenbdc444e2016-05-25 13:44:15431
agrievef32bcc72016-04-04 14:57:40432_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
433
434
[email protected]55459852011-08-10 15:17:19435def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
436 """Attempts to prevent use of functions intended only for testing in
437 non-testing code. For now this is just a best-effort implementation
438 that ignores header files and may have some false positives. A
439 better implementation would probably need a proper C++ parser.
440 """
441 # We only scan .cc files and the like, as the declaration of
442 # for-testing functions in header files are hard to distinguish from
443 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44444 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19445
jochenc0d4808c2015-07-27 09:25:42446 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19447 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09448 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19449 exclusion_pattern = input_api.re.compile(
450 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
451 base_function_pattern, base_function_pattern))
452
453 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44454 black_list = (_EXCLUDED_PATHS +
455 _TEST_CODE_EXCLUDED_PATHS +
456 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19457 return input_api.FilterSourceFile(
458 affected_file,
459 white_list=(file_inclusion_pattern, ),
460 black_list=black_list)
461
462 problems = []
463 for f in input_api.AffectedSourceFiles(FilterFile):
464 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24465 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03466 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46467 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03468 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19469 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03470 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19471
472 if problems:
[email protected]f7051d52013-04-02 18:31:42473 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03474 else:
475 return []
[email protected]55459852011-08-10 15:17:19476
477
[email protected]10689ca2011-09-02 02:31:54478def _CheckNoIOStreamInHeaders(input_api, output_api):
479 """Checks to make sure no .h files include <iostream>."""
480 files = []
481 pattern = input_api.re.compile(r'^#include\s*<iostream>',
482 input_api.re.MULTILINE)
483 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
484 if not f.LocalPath().endswith('.h'):
485 continue
486 contents = input_api.ReadFile(f)
487 if pattern.search(contents):
488 files.append(f)
489
490 if len(files):
yolandyandaabc6d2016-04-18 18:29:39491 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06492 'Do not #include <iostream> in header files, since it inserts static '
493 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54494 '#include <ostream>. See http://crbug.com/94794',
495 files) ]
496 return []
497
498
[email protected]72df4e782012-06-21 16:28:18499def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52500 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18501 problems = []
502 for f in input_api.AffectedFiles():
503 if (not f.LocalPath().endswith(('.cc', '.mm'))):
504 continue
505
506 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04507 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18508 problems.append(' %s:%d' % (f.LocalPath(), line_num))
509
510 if not problems:
511 return []
512 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
513 '\n'.join(problems))]
514
515
danakj61c1aa22015-10-26 19:55:52516def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57517 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52518 errors = []
519 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
520 input_api.re.MULTILINE)
521 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
522 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
523 continue
524 for lnum, line in f.ChangedContents():
525 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17526 errors.append(output_api.PresubmitError(
527 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57528 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17529 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52530 return errors
531
532
mcasasb7440c282015-02-04 14:52:19533def _FindHistogramNameInLine(histogram_name, line):
534 """Tries to find a histogram name or prefix in a line."""
535 if not "affected-histogram" in line:
536 return histogram_name in line
537 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
538 # the histogram_name.
539 if not '"' in line:
540 return False
541 histogram_prefix = line.split('\"')[1]
542 return histogram_prefix in histogram_name
543
544
545def _CheckUmaHistogramChanges(input_api, output_api):
546 """Check that UMA histogram names in touched lines can still be found in other
547 lines of the patch or in histograms.xml. Note that this check would not catch
548 the reverse: changes in histograms.xml not matched in the code itself."""
549 touched_histograms = []
550 histograms_xml_modifications = []
551 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
552 for f in input_api.AffectedFiles():
553 # If histograms.xml itself is modified, keep the modified lines for later.
554 if f.LocalPath().endswith(('histograms.xml')):
555 histograms_xml_modifications = f.ChangedContents()
556 continue
557 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
558 continue
559 for line_num, line in f.ChangedContents():
560 found = pattern.search(line)
561 if found:
562 touched_histograms.append([found.group(1), f, line_num])
563
564 # Search for the touched histogram names in the local modifications to
565 # histograms.xml, and, if not found, on the base histograms.xml file.
566 unmatched_histograms = []
567 for histogram_info in touched_histograms:
568 histogram_name_found = False
569 for line_num, line in histograms_xml_modifications:
570 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
571 if histogram_name_found:
572 break
573 if not histogram_name_found:
574 unmatched_histograms.append(histogram_info)
575
eromanb90c82e7e32015-04-01 15:13:49576 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19577 problems = []
578 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49579 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19580 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45581 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19582 histogram_name_found = False
583 for line in histograms_xml:
584 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
585 if histogram_name_found:
586 break
587 if not histogram_name_found:
588 problems.append(' [%s:%d] %s' %
589 (f.LocalPath(), line_num, histogram_name))
590
591 if not problems:
592 return []
593 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
594 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49595 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19596
wnwenbdc444e2016-05-25 13:44:15597
yolandyandaabc6d2016-04-18 18:29:39598def _CheckFlakyTestUsage(input_api, output_api):
599 """Check that FlakyTest annotation is our own instead of the android one"""
600 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
601 files = []
602 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
603 if f.LocalPath().endswith('Test.java'):
604 if pattern.search(input_api.ReadFile(f)):
605 files.append(f)
606 if len(files):
607 return [output_api.PresubmitError(
608 'Use org.chromium.base.test.util.FlakyTest instead of '
609 'android.test.FlakyTest',
610 files)]
611 return []
mcasasb7440c282015-02-04 14:52:19612
wnwenbdc444e2016-05-25 13:44:15613
[email protected]8ea5d4b2011-09-13 21:49:22614def _CheckNoNewWStrings(input_api, output_api):
615 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27616 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22617 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20618 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57619 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34620 '/win/' in f.LocalPath() or
621 'chrome_elf' in f.LocalPath() or
622 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20623 continue
[email protected]8ea5d4b2011-09-13 21:49:22624
[email protected]a11dbe9b2012-08-07 01:32:58625 allowWString = False
[email protected]b5c24292011-11-28 14:38:20626 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58627 if 'presubmit: allow wstring' in line:
628 allowWString = True
629 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27630 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58631 allowWString = False
632 else:
633 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22634
[email protected]55463aa62011-10-12 00:48:27635 if not problems:
636 return []
637 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58638 ' If you are calling a cross-platform API that accepts a wstring, '
639 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27640 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22641
642
[email protected]2a8ac9c2011-10-19 17:20:44643def _CheckNoDEPSGIT(input_api, output_api):
644 """Make sure .DEPS.git is never modified manually."""
645 if any(f.LocalPath().endswith('.DEPS.git') for f in
646 input_api.AffectedFiles()):
647 return [output_api.PresubmitError(
648 'Never commit changes to .DEPS.git. This file is maintained by an\n'
649 'automated system based on what\'s in DEPS and your changes will be\n'
650 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34651 '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:44652 'for more information')]
653 return []
654
655
tandriief664692014-09-23 14:51:47656def _CheckValidHostsInDEPS(input_api, output_api):
657 """Checks that DEPS file deps are from allowed_hosts."""
658 # Run only if DEPS file has been modified to annoy fewer bystanders.
659 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
660 return []
661 # Outsource work to gclient verify
662 try:
663 input_api.subprocess.check_output(['gclient', 'verify'])
664 return []
665 except input_api.subprocess.CalledProcessError, error:
666 return [output_api.PresubmitError(
667 'DEPS file must have only git dependencies.',
668 long_text=error.output)]
669
670
[email protected]127f18ec2012-06-16 05:05:59671def _CheckNoBannedFunctions(input_api, output_api):
672 """Make sure that banned functions are not used."""
673 warnings = []
674 errors = []
675
wnwenbdc444e2016-05-25 13:44:15676 def IsBlacklisted(affected_file, blacklist):
677 local_path = affected_file.LocalPath()
678 for item in blacklist:
679 if input_api.re.match(item, local_path):
680 return True
681 return False
682
683 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
684 matched = False
685 if func_name[0:1] == '/':
686 regex = func_name[1:]
687 if input_api.re.search(regex, line):
688 matched = True
689 elif func_name in line:
dchenge07de812016-06-20 19:27:17690 matched = True
wnwenbdc444e2016-05-25 13:44:15691 if matched:
dchenge07de812016-06-20 19:27:17692 problems = warnings
wnwenbdc444e2016-05-25 13:44:15693 if error:
dchenge07de812016-06-20 19:27:17694 problems = errors
wnwenbdc444e2016-05-25 13:44:15695 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
696 for message_line in message:
697 problems.append(' %s' % message_line)
698
[email protected]127f18ec2012-06-16 05:05:59699 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
700 for f in input_api.AffectedFiles(file_filter=file_filter):
701 for line_num, line in f.ChangedContents():
702 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:15703 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59704
705 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
706 for f in input_api.AffectedFiles(file_filter=file_filter):
707 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49708 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:49709 if IsBlacklisted(f, excluded_paths):
710 continue
wnwenbdc444e2016-05-25 13:44:15711 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59712
713 result = []
714 if (warnings):
715 result.append(output_api.PresubmitPromptWarning(
716 'Banned functions were used.\n' + '\n'.join(warnings)))
717 if (errors):
718 result.append(output_api.PresubmitError(
719 'Banned functions were used.\n' + '\n'.join(errors)))
720 return result
721
722
[email protected]6c063c62012-07-11 19:11:06723def _CheckNoPragmaOnce(input_api, output_api):
724 """Make sure that banned functions are not used."""
725 files = []
726 pattern = input_api.re.compile(r'^#pragma\s+once',
727 input_api.re.MULTILINE)
728 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
729 if not f.LocalPath().endswith('.h'):
730 continue
731 contents = input_api.ReadFile(f)
732 if pattern.search(contents):
733 files.append(f)
734
735 if files:
736 return [output_api.PresubmitError(
737 'Do not use #pragma once in header files.\n'
738 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
739 files)]
740 return []
741
[email protected]127f18ec2012-06-16 05:05:59742
[email protected]e7479052012-09-19 00:26:12743def _CheckNoTrinaryTrueFalse(input_api, output_api):
744 """Checks to make sure we don't introduce use of foo ? true : false."""
745 problems = []
746 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
747 for f in input_api.AffectedFiles():
748 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
749 continue
750
751 for line_num, line in f.ChangedContents():
752 if pattern.match(line):
753 problems.append(' %s:%d' % (f.LocalPath(), line_num))
754
755 if not problems:
756 return []
757 return [output_api.PresubmitPromptWarning(
758 'Please consider avoiding the "? true : false" pattern if possible.\n' +
759 '\n'.join(problems))]
760
761
[email protected]55f9f382012-07-31 11:02:18762def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:28763 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:18764 change. Breaking - rules is an error, breaking ! rules is a
765 warning.
766 """
mohan.reddyf21db962014-10-16 12:26:47767 import sys
[email protected]55f9f382012-07-31 11:02:18768 # We need to wait until we have an input_api object and use this
769 # roundabout construct to import checkdeps because this file is
770 # eval-ed and thus doesn't have __file__.
771 original_sys_path = sys.path
772 try:
773 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47774 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18775 import checkdeps
776 from cpp_checker import CppChecker
rhalavati08acd232017-04-03 07:23:28777 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:18778 from rules import Rule
779 finally:
780 # Restore sys.path to what it was before.
781 sys.path = original_sys_path
782
783 added_includes = []
rhalavati08acd232017-04-03 07:23:28784 added_imports = []
[email protected]55f9f382012-07-31 11:02:18785 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:28786 if CppChecker.IsCppFile(f.LocalPath()):
787 changed_lines = [line for line_num, line in f.ChangedContents()]
788 added_includes.append([f.LocalPath(), changed_lines])
789 elif ProtoChecker.IsProtoFile(f.LocalPath()):
790 changed_lines = [line for line_num, line in f.ChangedContents()]
791 added_imports.append([f.LocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:18792
[email protected]26385172013-05-09 23:11:35793 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18794
795 error_descriptions = []
796 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:28797 error_subjects = set()
798 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:18799 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
800 added_includes):
801 description_with_path = '%s\n %s' % (path, rule_description)
802 if rule_type == Rule.DISALLOW:
803 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28804 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:18805 else:
806 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28807 warning_subjects.add("#includes")
808
809 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
810 added_imports):
811 description_with_path = '%s\n %s' % (path, rule_description)
812 if rule_type == Rule.DISALLOW:
813 error_descriptions.append(description_with_path)
814 error_subjects.add("imports")
815 else:
816 warning_descriptions.append(description_with_path)
817 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:18818
819 results = []
820 if error_descriptions:
821 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:28822 'You added one or more %s that violate checkdeps rules.'
823 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:18824 error_descriptions))
825 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42826 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:28827 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:18828 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:28829 '%s? See relevant DEPS file(s) for details and contacts.' %
830 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:18831 warning_descriptions))
832 return results
833
834
[email protected]fbcafe5a2012-08-08 15:31:22835def _CheckFilePermissions(input_api, output_api):
836 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15837 if input_api.platform == 'win32':
838 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29839 checkperms_tool = input_api.os_path.join(
840 input_api.PresubmitLocalPath(),
841 'tools', 'checkperms', 'checkperms.py')
842 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47843 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22844 for f in input_api.AffectedFiles():
845 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11846 try:
847 input_api.subprocess.check_output(args)
848 return []
849 except input_api.subprocess.CalledProcessError as error:
850 return [output_api.PresubmitError(
851 'checkperms.py failed:',
852 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22853
854
robertocn832f5992017-01-04 19:01:30855def _CheckTeamTags(input_api, output_api):
856 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
857 checkteamtags_tool = input_api.os_path.join(
858 input_api.PresubmitLocalPath(),
859 'tools', 'checkteamtags', 'checkteamtags.py')
860 args = [input_api.python_executable, checkteamtags_tool,
861 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:22862 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:30863 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
864 'OWNERS']
865 try:
866 if files:
867 input_api.subprocess.check_output(args + files)
868 return []
869 except input_api.subprocess.CalledProcessError as error:
870 return [output_api.PresubmitError(
871 'checkteamtags.py failed:',
872 long_text=error.output)]
873
874
[email protected]c8278b32012-10-30 20:35:49875def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
876 """Makes sure we don't include ui/aura/window_property.h
877 in header files.
878 """
879 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
880 errors = []
881 for f in input_api.AffectedFiles():
882 if not f.LocalPath().endswith('.h'):
883 continue
884 for line_num, line in f.ChangedContents():
885 if pattern.match(line):
886 errors.append(' %s:%d' % (f.LocalPath(), line_num))
887
888 results = []
889 if errors:
890 results.append(output_api.PresubmitError(
891 'Header files should not include ui/aura/window_property.h', errors))
892 return results
893
894
[email protected]70ca77752012-11-20 03:45:03895def _CheckForVersionControlConflictsInFile(input_api, f):
896 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
897 errors = []
898 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:23899 if f.LocalPath().endswith('.md'):
900 # First-level headers in markdown look a lot like version control
901 # conflict markers. http://daringfireball.net/projects/markdown/basics
902 continue
[email protected]70ca77752012-11-20 03:45:03903 if pattern.match(line):
904 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
905 return errors
906
907
908def _CheckForVersionControlConflicts(input_api, output_api):
909 """Usually this is not intentional and will cause a compile failure."""
910 errors = []
911 for f in input_api.AffectedFiles():
912 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
913
914 results = []
915 if errors:
916 results.append(output_api.PresubmitError(
917 'Version control conflict markers found, please resolve.', errors))
918 return results
919
estadee17314a02017-01-12 16:22:16920def _CheckGoogleSupportAnswerUrl(input_api, output_api):
921 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
922 errors = []
923 for f in input_api.AffectedFiles():
924 for line_num, line in f.ChangedContents():
925 if pattern.search(line):
926 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
927
928 results = []
929 if errors:
930 results.append(output_api.PresubmitPromptWarning(
931 'Found Google support URL addressed by answer number. Please replace with '
932 'a p= identifier instead. See crbug.com/679462\n', errors))
933 return results
934
[email protected]70ca77752012-11-20 03:45:03935
[email protected]06e6d0ff2012-12-11 01:36:44936def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
937 def FilterFile(affected_file):
938 """Filter function for use with input_api.AffectedSourceFiles,
939 below. This filters out everything except non-test files from
940 top-level directories that generally speaking should not hard-code
941 service URLs (e.g. src/android_webview/, src/content/ and others).
942 """
943 return input_api.FilterSourceFile(
944 affected_file,
[email protected]78bb39d62012-12-11 15:11:56945 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:44946 black_list=(_EXCLUDED_PATHS +
947 _TEST_CODE_EXCLUDED_PATHS +
948 input_api.DEFAULT_BLACK_LIST))
949
reillyi38965732015-11-16 18:27:33950 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
951 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:46952 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
953 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:44954 problems = [] # items are (filename, line_number, line)
955 for f in input_api.AffectedSourceFiles(FilterFile):
956 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:46957 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:44958 problems.append((f.LocalPath(), line_num, line))
959
960 if problems:
[email protected]f7051d52013-04-02 18:31:42961 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:44962 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:58963 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:44964 [' %s:%d: %s' % (
965 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:03966 else:
967 return []
[email protected]06e6d0ff2012-12-11 01:36:44968
969
[email protected]d2530012013-01-25 16:39:27970def _CheckNoAbbreviationInPngFileName(input_api, output_api):
971 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:31972 The native_client_sdk directory is excluded because it has auto-generated PNG
973 files for documentation.
[email protected]d2530012013-01-25 16:39:27974 """
[email protected]d2530012013-01-25 16:39:27975 errors = []
binji0dcdf342014-12-12 18:32:31976 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
977 black_list = (r'^native_client_sdk[\\\/]',)
978 file_filter = lambda f: input_api.FilterSourceFile(
979 f, white_list=white_list, black_list=black_list)
980 for f in input_api.AffectedFiles(include_deletes=False,
981 file_filter=file_filter):
982 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:27983
984 results = []
985 if errors:
986 results.append(output_api.PresubmitError(
987 'The name of PNG files should not have abbreviations. \n'
988 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
989 'Contact [email protected] if you have questions.', errors))
990 return results
991
992
Daniel Cheng4dcdb6b2017-04-13 08:30:17993def _ExtractAddRulesFromParsedDeps(parsed_deps):
994 """Extract the rules that add dependencies from a parsed DEPS file.
995
996 Args:
997 parsed_deps: the locals dictionary from evaluating the DEPS file."""
998 add_rules = set()
999 add_rules.update([
1000 rule[1:] for rule in parsed_deps.get('include_rules', [])
1001 if rule.startswith('+') or rule.startswith('!')
1002 ])
1003 for specific_file, rules in parsed_deps.get('specific_include_rules',
1004 {}).iteritems():
1005 add_rules.update([
1006 rule[1:] for rule in rules
1007 if rule.startswith('+') or rule.startswith('!')
1008 ])
1009 return add_rules
1010
1011
1012def _ParseDeps(contents):
1013 """Simple helper for parsing DEPS files."""
1014 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171015 class _VarImpl:
1016
1017 def __init__(self, local_scope):
1018 self._local_scope = local_scope
1019
1020 def Lookup(self, var_name):
1021 """Implements the Var syntax."""
1022 try:
1023 return self._local_scope['vars'][var_name]
1024 except KeyError:
1025 raise Exception('Var is not defined: %s' % var_name)
1026
1027 local_scope = {}
1028 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171029 'Var': _VarImpl(local_scope).Lookup,
1030 }
1031 exec contents in global_scope, local_scope
1032 return local_scope
1033
1034
1035def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081036 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411037 a set of DEPS entries that we should look up.
1038
1039 For a directory (rather than a specific filename) we fake a path to
1040 a specific filename by adding /DEPS. This is chosen as a file that
1041 will seldom or never be subject to per-file include_rules.
1042 """
[email protected]2b438d62013-11-14 17:54:141043 # We ignore deps entries on auto-generated directories.
1044 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081045
Daniel Cheng4dcdb6b2017-04-13 08:30:171046 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1047 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1048
1049 added_deps = new_deps.difference(old_deps)
1050
[email protected]2b438d62013-11-14 17:54:141051 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171052 for added_dep in added_deps:
1053 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1054 continue
1055 # Assume that a rule that ends in .h is a rule for a specific file.
1056 if added_dep.endswith('.h'):
1057 results.add(added_dep)
1058 else:
1059 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081060 return results
1061
1062
[email protected]e871964c2013-05-13 14:14:551063def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1064 """When a dependency prefixed with + is added to a DEPS file, we
1065 want to make sure that the change is reviewed by an OWNER of the
1066 target file or directory, to avoid layering violations from being
1067 introduced. This check verifies that this happens.
1068 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171069 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241070
1071 file_filter = lambda f: not input_api.re.match(
1072 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1073 for f in input_api.AffectedFiles(include_deletes=False,
1074 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551075 filename = input_api.os_path.basename(f.LocalPath())
1076 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171077 virtual_depended_on_files.update(_CalculateAddedDeps(
1078 input_api.os_path,
1079 '\n'.join(f.OldContents()),
1080 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551081
[email protected]e871964c2013-05-13 14:14:551082 if not virtual_depended_on_files:
1083 return []
1084
1085 if input_api.is_committing:
1086 if input_api.tbr:
1087 return [output_api.PresubmitNotifyResult(
1088 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271089 if input_api.dry_run:
1090 return [output_api.PresubmitNotifyResult(
1091 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551092 if not input_api.change.issue:
1093 return [output_api.PresubmitError(
1094 "DEPS approval by OWNERS check failed: this change has "
1095 "no Rietveld issue number, so we can't check it for approvals.")]
1096 output = output_api.PresubmitError
1097 else:
1098 output = output_api.PresubmitNotifyResult
1099
1100 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501101 owner_email, reviewers = (
1102 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1103 input_api,
1104 owners_db.email_regexp,
1105 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551106
1107 owner_email = owner_email or input_api.change.author_email
1108
[email protected]de4f7d22013-05-23 14:27:461109 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511110 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461111 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551112 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1113 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411114
1115 # We strip the /DEPS part that was added by
1116 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1117 # directory.
1118 def StripDeps(path):
1119 start_deps = path.rfind('/DEPS')
1120 if start_deps != -1:
1121 return path[:start_deps]
1122 else:
1123 return path
1124 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551125 for path in missing_files]
1126
1127 if unapproved_dependencies:
1128 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151129 output('You need LGTM from owners of depends-on paths in DEPS that were '
1130 'modified in this CL:\n %s' %
1131 '\n '.join(sorted(unapproved_dependencies)))]
1132 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1133 output_list.append(output(
1134 'Suggested missing target path OWNERS:\n %s' %
1135 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551136 return output_list
1137
1138 return []
1139
1140
[email protected]85218562013-11-22 07:41:401141def _CheckSpamLogging(input_api, output_api):
1142 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1143 black_list = (_EXCLUDED_PATHS +
1144 _TEST_CODE_EXCLUDED_PATHS +
1145 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501146 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191147 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481148 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461149 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121150 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1151 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581152 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161153 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031154 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151155 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1156 r"^chromecast[\\\/]",
1157 r"^cloud_print[\\\/]",
manzagop85e629e2017-05-09 22:11:481158 r"^components[\\\/]browser_watcher[\\\/]"
1159 r"dump_stability_report_main_win.cc$",
jochen34415e52015-07-10 08:34:311160 r"^components[\\\/]html_viewer[\\\/]"
1161 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461162 # TODO(peter): Remove this exception. https://crbug.com/534537
1163 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1164 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251165 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1166 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241167 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111168 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151169 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111170 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521171 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501172 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361173 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311174 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131175 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001176 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441177 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451178 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021179 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351180 r"dump_file_system.cc$",
1181 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401182 source_file_filter = lambda x: input_api.FilterSourceFile(
1183 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1184
thomasanderson625d3932017-03-29 07:16:581185 log_info = set([])
1186 printf = set([])
[email protected]85218562013-11-22 07:41:401187
1188 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581189 for _, line in f.ChangedContents():
1190 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1191 log_info.add(f.LocalPath())
1192 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1193 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371194
thomasanderson625d3932017-03-29 07:16:581195 if input_api.re.search(r"\bprintf\(", line):
1196 printf.add(f.LocalPath())
1197 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1198 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401199
1200 if log_info:
1201 return [output_api.PresubmitError(
1202 'These files spam the console log with LOG(INFO):',
1203 items=log_info)]
1204 if printf:
1205 return [output_api.PresubmitError(
1206 'These files spam the console log with printf/fprintf:',
1207 items=printf)]
1208 return []
1209
1210
[email protected]49aa76a2013-12-04 06:59:161211def _CheckForAnonymousVariables(input_api, output_api):
1212 """These types are all expected to hold locks while in scope and
1213 so should never be anonymous (which causes them to be immediately
1214 destroyed)."""
1215 they_who_must_be_named = [
1216 'base::AutoLock',
1217 'base::AutoReset',
1218 'base::AutoUnlock',
1219 'SkAutoAlphaRestore',
1220 'SkAutoBitmapShaderInstall',
1221 'SkAutoBlitterChoose',
1222 'SkAutoBounderCommit',
1223 'SkAutoCallProc',
1224 'SkAutoCanvasRestore',
1225 'SkAutoCommentBlock',
1226 'SkAutoDescriptor',
1227 'SkAutoDisableDirectionCheck',
1228 'SkAutoDisableOvalCheck',
1229 'SkAutoFree',
1230 'SkAutoGlyphCache',
1231 'SkAutoHDC',
1232 'SkAutoLockColors',
1233 'SkAutoLockPixels',
1234 'SkAutoMalloc',
1235 'SkAutoMaskFreeImage',
1236 'SkAutoMutexAcquire',
1237 'SkAutoPathBoundsUpdate',
1238 'SkAutoPDFRelease',
1239 'SkAutoRasterClipValidate',
1240 'SkAutoRef',
1241 'SkAutoTime',
1242 'SkAutoTrace',
1243 'SkAutoUnref',
1244 ]
1245 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1246 # bad: base::AutoLock(lock.get());
1247 # not bad: base::AutoLock lock(lock.get());
1248 bad_pattern = input_api.re.compile(anonymous)
1249 # good: new base::AutoLock(lock.get())
1250 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1251 errors = []
1252
1253 for f in input_api.AffectedFiles():
1254 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1255 continue
1256 for linenum, line in f.ChangedContents():
1257 if bad_pattern.search(line) and not good_pattern.search(line):
1258 errors.append('%s:%d' % (f.LocalPath(), linenum))
1259
1260 if errors:
1261 return [output_api.PresubmitError(
1262 'These lines create anonymous variables that need to be named:',
1263 items=errors)]
1264 return []
1265
1266
[email protected]999261d2014-03-03 20:08:081267def _CheckUserActionUpdate(input_api, output_api):
1268 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521269 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081270 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521271 # If actions.xml is already included in the changelist, the PRESUBMIT
1272 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081273 return []
1274
[email protected]999261d2014-03-03 20:08:081275 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1276 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521277 current_actions = None
[email protected]999261d2014-03-03 20:08:081278 for f in input_api.AffectedFiles(file_filter=file_filter):
1279 for line_num, line in f.ChangedContents():
1280 match = input_api.re.search(action_re, line)
1281 if match:
[email protected]2f92dec2014-03-07 19:21:521282 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1283 # loaded only once.
1284 if not current_actions:
1285 with open('tools/metrics/actions/actions.xml') as actions_f:
1286 current_actions = actions_f.read()
1287 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081288 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521289 action = 'name="{0}"'.format(action_name)
1290 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081291 return [output_api.PresubmitPromptWarning(
1292 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521293 'tools/metrics/actions/actions.xml. Please run '
1294 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081295 % (f.LocalPath(), line_num, action_name))]
1296 return []
1297
1298
[email protected]99171a92014-06-03 08:44:471299def _GetJSONParseError(input_api, filename, eat_comments=True):
1300 try:
1301 contents = input_api.ReadFile(filename)
1302 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131303 import sys
1304 original_sys_path = sys.path
1305 try:
1306 sys.path = sys.path + [input_api.os_path.join(
1307 input_api.PresubmitLocalPath(),
1308 'tools', 'json_comment_eater')]
1309 import json_comment_eater
1310 finally:
1311 sys.path = original_sys_path
1312 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471313
1314 input_api.json.loads(contents)
1315 except ValueError as e:
1316 return e
1317 return None
1318
1319
1320def _GetIDLParseError(input_api, filename):
1321 try:
1322 contents = input_api.ReadFile(filename)
1323 idl_schema = input_api.os_path.join(
1324 input_api.PresubmitLocalPath(),
1325 'tools', 'json_schema_compiler', 'idl_schema.py')
1326 process = input_api.subprocess.Popen(
1327 [input_api.python_executable, idl_schema],
1328 stdin=input_api.subprocess.PIPE,
1329 stdout=input_api.subprocess.PIPE,
1330 stderr=input_api.subprocess.PIPE,
1331 universal_newlines=True)
1332 (_, error) = process.communicate(input=contents)
1333 return error or None
1334 except ValueError as e:
1335 return e
1336
1337
1338def _CheckParseErrors(input_api, output_api):
1339 """Check that IDL and JSON files do not contain syntax errors."""
1340 actions = {
1341 '.idl': _GetIDLParseError,
1342 '.json': _GetJSONParseError,
1343 }
1344 # These paths contain test data and other known invalid JSON files.
1345 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491346 r'test[\\\/]data[\\\/]',
1347 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471348 ]
1349 # Most JSON files are preprocessed and support comments, but these do not.
1350 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491351 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471352 ]
1353 # Only run IDL checker on files in these directories.
1354 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491355 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1356 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471357 ]
1358
1359 def get_action(affected_file):
1360 filename = affected_file.LocalPath()
1361 return actions.get(input_api.os_path.splitext(filename)[1])
1362
1363 def MatchesFile(patterns, path):
1364 for pattern in patterns:
1365 if input_api.re.search(pattern, path):
1366 return True
1367 return False
1368
1369 def FilterFile(affected_file):
1370 action = get_action(affected_file)
1371 if not action:
1372 return False
1373 path = affected_file.LocalPath()
1374
1375 if MatchesFile(excluded_patterns, path):
1376 return False
1377
1378 if (action == _GetIDLParseError and
1379 not MatchesFile(idl_included_patterns, path)):
1380 return False
1381 return True
1382
1383 results = []
1384 for affected_file in input_api.AffectedFiles(
1385 file_filter=FilterFile, include_deletes=False):
1386 action = get_action(affected_file)
1387 kwargs = {}
1388 if (action == _GetJSONParseError and
1389 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1390 kwargs['eat_comments'] = False
1391 parse_error = action(input_api,
1392 affected_file.AbsoluteLocalPath(),
1393 **kwargs)
1394 if parse_error:
1395 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1396 (affected_file.LocalPath(), parse_error)))
1397 return results
1398
1399
[email protected]760deea2013-12-10 19:33:491400def _CheckJavaStyle(input_api, output_api):
1401 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471402 import sys
[email protected]760deea2013-12-10 19:33:491403 original_sys_path = sys.path
1404 try:
1405 sys.path = sys.path + [input_api.os_path.join(
1406 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1407 import checkstyle
1408 finally:
1409 # Restore sys.path to what it was before.
1410 sys.path = original_sys_path
1411
1412 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091413 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511414 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491415
1416
dchenge07de812016-06-20 19:27:171417def _CheckIpcOwners(input_api, output_api):
1418 """Checks that affected files involving IPC have an IPC OWNERS rule.
1419
1420 Whether or not a file affects IPC is determined by a simple whitelist of
1421 filename patterns."""
1422 file_patterns = [
palmerb19a0932017-01-24 04:00:311423 # Legacy IPC:
dchenge07de812016-06-20 19:27:171424 '*_messages.cc',
1425 '*_messages*.h',
1426 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311427 # Mojo IPC:
dchenge07de812016-06-20 19:27:171428 '*.mojom',
1429 '*_struct_traits*.*',
1430 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311431 '*.typemap',
1432 # Android native IPC:
1433 '*.aidl',
1434 # Blink uses a different file naming convention:
1435 '*EnumTraits*.*',
dchenge07de812016-06-20 19:27:171436 '*StructTraits*.*',
1437 '*TypeConverter*.*',
1438 ]
1439
scottmg7a6ed5ba2016-11-04 18:22:041440 # These third_party directories do not contain IPCs, but contain files
1441 # matching the above patterns, which trigger false positives.
1442 exclude_paths = [
1443 'third_party/crashpad/*',
1444 ]
1445
dchenge07de812016-06-20 19:27:171446 # Dictionary mapping an OWNERS file path to Patterns.
1447 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1448 # rules ) to a PatternEntry.
1449 # PatternEntry is a dictionary with two keys:
1450 # - 'files': the files that are matched by this pattern
1451 # - 'rules': the per-file rules needed for this pattern
1452 # For example, if we expect OWNERS file to contain rules for *.mojom and
1453 # *_struct_traits*.*, Patterns might look like this:
1454 # {
1455 # '*.mojom': {
1456 # 'files': ...,
1457 # 'rules': [
1458 # 'per-file *.mojom=set noparent',
1459 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1460 # ],
1461 # },
1462 # '*_struct_traits*.*': {
1463 # 'files': ...,
1464 # 'rules': [
1465 # 'per-file *_struct_traits*.*=set noparent',
1466 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1467 # ],
1468 # },
1469 # }
1470 to_check = {}
1471
1472 # Iterate through the affected files to see what we actually need to check
1473 # for. We should only nag patch authors about per-file rules if a file in that
1474 # directory would match that pattern. If a directory only contains *.mojom
1475 # files and no *_messages*.h files, we should only nag about rules for
1476 # *.mojom files.
rockot51249332016-06-23 16:32:251477 for f in input_api.change.AffectedFiles(include_deletes=False):
dchenge07de812016-06-20 19:27:171478 for pattern in file_patterns:
1479 if input_api.fnmatch.fnmatch(
1480 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041481 skip = False
1482 for exclude in exclude_paths:
1483 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1484 skip = True
1485 break
1486 if skip:
1487 continue
dchenge07de812016-06-20 19:27:171488 owners_file = input_api.os_path.join(
1489 input_api.os_path.dirname(f.LocalPath()), 'OWNERS')
1490 if owners_file not in to_check:
1491 to_check[owners_file] = {}
1492 if pattern not in to_check[owners_file]:
1493 to_check[owners_file][pattern] = {
1494 'files': [],
1495 'rules': [
1496 'per-file %s=set noparent' % pattern,
1497 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1498 ]
1499 }
1500 to_check[owners_file][pattern]['files'].append(f)
1501 break
1502
1503 # Now go through the OWNERS files we collected, filtering out rules that are
1504 # already present in that OWNERS file.
1505 for owners_file, patterns in to_check.iteritems():
1506 try:
1507 with file(owners_file) as f:
1508 lines = set(f.read().splitlines())
1509 for entry in patterns.itervalues():
1510 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1511 ]
1512 except IOError:
1513 # No OWNERS file, so all the rules are definitely missing.
1514 continue
1515
1516 # All the remaining lines weren't found in OWNERS files, so emit an error.
1517 errors = []
1518 for owners_file, patterns in to_check.iteritems():
1519 missing_lines = []
1520 files = []
1521 for pattern, entry in patterns.iteritems():
1522 missing_lines.extend(entry['rules'])
1523 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1524 if missing_lines:
1525 errors.append(
Daniel Cheng52111692017-06-14 08:00:591526 '%s needs the following lines added:\n\n%s\n\nfor files:\n%s' %
dchenge07de812016-06-20 19:27:171527 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1528
1529 results = []
1530 if errors:
vabrf5ce3bf92016-07-11 14:52:411531 if input_api.is_committing:
1532 output = output_api.PresubmitError
1533 else:
1534 output = output_api.PresubmitPromptWarning
1535 results.append(output(
Daniel Cheng52111692017-06-14 08:00:591536 'Found OWNERS files that need to be updated for IPC security ' +
1537 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:171538 long_text='\n\n'.join(errors)))
1539
1540 return results
1541
1542
jbriance9e12f162016-11-25 07:57:501543def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311544 """Checks that added or removed lines in non third party affected
1545 header files do not lead to new useless class or struct forward
1546 declaration.
jbriance9e12f162016-11-25 07:57:501547 """
1548 results = []
1549 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1550 input_api.re.MULTILINE)
1551 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1552 input_api.re.MULTILINE)
1553 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311554 if (f.LocalPath().startswith('third_party') and
1555 not f.LocalPath().startswith('third_party/WebKit') and
1556 not f.LocalPath().startswith('third_party\\WebKit')):
1557 continue
1558
jbriance9e12f162016-11-25 07:57:501559 if not f.LocalPath().endswith('.h'):
1560 continue
1561
1562 contents = input_api.ReadFile(f)
1563 fwd_decls = input_api.re.findall(class_pattern, contents)
1564 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1565
1566 useless_fwd_decls = []
1567 for decl in fwd_decls:
1568 count = sum(1 for _ in input_api.re.finditer(
1569 r'\b%s\b' % input_api.re.escape(decl), contents))
1570 if count == 1:
1571 useless_fwd_decls.append(decl)
1572
1573 if not useless_fwd_decls:
1574 continue
1575
1576 for line in f.GenerateScmDiff().splitlines():
1577 if (line.startswith('-') and not line.startswith('--') or
1578 line.startswith('+') and not line.startswith('++')):
1579 for decl in useless_fwd_decls:
1580 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1581 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:241582 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:501583 (f.LocalPath(), decl)))
1584 useless_fwd_decls.remove(decl)
1585
1586 return results
1587
1588
dskiba88634f4e2015-08-14 23:03:291589def _CheckAndroidToastUsage(input_api, output_api):
1590 """Checks that code uses org.chromium.ui.widget.Toast instead of
1591 android.widget.Toast (Chromium Toast doesn't force hardware
1592 acceleration on low-end devices, saving memory).
1593 """
1594 toast_import_pattern = input_api.re.compile(
1595 r'^import android\.widget\.Toast;$')
1596
1597 errors = []
1598
1599 sources = lambda affected_file: input_api.FilterSourceFile(
1600 affected_file,
1601 black_list=(_EXCLUDED_PATHS +
1602 _TEST_CODE_EXCLUDED_PATHS +
1603 input_api.DEFAULT_BLACK_LIST +
1604 (r'^chromecast[\\\/].*',
1605 r'^remoting[\\\/].*')),
1606 white_list=(r'.*\.java$',))
1607
1608 for f in input_api.AffectedSourceFiles(sources):
1609 for line_num, line in f.ChangedContents():
1610 if toast_import_pattern.search(line):
1611 errors.append("%s:%d" % (f.LocalPath(), line_num))
1612
1613 results = []
1614
1615 if errors:
1616 results.append(output_api.PresubmitError(
1617 'android.widget.Toast usage is detected. Android toasts use hardware'
1618 ' acceleration, and can be\ncostly on low-end devices. Please use'
1619 ' org.chromium.ui.widget.Toast instead.\n'
1620 'Contact [email protected] if you have any questions.',
1621 errors))
1622
1623 return results
1624
1625
dgnaa68d5e2015-06-10 10:08:221626def _CheckAndroidCrLogUsage(input_api, output_api):
1627 """Checks that new logs using org.chromium.base.Log:
1628 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511629 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221630 """
pkotwicza1dd0b002016-05-16 14:41:041631
torne89540622017-03-24 19:41:301632 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:041633 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:301634 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:041635 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:301636 # WebView license viewer code cannot depend on //base; used in stub APK.
1637 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
1638 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:041639 ]
1640
dgnaa68d5e2015-06-10 10:08:221641 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121642 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1643 class_in_base_pattern = input_api.re.compile(
1644 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1645 has_some_log_import_pattern = input_api.re.compile(
1646 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221647 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121648 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221649 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511650 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221651 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221652
Vincent Scheib16d7b272015-09-15 18:09:071653 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221654 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041655 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1656 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121657
dgnaa68d5e2015-06-10 10:08:221658 tag_decl_errors = []
1659 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121660 tag_errors = []
dgn38736db2015-09-18 19:20:511661 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121662 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221663
1664 for f in input_api.AffectedSourceFiles(sources):
1665 file_content = input_api.ReadFile(f)
1666 has_modified_logs = False
1667
1668 # Per line checks
dgn87d9fb62015-06-12 09:15:121669 if (cr_log_import_pattern.search(file_content) or
1670 (class_in_base_pattern.search(file_content) and
1671 not has_some_log_import_pattern.search(file_content))):
1672 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221673 for line_num, line in f.ChangedContents():
1674
1675 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121676 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221677 if match:
1678 has_modified_logs = True
1679
1680 # Make sure it uses "TAG"
1681 if not match.group('tag') == 'TAG':
1682 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121683 else:
1684 # Report non cr Log function calls in changed lines
1685 for line_num, line in f.ChangedContents():
1686 if log_call_pattern.search(line):
1687 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221688
1689 # Per file checks
1690 if has_modified_logs:
1691 # Make sure the tag is using the "cr" prefix and is not too long
1692 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511693 tag_name = match.group('name') if match else None
1694 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221695 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511696 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221697 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511698 elif '.' in tag_name:
1699 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221700
1701 results = []
1702 if tag_decl_errors:
1703 results.append(output_api.PresubmitPromptWarning(
1704 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511705 '"private static final String TAG = "<package tag>".\n'
1706 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221707 tag_decl_errors))
1708
1709 if tag_length_errors:
1710 results.append(output_api.PresubmitError(
1711 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511712 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221713 tag_length_errors))
1714
1715 if tag_errors:
1716 results.append(output_api.PresubmitPromptWarning(
1717 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1718 tag_errors))
1719
dgn87d9fb62015-06-12 09:15:121720 if util_log_errors:
dgn4401aa52015-04-29 16:26:171721 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121722 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1723 util_log_errors))
1724
dgn38736db2015-09-18 19:20:511725 if tag_with_dot_errors:
1726 results.append(output_api.PresubmitPromptWarning(
1727 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1728 tag_with_dot_errors))
1729
dgn4401aa52015-04-29 16:26:171730 return results
1731
1732
yolandyan45001472016-12-21 21:12:421733def _CheckAndroidTestAnnotationUsage(input_api, output_api):
1734 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
1735 deprecated_annotation_import_pattern = input_api.re.compile(
1736 r'^import android\.test\.suitebuilder\.annotation\..*;',
1737 input_api.re.MULTILINE)
1738 sources = lambda x: input_api.FilterSourceFile(
1739 x, white_list=(r'.*\.java$',), black_list=None)
1740 errors = []
1741 for f in input_api.AffectedFiles(sources):
1742 for line_num, line in f.ChangedContents():
1743 if deprecated_annotation_import_pattern.search(line):
1744 errors.append("%s:%d" % (f.LocalPath(), line_num))
1745
1746 results = []
1747 if errors:
1748 results.append(output_api.PresubmitError(
1749 'Annotations in android.test.suitebuilder.annotation have been'
1750 ' deprecated since API level 24. Please use android.support.test.filters'
1751 ' from //third_party/android_support_test_runner:runner_java instead.'
1752 ' Contact [email protected] if you have any questions.', errors))
1753 return results
1754
1755
agrieve7b6479d82015-10-07 14:24:221756def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1757 """Checks if MDPI assets are placed in a correct directory."""
1758 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1759 ('/res/drawable/' in f.LocalPath() or
1760 '/res/drawable-ldrtl/' in f.LocalPath()))
1761 errors = []
1762 for f in input_api.AffectedFiles(include_deletes=False,
1763 file_filter=file_filter):
1764 errors.append(' %s' % f.LocalPath())
1765
1766 results = []
1767 if errors:
1768 results.append(output_api.PresubmitError(
1769 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1770 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1771 '/res/drawable-ldrtl/.\n'
1772 'Contact [email protected] if you have questions.', errors))
1773 return results
1774
1775
agrievef32bcc72016-04-04 14:57:401776class PydepsChecker(object):
1777 def __init__(self, input_api, pydeps_files):
1778 self._file_cache = {}
1779 self._input_api = input_api
1780 self._pydeps_files = pydeps_files
1781
1782 def _LoadFile(self, path):
1783 """Returns the list of paths within a .pydeps file relative to //."""
1784 if path not in self._file_cache:
1785 with open(path) as f:
1786 self._file_cache[path] = f.read()
1787 return self._file_cache[path]
1788
1789 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1790 """Returns an interable of paths within the .pydep, relativized to //."""
1791 os_path = self._input_api.os_path
1792 pydeps_dir = os_path.dirname(pydeps_path)
1793 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1794 if not l.startswith('*'))
1795 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1796
1797 def _CreateFilesToPydepsMap(self):
1798 """Returns a map of local_path -> list_of_pydeps."""
1799 ret = {}
1800 for pydep_local_path in self._pydeps_files:
1801 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1802 ret.setdefault(path, []).append(pydep_local_path)
1803 return ret
1804
1805 def ComputeAffectedPydeps(self):
1806 """Returns an iterable of .pydeps files that might need regenerating."""
1807 affected_pydeps = set()
1808 file_to_pydeps_map = None
1809 for f in self._input_api.AffectedFiles(include_deletes=True):
1810 local_path = f.LocalPath()
1811 if local_path == 'DEPS':
1812 return self._pydeps_files
1813 elif local_path.endswith('.pydeps'):
1814 if local_path in self._pydeps_files:
1815 affected_pydeps.add(local_path)
1816 elif local_path.endswith('.py'):
1817 if file_to_pydeps_map is None:
1818 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1819 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1820 return affected_pydeps
1821
1822 def DetermineIfStale(self, pydeps_path):
1823 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:411824 import difflib
agrievef32bcc72016-04-04 14:57:401825 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
1826 cmd = old_pydeps_data[1][1:].strip()
1827 new_pydeps_data = self._input_api.subprocess.check_output(
1828 cmd + ' --output ""', shell=True)
phajdan.jr0d9878552016-11-04 10:49:411829 old_contents = old_pydeps_data[2:]
1830 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:401831 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:411832 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:401833
1834
1835def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
1836 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:001837 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:281838 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
1839 # Mac, so skip it on other platforms.
1840 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:001841 return []
agrievef32bcc72016-04-04 14:57:401842 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
1843 is_android = input_api.os_path.exists('third_party/android_tools')
1844 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
1845 results = []
1846 # First, check for new / deleted .pydeps.
1847 for f in input_api.AffectedFiles(include_deletes=True):
1848 if f.LocalPath().endswith('.pydeps'):
1849 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
1850 results.append(output_api.PresubmitError(
1851 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1852 'remove %s' % f.LocalPath()))
1853 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
1854 results.append(output_api.PresubmitError(
1855 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
1856 'include %s' % f.LocalPath()))
1857
1858 if results:
1859 return results
1860
1861 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
1862
1863 for pydep_path in checker.ComputeAffectedPydeps():
1864 try:
phajdan.jr0d9878552016-11-04 10:49:411865 result = checker.DetermineIfStale(pydep_path)
1866 if result:
1867 cmd, diff = result
agrievef32bcc72016-04-04 14:57:401868 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:411869 'File is stale: %s\nDiff (apply to fix):\n%s\n'
1870 'To regenerate, run:\n\n %s' %
1871 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:401872 except input_api.subprocess.CalledProcessError as error:
1873 return [output_api.PresubmitError('Error running: %s' % error.cmd,
1874 long_text=error.output)]
1875
1876 return results
1877
1878
glidere61efad2015-02-18 17:39:431879def _CheckSingletonInHeaders(input_api, output_api):
1880 """Checks to make sure no header files have |Singleton<|."""
1881 def FileFilter(affected_file):
1882 # It's ok for base/memory/singleton.h to have |Singleton<|.
1883 black_list = (_EXCLUDED_PATHS +
1884 input_api.DEFAULT_BLACK_LIST +
1885 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
1886 return input_api.FilterSourceFile(affected_file, black_list=black_list)
1887
sergeyu34d21222015-09-16 00:11:441888 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:431889 files = []
1890 for f in input_api.AffectedSourceFiles(FileFilter):
1891 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
1892 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
1893 contents = input_api.ReadFile(f)
1894 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:241895 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:431896 pattern.search(line)):
1897 files.append(f)
1898 break
1899
1900 if files:
yolandyandaabc6d2016-04-18 18:29:391901 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:441902 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:431903 'Please move them to an appropriate source file so that the ' +
1904 'template gets instantiated in a single compilation unit.',
1905 files) ]
1906 return []
1907
1908
[email protected]fd20b902014-05-09 02:14:531909_DEPRECATED_CSS = [
1910 # Values
1911 ( "-webkit-box", "flex" ),
1912 ( "-webkit-inline-box", "inline-flex" ),
1913 ( "-webkit-flex", "flex" ),
1914 ( "-webkit-inline-flex", "inline-flex" ),
1915 ( "-webkit-min-content", "min-content" ),
1916 ( "-webkit-max-content", "max-content" ),
1917
1918 # Properties
1919 ( "-webkit-background-clip", "background-clip" ),
1920 ( "-webkit-background-origin", "background-origin" ),
1921 ( "-webkit-background-size", "background-size" ),
1922 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:441923 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:531924
1925 # Functions
1926 ( "-webkit-gradient", "gradient" ),
1927 ( "-webkit-repeating-gradient", "repeating-gradient" ),
1928 ( "-webkit-linear-gradient", "linear-gradient" ),
1929 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
1930 ( "-webkit-radial-gradient", "radial-gradient" ),
1931 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
1932]
1933
dbeam1ec68ac2016-12-15 05:22:241934def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:531935 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:251936 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:341937 documentation and iOS CSS for dom distiller
1938 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:251939 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:531940 results = []
dbeam070cfe62014-10-22 06:44:021941 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:251942 black_list = (_EXCLUDED_PATHS +
1943 _TEST_CODE_EXCLUDED_PATHS +
1944 input_api.DEFAULT_BLACK_LIST +
1945 (r"^chrome/common/extensions/docs",
1946 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:341947 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:051948 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:441949 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:251950 r"^native_client_sdk"))
1951 file_filter = lambda f: input_api.FilterSourceFile(
1952 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:531953 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1954 for line_num, line in fpath.ChangedContents():
1955 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:021956 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:531957 results.append(output_api.PresubmitError(
1958 "%s:%d: Use of deprecated CSS %s, use %s instead" %
1959 (fpath.LocalPath(), line_num, deprecated_value, value)))
1960 return results
1961
mohan.reddyf21db962014-10-16 12:26:471962
dbeam070cfe62014-10-22 06:44:021963_DEPRECATED_JS = [
1964 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
1965 ( "__defineGetter__", "Object.defineProperty" ),
1966 ( "__defineSetter__", "Object.defineProperty" ),
1967]
1968
dbeam1ec68ac2016-12-15 05:22:241969def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:021970 """Make sure that we don't use deprecated JS in Chrome code."""
1971 results = []
1972 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
1973 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1974 input_api.DEFAULT_BLACK_LIST)
1975 file_filter = lambda f: input_api.FilterSourceFile(
1976 f, white_list=file_inclusion_pattern, black_list=black_list)
1977 for fpath in input_api.AffectedFiles(file_filter=file_filter):
1978 for lnum, line in fpath.ChangedContents():
1979 for (deprecated, replacement) in _DEPRECATED_JS:
1980 if deprecated in line:
1981 results.append(output_api.PresubmitError(
1982 "%s:%d: Use of deprecated JS %s, use %s instead" %
1983 (fpath.LocalPath(), lnum, deprecated, replacement)))
1984 return results
1985
1986
dbeam1ec68ac2016-12-15 05:22:241987def _CheckForRiskyJsFeatures(input_api, output_api):
1988 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
1989 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js)
1990
1991 arrow_lines = []
1992 for f in input_api.AffectedFiles(file_filter=file_filter):
1993 for lnum, line in f.ChangedContents():
1994 if ' => ' in line:
1995 arrow_lines.append((f.LocalPath(), lnum))
1996
1997 if not arrow_lines:
1998 return []
1999
2000 return [output_api.PresubmitPromptWarning("""
2001Use of => operator detected in:
2002%s
2003Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2004https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
2005""" % "\n".join(" %s:%d\n" % line for line in arrow_lines))]
2006
2007
rlanday6802cf632017-05-30 17:48:362008def _CheckForRelativeIncludes(input_api, output_api):
2009 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2010 import sys
2011 original_sys_path = sys.path
2012 try:
2013 sys.path = sys.path + [input_api.os_path.join(
2014 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2015 from cpp_checker import CppChecker
2016 finally:
2017 # Restore sys.path to what it was before.
2018 sys.path = original_sys_path
2019
2020 bad_files = {}
2021 for f in input_api.AffectedFiles(include_deletes=False):
2022 if (f.LocalPath().startswith('third_party') and
2023 not f.LocalPath().startswith('third_party/WebKit') and
2024 not f.LocalPath().startswith('third_party\\WebKit')):
2025 continue
2026
2027 if not CppChecker.IsCppFile(f.LocalPath()):
2028 continue
2029
2030 relative_includes = [line for line_num, line in f.ChangedContents()
2031 if "#include" in line and "../" in line]
2032 if not relative_includes:
2033 continue
2034 bad_files[f.LocalPath()] = relative_includes
2035
2036 if not bad_files:
2037 return []
2038
2039 error_descriptions = []
2040 for file_path, bad_lines in bad_files.iteritems():
2041 error_description = file_path
2042 for line in bad_lines:
2043 error_description += '\n ' + line
2044 error_descriptions.append(error_description)
2045
2046 results = []
2047 results.append(output_api.PresubmitError(
2048 'You added one or more relative #include paths (including "../").\n'
2049 'These shouldn\'t be used because they can be used to include headers\n'
2050 'from code that\'s not correctly specified as a dependency in the\n'
2051 'relevant BUILD.gn file(s).',
2052 error_descriptions))
2053
2054 return results
2055
dgnaa68d5e2015-06-10 10:08:222056def _AndroidSpecificOnUploadChecks(input_api, output_api):
2057 """Groups checks that target android code."""
2058 results = []
dgnaa68d5e2015-06-10 10:08:222059 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222060 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292061 results.extend(_CheckAndroidToastUsage(input_api, output_api))
yolandyan45001472016-12-21 21:12:422062 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222063 return results
2064
2065
[email protected]22c9bd72011-03-27 16:47:392066def _CommonChecks(input_api, output_api):
2067 """Checks common to both upload and commit."""
2068 results = []
2069 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382070 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542071 excluded_paths=_EXCLUDED_PATHS))
machenbachfbda9b72016-12-06 13:13:582072 results.extend(
2073 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:192074 results.extend(
[email protected]760deea2013-12-10 19:33:492075 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542076 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182077 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522078 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222079 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442080 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592081 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062082 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122083 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182084 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222085 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302086 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492087 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032088 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492089 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442090 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272091 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:072092 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542093 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442094 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392095 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552096 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042097 results.extend(
2098 input_api.canned_checks.CheckChangeHasNoTabs(
2099 input_api,
2100 output_api,
2101 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402102 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162103 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082104 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242105 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2106 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472107 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042108 results.extend(_CheckForIPCRules(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232109 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432110 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402111 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152112 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172113 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502114 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242115 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:362116 results.extend(_CheckForRelativeIncludes(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242117
2118 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
2119 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2120 input_api, output_api,
2121 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:382122 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392123 return results
[email protected]1f7b4172010-01-28 01:17:342124
[email protected]b337cb5b2011-01-23 21:24:052125
[email protected]b8079ae4a2012-12-05 19:56:492126def _CheckPatchFiles(input_api, output_api):
2127 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2128 if f.LocalPath().endswith(('.orig', '.rej'))]
2129 if problems:
2130 return [output_api.PresubmitError(
2131 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032132 else:
2133 return []
[email protected]b8079ae4a2012-12-05 19:56:492134
2135
Kent Tamura5a8755d2017-06-29 23:37:072136def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
2137 macro_re = input_api.re.compile(
2138 r'^\s*#(el)?if.*\bdefined\(((OS_|COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
2139 include_re = input_api.re.compile(
2140 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
2141 extension_re = input_api.re.compile(r'\.[a-z]+$')
2142 errors = []
2143 for f in input_api.AffectedFiles():
2144 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
2145 continue
2146 found_line_number = None
2147 found_macro = None
2148 for line_num, line in f.ChangedContents():
2149 match = macro_re.search(line)
2150 if match:
2151 found_line_number = line_num
2152 found_macro = match.group(2)
2153 break
2154 if not found_line_number:
2155 continue
2156
2157 found_include = False
2158 for line in f.NewContents():
2159 if include_re.search(line):
2160 found_include = True
2161 break
2162 if found_include:
2163 continue
2164
2165 if not f.LocalPath().endswith('.h'):
2166 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
2167 try:
2168 content = input_api.ReadFile(primary_header_path, 'r')
2169 if include_re.search(content):
2170 continue
2171 except IOError:
2172 pass
2173 errors.append('%s:%d %s macro is used without including build/'
2174 'build_config.h.'
2175 % (f.LocalPath(), found_line_number, found_macro))
2176 if errors:
2177 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
2178 return []
2179
2180
[email protected]b00342e7f2013-03-26 16:21:542181def _DidYouMeanOSMacro(bad_macro):
2182 try:
2183 return {'A': 'OS_ANDROID',
2184 'B': 'OS_BSD',
2185 'C': 'OS_CHROMEOS',
2186 'F': 'OS_FREEBSD',
2187 'L': 'OS_LINUX',
2188 'M': 'OS_MACOSX',
2189 'N': 'OS_NACL',
2190 'O': 'OS_OPENBSD',
2191 'P': 'OS_POSIX',
2192 'S': 'OS_SOLARIS',
2193 'W': 'OS_WIN'}[bad_macro[3].upper()]
2194 except KeyError:
2195 return ''
2196
2197
2198def _CheckForInvalidOSMacrosInFile(input_api, f):
2199 """Check for sensible looking, totally invalid OS macros."""
2200 preprocessor_statement = input_api.re.compile(r'^\s*#')
2201 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2202 results = []
2203 for lnum, line in f.ChangedContents():
2204 if preprocessor_statement.search(line):
2205 for match in os_macro.finditer(line):
2206 if not match.group(1) in _VALID_OS_MACROS:
2207 good = _DidYouMeanOSMacro(match.group(1))
2208 did_you_mean = ' (did you mean %s?)' % good if good else ''
2209 results.append(' %s:%d %s%s' % (f.LocalPath(),
2210 lnum,
2211 match.group(1),
2212 did_you_mean))
2213 return results
2214
2215
2216def _CheckForInvalidOSMacros(input_api, output_api):
2217 """Check all affected files for invalid OS macros."""
2218 bad_macros = []
2219 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472220 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542221 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2222
2223 if not bad_macros:
2224 return []
2225
2226 return [output_api.PresubmitError(
2227 'Possibly invalid OS macro[s] found. Please fix your code\n'
2228 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2229
lliabraa35bab3932014-10-01 12:16:442230
2231def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2232 """Check all affected files for invalid "if defined" macros."""
2233 ALWAYS_DEFINED_MACROS = (
2234 "TARGET_CPU_PPC",
2235 "TARGET_CPU_PPC64",
2236 "TARGET_CPU_68K",
2237 "TARGET_CPU_X86",
2238 "TARGET_CPU_ARM",
2239 "TARGET_CPU_MIPS",
2240 "TARGET_CPU_SPARC",
2241 "TARGET_CPU_ALPHA",
2242 "TARGET_IPHONE_SIMULATOR",
2243 "TARGET_OS_EMBEDDED",
2244 "TARGET_OS_IPHONE",
2245 "TARGET_OS_MAC",
2246 "TARGET_OS_UNIX",
2247 "TARGET_OS_WIN32",
2248 )
2249 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2250 results = []
2251 for lnum, line in f.ChangedContents():
2252 for match in ifdef_macro.finditer(line):
2253 if match.group(1) in ALWAYS_DEFINED_MACROS:
2254 always_defined = ' %s is always defined. ' % match.group(1)
2255 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2256 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2257 lnum,
2258 always_defined,
2259 did_you_mean))
2260 return results
2261
2262
2263def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2264 """Check all affected files for invalid "if defined" macros."""
2265 bad_macros = []
2266 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:212267 if f.LocalPath().startswith('third_party/sqlite/'):
2268 continue
lliabraa35bab3932014-10-01 12:16:442269 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2270 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2271
2272 if not bad_macros:
2273 return []
2274
2275 return [output_api.PresubmitError(
2276 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2277 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2278 bad_macros)]
2279
2280
mlamouria82272622014-09-16 18:45:042281def _CheckForIPCRules(input_api, output_api):
2282 """Check for same IPC rules described in
2283 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2284 """
2285 base_pattern = r'IPC_ENUM_TRAITS\('
2286 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2287 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2288
2289 problems = []
2290 for f in input_api.AffectedSourceFiles(None):
2291 local_path = f.LocalPath()
2292 if not local_path.endswith('.h'):
2293 continue
2294 for line_number, line in f.ChangedContents():
2295 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2296 problems.append(
2297 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2298
2299 if problems:
2300 return [output_api.PresubmitPromptWarning(
2301 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2302 else:
2303 return []
2304
[email protected]b00342e7f2013-03-26 16:21:542305
mostynbb639aca52015-01-07 20:31:232306def _CheckForWindowsLineEndings(input_api, output_api):
2307 """Check source code and known ascii text files for Windows style line
2308 endings.
2309 """
earthdok1b5e0ee2015-03-10 15:19:102310 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232311
2312 file_inclusion_pattern = (
2313 known_text_files,
2314 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2315 )
2316
2317 filter = lambda f: input_api.FilterSourceFile(
2318 f, white_list=file_inclusion_pattern, black_list=None)
2319 files = [f.LocalPath() for f in
2320 input_api.AffectedSourceFiles(filter)]
2321
2322 problems = []
2323
2324 for file in files:
2325 fp = open(file, 'r')
2326 for line in fp:
2327 if line.endswith('\r\n'):
2328 problems.append(file)
2329 break
2330 fp.close()
2331
2332 if problems:
2333 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2334 'these files to contain Windows style line endings?\n' +
2335 '\n'.join(problems))]
2336
2337 return []
2338
2339
pastarmovj89f7ee12016-09-20 14:58:132340def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None,
2341 lint_filters=None, verbose_level=None):
2342 """Checks that all source files use SYSLOG properly."""
2343 syslog_files = []
2344 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:562345 for line_number, line in f.ChangedContents():
2346 if 'SYSLOG' in line:
2347 syslog_files.append(f.LocalPath() + ':' + str(line_number))
2348
pastarmovj89f7ee12016-09-20 14:58:132349 if syslog_files:
2350 return [output_api.PresubmitPromptWarning(
2351 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
2352 ' calls.\nFiles to check:\n', items=syslog_files)]
2353 return []
2354
2355
[email protected]1f7b4172010-01-28 01:17:342356def CheckChangeOnUpload(input_api, output_api):
2357 results = []
2358 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472359 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282360 results.extend(
jam93a6ee792017-02-08 23:59:222361 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192362 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222363 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:132364 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:162365 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542366 return results
[email protected]ca8d19842009-02-19 16:33:122367
2368
[email protected]1bfb8322014-04-23 01:02:412369def GetTryServerMasterForBot(bot):
2370 """Returns the Try Server master for the given bot.
2371
[email protected]0bb112362014-07-26 04:38:322372 It tries to guess the master from the bot name, but may still fail
2373 and return None. There is no longer a default master.
2374 """
2375 # Potentially ambiguous bot names are listed explicitly.
2376 master_map = {
tandriie5587792016-07-14 00:34:502377 'chromium_presubmit': 'master.tryserver.chromium.linux',
2378 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412379 }
[email protected]0bb112362014-07-26 04:38:322380 master = master_map.get(bot)
2381 if not master:
wnwen4fbaab82016-05-25 12:54:362382 if 'android' in bot:
tandriie5587792016-07-14 00:34:502383 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:362384 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:502385 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:322386 elif 'win' in bot:
tandriie5587792016-07-14 00:34:502387 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:322388 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:502389 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:322390 return master
[email protected]1bfb8322014-04-23 01:02:412391
2392
Paweł Hajdan, Jr55083782014-12-19 20:32:562393def GetDefaultTryConfigs(bots):
2394 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012395 """
2396
Paweł Hajdan, Jr55083782014-12-19 20:32:562397 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412398
2399 # Build up the mapping from tryserver master to bot/test.
2400 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562401 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412402 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2403 return out
[email protected]38c6a512013-12-18 23:48:012404
2405
[email protected]ca8d19842009-02-19 16:33:122406def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542407 results = []
[email protected]1f7b4172010-01-28 01:17:342408 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542409 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272410 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342411 input_api,
2412 output_api,
[email protected]2fdd1f362013-01-16 03:56:032413 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272414
jam93a6ee792017-02-08 23:59:222415 results.extend(
2416 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:542417 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2418 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412419 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2420 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542421 return results