blob: 6d09321209f2452fdfd08bb2e8f9668f5834177d [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]3e4eb112011-01-18 03:29:5413 r"^breakpad[\\\/].*",
[email protected]40d1dbb2012-10-26 07:18:0014 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
15 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2816 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0817 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5418 r"^skia[\\\/].*",
primiano0166ccc82015-10-06 12:12:2819 r"^third_party[\\\/]WebKit[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
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]ca8d1982009-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]ca8d1982009-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$",
sky0e07a142016-03-25 21:27:31218 r"^chrome[\\\/]browser[\\\/]lifetime[\\\/]application_lifetime\.cc$",
philipj3f9d5bde2014-08-28 14:09:09219 r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
jochene9ba6dd2016-02-23 17:20:49220 r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
221 r"test_info_extractor\.cc$",
[email protected]de7d61ff2013-08-20 11:30:41222 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
223 r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
lukasza7947ccd2016-07-28 21:56:25224 r"^content[\\\/]test[\\\/]ppapi[\\\/]ppapi_test\.cc$",
miu8e0e80c2017-05-31 03:35:57225 r"^media[\\\/]cast[\\\/]test[\\\/]utility[\\\/]" +
226 r"standalone_cast_environment\.cc$",
jamesra03ae492014-10-03 04:26:48227 r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
228 r"simple_platform_shared_buffer_posix\.cc$",
[email protected]398ad132013-04-02 15:11:01229 r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
lukasza7947ccd2016-07-28 21:56:25230 r"^net[\\\/]cert[\\\/]test_root_certs\.cc$",
231 r"^net[\\\/]test[\\\/]embedded_test_server[\\\/]" +
232 r"embedded_test_server\.cc$",
233 r"^net[\\\/]test[\\\/]spawned_test_server[\\\/]local_test_server\.cc$",
234 r"^net[\\\/]test[\\\/]test_data_directory\.cc$",
[email protected]1f52a572014-05-12 23:21:54235 r"^net[\\\/]url_request[\\\/]test_url_fetcher_factory\.cc$",
sergeyu2c41f9842016-12-10 01:45:16236 r"^remoting[\\\/]protocol[\\\/]webrtc_transport\.cc$",
lambroslambrouf6fb94ea2016-06-27 21:21:53237 r"^ui[\\\/]base[\\\/]material_design[\\\/]"
238 "material_design_controller\.cc$",
kylechar16666242016-07-04 20:54:45239 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_mac\.cc$",
240 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_win\.cc$",
241 r"^ui[\\\/]gl[\\\/]init[\\\/]gl_initializer_x11\.cc$",
242 r"^ui[\\\/]ozone[\\\/]platform[\\\/]drm[\\\/]host[\\\/]"
243 "drm_display_host_manager\.cc$",
[email protected]7345da02012-11-27 14:31:49244 ),
[email protected]23e6cbc2012-06-16 18:51:20245 ),
[email protected]52657f62013-05-20 05:30:31246 (
tomhudsone2c14d552016-05-26 17:07:46247 'setMatrixClip',
248 (
249 'Overriding setMatrixClip() is prohibited; ',
250 'the base function is deprecated. ',
251 ),
252 True,
253 (),
254 ),
255 (
[email protected]52657f62013-05-20 05:30:31256 'SkRefPtr',
257 (
258 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22259 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31260 ),
261 True,
262 (),
263 ),
264 (
265 'SkAutoRef',
266 (
267 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22268 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31269 ),
270 True,
271 (),
272 ),
273 (
274 'SkAutoTUnref',
275 (
276 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22277 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31278 ),
279 True,
280 (),
281 ),
282 (
283 'SkAutoUnref',
284 (
285 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
286 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22287 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31288 ),
289 True,
290 (),
291 ),
[email protected]d89eec82013-12-03 14:10:59292 (
293 r'/HANDLE_EINTR\(.*close',
294 (
295 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
296 'descriptor will be closed, and it is incorrect to retry the close.',
297 'Either call close directly and ignore its return value, or wrap close',
298 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
299 ),
300 True,
301 (),
302 ),
303 (
304 r'/IGNORE_EINTR\((?!.*close)',
305 (
306 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
307 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
308 ),
309 True,
310 (
311 # Files that #define IGNORE_EINTR.
312 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
313 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
314 ),
315 ),
[email protected]ec5b3f02014-04-04 18:43:43316 (
317 r'/v8::Extension\(',
318 (
319 'Do not introduce new v8::Extensions into the code base, use',
320 'gin::Wrappable instead. See http://crbug.com/334679',
321 ),
322 True,
[email protected]f55c90ee62014-04-12 00:50:03323 (
joaodasilva718f87672014-08-30 09:25:49324 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03325 ),
[email protected]ec5b3f02014-04-04 18:43:43326 ),
skyostilf9469f72015-04-20 10:38:52327 (
jame2d1a952016-04-02 00:27:10328 '#pragma comment(lib,',
329 (
330 'Specify libraries to link with in build files and not in the source.',
331 ),
332 True,
333 (),
334 ),
fdorayc4ac18d2017-05-01 21:39:59335 (
336 'BrowserThread::GetBlockingPool',
337 (
338 'Use base/task_scheduler/post_task.h instead of the blocking pool. See',
339 'mapping between both APIs in content/public/browser/browser_thread.h.',
340 'For questions, contact base/task_scheduler/OWNERS.',
341 ),
342 True,
343 (),
344 ),
gabd52c912a2017-05-11 04:15:59345 (
Gabriel Charette664e4482017-06-13 19:55:29346 'BrowserThread::(FILE|FILE_USER_BLOCKING|DB|PROCESS_LAUNCHER|CACHE)',
347 (
348 'The non-UI/IO BrowserThreads are deprecated, please migrate this',
349 'code to TaskScheduler. See https://goo.gl/mDSxKl for details.',
350 'For questions, contact base/task_scheduler/OWNERS.',
351 ),
352 True,
353 (),
354 ),
355 (
gabd52c912a2017-05-11 04:15:59356 'base::SequenceChecker',
357 (
358 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
359 ),
360 False,
361 (),
362 ),
363 (
364 'base::ThreadChecker',
365 (
366 'Consider using THREAD_CHECKER macros instead of the class directly.',
367 ),
368 False,
369 (),
370 ),
dbeamb6f4fde2017-06-15 04:03:06371 (
372 'CallJavascriptFunctionUnsafe',
373 (
374 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
375 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
376 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
377 ),
378 False,
379 (
380 r'^content[\\\/]browser[\\\/]webui[\\\/]web_ui_impl\.(cc|h)$',
381 r'^content[\\\/]public[\\\/]browser[\\\/]web_ui\.h$',
382 r'^content[\\\/]public[\\\/]test[\\\/]test_web_ui\.(cc|h)$',
383 ),
384 ),
[email protected]127f18ec2012-06-16 05:05:59385)
386
wnwenbdc444e2016-05-25 13:44:15387
mlamouria82272622014-09-16 18:45:04388_IPC_ENUM_TRAITS_DEPRECATED = (
389 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
390 'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
391
[email protected]127f18ec2012-06-16 05:05:59392
[email protected]b00342e7f2013-03-26 16:21:54393_VALID_OS_MACROS = (
394 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08395 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54396 'OS_ANDROID',
397 'OS_BSD',
398 'OS_CAT', # For testing.
399 'OS_CHROMEOS',
400 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37401 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54402 'OS_IOS',
403 'OS_LINUX',
404 'OS_MACOSX',
405 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21406 'OS_NACL_NONSFI',
407 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12408 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54409 'OS_OPENBSD',
410 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37411 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54412 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54413 'OS_WIN',
414)
415
416
agrievef32bcc72016-04-04 14:57:40417_ANDROID_SPECIFIC_PYDEPS_FILES = [
418 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04419 'build/android/test_wrapper/logdog_wrapper.pydeps',
jbudorick276cc562017-04-29 01:34:58420 'build/secondary/third_party/android_platform/'
421 'development/scripts/stack.pydeps',
agrieve732db3a2016-04-26 19:18:19422 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40423]
424
wnwenbdc444e2016-05-25 13:44:15425
agrievef32bcc72016-04-04 14:57:40426_GENERIC_PYDEPS_FILES = [
agrievef32bcc72016-04-04 14:57:40427]
428
wnwenbdc444e2016-05-25 13:44:15429
agrievef32bcc72016-04-04 14:57:40430_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
431
432
[email protected]55459852011-08-10 15:17:19433def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
434 """Attempts to prevent use of functions intended only for testing in
435 non-testing code. For now this is just a best-effort implementation
436 that ignores header files and may have some false positives. A
437 better implementation would probably need a proper C++ parser.
438 """
439 # We only scan .cc files and the like, as the declaration of
440 # for-testing functions in header files are hard to distinguish from
441 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44442 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19443
jochenc0d4808c2015-07-27 09:25:42444 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19445 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09446 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19447 exclusion_pattern = input_api.re.compile(
448 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
449 base_function_pattern, base_function_pattern))
450
451 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44452 black_list = (_EXCLUDED_PATHS +
453 _TEST_CODE_EXCLUDED_PATHS +
454 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19455 return input_api.FilterSourceFile(
456 affected_file,
457 white_list=(file_inclusion_pattern, ),
458 black_list=black_list)
459
460 problems = []
461 for f in input_api.AffectedSourceFiles(FilterFile):
462 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24463 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03464 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46465 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03466 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19467 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03468 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19469
470 if problems:
[email protected]f7051d52013-04-02 18:31:42471 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03472 else:
473 return []
[email protected]55459852011-08-10 15:17:19474
475
[email protected]10689ca2011-09-02 02:31:54476def _CheckNoIOStreamInHeaders(input_api, output_api):
477 """Checks to make sure no .h files include <iostream>."""
478 files = []
479 pattern = input_api.re.compile(r'^#include\s*<iostream>',
480 input_api.re.MULTILINE)
481 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
482 if not f.LocalPath().endswith('.h'):
483 continue
484 contents = input_api.ReadFile(f)
485 if pattern.search(contents):
486 files.append(f)
487
488 if len(files):
yolandyandaabc6d2016-04-18 18:29:39489 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06490 'Do not #include <iostream> in header files, since it inserts static '
491 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54492 '#include <ostream>. See http://crbug.com/94794',
493 files) ]
494 return []
495
496
[email protected]72df4e782012-06-21 16:28:18497def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52498 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18499 problems = []
500 for f in input_api.AffectedFiles():
501 if (not f.LocalPath().endswith(('.cc', '.mm'))):
502 continue
503
504 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04505 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18506 problems.append(' %s:%d' % (f.LocalPath(), line_num))
507
508 if not problems:
509 return []
510 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
511 '\n'.join(problems))]
512
513
danakj61c1aa22015-10-26 19:55:52514def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57515 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52516 errors = []
517 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
518 input_api.re.MULTILINE)
519 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
520 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
521 continue
522 for lnum, line in f.ChangedContents():
523 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17524 errors.append(output_api.PresubmitError(
525 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57526 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17527 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52528 return errors
529
530
mcasasb7440c282015-02-04 14:52:19531def _FindHistogramNameInLine(histogram_name, line):
532 """Tries to find a histogram name or prefix in a line."""
533 if not "affected-histogram" in line:
534 return histogram_name in line
535 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
536 # the histogram_name.
537 if not '"' in line:
538 return False
539 histogram_prefix = line.split('\"')[1]
540 return histogram_prefix in histogram_name
541
542
543def _CheckUmaHistogramChanges(input_api, output_api):
544 """Check that UMA histogram names in touched lines can still be found in other
545 lines of the patch or in histograms.xml. Note that this check would not catch
546 the reverse: changes in histograms.xml not matched in the code itself."""
547 touched_histograms = []
548 histograms_xml_modifications = []
549 pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
550 for f in input_api.AffectedFiles():
551 # If histograms.xml itself is modified, keep the modified lines for later.
552 if f.LocalPath().endswith(('histograms.xml')):
553 histograms_xml_modifications = f.ChangedContents()
554 continue
555 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
556 continue
557 for line_num, line in f.ChangedContents():
558 found = pattern.search(line)
559 if found:
560 touched_histograms.append([found.group(1), f, line_num])
561
562 # Search for the touched histogram names in the local modifications to
563 # histograms.xml, and, if not found, on the base histograms.xml file.
564 unmatched_histograms = []
565 for histogram_info in touched_histograms:
566 histogram_name_found = False
567 for line_num, line in histograms_xml_modifications:
568 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
569 if histogram_name_found:
570 break
571 if not histogram_name_found:
572 unmatched_histograms.append(histogram_info)
573
eromanb90c82e7e32015-04-01 15:13:49574 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19575 problems = []
576 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49577 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19578 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45579 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19580 histogram_name_found = False
581 for line in histograms_xml:
582 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
583 if histogram_name_found:
584 break
585 if not histogram_name_found:
586 problems.append(' [%s:%d] %s' %
587 (f.LocalPath(), line_num, histogram_name))
588
589 if not problems:
590 return []
591 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
592 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49593 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19594
wnwenbdc444e2016-05-25 13:44:15595
yolandyandaabc6d2016-04-18 18:29:39596def _CheckFlakyTestUsage(input_api, output_api):
597 """Check that FlakyTest annotation is our own instead of the android one"""
598 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
599 files = []
600 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
601 if f.LocalPath().endswith('Test.java'):
602 if pattern.search(input_api.ReadFile(f)):
603 files.append(f)
604 if len(files):
605 return [output_api.PresubmitError(
606 'Use org.chromium.base.test.util.FlakyTest instead of '
607 'android.test.FlakyTest',
608 files)]
609 return []
mcasasb7440c282015-02-04 14:52:19610
wnwenbdc444e2016-05-25 13:44:15611
[email protected]8ea5d4b2011-09-13 21:49:22612def _CheckNoNewWStrings(input_api, output_api):
613 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27614 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22615 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20616 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57617 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34618 '/win/' in f.LocalPath() or
619 'chrome_elf' in f.LocalPath() or
620 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20621 continue
[email protected]8ea5d4b2011-09-13 21:49:22622
[email protected]a11dbe9b2012-08-07 01:32:58623 allowWString = False
[email protected]b5c24292011-11-28 14:38:20624 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58625 if 'presubmit: allow wstring' in line:
626 allowWString = True
627 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27628 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58629 allowWString = False
630 else:
631 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22632
[email protected]55463aa62011-10-12 00:48:27633 if not problems:
634 return []
635 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58636 ' If you are calling a cross-platform API that accepts a wstring, '
637 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27638 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22639
640
[email protected]2a8ac9c2011-10-19 17:20:44641def _CheckNoDEPSGIT(input_api, output_api):
642 """Make sure .DEPS.git is never modified manually."""
643 if any(f.LocalPath().endswith('.DEPS.git') for f in
644 input_api.AffectedFiles()):
645 return [output_api.PresubmitError(
646 'Never commit changes to .DEPS.git. This file is maintained by an\n'
647 'automated system based on what\'s in DEPS and your changes will be\n'
648 'overwritten.\n'
[email protected]cb706912014-06-28 20:46:34649 '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:44650 'for more information')]
651 return []
652
653
tandriief664692014-09-23 14:51:47654def _CheckValidHostsInDEPS(input_api, output_api):
655 """Checks that DEPS file deps are from allowed_hosts."""
656 # Run only if DEPS file has been modified to annoy fewer bystanders.
657 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
658 return []
659 # Outsource work to gclient verify
660 try:
661 input_api.subprocess.check_output(['gclient', 'verify'])
662 return []
663 except input_api.subprocess.CalledProcessError, error:
664 return [output_api.PresubmitError(
665 'DEPS file must have only git dependencies.',
666 long_text=error.output)]
667
668
[email protected]127f18ec2012-06-16 05:05:59669def _CheckNoBannedFunctions(input_api, output_api):
670 """Make sure that banned functions are not used."""
671 warnings = []
672 errors = []
673
wnwenbdc444e2016-05-25 13:44:15674 def IsBlacklisted(affected_file, blacklist):
675 local_path = affected_file.LocalPath()
676 for item in blacklist:
677 if input_api.re.match(item, local_path):
678 return True
679 return False
680
681 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
682 matched = False
683 if func_name[0:1] == '/':
684 regex = func_name[1:]
685 if input_api.re.search(regex, line):
686 matched = True
687 elif func_name in line:
dchenge07de812016-06-20 19:27:17688 matched = True
wnwenbdc444e2016-05-25 13:44:15689 if matched:
dchenge07de812016-06-20 19:27:17690 problems = warnings
wnwenbdc444e2016-05-25 13:44:15691 if error:
dchenge07de812016-06-20 19:27:17692 problems = errors
wnwenbdc444e2016-05-25 13:44:15693 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
694 for message_line in message:
695 problems.append(' %s' % message_line)
696
[email protected]127f18ec2012-06-16 05:05:59697 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
698 for f in input_api.AffectedFiles(file_filter=file_filter):
699 for line_num, line in f.ChangedContents():
700 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:15701 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59702
703 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
704 for f in input_api.AffectedFiles(file_filter=file_filter):
705 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49706 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:49707 if IsBlacklisted(f, excluded_paths):
708 continue
wnwenbdc444e2016-05-25 13:44:15709 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59710
711 result = []
712 if (warnings):
713 result.append(output_api.PresubmitPromptWarning(
714 'Banned functions were used.\n' + '\n'.join(warnings)))
715 if (errors):
716 result.append(output_api.PresubmitError(
717 'Banned functions were used.\n' + '\n'.join(errors)))
718 return result
719
720
[email protected]6c063c62012-07-11 19:11:06721def _CheckNoPragmaOnce(input_api, output_api):
722 """Make sure that banned functions are not used."""
723 files = []
724 pattern = input_api.re.compile(r'^#pragma\s+once',
725 input_api.re.MULTILINE)
726 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
727 if not f.LocalPath().endswith('.h'):
728 continue
729 contents = input_api.ReadFile(f)
730 if pattern.search(contents):
731 files.append(f)
732
733 if files:
734 return [output_api.PresubmitError(
735 'Do not use #pragma once in header files.\n'
736 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
737 files)]
738 return []
739
[email protected]127f18ec2012-06-16 05:05:59740
[email protected]e7479052012-09-19 00:26:12741def _CheckNoTrinaryTrueFalse(input_api, output_api):
742 """Checks to make sure we don't introduce use of foo ? true : false."""
743 problems = []
744 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
745 for f in input_api.AffectedFiles():
746 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
747 continue
748
749 for line_num, line in f.ChangedContents():
750 if pattern.match(line):
751 problems.append(' %s:%d' % (f.LocalPath(), line_num))
752
753 if not problems:
754 return []
755 return [output_api.PresubmitPromptWarning(
756 'Please consider avoiding the "? true : false" pattern if possible.\n' +
757 '\n'.join(problems))]
758
759
[email protected]55f9f382012-07-31 11:02:18760def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:28761 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:18762 change. Breaking - rules is an error, breaking ! rules is a
763 warning.
764 """
mohan.reddyf21db962014-10-16 12:26:47765 import sys
[email protected]55f9f382012-07-31 11:02:18766 # We need to wait until we have an input_api object and use this
767 # roundabout construct to import checkdeps because this file is
768 # eval-ed and thus doesn't have __file__.
769 original_sys_path = sys.path
770 try:
771 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47772 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18773 import checkdeps
774 from cpp_checker import CppChecker
rhalavati08acd232017-04-03 07:23:28775 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:18776 from rules import Rule
777 finally:
778 # Restore sys.path to what it was before.
779 sys.path = original_sys_path
780
781 added_includes = []
rhalavati08acd232017-04-03 07:23:28782 added_imports = []
[email protected]55f9f382012-07-31 11:02:18783 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:28784 if CppChecker.IsCppFile(f.LocalPath()):
785 changed_lines = [line for line_num, line in f.ChangedContents()]
786 added_includes.append([f.LocalPath(), changed_lines])
787 elif ProtoChecker.IsProtoFile(f.LocalPath()):
788 changed_lines = [line for line_num, line in f.ChangedContents()]
789 added_imports.append([f.LocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:18790
[email protected]26385172013-05-09 23:11:35791 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:18792
793 error_descriptions = []
794 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:28795 error_subjects = set()
796 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:18797 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
798 added_includes):
799 description_with_path = '%s\n %s' % (path, rule_description)
800 if rule_type == Rule.DISALLOW:
801 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28802 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:18803 else:
804 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:28805 warning_subjects.add("#includes")
806
807 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
808 added_imports):
809 description_with_path = '%s\n %s' % (path, rule_description)
810 if rule_type == Rule.DISALLOW:
811 error_descriptions.append(description_with_path)
812 error_subjects.add("imports")
813 else:
814 warning_descriptions.append(description_with_path)
815 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:18816
817 results = []
818 if error_descriptions:
819 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:28820 'You added one or more %s that violate checkdeps rules.'
821 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:18822 error_descriptions))
823 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:42824 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:28825 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:18826 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:28827 '%s? See relevant DEPS file(s) for details and contacts.' %
828 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:18829 warning_descriptions))
830 return results
831
832
[email protected]fbcafe5a2012-08-08 15:31:22833def _CheckFilePermissions(input_api, output_api):
834 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:15835 if input_api.platform == 'win32':
836 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:29837 checkperms_tool = input_api.os_path.join(
838 input_api.PresubmitLocalPath(),
839 'tools', 'checkperms', 'checkperms.py')
840 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:47841 '--root', input_api.change.RepositoryRoot()]
[email protected]fbcafe5a2012-08-08 15:31:22842 for f in input_api.AffectedFiles():
843 args += ['--file', f.LocalPath()]
phajdan.jr5ea54792015-10-14 10:51:11844 try:
845 input_api.subprocess.check_output(args)
846 return []
847 except input_api.subprocess.CalledProcessError as error:
848 return [output_api.PresubmitError(
849 'checkperms.py failed:',
850 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:22851
852
robertocn832f5992017-01-04 19:01:30853def _CheckTeamTags(input_api, output_api):
854 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
855 checkteamtags_tool = input_api.os_path.join(
856 input_api.PresubmitLocalPath(),
857 'tools', 'checkteamtags', 'checkteamtags.py')
858 args = [input_api.python_executable, checkteamtags_tool,
859 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:22860 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:30861 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
862 'OWNERS']
863 try:
864 if files:
865 input_api.subprocess.check_output(args + files)
866 return []
867 except input_api.subprocess.CalledProcessError as error:
868 return [output_api.PresubmitError(
869 'checkteamtags.py failed:',
870 long_text=error.output)]
871
872
[email protected]c8278b32012-10-30 20:35:49873def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
874 """Makes sure we don't include ui/aura/window_property.h
875 in header files.
876 """
877 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
878 errors = []
879 for f in input_api.AffectedFiles():
880 if not f.LocalPath().endswith('.h'):
881 continue
882 for line_num, line in f.ChangedContents():
883 if pattern.match(line):
884 errors.append(' %s:%d' % (f.LocalPath(), line_num))
885
886 results = []
887 if errors:
888 results.append(output_api.PresubmitError(
889 'Header files should not include ui/aura/window_property.h', errors))
890 return results
891
892
[email protected]cf9b78f2012-11-14 11:40:28893def _CheckIncludeOrderForScope(scope, input_api, file_path, changed_linenums):
894 """Checks that the lines in scope occur in the right order.
895
896 1. C system files in alphabetical order
897 2. C++ system files in alphabetical order
898 3. Project's .h files
899 """
900
901 c_system_include_pattern = input_api.re.compile(r'\s*#include <.*\.h>')
902 cpp_system_include_pattern = input_api.re.compile(r'\s*#include <.*>')
903 custom_include_pattern = input_api.re.compile(r'\s*#include ".*')
904
905 C_SYSTEM_INCLUDES, CPP_SYSTEM_INCLUDES, CUSTOM_INCLUDES = range(3)
906
907 state = C_SYSTEM_INCLUDES
908
909 previous_line = ''
[email protected]728b9bb2012-11-14 20:38:57910 previous_line_num = 0
[email protected]cf9b78f2012-11-14 11:40:28911 problem_linenums = []
brucedawson70fadb02015-06-30 17:47:55912 out_of_order = " - line belongs before previous line"
[email protected]cf9b78f2012-11-14 11:40:28913 for line_num, line in scope:
914 if c_system_include_pattern.match(line):
915 if state != C_SYSTEM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55916 problem_linenums.append((line_num, previous_line_num,
917 " - C system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28918 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55919 problem_linenums.append((line_num, previous_line_num,
920 out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28921 elif cpp_system_include_pattern.match(line):
922 if state == C_SYSTEM_INCLUDES:
923 state = CPP_SYSTEM_INCLUDES
924 elif state == CUSTOM_INCLUDES:
brucedawson70fadb02015-06-30 17:47:55925 problem_linenums.append((line_num, previous_line_num,
926 " - c++ system include file in wrong block"))
[email protected]cf9b78f2012-11-14 11:40:28927 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55928 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28929 elif custom_include_pattern.match(line):
930 if state != CUSTOM_INCLUDES:
931 state = CUSTOM_INCLUDES
932 elif previous_line and previous_line > line:
brucedawson70fadb02015-06-30 17:47:55933 problem_linenums.append((line_num, previous_line_num, out_of_order))
[email protected]cf9b78f2012-11-14 11:40:28934 else:
brucedawson70fadb02015-06-30 17:47:55935 problem_linenums.append((line_num, previous_line_num,
936 "Unknown include type"))
[email protected]cf9b78f2012-11-14 11:40:28937 previous_line = line
[email protected]728b9bb2012-11-14 20:38:57938 previous_line_num = line_num
[email protected]cf9b78f2012-11-14 11:40:28939
940 warnings = []
brucedawson70fadb02015-06-30 17:47:55941 for (line_num, previous_line_num, failure_type) in problem_linenums:
[email protected]728b9bb2012-11-14 20:38:57942 if line_num in changed_linenums or previous_line_num in changed_linenums:
brucedawson70fadb02015-06-30 17:47:55943 warnings.append(' %s:%d:%s' % (file_path, line_num, failure_type))
[email protected]cf9b78f2012-11-14 11:40:28944 return warnings
945
946
[email protected]ac294a12012-12-06 16:38:43947def _CheckIncludeOrderInFile(input_api, f, changed_linenums):
[email protected]cf9b78f2012-11-14 11:40:28948 """Checks the #include order for the given file f."""
949
[email protected]2299dcf2012-11-15 19:56:24950 system_include_pattern = input_api.re.compile(r'\s*#include \<.*')
[email protected]23093b62013-09-20 12:16:30951 # Exclude the following includes from the check:
952 # 1) #include <.../...>, e.g., <sys/...> includes often need to appear in a
953 # specific order.
954 # 2) <atlbase.h>, "build/build_config.h"
955 excluded_include_pattern = input_api.re.compile(
956 r'\s*#include (\<.*/.*|\<atlbase\.h\>|"build/build_config.h")')
[email protected]2299dcf2012-11-15 19:56:24957 custom_include_pattern = input_api.re.compile(r'\s*#include "(?P<FILE>.*)"')
[email protected]3e83618c2013-10-09 22:32:33958 # Match the final or penultimate token if it is xxxtest so we can ignore it
959 # when considering the special first include.
960 test_file_tag_pattern = input_api.re.compile(
961 r'_[a-z]+test(?=(_[a-zA-Z0-9]+)?\.)')
[email protected]0e5c1852012-12-18 20:17:11962 if_pattern = input_api.re.compile(
963 r'\s*#\s*(if|elif|else|endif|define|undef).*')
964 # Some files need specialized order of includes; exclude such files from this
965 # check.
966 uncheckable_includes_pattern = input_api.re.compile(
967 r'\s*#include '
968 '("ipc/.*macros\.h"|<windows\.h>|".*gl.*autogen.h")\s*')
[email protected]cf9b78f2012-11-14 11:40:28969
970 contents = f.NewContents()
971 warnings = []
972 line_num = 0
973
[email protected]ac294a12012-12-06 16:38:43974 # Handle the special first include. If the first include file is
975 # some/path/file.h, the corresponding including file can be some/path/file.cc,
976 # some/other/path/file.cc, some/path/file_platform.cc, some/path/file-suffix.h
977 # etc. It's also possible that no special first include exists.
[email protected]3e83618c2013-10-09 22:32:33978 # If the included file is some/path/file_platform.h the including file could
979 # also be some/path/file_xxxtest_platform.h.
980 including_file_base_name = test_file_tag_pattern.sub(
981 '', input_api.os_path.basename(f.LocalPath()))
982
[email protected]ac294a12012-12-06 16:38:43983 for line in contents:
984 line_num += 1
985 if system_include_pattern.match(line):
986 # No special first include -> process the line again along with normal
987 # includes.
988 line_num -= 1
989 break
990 match = custom_include_pattern.match(line)
991 if match:
992 match_dict = match.groupdict()
[email protected]3e83618c2013-10-09 22:32:33993 header_basename = test_file_tag_pattern.sub(
994 '', input_api.os_path.basename(match_dict['FILE'])).replace('.h', '')
995
996 if header_basename not in including_file_base_name:
[email protected]2299dcf2012-11-15 19:56:24997 # No special first include -> process the line again along with normal
998 # includes.
999 line_num -= 1
[email protected]ac294a12012-12-06 16:38:431000 break
[email protected]cf9b78f2012-11-14 11:40:281001
1002 # Split into scopes: Each region between #if and #endif is its own scope.
1003 scopes = []
1004 current_scope = []
1005 for line in contents[line_num:]:
1006 line_num += 1
[email protected]0e5c1852012-12-18 20:17:111007 if uncheckable_includes_pattern.match(line):
[email protected]4436c9e2014-01-07 23:19:541008 continue
[email protected]2309b0fa02012-11-16 12:18:271009 if if_pattern.match(line):
[email protected]cf9b78f2012-11-14 11:40:281010 scopes.append(current_scope)
1011 current_scope = []
[email protected]962f117e2012-11-22 18:11:561012 elif ((system_include_pattern.match(line) or
1013 custom_include_pattern.match(line)) and
1014 not excluded_include_pattern.match(line)):
[email protected]cf9b78f2012-11-14 11:40:281015 current_scope.append((line_num, line))
1016 scopes.append(current_scope)
1017
1018 for scope in scopes:
1019 warnings.extend(_CheckIncludeOrderForScope(scope, input_api, f.LocalPath(),
1020 changed_linenums))
1021 return warnings
1022
1023
1024def _CheckIncludeOrder(input_api, output_api):
1025 """Checks that the #include order is correct.
1026
1027 1. The corresponding header for source files.
1028 2. C system files in alphabetical order
1029 3. C++ system files in alphabetical order
1030 4. Project's .h files in alphabetical order
1031
[email protected]ac294a12012-12-06 16:38:431032 Each region separated by #if, #elif, #else, #endif, #define and #undef follows
1033 these rules separately.
[email protected]cf9b78f2012-11-14 11:40:281034 """
[email protected]e120b012014-08-15 19:08:351035 def FileFilterIncludeOrder(affected_file):
1036 black_list = (_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
1037 return input_api.FilterSourceFile(affected_file, black_list=black_list)
[email protected]cf9b78f2012-11-14 11:40:281038
1039 warnings = []
[email protected]e120b012014-08-15 19:08:351040 for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder):
tapted574f09c2015-05-19 13:08:081041 if f.LocalPath().endswith(('.cc', '.h', '.mm')):
[email protected]ac294a12012-12-06 16:38:431042 changed_linenums = set(line_num for line_num, _ in f.ChangedContents())
1043 warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums))
[email protected]cf9b78f2012-11-14 11:40:281044
1045 results = []
1046 if warnings:
[email protected]f7051d52013-04-02 18:31:421047 results.append(output_api.PresubmitPromptOrNotify(_INCLUDE_ORDER_WARNING,
[email protected]120cf540d2012-12-10 17:55:531048 warnings))
[email protected]cf9b78f2012-11-14 11:40:281049 return results
1050
1051
[email protected]70ca77752012-11-20 03:45:031052def _CheckForVersionControlConflictsInFile(input_api, f):
1053 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1054 errors = []
1055 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:231056 if f.LocalPath().endswith('.md'):
1057 # First-level headers in markdown look a lot like version control
1058 # conflict markers. http://daringfireball.net/projects/markdown/basics
1059 continue
[email protected]70ca77752012-11-20 03:45:031060 if pattern.match(line):
1061 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1062 return errors
1063
1064
1065def _CheckForVersionControlConflicts(input_api, output_api):
1066 """Usually this is not intentional and will cause a compile failure."""
1067 errors = []
1068 for f in input_api.AffectedFiles():
1069 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1070
1071 results = []
1072 if errors:
1073 results.append(output_api.PresubmitError(
1074 'Version control conflict markers found, please resolve.', errors))
1075 return results
1076
estadee17314a02017-01-12 16:22:161077def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1078 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1079 errors = []
1080 for f in input_api.AffectedFiles():
1081 for line_num, line in f.ChangedContents():
1082 if pattern.search(line):
1083 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1084
1085 results = []
1086 if errors:
1087 results.append(output_api.PresubmitPromptWarning(
1088 'Found Google support URL addressed by answer number. Please replace with '
1089 'a p= identifier instead. See crbug.com/679462\n', errors))
1090 return results
1091
[email protected]70ca77752012-11-20 03:45:031092
[email protected]06e6d0ff2012-12-11 01:36:441093def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1094 def FilterFile(affected_file):
1095 """Filter function for use with input_api.AffectedSourceFiles,
1096 below. This filters out everything except non-test files from
1097 top-level directories that generally speaking should not hard-code
1098 service URLs (e.g. src/android_webview/, src/content/ and others).
1099 """
1100 return input_api.FilterSourceFile(
1101 affected_file,
[email protected]78bb39d62012-12-11 15:11:561102 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:441103 black_list=(_EXCLUDED_PATHS +
1104 _TEST_CODE_EXCLUDED_PATHS +
1105 input_api.DEFAULT_BLACK_LIST))
1106
reillyi38965732015-11-16 18:27:331107 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1108 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461109 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1110 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441111 problems = [] # items are (filename, line_number, line)
1112 for f in input_api.AffectedSourceFiles(FilterFile):
1113 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461114 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441115 problems.append((f.LocalPath(), line_num, line))
1116
1117 if problems:
[email protected]f7051d52013-04-02 18:31:421118 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441119 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581120 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441121 [' %s:%d: %s' % (
1122 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031123 else:
1124 return []
[email protected]06e6d0ff2012-12-11 01:36:441125
1126
[email protected]d2530012013-01-25 16:39:271127def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1128 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311129 The native_client_sdk directory is excluded because it has auto-generated PNG
1130 files for documentation.
[email protected]d2530012013-01-25 16:39:271131 """
[email protected]d2530012013-01-25 16:39:271132 errors = []
binji0dcdf342014-12-12 18:32:311133 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
1134 black_list = (r'^native_client_sdk[\\\/]',)
1135 file_filter = lambda f: input_api.FilterSourceFile(
1136 f, white_list=white_list, black_list=black_list)
1137 for f in input_api.AffectedFiles(include_deletes=False,
1138 file_filter=file_filter):
1139 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271140
1141 results = []
1142 if errors:
1143 results.append(output_api.PresubmitError(
1144 'The name of PNG files should not have abbreviations. \n'
1145 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1146 'Contact [email protected] if you have questions.', errors))
1147 return results
1148
1149
Daniel Cheng4dcdb6b2017-04-13 08:30:171150def _ExtractAddRulesFromParsedDeps(parsed_deps):
1151 """Extract the rules that add dependencies from a parsed DEPS file.
1152
1153 Args:
1154 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1155 add_rules = set()
1156 add_rules.update([
1157 rule[1:] for rule in parsed_deps.get('include_rules', [])
1158 if rule.startswith('+') or rule.startswith('!')
1159 ])
1160 for specific_file, rules in parsed_deps.get('specific_include_rules',
1161 {}).iteritems():
1162 add_rules.update([
1163 rule[1:] for rule in rules
1164 if rule.startswith('+') or rule.startswith('!')
1165 ])
1166 return add_rules
1167
1168
1169def _ParseDeps(contents):
1170 """Simple helper for parsing DEPS files."""
1171 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171172 class _VarImpl:
1173
1174 def __init__(self, local_scope):
1175 self._local_scope = local_scope
1176
1177 def Lookup(self, var_name):
1178 """Implements the Var syntax."""
1179 try:
1180 return self._local_scope['vars'][var_name]
1181 except KeyError:
1182 raise Exception('Var is not defined: %s' % var_name)
1183
1184 local_scope = {}
1185 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171186 'Var': _VarImpl(local_scope).Lookup,
1187 }
1188 exec contents in global_scope, local_scope
1189 return local_scope
1190
1191
1192def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081193 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411194 a set of DEPS entries that we should look up.
1195
1196 For a directory (rather than a specific filename) we fake a path to
1197 a specific filename by adding /DEPS. This is chosen as a file that
1198 will seldom or never be subject to per-file include_rules.
1199 """
[email protected]2b438d62013-11-14 17:54:141200 # We ignore deps entries on auto-generated directories.
1201 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081202
Daniel Cheng4dcdb6b2017-04-13 08:30:171203 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1204 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1205
1206 added_deps = new_deps.difference(old_deps)
1207
[email protected]2b438d62013-11-14 17:54:141208 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171209 for added_dep in added_deps:
1210 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1211 continue
1212 # Assume that a rule that ends in .h is a rule for a specific file.
1213 if added_dep.endswith('.h'):
1214 results.add(added_dep)
1215 else:
1216 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081217 return results
1218
1219
[email protected]e871964c2013-05-13 14:14:551220def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1221 """When a dependency prefixed with + is added to a DEPS file, we
1222 want to make sure that the change is reviewed by an OWNER of the
1223 target file or directory, to avoid layering violations from being
1224 introduced. This check verifies that this happens.
1225 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171226 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241227
1228 file_filter = lambda f: not input_api.re.match(
1229 r"^third_party[\\\/]WebKit[\\\/].*", f.LocalPath())
1230 for f in input_api.AffectedFiles(include_deletes=False,
1231 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551232 filename = input_api.os_path.basename(f.LocalPath())
1233 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171234 virtual_depended_on_files.update(_CalculateAddedDeps(
1235 input_api.os_path,
1236 '\n'.join(f.OldContents()),
1237 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551238
[email protected]e871964c2013-05-13 14:14:551239 if not virtual_depended_on_files:
1240 return []
1241
1242 if input_api.is_committing:
1243 if input_api.tbr:
1244 return [output_api.PresubmitNotifyResult(
1245 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271246 if input_api.dry_run:
1247 return [output_api.PresubmitNotifyResult(
1248 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551249 if not input_api.change.issue:
1250 return [output_api.PresubmitError(
1251 "DEPS approval by OWNERS check failed: this change has "
1252 "no Rietveld issue number, so we can't check it for approvals.")]
1253 output = output_api.PresubmitError
1254 else:
1255 output = output_api.PresubmitNotifyResult
1256
1257 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501258 owner_email, reviewers = (
1259 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1260 input_api,
1261 owners_db.email_regexp,
1262 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551263
1264 owner_email = owner_email or input_api.change.author_email
1265
[email protected]de4f7d22013-05-23 14:27:461266 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511267 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461268 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551269 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1270 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411271
1272 # We strip the /DEPS part that was added by
1273 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1274 # directory.
1275 def StripDeps(path):
1276 start_deps = path.rfind('/DEPS')
1277 if start_deps != -1:
1278 return path[:start_deps]
1279 else:
1280 return path
1281 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551282 for path in missing_files]
1283
1284 if unapproved_dependencies:
1285 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151286 output('You need LGTM from owners of depends-on paths in DEPS that were '
1287 'modified in this CL:\n %s' %
1288 '\n '.join(sorted(unapproved_dependencies)))]
1289 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1290 output_list.append(output(
1291 'Suggested missing target path OWNERS:\n %s' %
1292 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551293 return output_list
1294
1295 return []
1296
1297
[email protected]85218562013-11-22 07:41:401298def _CheckSpamLogging(input_api, output_api):
1299 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1300 black_list = (_EXCLUDED_PATHS +
1301 _TEST_CODE_EXCLUDED_PATHS +
1302 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501303 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191304 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481305 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461306 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121307 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1308 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581309 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161310 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031311 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151312 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1313 r"^chromecast[\\\/]",
1314 r"^cloud_print[\\\/]",
manzagop85e629e2017-05-09 22:11:481315 r"^components[\\\/]browser_watcher[\\\/]"
1316 r"dump_stability_report_main_win.cc$",
jochen34415e52015-07-10 08:34:311317 r"^components[\\\/]html_viewer[\\\/]"
1318 r"web_test_delegate_impl\.cc$",
peter80739bb2015-10-20 11:17:461319 # TODO(peter): Remove this exception. https://crbug.com/534537
1320 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1321 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251322 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1323 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241324 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111325 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151326 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111327 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521328 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501329 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361330 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311331 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131332 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001333 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441334 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451335 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021336 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351337 r"dump_file_system.cc$",
1338 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401339 source_file_filter = lambda x: input_api.FilterSourceFile(
1340 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1341
thomasanderson625d3932017-03-29 07:16:581342 log_info = set([])
1343 printf = set([])
[email protected]85218562013-11-22 07:41:401344
1345 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581346 for _, line in f.ChangedContents():
1347 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1348 log_info.add(f.LocalPath())
1349 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1350 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371351
thomasanderson625d3932017-03-29 07:16:581352 if input_api.re.search(r"\bprintf\(", line):
1353 printf.add(f.LocalPath())
1354 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1355 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401356
1357 if log_info:
1358 return [output_api.PresubmitError(
1359 'These files spam the console log with LOG(INFO):',
1360 items=log_info)]
1361 if printf:
1362 return [output_api.PresubmitError(
1363 'These files spam the console log with printf/fprintf:',
1364 items=printf)]
1365 return []
1366
1367
[email protected]49aa76a2013-12-04 06:59:161368def _CheckForAnonymousVariables(input_api, output_api):
1369 """These types are all expected to hold locks while in scope and
1370 so should never be anonymous (which causes them to be immediately
1371 destroyed)."""
1372 they_who_must_be_named = [
1373 'base::AutoLock',
1374 'base::AutoReset',
1375 'base::AutoUnlock',
1376 'SkAutoAlphaRestore',
1377 'SkAutoBitmapShaderInstall',
1378 'SkAutoBlitterChoose',
1379 'SkAutoBounderCommit',
1380 'SkAutoCallProc',
1381 'SkAutoCanvasRestore',
1382 'SkAutoCommentBlock',
1383 'SkAutoDescriptor',
1384 'SkAutoDisableDirectionCheck',
1385 'SkAutoDisableOvalCheck',
1386 'SkAutoFree',
1387 'SkAutoGlyphCache',
1388 'SkAutoHDC',
1389 'SkAutoLockColors',
1390 'SkAutoLockPixels',
1391 'SkAutoMalloc',
1392 'SkAutoMaskFreeImage',
1393 'SkAutoMutexAcquire',
1394 'SkAutoPathBoundsUpdate',
1395 'SkAutoPDFRelease',
1396 'SkAutoRasterClipValidate',
1397 'SkAutoRef',
1398 'SkAutoTime',
1399 'SkAutoTrace',
1400 'SkAutoUnref',
1401 ]
1402 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1403 # bad: base::AutoLock(lock.get());
1404 # not bad: base::AutoLock lock(lock.get());
1405 bad_pattern = input_api.re.compile(anonymous)
1406 # good: new base::AutoLock(lock.get())
1407 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1408 errors = []
1409
1410 for f in input_api.AffectedFiles():
1411 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1412 continue
1413 for linenum, line in f.ChangedContents():
1414 if bad_pattern.search(line) and not good_pattern.search(line):
1415 errors.append('%s:%d' % (f.LocalPath(), linenum))
1416
1417 if errors:
1418 return [output_api.PresubmitError(
1419 'These lines create anonymous variables that need to be named:',
1420 items=errors)]
1421 return []
1422
1423
[email protected]5fe0f8742013-11-29 01:04:591424def _CheckCygwinShell(input_api, output_api):
1425 source_file_filter = lambda x: input_api.FilterSourceFile(
1426 x, white_list=(r'.+\.(gyp|gypi)$',))
1427 cygwin_shell = []
1428
1429 for f in input_api.AffectedSourceFiles(source_file_filter):
1430 for linenum, line in f.ChangedContents():
1431 if 'msvs_cygwin_shell' in line:
1432 cygwin_shell.append(f.LocalPath())
1433 break
1434
1435 if cygwin_shell:
1436 return [output_api.PresubmitError(
1437 'These files should not use msvs_cygwin_shell (the default is 0):',
1438 items=cygwin_shell)]
1439 return []
1440
[email protected]85218562013-11-22 07:41:401441
[email protected]999261d2014-03-03 20:08:081442def _CheckUserActionUpdate(input_api, output_api):
1443 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521444 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081445 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521446 # If actions.xml is already included in the changelist, the PRESUBMIT
1447 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081448 return []
1449
[email protected]999261d2014-03-03 20:08:081450 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1451 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521452 current_actions = None
[email protected]999261d2014-03-03 20:08:081453 for f in input_api.AffectedFiles(file_filter=file_filter):
1454 for line_num, line in f.ChangedContents():
1455 match = input_api.re.search(action_re, line)
1456 if match:
[email protected]2f92dec2014-03-07 19:21:521457 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1458 # loaded only once.
1459 if not current_actions:
1460 with open('tools/metrics/actions/actions.xml') as actions_f:
1461 current_actions = actions_f.read()
1462 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081463 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521464 action = 'name="{0}"'.format(action_name)
1465 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081466 return [output_api.PresubmitPromptWarning(
1467 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521468 'tools/metrics/actions/actions.xml. Please run '
1469 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081470 % (f.LocalPath(), line_num, action_name))]
1471 return []
1472
1473
[email protected]99171a92014-06-03 08:44:471474def _GetJSONParseError(input_api, filename, eat_comments=True):
1475 try:
1476 contents = input_api.ReadFile(filename)
1477 if eat_comments:
plundblad1f5a4509f2015-07-23 11:31:131478 import sys
1479 original_sys_path = sys.path
1480 try:
1481 sys.path = sys.path + [input_api.os_path.join(
1482 input_api.PresubmitLocalPath(),
1483 'tools', 'json_comment_eater')]
1484 import json_comment_eater
1485 finally:
1486 sys.path = original_sys_path
1487 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471488
1489 input_api.json.loads(contents)
1490 except ValueError as e:
1491 return e
1492 return None
1493
1494
1495def _GetIDLParseError(input_api, filename):
1496 try:
1497 contents = input_api.ReadFile(filename)
1498 idl_schema = input_api.os_path.join(
1499 input_api.PresubmitLocalPath(),
1500 'tools', 'json_schema_compiler', 'idl_schema.py')
1501 process = input_api.subprocess.Popen(
1502 [input_api.python_executable, idl_schema],
1503 stdin=input_api.subprocess.PIPE,
1504 stdout=input_api.subprocess.PIPE,
1505 stderr=input_api.subprocess.PIPE,
1506 universal_newlines=True)
1507 (_, error) = process.communicate(input=contents)
1508 return error or None
1509 except ValueError as e:
1510 return e
1511
1512
1513def _CheckParseErrors(input_api, output_api):
1514 """Check that IDL and JSON files do not contain syntax errors."""
1515 actions = {
1516 '.idl': _GetIDLParseError,
1517 '.json': _GetJSONParseError,
1518 }
1519 # These paths contain test data and other known invalid JSON files.
1520 excluded_patterns = [
joaodasilva718f87672014-08-30 09:25:491521 r'test[\\\/]data[\\\/]',
1522 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
[email protected]99171a92014-06-03 08:44:471523 ]
1524 # Most JSON files are preprocessed and support comments, but these do not.
1525 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491526 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471527 ]
1528 # Only run IDL checker on files in these directories.
1529 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491530 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1531 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471532 ]
1533
1534 def get_action(affected_file):
1535 filename = affected_file.LocalPath()
1536 return actions.get(input_api.os_path.splitext(filename)[1])
1537
1538 def MatchesFile(patterns, path):
1539 for pattern in patterns:
1540 if input_api.re.search(pattern, path):
1541 return True
1542 return False
1543
1544 def FilterFile(affected_file):
1545 action = get_action(affected_file)
1546 if not action:
1547 return False
1548 path = affected_file.LocalPath()
1549
1550 if MatchesFile(excluded_patterns, path):
1551 return False
1552
1553 if (action == _GetIDLParseError and
1554 not MatchesFile(idl_included_patterns, path)):
1555 return False
1556 return True
1557
1558 results = []
1559 for affected_file in input_api.AffectedFiles(
1560 file_filter=FilterFile, include_deletes=False):
1561 action = get_action(affected_file)
1562 kwargs = {}
1563 if (action == _GetJSONParseError and
1564 MatchesFile(json_no_comments_patterns, affected_file.LocalPath())):
1565 kwargs['eat_comments'] = False
1566 parse_error = action(input_api,
1567 affected_file.AbsoluteLocalPath(),
1568 **kwargs)
1569 if parse_error:
1570 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1571 (affected_file.LocalPath(), parse_error)))
1572 return results
1573
1574
[email protected]760deea2013-12-10 19:33:491575def _CheckJavaStyle(input_api, output_api):
1576 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471577 import sys
[email protected]760deea2013-12-10 19:33:491578 original_sys_path = sys.path
1579 try:
1580 sys.path = sys.path + [input_api.os_path.join(
1581 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1582 import checkstyle
1583 finally:
1584 # Restore sys.path to what it was before.
1585 sys.path = original_sys_path
1586
1587 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091588 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511589 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491590
1591
dchenge07de812016-06-20 19:27:171592def _CheckIpcOwners(input_api, output_api):
1593 """Checks that affected files involving IPC have an IPC OWNERS rule.
1594
1595 Whether or not a file affects IPC is determined by a simple whitelist of
1596 filename patterns."""
1597 file_patterns = [
palmerb19a0932017-01-24 04:00:311598 # Legacy IPC:
dchenge07de812016-06-20 19:27:171599 '*_messages.cc',
1600 '*_messages*.h',
1601 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311602 # Mojo IPC:
dchenge07de812016-06-20 19:27:171603 '*.mojom',
1604 '*_struct_traits*.*',
1605 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311606 '*.typemap',
1607 # Android native IPC:
1608 '*.aidl',
1609 # Blink uses a different file naming convention:
1610 '*EnumTraits*.*',
dchenge07de812016-06-20 19:27:171611 '*StructTraits*.*',
1612 '*TypeConverter*.*',
1613 ]
1614
scottmg7a6ed5ba2016-11-04 18:22:041615 # These third_party directories do not contain IPCs, but contain files
1616 # matching the above patterns, which trigger false positives.
1617 exclude_paths = [
1618 'third_party/crashpad/*',
1619 ]
1620
dchenge07de812016-06-20 19:27:171621 # Dictionary mapping an OWNERS file path to Patterns.
1622 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1623 # rules ) to a PatternEntry.
1624 # PatternEntry is a dictionary with two keys:
1625 # - 'files': the files that are matched by this pattern
1626 # - 'rules': the per-file rules needed for this pattern
1627 # For example, if we expect OWNERS file to contain rules for *.mojom and
1628 # *_struct_traits*.*, Patterns might look like this:
1629 # {
1630 # '*.mojom': {
1631 # 'files': ...,
1632 # 'rules': [
1633 # 'per-file *.mojom=set noparent',
1634 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1635 # ],
1636 # },
1637 # '*_struct_traits*.*': {
1638 # 'files': ...,
1639 # 'rules': [
1640 # 'per-file *_struct_traits*.*=set noparent',
1641 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1642 # ],
1643 # },
1644 # }
1645 to_check = {}
1646
1647 # Iterate through the affected files to see what we actually need to check
1648 # for. We should only nag patch authors about per-file rules if a file in that
1649 # directory would match that pattern. If a directory only contains *.mojom
1650 # files and no *_messages*.h files, we should only nag about rules for
1651 # *.mojom files.
rockot51249332016-06-23 16:32:251652 for f in input_api.change.AffectedFiles(include_deletes=False):
dchenge07de812016-06-20 19:27:171653 for pattern in file_patterns:
1654 if input_api.fnmatch.fnmatch(
1655 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041656 skip = False
1657 for exclude in exclude_paths:
1658 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1659 skip = True
1660 break
1661 if skip:
1662 continue
dchenge07de812016-06-20 19:27:171663 owners_file = input_api.os_path.join(
1664 input_api.os_path.dirname(f.LocalPath()), 'OWNERS')
1665 if owners_file not in to_check:
1666 to_check[owners_file] = {}
1667 if pattern not in to_check[owners_file]:
1668 to_check[owners_file][pattern] = {
1669 'files': [],
1670 'rules': [
1671 'per-file %s=set noparent' % pattern,
1672 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1673 ]
1674 }
1675 to_check[owners_file][pattern]['files'].append(f)
1676 break
1677
1678 # Now go through the OWNERS files we collected, filtering out rules that are
1679 # already present in that OWNERS file.
1680 for owners_file, patterns in to_check.iteritems():
1681 try:
1682 with file(owners_file) as f:
1683 lines = set(f.read().splitlines())
1684 for entry in patterns.itervalues():
1685 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1686 ]
1687 except IOError:
1688 # No OWNERS file, so all the rules are definitely missing.
1689 continue
1690
1691 # All the remaining lines weren't found in OWNERS files, so emit an error.
1692 errors = []
1693 for owners_file, patterns in to_check.iteritems():
1694 missing_lines = []
1695 files = []
1696 for pattern, entry in patterns.iteritems():
1697 missing_lines.extend(entry['rules'])
1698 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1699 if missing_lines:
1700 errors.append(
Daniel Cheng52111692017-06-14 08:00:591701 '%s needs the following lines added:\n\n%s\n\nfor files:\n%s' %
dchenge07de812016-06-20 19:27:171702 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1703
1704 results = []
1705 if errors:
vabrf5ce3bf92016-07-11 14:52:411706 if input_api.is_committing:
1707 output = output_api.PresubmitError
1708 else:
1709 output = output_api.PresubmitPromptWarning
1710 results.append(output(
Daniel Cheng52111692017-06-14 08:00:591711 'Found OWNERS files that need to be updated for IPC security ' +
1712 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:171713 long_text='\n\n'.join(errors)))
1714
1715 return results
1716
1717
jbriance9e12f162016-11-25 07:57:501718def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311719 """Checks that added or removed lines in non third party affected
1720 header files do not lead to new useless class or struct forward
1721 declaration.
jbriance9e12f162016-11-25 07:57:501722 """
1723 results = []
1724 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1725 input_api.re.MULTILINE)
1726 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1727 input_api.re.MULTILINE)
1728 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311729 if (f.LocalPath().startswith('third_party') and
1730 not f.LocalPath().startswith('third_party/WebKit') and
1731 not f.LocalPath().startswith('third_party\\WebKit')):
1732 continue
1733
jbriance9e12f162016-11-25 07:57:501734 if not f.LocalPath().endswith('.h'):
1735 continue
1736
1737 contents = input_api.ReadFile(f)
1738 fwd_decls = input_api.re.findall(class_pattern, contents)
1739 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1740
1741 useless_fwd_decls = []
1742 for decl in fwd_decls:
1743 count = sum(1 for _ in input_api.re.finditer(
1744 r'\b%s\b' % input_api.re.escape(decl), contents))
1745 if count == 1:
1746 useless_fwd_decls.append(decl)
1747
1748 if not useless_fwd_decls:
1749 continue
1750
1751 for line in f.GenerateScmDiff().splitlines():
1752 if (line.startswith('-') and not line.startswith('--') or
1753 line.startswith('+') and not line.startswith('++')):
1754 for decl in useless_fwd_decls:
1755 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1756 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:241757 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:501758 (f.LocalPath(), decl)))
1759 useless_fwd_decls.remove(decl)
1760
1761 return results
1762
1763
dskiba88634f4e2015-08-14 23:03:291764def _CheckAndroidToastUsage(input_api, output_api):
1765 """Checks that code uses org.chromium.ui.widget.Toast instead of
1766 android.widget.Toast (Chromium Toast doesn't force hardware
1767 acceleration on low-end devices, saving memory).
1768 """
1769 toast_import_pattern = input_api.re.compile(
1770 r'^import android\.widget\.Toast;$')
1771
1772 errors = []
1773
1774 sources = lambda affected_file: input_api.FilterSourceFile(
1775 affected_file,
1776 black_list=(_EXCLUDED_PATHS +
1777 _TEST_CODE_EXCLUDED_PATHS +
1778 input_api.DEFAULT_BLACK_LIST +
1779 (r'^chromecast[\\\/].*',
1780 r'^remoting[\\\/].*')),
1781 white_list=(r'.*\.java$',))
1782
1783 for f in input_api.AffectedSourceFiles(sources):
1784 for line_num, line in f.ChangedContents():
1785 if toast_import_pattern.search(line):
1786 errors.append("%s:%d" % (f.LocalPath(), line_num))
1787
1788 results = []
1789
1790 if errors:
1791 results.append(output_api.PresubmitError(
1792 'android.widget.Toast usage is detected. Android toasts use hardware'
1793 ' acceleration, and can be\ncostly on low-end devices. Please use'
1794 ' org.chromium.ui.widget.Toast instead.\n'
1795 'Contact [email protected] if you have any questions.',
1796 errors))
1797
1798 return results
1799
1800
dgnaa68d5e2015-06-10 10:08:221801def _CheckAndroidCrLogUsage(input_api, output_api):
1802 """Checks that new logs using org.chromium.base.Log:
1803 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511804 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221805 """
pkotwicza1dd0b002016-05-16 14:41:041806
torne89540622017-03-24 19:41:301807 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:041808 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:301809 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:041810 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:301811 # WebView license viewer code cannot depend on //base; used in stub APK.
1812 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
1813 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:041814 ]
1815
dgnaa68d5e2015-06-10 10:08:221816 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121817 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1818 class_in_base_pattern = input_api.re.compile(
1819 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1820 has_some_log_import_pattern = input_api.re.compile(
1821 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221822 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121823 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221824 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511825 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221826 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221827
Vincent Scheib16d7b272015-09-15 18:09:071828 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221829 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041830 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1831 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121832
dgnaa68d5e2015-06-10 10:08:221833 tag_decl_errors = []
1834 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121835 tag_errors = []
dgn38736db2015-09-18 19:20:511836 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121837 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221838
1839 for f in input_api.AffectedSourceFiles(sources):
1840 file_content = input_api.ReadFile(f)
1841 has_modified_logs = False
1842
1843 # Per line checks
dgn87d9fb62015-06-12 09:15:121844 if (cr_log_import_pattern.search(file_content) or
1845 (class_in_base_pattern.search(file_content) and
1846 not has_some_log_import_pattern.search(file_content))):
1847 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221848 for line_num, line in f.ChangedContents():
1849
1850 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121851 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221852 if match:
1853 has_modified_logs = True
1854
1855 # Make sure it uses "TAG"
1856 if not match.group('tag') == 'TAG':
1857 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121858 else:
1859 # Report non cr Log function calls in changed lines
1860 for line_num, line in f.ChangedContents():
1861 if log_call_pattern.search(line):
1862 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221863
1864 # Per file checks
1865 if has_modified_logs:
1866 # Make sure the tag is using the "cr" prefix and is not too long
1867 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511868 tag_name = match.group('name') if match else None
1869 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221870 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511871 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221872 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511873 elif '.' in tag_name:
1874 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:221875
1876 results = []
1877 if tag_decl_errors:
1878 results.append(output_api.PresubmitPromptWarning(
1879 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:511880 '"private static final String TAG = "<package tag>".\n'
1881 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221882 tag_decl_errors))
1883
1884 if tag_length_errors:
1885 results.append(output_api.PresubmitError(
1886 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:511887 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:221888 tag_length_errors))
1889
1890 if tag_errors:
1891 results.append(output_api.PresubmitPromptWarning(
1892 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
1893 tag_errors))
1894
dgn87d9fb62015-06-12 09:15:121895 if util_log_errors:
dgn4401aa52015-04-29 16:26:171896 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:121897 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
1898 util_log_errors))
1899
dgn38736db2015-09-18 19:20:511900 if tag_with_dot_errors:
1901 results.append(output_api.PresubmitPromptWarning(
1902 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
1903 tag_with_dot_errors))
1904
dgn4401aa52015-04-29 16:26:171905 return results
1906
1907
yolandyan45001472016-12-21 21:12:421908def _CheckAndroidTestAnnotationUsage(input_api, output_api):
1909 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
1910 deprecated_annotation_import_pattern = input_api.re.compile(
1911 r'^import android\.test\.suitebuilder\.annotation\..*;',
1912 input_api.re.MULTILINE)
1913 sources = lambda x: input_api.FilterSourceFile(
1914 x, white_list=(r'.*\.java$',), black_list=None)
1915 errors = []
1916 for f in input_api.AffectedFiles(sources):
1917 for line_num, line in f.ChangedContents():
1918 if deprecated_annotation_import_pattern.search(line):
1919 errors.append("%s:%d" % (f.LocalPath(), line_num))
1920
1921 results = []
1922 if errors:
1923 results.append(output_api.PresubmitError(
1924 'Annotations in android.test.suitebuilder.annotation have been'
1925 ' deprecated since API level 24. Please use android.support.test.filters'
1926 ' from //third_party/android_support_test_runner:runner_java instead.'
1927 ' Contact [email protected] if you have any questions.', errors))
1928 return results
1929
1930
agrieve7b6479d82015-10-07 14:24:221931def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
1932 """Checks if MDPI assets are placed in a correct directory."""
1933 file_filter = lambda f: (f.LocalPath().endswith('.png') and
1934 ('/res/drawable/' in f.LocalPath() or
1935 '/res/drawable-ldrtl/' in f.LocalPath()))
1936 errors = []
1937 for f in input_api.AffectedFiles(include_deletes=False,
1938 file_filter=file_filter):
1939 errors.append(' %s' % f.LocalPath())
1940
1941 results = []
1942 if errors:
1943 results.append(output_api.PresubmitError(
1944 'MDPI assets should be placed in /res/drawable-mdpi/ or '
1945 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
1946 '/res/drawable-ldrtl/.\n'
1947 'Contact [email protected] if you have questions.', errors))
1948 return results
1949
1950
agrievef32bcc72016-04-04 14:57:401951class PydepsChecker(object):
1952 def __init__(self, input_api, pydeps_files):
1953 self._file_cache = {}
1954 self._input_api = input_api
1955 self._pydeps_files = pydeps_files
1956
1957 def _LoadFile(self, path):
1958 """Returns the list of paths within a .pydeps file relative to //."""
1959 if path not in self._file_cache:
1960 with open(path) as f:
1961 self._file_cache[path] = f.read()
1962 return self._file_cache[path]
1963
1964 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
1965 """Returns an interable of paths within the .pydep, relativized to //."""
1966 os_path = self._input_api.os_path
1967 pydeps_dir = os_path.dirname(pydeps_path)
1968 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
1969 if not l.startswith('*'))
1970 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
1971
1972 def _CreateFilesToPydepsMap(self):
1973 """Returns a map of local_path -> list_of_pydeps."""
1974 ret = {}
1975 for pydep_local_path in self._pydeps_files:
1976 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
1977 ret.setdefault(path, []).append(pydep_local_path)
1978 return ret
1979
1980 def ComputeAffectedPydeps(self):
1981 """Returns an iterable of .pydeps files that might need regenerating."""
1982 affected_pydeps = set()
1983 file_to_pydeps_map = None
1984 for f in self._input_api.AffectedFiles(include_deletes=True):
1985 local_path = f.LocalPath()
1986 if local_path == 'DEPS':
1987 return self._pydeps_files
1988 elif local_path.endswith('.pydeps'):
1989 if local_path in self._pydeps_files:
1990 affected_pydeps.add(local_path)
1991 elif local_path.endswith('.py'):
1992 if file_to_pydeps_map is None:
1993 file_to_pydeps_map = self._CreateFilesToPydepsMap()
1994 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
1995 return affected_pydeps
1996
1997 def DetermineIfStale(self, pydeps_path):
1998 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:411999 import difflib
agrievef32bcc72016-04-04 14:57:402000 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2001 cmd = old_pydeps_data[1][1:].strip()
2002 new_pydeps_data = self._input_api.subprocess.check_output(
2003 cmd + ' --output ""', shell=True)
phajdan.jr0d9878552016-11-04 10:49:412004 old_contents = old_pydeps_data[2:]
2005 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402006 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412007 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402008
2009
2010def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2011 """Checks if a .pydeps file needs to be regenerated."""
agrievebb9c5b472016-04-22 15:13:002012 # This check is mainly for Android, and involves paths not only in the
agrieve9bc4200b2016-05-04 16:33:282013 # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
2014 # Mac, so skip it on other platforms.
2015 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002016 return []
agrievef32bcc72016-04-04 14:57:402017 # TODO(agrieve): Update when there's a better way to detect this: crbug/570091
2018 is_android = input_api.os_path.exists('third_party/android_tools')
2019 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2020 results = []
2021 # First, check for new / deleted .pydeps.
2022 for f in input_api.AffectedFiles(include_deletes=True):
2023 if f.LocalPath().endswith('.pydeps'):
2024 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2025 results.append(output_api.PresubmitError(
2026 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2027 'remove %s' % f.LocalPath()))
2028 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2029 results.append(output_api.PresubmitError(
2030 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2031 'include %s' % f.LocalPath()))
2032
2033 if results:
2034 return results
2035
2036 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2037
2038 for pydep_path in checker.ComputeAffectedPydeps():
2039 try:
phajdan.jr0d9878552016-11-04 10:49:412040 result = checker.DetermineIfStale(pydep_path)
2041 if result:
2042 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402043 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412044 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2045 'To regenerate, run:\n\n %s' %
2046 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402047 except input_api.subprocess.CalledProcessError as error:
2048 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2049 long_text=error.output)]
2050
2051 return results
2052
2053
glidere61efad2015-02-18 17:39:432054def _CheckSingletonInHeaders(input_api, output_api):
2055 """Checks to make sure no header files have |Singleton<|."""
2056 def FileFilter(affected_file):
2057 # It's ok for base/memory/singleton.h to have |Singleton<|.
2058 black_list = (_EXCLUDED_PATHS +
2059 input_api.DEFAULT_BLACK_LIST +
2060 (r"^base[\\\/]memory[\\\/]singleton\.h$",))
2061 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2062
sergeyu34d21222015-09-16 00:11:442063 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432064 files = []
2065 for f in input_api.AffectedSourceFiles(FileFilter):
2066 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2067 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2068 contents = input_api.ReadFile(f)
2069 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242070 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432071 pattern.search(line)):
2072 files.append(f)
2073 break
2074
2075 if files:
yolandyandaabc6d2016-04-18 18:29:392076 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442077 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432078 'Please move them to an appropriate source file so that the ' +
2079 'template gets instantiated in a single compilation unit.',
2080 files) ]
2081 return []
2082
2083
[email protected]fd20b902014-05-09 02:14:532084_DEPRECATED_CSS = [
2085 # Values
2086 ( "-webkit-box", "flex" ),
2087 ( "-webkit-inline-box", "inline-flex" ),
2088 ( "-webkit-flex", "flex" ),
2089 ( "-webkit-inline-flex", "inline-flex" ),
2090 ( "-webkit-min-content", "min-content" ),
2091 ( "-webkit-max-content", "max-content" ),
2092
2093 # Properties
2094 ( "-webkit-background-clip", "background-clip" ),
2095 ( "-webkit-background-origin", "background-origin" ),
2096 ( "-webkit-background-size", "background-size" ),
2097 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442098 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532099
2100 # Functions
2101 ( "-webkit-gradient", "gradient" ),
2102 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2103 ( "-webkit-linear-gradient", "linear-gradient" ),
2104 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2105 ( "-webkit-radial-gradient", "radial-gradient" ),
2106 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2107]
2108
dbeam1ec68ac2016-12-15 05:22:242109def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532110 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252111 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342112 documentation and iOS CSS for dom distiller
2113 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252114 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532115 results = []
dbeam070cfe62014-10-22 06:44:022116 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:252117 black_list = (_EXCLUDED_PATHS +
2118 _TEST_CODE_EXCLUDED_PATHS +
2119 input_api.DEFAULT_BLACK_LIST +
2120 (r"^chrome/common/extensions/docs",
2121 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342122 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresneda218472015-12-07 18:38:052123 r"^components/flags_ui/resources/apple_flags.css",
sdefresne6308d7f2016-02-15 09:38:442124 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252125 r"^native_client_sdk"))
2126 file_filter = lambda f: input_api.FilterSourceFile(
2127 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532128 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2129 for line_num, line in fpath.ChangedContents():
2130 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022131 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532132 results.append(output_api.PresubmitError(
2133 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2134 (fpath.LocalPath(), line_num, deprecated_value, value)))
2135 return results
2136
mohan.reddyf21db962014-10-16 12:26:472137
dbeam070cfe62014-10-22 06:44:022138_DEPRECATED_JS = [
2139 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2140 ( "__defineGetter__", "Object.defineProperty" ),
2141 ( "__defineSetter__", "Object.defineProperty" ),
2142]
2143
dbeam1ec68ac2016-12-15 05:22:242144def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022145 """Make sure that we don't use deprecated JS in Chrome code."""
2146 results = []
2147 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2148 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2149 input_api.DEFAULT_BLACK_LIST)
2150 file_filter = lambda f: input_api.FilterSourceFile(
2151 f, white_list=file_inclusion_pattern, black_list=black_list)
2152 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2153 for lnum, line in fpath.ChangedContents():
2154 for (deprecated, replacement) in _DEPRECATED_JS:
2155 if deprecated in line:
2156 results.append(output_api.PresubmitError(
2157 "%s:%d: Use of deprecated JS %s, use %s instead" %
2158 (fpath.LocalPath(), lnum, deprecated, replacement)))
2159 return results
2160
2161
dbeam1ec68ac2016-12-15 05:22:242162def _CheckForRiskyJsFeatures(input_api, output_api):
2163 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
2164 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js)
2165
2166 arrow_lines = []
2167 for f in input_api.AffectedFiles(file_filter=file_filter):
2168 for lnum, line in f.ChangedContents():
2169 if ' => ' in line:
2170 arrow_lines.append((f.LocalPath(), lnum))
2171
2172 if not arrow_lines:
2173 return []
2174
2175 return [output_api.PresubmitPromptWarning("""
2176Use of => operator detected in:
2177%s
2178Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2179https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
2180""" % "\n".join(" %s:%d\n" % line for line in arrow_lines))]
2181
2182
rlanday6802cf632017-05-30 17:48:362183def _CheckForRelativeIncludes(input_api, output_api):
2184 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2185 import sys
2186 original_sys_path = sys.path
2187 try:
2188 sys.path = sys.path + [input_api.os_path.join(
2189 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2190 from cpp_checker import CppChecker
2191 finally:
2192 # Restore sys.path to what it was before.
2193 sys.path = original_sys_path
2194
2195 bad_files = {}
2196 for f in input_api.AffectedFiles(include_deletes=False):
2197 if (f.LocalPath().startswith('third_party') and
2198 not f.LocalPath().startswith('third_party/WebKit') and
2199 not f.LocalPath().startswith('third_party\\WebKit')):
2200 continue
2201
2202 if not CppChecker.IsCppFile(f.LocalPath()):
2203 continue
2204
2205 relative_includes = [line for line_num, line in f.ChangedContents()
2206 if "#include" in line and "../" in line]
2207 if not relative_includes:
2208 continue
2209 bad_files[f.LocalPath()] = relative_includes
2210
2211 if not bad_files:
2212 return []
2213
2214 error_descriptions = []
2215 for file_path, bad_lines in bad_files.iteritems():
2216 error_description = file_path
2217 for line in bad_lines:
2218 error_description += '\n ' + line
2219 error_descriptions.append(error_description)
2220
2221 results = []
2222 results.append(output_api.PresubmitError(
2223 'You added one or more relative #include paths (including "../").\n'
2224 'These shouldn\'t be used because they can be used to include headers\n'
2225 'from code that\'s not correctly specified as a dependency in the\n'
2226 'relevant BUILD.gn file(s).',
2227 error_descriptions))
2228
2229 return results
2230
dgnaa68d5e2015-06-10 10:08:222231def _AndroidSpecificOnUploadChecks(input_api, output_api):
2232 """Groups checks that target android code."""
2233 results = []
dgnaa68d5e2015-06-10 10:08:222234 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222235 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292236 results.extend(_CheckAndroidToastUsage(input_api, output_api))
yolandyan45001472016-12-21 21:12:422237 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222238 return results
2239
2240
[email protected]22c9bd72011-03-27 16:47:392241def _CommonChecks(input_api, output_api):
2242 """Checks common to both upload and commit."""
2243 results = []
2244 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382245 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542246 excluded_paths=_EXCLUDED_PATHS))
machenbachfbda9b72016-12-06 13:13:582247 results.extend(
2248 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
[email protected]55459852011-08-10 15:17:192249 results.extend(
[email protected]760deea2013-12-10 19:33:492250 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542251 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182252 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522253 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222254 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442255 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592256 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062257 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122258 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182259 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222260 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302261 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492262 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]2309b0fa02012-11-16 12:18:272263 results.extend(_CheckIncludeOrder(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032264 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492265 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442266 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272267 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542268 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442269 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392270 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552271 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042272 results.extend(
2273 input_api.canned_checks.CheckChangeHasNoTabs(
2274 input_api,
2275 output_api,
2276 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402277 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162278 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]5fe0f8742013-11-29 01:04:592279 results.extend(_CheckCygwinShell(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082280 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242281 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2282 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472283 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042284 results.extend(_CheckForIPCRules(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232285 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432286 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402287 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152288 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172289 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502290 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242291 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:362292 results.extend(_CheckForRelativeIncludes(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242293
2294 if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
2295 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2296 input_api, output_api,
2297 input_api.PresubmitLocalPath(),
[email protected]6be63382013-01-21 15:42:382298 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392299 return results
[email protected]1f7b4172010-01-28 01:17:342300
[email protected]b337cb5b2011-01-23 21:24:052301
[email protected]b8079ae4a2012-12-05 19:56:492302def _CheckPatchFiles(input_api, output_api):
2303 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2304 if f.LocalPath().endswith(('.orig', '.rej'))]
2305 if problems:
2306 return [output_api.PresubmitError(
2307 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032308 else:
2309 return []
[email protected]b8079ae4a2012-12-05 19:56:492310
2311
[email protected]b00342e7f2013-03-26 16:21:542312def _DidYouMeanOSMacro(bad_macro):
2313 try:
2314 return {'A': 'OS_ANDROID',
2315 'B': 'OS_BSD',
2316 'C': 'OS_CHROMEOS',
2317 'F': 'OS_FREEBSD',
2318 'L': 'OS_LINUX',
2319 'M': 'OS_MACOSX',
2320 'N': 'OS_NACL',
2321 'O': 'OS_OPENBSD',
2322 'P': 'OS_POSIX',
2323 'S': 'OS_SOLARIS',
2324 'W': 'OS_WIN'}[bad_macro[3].upper()]
2325 except KeyError:
2326 return ''
2327
2328
2329def _CheckForInvalidOSMacrosInFile(input_api, f):
2330 """Check for sensible looking, totally invalid OS macros."""
2331 preprocessor_statement = input_api.re.compile(r'^\s*#')
2332 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2333 results = []
2334 for lnum, line in f.ChangedContents():
2335 if preprocessor_statement.search(line):
2336 for match in os_macro.finditer(line):
2337 if not match.group(1) in _VALID_OS_MACROS:
2338 good = _DidYouMeanOSMacro(match.group(1))
2339 did_you_mean = ' (did you mean %s?)' % good if good else ''
2340 results.append(' %s:%d %s%s' % (f.LocalPath(),
2341 lnum,
2342 match.group(1),
2343 did_you_mean))
2344 return results
2345
2346
2347def _CheckForInvalidOSMacros(input_api, output_api):
2348 """Check all affected files for invalid OS macros."""
2349 bad_macros = []
2350 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472351 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542352 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2353
2354 if not bad_macros:
2355 return []
2356
2357 return [output_api.PresubmitError(
2358 'Possibly invalid OS macro[s] found. Please fix your code\n'
2359 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2360
lliabraa35bab3932014-10-01 12:16:442361
2362def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2363 """Check all affected files for invalid "if defined" macros."""
2364 ALWAYS_DEFINED_MACROS = (
2365 "TARGET_CPU_PPC",
2366 "TARGET_CPU_PPC64",
2367 "TARGET_CPU_68K",
2368 "TARGET_CPU_X86",
2369 "TARGET_CPU_ARM",
2370 "TARGET_CPU_MIPS",
2371 "TARGET_CPU_SPARC",
2372 "TARGET_CPU_ALPHA",
2373 "TARGET_IPHONE_SIMULATOR",
2374 "TARGET_OS_EMBEDDED",
2375 "TARGET_OS_IPHONE",
2376 "TARGET_OS_MAC",
2377 "TARGET_OS_UNIX",
2378 "TARGET_OS_WIN32",
2379 )
2380 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2381 results = []
2382 for lnum, line in f.ChangedContents():
2383 for match in ifdef_macro.finditer(line):
2384 if match.group(1) in ALWAYS_DEFINED_MACROS:
2385 always_defined = ' %s is always defined. ' % match.group(1)
2386 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2387 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2388 lnum,
2389 always_defined,
2390 did_you_mean))
2391 return results
2392
2393
2394def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2395 """Check all affected files for invalid "if defined" macros."""
2396 bad_macros = []
2397 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:212398 if f.LocalPath().startswith('third_party/sqlite/'):
2399 continue
lliabraa35bab3932014-10-01 12:16:442400 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2401 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2402
2403 if not bad_macros:
2404 return []
2405
2406 return [output_api.PresubmitError(
2407 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2408 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2409 bad_macros)]
2410
2411
mlamouria82272622014-09-16 18:45:042412def _CheckForIPCRules(input_api, output_api):
2413 """Check for same IPC rules described in
2414 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2415 """
2416 base_pattern = r'IPC_ENUM_TRAITS\('
2417 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2418 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2419
2420 problems = []
2421 for f in input_api.AffectedSourceFiles(None):
2422 local_path = f.LocalPath()
2423 if not local_path.endswith('.h'):
2424 continue
2425 for line_number, line in f.ChangedContents():
2426 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2427 problems.append(
2428 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2429
2430 if problems:
2431 return [output_api.PresubmitPromptWarning(
2432 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2433 else:
2434 return []
2435
[email protected]b00342e7f2013-03-26 16:21:542436
mostynbb639aca52015-01-07 20:31:232437def _CheckForWindowsLineEndings(input_api, output_api):
2438 """Check source code and known ascii text files for Windows style line
2439 endings.
2440 """
earthdok1b5e0ee2015-03-10 15:19:102441 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232442
2443 file_inclusion_pattern = (
2444 known_text_files,
2445 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
2446 )
2447
2448 filter = lambda f: input_api.FilterSourceFile(
2449 f, white_list=file_inclusion_pattern, black_list=None)
2450 files = [f.LocalPath() for f in
2451 input_api.AffectedSourceFiles(filter)]
2452
2453 problems = []
2454
2455 for file in files:
2456 fp = open(file, 'r')
2457 for line in fp:
2458 if line.endswith('\r\n'):
2459 problems.append(file)
2460 break
2461 fp.close()
2462
2463 if problems:
2464 return [output_api.PresubmitPromptWarning('Are you sure that you want '
2465 'these files to contain Windows style line endings?\n' +
2466 '\n'.join(problems))]
2467
2468 return []
2469
2470
pastarmovj89f7ee12016-09-20 14:58:132471def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None,
2472 lint_filters=None, verbose_level=None):
2473 """Checks that all source files use SYSLOG properly."""
2474 syslog_files = []
2475 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:562476 for line_number, line in f.ChangedContents():
2477 if 'SYSLOG' in line:
2478 syslog_files.append(f.LocalPath() + ':' + str(line_number))
2479
pastarmovj89f7ee12016-09-20 14:58:132480 if syslog_files:
2481 return [output_api.PresubmitPromptWarning(
2482 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
2483 ' calls.\nFiles to check:\n', items=syslog_files)]
2484 return []
2485
2486
[email protected]1f7b4172010-01-28 01:17:342487def CheckChangeOnUpload(input_api, output_api):
2488 results = []
2489 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:472490 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:282491 results.extend(
jam93a6ee792017-02-08 23:59:222492 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:192493 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222494 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:132495 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:162496 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542497 return results
[email protected]ca8d1982009-02-19 16:33:122498
2499
[email protected]1bfb8322014-04-23 01:02:412500def GetTryServerMasterForBot(bot):
2501 """Returns the Try Server master for the given bot.
2502
[email protected]0bb112362014-07-26 04:38:322503 It tries to guess the master from the bot name, but may still fail
2504 and return None. There is no longer a default master.
2505 """
2506 # Potentially ambiguous bot names are listed explicitly.
2507 master_map = {
tandriie5587792016-07-14 00:34:502508 'chromium_presubmit': 'master.tryserver.chromium.linux',
2509 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:412510 }
[email protected]0bb112362014-07-26 04:38:322511 master = master_map.get(bot)
2512 if not master:
wnwen4fbaab82016-05-25 12:54:362513 if 'android' in bot:
tandriie5587792016-07-14 00:34:502514 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:362515 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:502516 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:322517 elif 'win' in bot:
tandriie5587792016-07-14 00:34:502518 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:322519 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:502520 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:322521 return master
[email protected]1bfb8322014-04-23 01:02:412522
2523
Paweł Hajdan, Jr55083782014-12-19 20:32:562524def GetDefaultTryConfigs(bots):
2525 """Returns a list of ('bot', set(['tests']), filtered by [bots].
[email protected]38c6a512013-12-18 23:48:012526 """
2527
Paweł Hajdan, Jr55083782014-12-19 20:32:562528 builders_and_tests = dict((bot, set(['defaulttests'])) for bot in bots)
[email protected]1bfb8322014-04-23 01:02:412529
2530 # Build up the mapping from tryserver master to bot/test.
2531 out = dict()
Paweł Hajdan, Jr55083782014-12-19 20:32:562532 for bot, tests in builders_and_tests.iteritems():
[email protected]1bfb8322014-04-23 01:02:412533 out.setdefault(GetTryServerMasterForBot(bot), {})[bot] = tests
2534 return out
[email protected]38c6a512013-12-18 23:48:012535
2536
[email protected]ca8d1982009-02-19 16:33:122537def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:542538 results = []
[email protected]1f7b4172010-01-28 01:17:342539 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542540 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:272541 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:342542 input_api,
2543 output_api,
[email protected]2fdd1f362013-01-16 03:56:032544 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:272545
jam93a6ee792017-02-08 23:59:222546 results.extend(
2547 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:542548 results.extend(input_api.canned_checks.CheckChangeHasBugField(
2549 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:412550 results.extend(input_api.canned_checks.CheckChangeHasDescription(
2551 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:542552 return results