blob: c06e021695fee2403c0b49fed58fe21a64b3f6ce [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]40d1dbb2012-10-26 07:18:0013 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
14 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2815 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0816 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5417 r"^skia[\\\/].*",
Kent Tamurae9b3a9ec2017-08-31 02:20:1918 r"^third_party[\\\/](WebKit|blink)[\\\/].*",
Mark Mentovaiebb9ddd62017-09-25 17:24:4119 r"^third_party[\\\/]breakpad[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
vapierb2053f542017-03-09 19:46:1026 r"tools[\\\/]md_browser[\\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1427 # Test pages for Maps telemetry tests.
28 r"tools[\\\/]perf[\\\/]page_sets[\\\/]maps_perf_test.*",
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,
Steven Holte27008b7422018-01-29 20:55:4444 r'.+_(api|browser|eg|int|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
Eric Stevensona9a980972017-09-23 00:04:4170_BANNED_JAVA_FUNCTIONS = (
71 (
72 'StrictMode.allowThreadDiskReads()',
73 (
74 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
75 'directly.',
76 ),
77 False,
78 ),
79 (
80 'StrictMode.allowThreadDiskWrites()',
81 (
82 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
83 'directly.',
84 ),
85 False,
86 ),
87)
88
[email protected]127f18ec2012-06-16 05:05:5989_BANNED_OBJC_FUNCTIONS = (
90 (
91 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2092 (
93 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5994 'prohibited. Please use CrTrackingArea instead.',
95 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
96 ),
97 False,
98 ),
99 (
[email protected]eaae1972014-04-16 04:17:26100 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20101 (
102 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59103 'instead.',
104 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
105 ),
106 False,
107 ),
108 (
109 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20110 (
111 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59112 'Please use |convertPoint:(point) fromView:nil| instead.',
113 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
114 ),
115 True,
116 ),
117 (
118 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20119 (
120 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59121 'Please use |convertPoint:(point) toView:nil| instead.',
122 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
123 ),
124 True,
125 ),
126 (
127 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20128 (
129 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59130 'Please use |convertRect:(point) fromView:nil| instead.',
131 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
132 ),
133 True,
134 ),
135 (
136 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20137 (
138 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59139 'Please use |convertRect:(point) toView:nil| instead.',
140 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
141 ),
142 True,
143 ),
144 (
145 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20146 (
147 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59148 'Please use |convertSize:(point) fromView:nil| instead.',
149 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
150 ),
151 True,
152 ),
153 (
154 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20155 (
156 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59157 'Please use |convertSize:(point) toView:nil| instead.',
158 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
159 ),
160 True,
161 ),
jif65398702016-10-27 10:19:48162 (
163 r"/\s+UTF8String\s*]",
164 (
165 'The use of -[NSString UTF8String] is dangerous as it can return null',
166 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
167 'Please use |SysNSStringToUTF8| instead.',
168 ),
169 True,
170 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34171 (
172 r'__unsafe_unretained',
173 (
174 'The use of __unsafe_unretained is almost certainly wrong, unless',
175 'when interacting with NSFastEnumeration or NSInvocation.',
176 'Please use __weak in files build with ARC, nothing otherwise.',
177 ),
178 False,
179 ),
[email protected]127f18ec2012-06-16 05:05:59180)
181
Sylvain Defresnea8b73d252018-02-28 15:45:54182_BANNED_IOS_OBJC_FUNCTIONS = (
183 (
184 r'/\bTEST[(]',
185 (
186 'TEST() macro should not be used in Objective-C++ code as it does not ',
187 'drain the autorelease pool at the end of the test. Use TEST_F() ',
188 'macro instead with a fixture inheriting from PlatformTest (or a ',
189 'typedef).'
190 ),
191 True,
192 ),
193 (
194 r'/\btesting::Test\b',
195 (
196 'testing::Test should not be used in Objective-C++ code as it does ',
197 'not drain the autorelease pool at the end of the test. Use ',
198 'PlatformTest instead.'
199 ),
200 True,
201 ),
202)
203
[email protected]127f18ec2012-06-16 05:05:59204
205_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20206 # Make sure that gtest's FRIEND_TEST() macro is not used; the
207 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30208 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20209 (
thomasandersone7caaa9b2017-03-29 19:22:53210 r'\bNULL\b',
211 (
212 'New code should not use NULL. Use nullptr instead.',
213 ),
214 True,
215 (),
216 ),
217 (
[email protected]23e6cbc2012-06-16 18:51:20218 'FRIEND_TEST(',
219 (
[email protected]e3c945502012-06-26 20:01:49220 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20221 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
222 ),
223 False,
[email protected]7345da02012-11-27 14:31:49224 (),
[email protected]23e6cbc2012-06-16 18:51:20225 ),
226 (
thomasanderson4b569052016-09-14 20:15:53227 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
228 (
229 'Chrome clients wishing to select events on X windows should use',
230 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
231 'you are selecting events from the GPU process, or if you are using',
232 'an XDisplay other than gfx::GetXDisplay().',
233 ),
234 True,
235 (
236 r"^ui[\\\/]gl[\\\/].*\.cc$",
237 r"^media[\\\/]gpu[\\\/].*\.cc$",
238 r"^gpu[\\\/].*\.cc$",
239 ),
240 ),
241 (
thomasandersone043e3ce2017-06-08 00:43:20242 r'XInternAtom|xcb_intern_atom',
243 (
thomasanderson11aa41d2017-06-08 22:22:38244 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20245 ),
246 True,
247 (
thomasanderson11aa41d2017-06-08 22:22:38248 r"^gpu[\\\/]ipc[\\\/]service[\\\/]gpu_watchdog_thread\.cc$",
249 r"^remoting[\\\/]host[\\\/]linux[\\\/]x_server_clipboard\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20250 r"^ui[\\\/]gfx[\\\/]x[\\\/]x11_atom_cache\.cc$",
251 ),
252 ),
253 (
tomhudsone2c14d552016-05-26 17:07:46254 'setMatrixClip',
255 (
256 'Overriding setMatrixClip() is prohibited; ',
257 'the base function is deprecated. ',
258 ),
259 True,
260 (),
261 ),
262 (
[email protected]52657f62013-05-20 05:30:31263 'SkRefPtr',
264 (
265 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22266 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31267 ),
268 True,
269 (),
270 ),
271 (
272 'SkAutoRef',
273 (
274 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22275 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31276 ),
277 True,
278 (),
279 ),
280 (
281 'SkAutoTUnref',
282 (
283 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22284 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31285 ),
286 True,
287 (),
288 ),
289 (
290 'SkAutoUnref',
291 (
292 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
293 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22294 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31295 ),
296 True,
297 (),
298 ),
[email protected]d89eec82013-12-03 14:10:59299 (
300 r'/HANDLE_EINTR\(.*close',
301 (
302 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
303 'descriptor will be closed, and it is incorrect to retry the close.',
304 'Either call close directly and ignore its return value, or wrap close',
305 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
306 ),
307 True,
308 (),
309 ),
310 (
311 r'/IGNORE_EINTR\((?!.*close)',
312 (
313 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
314 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
315 ),
316 True,
317 (
318 # Files that #define IGNORE_EINTR.
319 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
320 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
321 ),
322 ),
[email protected]ec5b3f02014-04-04 18:43:43323 (
324 r'/v8::Extension\(',
325 (
326 'Do not introduce new v8::Extensions into the code base, use',
327 'gin::Wrappable instead. See http://crbug.com/334679',
328 ),
329 True,
[email protected]f55c90ee62014-04-12 00:50:03330 (
joaodasilva718f87672014-08-30 09:25:49331 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03332 ),
[email protected]ec5b3f02014-04-04 18:43:43333 ),
skyostilf9469f72015-04-20 10:38:52334 (
jame2d1a952016-04-02 00:27:10335 '#pragma comment(lib,',
336 (
337 'Specify libraries to link with in build files and not in the source.',
338 ),
339 True,
340 (),
341 ),
fdorayc4ac18d2017-05-01 21:39:59342 (
gabd52c912a2017-05-11 04:15:59343 'base::SequenceChecker',
344 (
345 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
346 ),
347 False,
348 (),
349 ),
350 (
351 'base::ThreadChecker',
352 (
353 'Consider using THREAD_CHECKER macros instead of the class directly.',
354 ),
355 False,
356 (),
357 ),
dbeamb6f4fde2017-06-15 04:03:06358 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06359 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
360 (
361 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
362 'deprecated (http://crbug.com/634507). Please avoid converting away',
363 'from the Time types in Chromium code, especially if any math is',
364 'being done on time values. For interfacing with platform/library',
365 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
366 'type converter methods instead. For faking TimeXXX values (for unit',
367 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
368 'other use cases, please contact base/time/OWNERS.',
369 ),
370 False,
371 (),
372 ),
373 (
dbeamb6f4fde2017-06-15 04:03:06374 'CallJavascriptFunctionUnsafe',
375 (
376 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
377 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
378 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
379 ),
380 False,
381 (
382 r'^content[\\\/]browser[\\\/]webui[\\\/]web_ui_impl\.(cc|h)$',
383 r'^content[\\\/]public[\\\/]browser[\\\/]web_ui\.h$',
384 r'^content[\\\/]public[\\\/]test[\\\/]test_web_ui\.(cc|h)$',
385 ),
386 ),
dskiba1474c2bfd62017-07-20 02:19:24387 (
388 'leveldb::DB::Open',
389 (
390 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
391 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
392 "Chrome's tracing, making their memory usage visible.",
393 ),
394 True,
395 (
396 r'^third_party/leveldatabase/.*\.(cc|h)$',
397 ),
Gabriel Charette0592c3a2017-07-26 12:02:04398 ),
399 (
Chris Mumfordc38afb62017-10-09 17:55:08400 'leveldb::NewMemEnv',
401 (
402 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
403 'third_party/leveldatabase/leveldb_chrome.h.',
404 ),
405 True,
406 (
407 r'^third_party/leveldatabase/.*\.(cc|h)$',
408 ),
409 ),
410 (
Gabriel Charetted9839bc2017-07-29 14:17:47411 'MessageLoop::QuitWhenIdleClosure',
Gabriel Charette0592c3a2017-07-26 12:02:04412 (
Peter Kasting9e7ccfa52018-02-06 00:01:20413 'MessageLoop::QuitWhenIdleClosure is deprecated. Please use a',
414 'QuitWhenIdleClosure obtained from a specific RunLoop instance.',
Gabriel Charette0592c3a2017-07-26 12:02:04415 ),
Peter Kasting9e7ccfa52018-02-06 00:01:20416 False,
Gabriel Charette0592c3a2017-07-26 12:02:04417 (),
Gabriel Charetted9839bc2017-07-29 14:17:47418 ),
419 (
420 'RunLoop::QuitCurrent',
421 (
Robert Liao64b7ab22017-08-04 23:03:43422 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
423 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47424 ),
425 True,
426 (),
Gabriel Charettea44975052017-08-21 23:14:04427 ),
428 (
429 'base::ScopedMockTimeMessageLoopTaskRunner',
430 (
431 'ScopedMockTimeMessageLoopTaskRunner is deprecated.',
432 ),
433 True,
434 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57435 ),
436 (
437 r'std::regex',
438 (
439 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02440 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57441 ),
442 True,
443 (),
Francois Doray43670e32017-09-27 12:40:38444 ),
445 (
446 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
447 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
448 (
449 'Use the new API in base/threading/thread_restrictions.h.',
450 ),
451 True,
452 (),
453 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38454 (
455 r'/\bbase::Bind\(',
456 (
Gabriel Charette147335ea2018-03-22 15:59:19457 'Please consider using base::Bind{Once,Repeating} instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02458 'of base::Bind. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38459 ),
460 False,
461 (),
462 ),
463 (
464 r'/\bbase::Callback<',
465 (
Gabriel Charette147335ea2018-03-22 15:59:19466 'Please consider using base::{Once,Repeating}Callback instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02467 'of base::Callback. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38468 ),
469 False,
470 (),
471 ),
472 (
473 r'/\bbase::Closure\b',
474 (
Gabriel Charette147335ea2018-03-22 15:59:19475 'Please consider using base::{Once,Repeating}Closure instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02476 'of base::Closure. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38477 ),
478 False,
479 (),
480 ),
Victor Costan3653df62018-02-08 21:38:16481 (
Gabriel Charette147335ea2018-03-22 15:59:19482 r'RunMessageLoop',
483 (
484 'RunMessageLoop is deprecated, use RunLoop instead.',
485 ),
486 False,
487 (),
488 ),
489 (
490 r'RunThisRunLoop',
491 (
492 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
493 ),
494 False,
495 (),
496 ),
497 (
498 r'RunAllPendingInMessageLoop()',
499 (
500 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
501 "if you're convinced you need this.",
502 ),
503 False,
504 (),
505 ),
506 (
507 r'RunAllPendingInMessageLoop(BrowserThread',
508 (
509 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
510 'BrowserThread::UI, TestBrowserThreadBundle::RunIOThreadUntilIdle',
511 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
512 'async events instead of flushing threads.',
513 ),
514 False,
515 (),
516 ),
517 (
518 r'MessageLoopRunner',
519 (
520 'MessageLoopRunner is deprecated, use RunLoop instead.',
521 ),
522 False,
523 (),
524 ),
525 (
526 r'GetDeferredQuitTaskForRunLoop',
527 (
528 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
529 "gab@ if you found a use case where this is the only solution.",
530 ),
531 False,
532 (),
533 ),
534 (
Victor Costan3653df62018-02-08 21:38:16535 'sqlite3_initialize',
536 (
537 'Instead of sqlite3_initialize, depend on //sql, ',
538 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
539 ),
540 True,
541 (
542 r'^sql/initialization\.(cc|h)$',
543 r'^third_party/sqlite/.*\.(c|cc|h)$',
544 ),
545 ),
[email protected]127f18ec2012-06-16 05:05:59546)
547
wnwenbdc444e2016-05-25 13:44:15548
mlamouria82272622014-09-16 18:45:04549_IPC_ENUM_TRAITS_DEPRECATED = (
550 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50551 'See http://www.chromium.org/Home/chromium-security/education/'
552 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:04553
Shenghua Zhangbfaa38b82017-11-16 21:58:02554_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
555 r".*[\\\/]BuildHooksAndroidImpl\.java",
556 r".*[\\\/]LicenseContentProvider\.java",
557]
[email protected]127f18ec2012-06-16 05:05:59558
Sean Kau46e29bc2017-08-28 16:31:16559# These paths contain test data and other known invalid JSON files.
560_KNOWN_INVALID_JSON_FILE_PATTERNS = [
561 r'test[\\\/]data[\\\/]',
562 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
563 r'^third_party[\\\/]protobuf[\\\/]',
Raphael Kubo da Costa211f3b472017-11-16 00:27:16564 r'^third_party[\\\/]WebKit[\\\/]LayoutTests[\\\/]external[\\\/]wpt[\\\/]',
Sean Kau46e29bc2017-08-28 16:31:16565]
566
567
[email protected]b00342e7f2013-03-26 16:21:54568_VALID_OS_MACROS = (
569 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08570 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54571 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:12572 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:54573 'OS_BSD',
574 'OS_CAT', # For testing.
575 'OS_CHROMEOS',
576 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37577 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54578 'OS_IOS',
579 'OS_LINUX',
580 'OS_MACOSX',
581 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21582 'OS_NACL_NONSFI',
583 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12584 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54585 'OS_OPENBSD',
586 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37587 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54588 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54589 'OS_WIN',
590)
591
592
agrievef32bcc72016-04-04 14:57:40593_ANDROID_SPECIFIC_PYDEPS_FILES = [
594 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04595 'build/android/test_wrapper/logdog_wrapper.pydeps',
jbudorick276cc562017-04-29 01:34:58596 'build/secondary/third_party/android_platform/'
597 'development/scripts/stack.pydeps',
agrieve732db3a2016-04-26 19:18:19598 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40599]
600
wnwenbdc444e2016-05-25 13:44:15601
agrievef32bcc72016-04-04 14:57:40602_GENERIC_PYDEPS_FILES = [
John Chencde89192018-01-27 21:18:40603 'chrome/test/chromedriver/test/run_py_tests.pydeps',
agrievef32bcc72016-04-04 14:57:40604]
605
wnwenbdc444e2016-05-25 13:44:15606
agrievef32bcc72016-04-04 14:57:40607_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
608
609
Eric Boren6fd2b932018-01-25 15:05:08610# Bypass the AUTHORS check for these accounts.
611_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:29612 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
613 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
614 'fuchsia-sdk', 'nacl', 'pdfium', 'skia', 'src-internal', 'webrtc')
615 ) | set('%[email protected]' % s for s in ('findit-for-me',))
Eric Boren6fd2b932018-01-25 15:05:08616
617
[email protected]55459852011-08-10 15:17:19618def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
619 """Attempts to prevent use of functions intended only for testing in
620 non-testing code. For now this is just a best-effort implementation
621 that ignores header files and may have some false positives. A
622 better implementation would probably need a proper C++ parser.
623 """
624 # We only scan .cc files and the like, as the declaration of
625 # for-testing functions in header files are hard to distinguish from
626 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44627 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19628
jochenc0d4808c2015-07-27 09:25:42629 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19630 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09631 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19632 exclusion_pattern = input_api.re.compile(
633 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
634 base_function_pattern, base_function_pattern))
635
636 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44637 black_list = (_EXCLUDED_PATHS +
638 _TEST_CODE_EXCLUDED_PATHS +
639 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19640 return input_api.FilterSourceFile(
641 affected_file,
642 white_list=(file_inclusion_pattern, ),
643 black_list=black_list)
644
645 problems = []
646 for f in input_api.AffectedSourceFiles(FilterFile):
647 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24648 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03649 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46650 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03651 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19652 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03653 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19654
655 if problems:
[email protected]f7051d52013-04-02 18:31:42656 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03657 else:
658 return []
[email protected]55459852011-08-10 15:17:19659
660
[email protected]10689ca2011-09-02 02:31:54661def _CheckNoIOStreamInHeaders(input_api, output_api):
662 """Checks to make sure no .h files include <iostream>."""
663 files = []
664 pattern = input_api.re.compile(r'^#include\s*<iostream>',
665 input_api.re.MULTILINE)
666 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
667 if not f.LocalPath().endswith('.h'):
668 continue
669 contents = input_api.ReadFile(f)
670 if pattern.search(contents):
671 files.append(f)
672
673 if len(files):
yolandyandaabc6d2016-04-18 18:29:39674 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06675 'Do not #include <iostream> in header files, since it inserts static '
676 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54677 '#include <ostream>. See http://crbug.com/94794',
678 files) ]
679 return []
680
681
[email protected]72df4e782012-06-21 16:28:18682def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52683 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18684 problems = []
685 for f in input_api.AffectedFiles():
686 if (not f.LocalPath().endswith(('.cc', '.mm'))):
687 continue
688
689 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04690 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18691 problems.append(' %s:%d' % (f.LocalPath(), line_num))
692
693 if not problems:
694 return []
695 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
696 '\n'.join(problems))]
697
698
danakj61c1aa22015-10-26 19:55:52699def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57700 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52701 errors = []
702 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
703 input_api.re.MULTILINE)
704 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
705 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
706 continue
707 for lnum, line in f.ChangedContents():
708 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17709 errors.append(output_api.PresubmitError(
710 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57711 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17712 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52713 return errors
714
715
mcasasb7440c282015-02-04 14:52:19716def _FindHistogramNameInLine(histogram_name, line):
717 """Tries to find a histogram name or prefix in a line."""
718 if not "affected-histogram" in line:
719 return histogram_name in line
720 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
721 # the histogram_name.
722 if not '"' in line:
723 return False
724 histogram_prefix = line.split('\"')[1]
725 return histogram_prefix in histogram_name
726
727
728def _CheckUmaHistogramChanges(input_api, output_api):
729 """Check that UMA histogram names in touched lines can still be found in other
730 lines of the patch or in histograms.xml. Note that this check would not catch
731 the reverse: changes in histograms.xml not matched in the code itself."""
732 touched_histograms = []
733 histograms_xml_modifications = []
Vaclav Brozek8a8e2e202018-03-23 22:01:06734 # For now, the check only detects the case of the macro and histogram names
735 # being on a single line.
736 single_line_re = input_api.re.compile(r'\bUMA_HISTOGRAM.*\("(.*?)"')
mcasasb7440c282015-02-04 14:52:19737 for f in input_api.AffectedFiles():
738 # If histograms.xml itself is modified, keep the modified lines for later.
739 if f.LocalPath().endswith(('histograms.xml')):
740 histograms_xml_modifications = f.ChangedContents()
741 continue
742 if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
743 continue
744 for line_num, line in f.ChangedContents():
Vaclav Brozek8a8e2e202018-03-23 22:01:06745 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:19746 if found:
747 touched_histograms.append([found.group(1), f, line_num])
748
749 # Search for the touched histogram names in the local modifications to
750 # histograms.xml, and, if not found, on the base histograms.xml file.
751 unmatched_histograms = []
752 for histogram_info in touched_histograms:
753 histogram_name_found = False
754 for line_num, line in histograms_xml_modifications:
755 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
756 if histogram_name_found:
757 break
758 if not histogram_name_found:
759 unmatched_histograms.append(histogram_info)
760
eromanb90c82e7e32015-04-01 15:13:49761 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19762 problems = []
763 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49764 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19765 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45766 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19767 histogram_name_found = False
768 for line in histograms_xml:
769 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
770 if histogram_name_found:
771 break
772 if not histogram_name_found:
773 problems.append(' [%s:%d] %s' %
774 (f.LocalPath(), line_num, histogram_name))
775
776 if not problems:
777 return []
778 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
779 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49780 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19781
wnwenbdc444e2016-05-25 13:44:15782
yolandyandaabc6d2016-04-18 18:29:39783def _CheckFlakyTestUsage(input_api, output_api):
784 """Check that FlakyTest annotation is our own instead of the android one"""
785 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
786 files = []
787 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
788 if f.LocalPath().endswith('Test.java'):
789 if pattern.search(input_api.ReadFile(f)):
790 files.append(f)
791 if len(files):
792 return [output_api.PresubmitError(
793 'Use org.chromium.base.test.util.FlakyTest instead of '
794 'android.test.FlakyTest',
795 files)]
796 return []
mcasasb7440c282015-02-04 14:52:19797
wnwenbdc444e2016-05-25 13:44:15798
[email protected]8ea5d4b2011-09-13 21:49:22799def _CheckNoNewWStrings(input_api, output_api):
800 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27801 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22802 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20803 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57804 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34805 '/win/' in f.LocalPath() or
806 'chrome_elf' in f.LocalPath() or
807 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20808 continue
[email protected]8ea5d4b2011-09-13 21:49:22809
[email protected]a11dbe9b2012-08-07 01:32:58810 allowWString = False
[email protected]b5c24292011-11-28 14:38:20811 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58812 if 'presubmit: allow wstring' in line:
813 allowWString = True
814 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27815 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58816 allowWString = False
817 else:
818 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22819
[email protected]55463aa62011-10-12 00:48:27820 if not problems:
821 return []
822 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58823 ' If you are calling a cross-platform API that accepts a wstring, '
824 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27825 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22826
827
[email protected]2a8ac9c2011-10-19 17:20:44828def _CheckNoDEPSGIT(input_api, output_api):
829 """Make sure .DEPS.git is never modified manually."""
830 if any(f.LocalPath().endswith('.DEPS.git') for f in
831 input_api.AffectedFiles()):
832 return [output_api.PresubmitError(
833 'Never commit changes to .DEPS.git. This file is maintained by an\n'
834 'automated system based on what\'s in DEPS and your changes will be\n'
835 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50836 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
837 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:44838 'for more information')]
839 return []
840
841
tandriief664692014-09-23 14:51:47842def _CheckValidHostsInDEPS(input_api, output_api):
843 """Checks that DEPS file deps are from allowed_hosts."""
844 # Run only if DEPS file has been modified to annoy fewer bystanders.
845 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
846 return []
847 # Outsource work to gclient verify
848 try:
849 input_api.subprocess.check_output(['gclient', 'verify'])
850 return []
851 except input_api.subprocess.CalledProcessError, error:
852 return [output_api.PresubmitError(
853 'DEPS file must have only git dependencies.',
854 long_text=error.output)]
855
856
[email protected]127f18ec2012-06-16 05:05:59857def _CheckNoBannedFunctions(input_api, output_api):
858 """Make sure that banned functions are not used."""
859 warnings = []
860 errors = []
861
wnwenbdc444e2016-05-25 13:44:15862 def IsBlacklisted(affected_file, blacklist):
863 local_path = affected_file.LocalPath()
864 for item in blacklist:
865 if input_api.re.match(item, local_path):
866 return True
867 return False
868
Sylvain Defresnea8b73d252018-02-28 15:45:54869 def IsIosObcjFile(affected_file):
870 local_path = affected_file.LocalPath()
871 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
872 return False
873 basename = input_api.os_path.basename(local_path)
874 if 'ios' in basename.split('_'):
875 return True
876 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
877 if sep and 'ios' in local_path.split(sep):
878 return True
879 return False
880
wnwenbdc444e2016-05-25 13:44:15881 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
882 matched = False
883 if func_name[0:1] == '/':
884 regex = func_name[1:]
885 if input_api.re.search(regex, line):
886 matched = True
887 elif func_name in line:
dchenge07de812016-06-20 19:27:17888 matched = True
wnwenbdc444e2016-05-25 13:44:15889 if matched:
dchenge07de812016-06-20 19:27:17890 problems = warnings
wnwenbdc444e2016-05-25 13:44:15891 if error:
dchenge07de812016-06-20 19:27:17892 problems = errors
wnwenbdc444e2016-05-25 13:44:15893 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
894 for message_line in message:
895 problems.append(' %s' % message_line)
896
Eric Stevensona9a980972017-09-23 00:04:41897 file_filter = lambda f: f.LocalPath().endswith(('.java'))
898 for f in input_api.AffectedFiles(file_filter=file_filter):
899 for line_num, line in f.ChangedContents():
900 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
901 CheckForMatch(f, line_num, line, func_name, message, error)
902
[email protected]127f18ec2012-06-16 05:05:59903 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
904 for f in input_api.AffectedFiles(file_filter=file_filter):
905 for line_num, line in f.ChangedContents():
906 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:15907 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59908
Sylvain Defresnea8b73d252018-02-28 15:45:54909 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
910 for line_num, line in f.ChangedContents():
911 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
912 CheckForMatch(f, line_num, line, func_name, message, error)
913
[email protected]127f18ec2012-06-16 05:05:59914 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
915 for f in input_api.AffectedFiles(file_filter=file_filter):
916 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:49917 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:49918 if IsBlacklisted(f, excluded_paths):
919 continue
wnwenbdc444e2016-05-25 13:44:15920 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:59921
922 result = []
923 if (warnings):
924 result.append(output_api.PresubmitPromptWarning(
925 'Banned functions were used.\n' + '\n'.join(warnings)))
926 if (errors):
927 result.append(output_api.PresubmitError(
928 'Banned functions were used.\n' + '\n'.join(errors)))
929 return result
930
931
[email protected]6c063c62012-07-11 19:11:06932def _CheckNoPragmaOnce(input_api, output_api):
933 """Make sure that banned functions are not used."""
934 files = []
935 pattern = input_api.re.compile(r'^#pragma\s+once',
936 input_api.re.MULTILINE)
937 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
938 if not f.LocalPath().endswith('.h'):
939 continue
940 contents = input_api.ReadFile(f)
941 if pattern.search(contents):
942 files.append(f)
943
944 if files:
945 return [output_api.PresubmitError(
946 'Do not use #pragma once in header files.\n'
947 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
948 files)]
949 return []
950
[email protected]127f18ec2012-06-16 05:05:59951
[email protected]e7479052012-09-19 00:26:12952def _CheckNoTrinaryTrueFalse(input_api, output_api):
953 """Checks to make sure we don't introduce use of foo ? true : false."""
954 problems = []
955 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
956 for f in input_api.AffectedFiles():
957 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
958 continue
959
960 for line_num, line in f.ChangedContents():
961 if pattern.match(line):
962 problems.append(' %s:%d' % (f.LocalPath(), line_num))
963
964 if not problems:
965 return []
966 return [output_api.PresubmitPromptWarning(
967 'Please consider avoiding the "? true : false" pattern if possible.\n' +
968 '\n'.join(problems))]
969
970
[email protected]55f9f382012-07-31 11:02:18971def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:28972 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:18973 change. Breaking - rules is an error, breaking ! rules is a
974 warning.
975 """
mohan.reddyf21db962014-10-16 12:26:47976 import sys
[email protected]55f9f382012-07-31 11:02:18977 # We need to wait until we have an input_api object and use this
978 # roundabout construct to import checkdeps because this file is
979 # eval-ed and thus doesn't have __file__.
980 original_sys_path = sys.path
981 try:
982 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:47983 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:18984 import checkdeps
985 from cpp_checker import CppChecker
Jinsuk Kim5a092672017-10-24 22:42:24986 from java_checker import JavaChecker
rhalavati08acd232017-04-03 07:23:28987 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:18988 from rules import Rule
989 finally:
990 # Restore sys.path to what it was before.
991 sys.path = original_sys_path
992
993 added_includes = []
rhalavati08acd232017-04-03 07:23:28994 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:24995 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:18996 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:28997 if CppChecker.IsCppFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:50998 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:08999 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
rhalavati08acd232017-04-03 07:23:281000 elif ProtoChecker.IsProtoFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501001 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081002 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241003 elif JavaChecker.IsJavaFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501004 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081005 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181006
[email protected]26385172013-05-09 23:11:351007 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181008
1009 error_descriptions = []
1010 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281011 error_subjects = set()
1012 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181013 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1014 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081015 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181016 description_with_path = '%s\n %s' % (path, rule_description)
1017 if rule_type == Rule.DISALLOW:
1018 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281019 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181020 else:
1021 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281022 warning_subjects.add("#includes")
1023
1024 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1025 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081026 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281027 description_with_path = '%s\n %s' % (path, rule_description)
1028 if rule_type == Rule.DISALLOW:
1029 error_descriptions.append(description_with_path)
1030 error_subjects.add("imports")
1031 else:
1032 warning_descriptions.append(description_with_path)
1033 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181034
Jinsuk Kim5a092672017-10-24 22:42:241035 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021036 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081037 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241038 description_with_path = '%s\n %s' % (path, rule_description)
1039 if rule_type == Rule.DISALLOW:
1040 error_descriptions.append(description_with_path)
1041 error_subjects.add("imports")
1042 else:
1043 warning_descriptions.append(description_with_path)
1044 warning_subjects.add("imports")
1045
[email protected]55f9f382012-07-31 11:02:181046 results = []
1047 if error_descriptions:
1048 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281049 'You added one or more %s that violate checkdeps rules.'
1050 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181051 error_descriptions))
1052 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421053 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281054 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181055 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281056 '%s? See relevant DEPS file(s) for details and contacts.' %
1057 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181058 warning_descriptions))
1059 return results
1060
1061
[email protected]fbcafe5a2012-08-08 15:31:221062def _CheckFilePermissions(input_api, output_api):
1063 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151064 if input_api.platform == 'win32':
1065 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291066 checkperms_tool = input_api.os_path.join(
1067 input_api.PresubmitLocalPath(),
1068 'tools', 'checkperms', 'checkperms.py')
1069 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471070 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391071 with input_api.CreateTemporaryFile() as file_list:
1072 for f in input_api.AffectedFiles():
1073 # checkperms.py file/directory arguments must be relative to the
1074 # repository.
1075 file_list.write(f.LocalPath() + '\n')
1076 file_list.close()
1077 args += ['--file-list', file_list.name]
1078 try:
1079 input_api.subprocess.check_output(args)
1080 return []
1081 except input_api.subprocess.CalledProcessError as error:
1082 return [output_api.PresubmitError(
1083 'checkperms.py failed:',
1084 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221085
1086
robertocn832f5992017-01-04 19:01:301087def _CheckTeamTags(input_api, output_api):
1088 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1089 checkteamtags_tool = input_api.os_path.join(
1090 input_api.PresubmitLocalPath(),
1091 'tools', 'checkteamtags', 'checkteamtags.py')
1092 args = [input_api.python_executable, checkteamtags_tool,
1093 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221094 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301095 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1096 'OWNERS']
1097 try:
1098 if files:
1099 input_api.subprocess.check_output(args + files)
1100 return []
1101 except input_api.subprocess.CalledProcessError as error:
1102 return [output_api.PresubmitError(
1103 'checkteamtags.py failed:',
1104 long_text=error.output)]
1105
1106
[email protected]c8278b32012-10-30 20:35:491107def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1108 """Makes sure we don't include ui/aura/window_property.h
1109 in header files.
1110 """
1111 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1112 errors = []
1113 for f in input_api.AffectedFiles():
1114 if not f.LocalPath().endswith('.h'):
1115 continue
1116 for line_num, line in f.ChangedContents():
1117 if pattern.match(line):
1118 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1119
1120 results = []
1121 if errors:
1122 results.append(output_api.PresubmitError(
1123 'Header files should not include ui/aura/window_property.h', errors))
1124 return results
1125
1126
[email protected]70ca77752012-11-20 03:45:031127def _CheckForVersionControlConflictsInFile(input_api, f):
1128 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1129 errors = []
1130 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:231131 if f.LocalPath().endswith('.md'):
1132 # First-level headers in markdown look a lot like version control
1133 # conflict markers. http://daringfireball.net/projects/markdown/basics
1134 continue
[email protected]70ca77752012-11-20 03:45:031135 if pattern.match(line):
1136 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1137 return errors
1138
1139
1140def _CheckForVersionControlConflicts(input_api, output_api):
1141 """Usually this is not intentional and will cause a compile failure."""
1142 errors = []
1143 for f in input_api.AffectedFiles():
1144 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1145
1146 results = []
1147 if errors:
1148 results.append(output_api.PresubmitError(
1149 'Version control conflict markers found, please resolve.', errors))
1150 return results
1151
estadee17314a02017-01-12 16:22:161152def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1153 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1154 errors = []
1155 for f in input_api.AffectedFiles():
1156 for line_num, line in f.ChangedContents():
1157 if pattern.search(line):
1158 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1159
1160 results = []
1161 if errors:
1162 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501163 'Found Google support URL addressed by answer number. Please replace '
1164 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161165 return results
1166
[email protected]70ca77752012-11-20 03:45:031167
[email protected]06e6d0ff2012-12-11 01:36:441168def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1169 def FilterFile(affected_file):
1170 """Filter function for use with input_api.AffectedSourceFiles,
1171 below. This filters out everything except non-test files from
1172 top-level directories that generally speaking should not hard-code
1173 service URLs (e.g. src/android_webview/, src/content/ and others).
1174 """
1175 return input_api.FilterSourceFile(
1176 affected_file,
[email protected]78bb39d62012-12-11 15:11:561177 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:441178 black_list=(_EXCLUDED_PATHS +
1179 _TEST_CODE_EXCLUDED_PATHS +
1180 input_api.DEFAULT_BLACK_LIST))
1181
reillyi38965732015-11-16 18:27:331182 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1183 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461184 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1185 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441186 problems = [] # items are (filename, line_number, line)
1187 for f in input_api.AffectedSourceFiles(FilterFile):
1188 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461189 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441190 problems.append((f.LocalPath(), line_num, line))
1191
1192 if problems:
[email protected]f7051d52013-04-02 18:31:421193 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441194 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581195 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441196 [' %s:%d: %s' % (
1197 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031198 else:
1199 return []
[email protected]06e6d0ff2012-12-11 01:36:441200
1201
[email protected]d2530012013-01-25 16:39:271202def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1203 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311204 The native_client_sdk directory is excluded because it has auto-generated PNG
1205 files for documentation.
[email protected]d2530012013-01-25 16:39:271206 """
[email protected]d2530012013-01-25 16:39:271207 errors = []
binji0dcdf342014-12-12 18:32:311208 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
1209 black_list = (r'^native_client_sdk[\\\/]',)
1210 file_filter = lambda f: input_api.FilterSourceFile(
1211 f, white_list=white_list, black_list=black_list)
1212 for f in input_api.AffectedFiles(include_deletes=False,
1213 file_filter=file_filter):
1214 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271215
1216 results = []
1217 if errors:
1218 results.append(output_api.PresubmitError(
1219 'The name of PNG files should not have abbreviations. \n'
1220 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1221 'Contact [email protected] if you have questions.', errors))
1222 return results
1223
1224
Daniel Cheng4dcdb6b2017-04-13 08:30:171225def _ExtractAddRulesFromParsedDeps(parsed_deps):
1226 """Extract the rules that add dependencies from a parsed DEPS file.
1227
1228 Args:
1229 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1230 add_rules = set()
1231 add_rules.update([
1232 rule[1:] for rule in parsed_deps.get('include_rules', [])
1233 if rule.startswith('+') or rule.startswith('!')
1234 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501235 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171236 {}).iteritems():
1237 add_rules.update([
1238 rule[1:] for rule in rules
1239 if rule.startswith('+') or rule.startswith('!')
1240 ])
1241 return add_rules
1242
1243
1244def _ParseDeps(contents):
1245 """Simple helper for parsing DEPS files."""
1246 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171247 class _VarImpl:
1248
1249 def __init__(self, local_scope):
1250 self._local_scope = local_scope
1251
1252 def Lookup(self, var_name):
1253 """Implements the Var syntax."""
1254 try:
1255 return self._local_scope['vars'][var_name]
1256 except KeyError:
1257 raise Exception('Var is not defined: %s' % var_name)
1258
1259 local_scope = {}
1260 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171261 'Var': _VarImpl(local_scope).Lookup,
1262 }
1263 exec contents in global_scope, local_scope
1264 return local_scope
1265
1266
1267def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081268 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411269 a set of DEPS entries that we should look up.
1270
1271 For a directory (rather than a specific filename) we fake a path to
1272 a specific filename by adding /DEPS. This is chosen as a file that
1273 will seldom or never be subject to per-file include_rules.
1274 """
[email protected]2b438d62013-11-14 17:54:141275 # We ignore deps entries on auto-generated directories.
1276 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081277
Daniel Cheng4dcdb6b2017-04-13 08:30:171278 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1279 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1280
1281 added_deps = new_deps.difference(old_deps)
1282
[email protected]2b438d62013-11-14 17:54:141283 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171284 for added_dep in added_deps:
1285 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1286 continue
1287 # Assume that a rule that ends in .h is a rule for a specific file.
1288 if added_dep.endswith('.h'):
1289 results.add(added_dep)
1290 else:
1291 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081292 return results
1293
1294
[email protected]e871964c2013-05-13 14:14:551295def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1296 """When a dependency prefixed with + is added to a DEPS file, we
1297 want to make sure that the change is reviewed by an OWNER of the
1298 target file or directory, to avoid layering violations from being
1299 introduced. This check verifies that this happens.
1300 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171301 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241302
1303 file_filter = lambda f: not input_api.re.match(
Kent Tamurae9b3a9ec2017-08-31 02:20:191304 r"^third_party[\\\/](WebKit|blink)[\\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241305 for f in input_api.AffectedFiles(include_deletes=False,
1306 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551307 filename = input_api.os_path.basename(f.LocalPath())
1308 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171309 virtual_depended_on_files.update(_CalculateAddedDeps(
1310 input_api.os_path,
1311 '\n'.join(f.OldContents()),
1312 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551313
[email protected]e871964c2013-05-13 14:14:551314 if not virtual_depended_on_files:
1315 return []
1316
1317 if input_api.is_committing:
1318 if input_api.tbr:
1319 return [output_api.PresubmitNotifyResult(
1320 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271321 if input_api.dry_run:
1322 return [output_api.PresubmitNotifyResult(
1323 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551324 if not input_api.change.issue:
1325 return [output_api.PresubmitError(
1326 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401327 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551328 output = output_api.PresubmitError
1329 else:
1330 output = output_api.PresubmitNotifyResult
1331
1332 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501333 owner_email, reviewers = (
1334 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1335 input_api,
1336 owners_db.email_regexp,
1337 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551338
1339 owner_email = owner_email or input_api.change.author_email
1340
[email protected]de4f7d22013-05-23 14:27:461341 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511342 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461343 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551344 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1345 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411346
1347 # We strip the /DEPS part that was added by
1348 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1349 # directory.
1350 def StripDeps(path):
1351 start_deps = path.rfind('/DEPS')
1352 if start_deps != -1:
1353 return path[:start_deps]
1354 else:
1355 return path
1356 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551357 for path in missing_files]
1358
1359 if unapproved_dependencies:
1360 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151361 output('You need LGTM from owners of depends-on paths in DEPS that were '
1362 'modified in this CL:\n %s' %
1363 '\n '.join(sorted(unapproved_dependencies)))]
1364 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1365 output_list.append(output(
1366 'Suggested missing target path OWNERS:\n %s' %
1367 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551368 return output_list
1369
1370 return []
1371
1372
[email protected]85218562013-11-22 07:41:401373def _CheckSpamLogging(input_api, output_api):
1374 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1375 black_list = (_EXCLUDED_PATHS +
1376 _TEST_CODE_EXCLUDED_PATHS +
1377 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501378 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191379 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481380 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461381 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121382 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1383 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581384 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161385 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031386 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151387 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1388 r"^chromecast[\\\/]",
1389 r"^cloud_print[\\\/]",
manzagop85e629e2017-05-09 22:11:481390 r"^components[\\\/]browser_watcher[\\\/]"
1391 r"dump_stability_report_main_win.cc$",
jochen34415e52015-07-10 08:34:311392 r"^components[\\\/]html_viewer[\\\/]"
1393 r"web_test_delegate_impl\.cc$",
Samuel Huang577ef6c2018-03-13 18:19:341394 r"^components[\\\/]zucchini[\\\/].*",
peter80739bb2015-10-20 11:17:461395 # TODO(peter): Remove this exception. https://crbug.com/534537
1396 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1397 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251398 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1399 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241400 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111401 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151402 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111403 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521404 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501405 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361406 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311407 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131408 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001409 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441410 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451411 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021412 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351413 r"dump_file_system.cc$",
1414 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401415 source_file_filter = lambda x: input_api.FilterSourceFile(
1416 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1417
thomasanderson625d3932017-03-29 07:16:581418 log_info = set([])
1419 printf = set([])
[email protected]85218562013-11-22 07:41:401420
1421 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581422 for _, line in f.ChangedContents():
1423 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1424 log_info.add(f.LocalPath())
1425 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1426 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371427
thomasanderson625d3932017-03-29 07:16:581428 if input_api.re.search(r"\bprintf\(", line):
1429 printf.add(f.LocalPath())
1430 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1431 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401432
1433 if log_info:
1434 return [output_api.PresubmitError(
1435 'These files spam the console log with LOG(INFO):',
1436 items=log_info)]
1437 if printf:
1438 return [output_api.PresubmitError(
1439 'These files spam the console log with printf/fprintf:',
1440 items=printf)]
1441 return []
1442
1443
[email protected]49aa76a2013-12-04 06:59:161444def _CheckForAnonymousVariables(input_api, output_api):
1445 """These types are all expected to hold locks while in scope and
1446 so should never be anonymous (which causes them to be immediately
1447 destroyed)."""
1448 they_who_must_be_named = [
1449 'base::AutoLock',
1450 'base::AutoReset',
1451 'base::AutoUnlock',
1452 'SkAutoAlphaRestore',
1453 'SkAutoBitmapShaderInstall',
1454 'SkAutoBlitterChoose',
1455 'SkAutoBounderCommit',
1456 'SkAutoCallProc',
1457 'SkAutoCanvasRestore',
1458 'SkAutoCommentBlock',
1459 'SkAutoDescriptor',
1460 'SkAutoDisableDirectionCheck',
1461 'SkAutoDisableOvalCheck',
1462 'SkAutoFree',
1463 'SkAutoGlyphCache',
1464 'SkAutoHDC',
1465 'SkAutoLockColors',
1466 'SkAutoLockPixels',
1467 'SkAutoMalloc',
1468 'SkAutoMaskFreeImage',
1469 'SkAutoMutexAcquire',
1470 'SkAutoPathBoundsUpdate',
1471 'SkAutoPDFRelease',
1472 'SkAutoRasterClipValidate',
1473 'SkAutoRef',
1474 'SkAutoTime',
1475 'SkAutoTrace',
1476 'SkAutoUnref',
1477 ]
1478 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1479 # bad: base::AutoLock(lock.get());
1480 # not bad: base::AutoLock lock(lock.get());
1481 bad_pattern = input_api.re.compile(anonymous)
1482 # good: new base::AutoLock(lock.get())
1483 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1484 errors = []
1485
1486 for f in input_api.AffectedFiles():
1487 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1488 continue
1489 for linenum, line in f.ChangedContents():
1490 if bad_pattern.search(line) and not good_pattern.search(line):
1491 errors.append('%s:%d' % (f.LocalPath(), linenum))
1492
1493 if errors:
1494 return [output_api.PresubmitError(
1495 'These lines create anonymous variables that need to be named:',
1496 items=errors)]
1497 return []
1498
1499
Peter Kasting4844e46e2018-02-23 07:27:101500def _CheckUniquePtr(input_api, output_api):
1501 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1502 sources = lambda affected_file: input_api.FilterSourceFile(
1503 affected_file,
1504 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1505 input_api.DEFAULT_BLACK_LIST),
1506 white_list=(file_inclusion_pattern,))
1507 return_construct_pattern = input_api.re.compile(
1508 r'(=|\breturn)\s*std::unique_ptr<.*?(?<!])>\([^)]+\)')
1509 null_construct_pattern = input_api.re.compile(
1510 r'\b(?<!<)std::unique_ptr<.*?>\(\)')
1511 errors = []
1512 for f in input_api.AffectedSourceFiles(sources):
1513 for line_number, line in f.ChangedContents():
1514 # Disallow:
1515 # return std::unique_ptr<T>(foo);
1516 # bar = std::unique_ptr<T>(foo);
1517 # But allow:
1518 # return std::unique_ptr<T[]>(foo);
1519 # bar = std::unique_ptr<T[]>(foo);
1520 if return_construct_pattern.search(line):
1521 errors.append(output_api.PresubmitError(
1522 ('%s:%d uses explicit std::unique_ptr constructor. ' +
1523 'Use std::make_unique<T>() instead.') %
1524 (f.LocalPath(), line_number)))
1525 # Disallow:
1526 # std::unique_ptr<T>()
1527 if null_construct_pattern.search(line):
1528 errors.append(output_api.PresubmitError(
1529 '%s:%d uses std::unique_ptr<T>(). Use nullptr instead.' %
1530 (f.LocalPath(), line_number)))
1531 return errors
1532
1533
[email protected]999261d2014-03-03 20:08:081534def _CheckUserActionUpdate(input_api, output_api):
1535 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521536 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081537 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521538 # If actions.xml is already included in the changelist, the PRESUBMIT
1539 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081540 return []
1541
[email protected]999261d2014-03-03 20:08:081542 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1543 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521544 current_actions = None
[email protected]999261d2014-03-03 20:08:081545 for f in input_api.AffectedFiles(file_filter=file_filter):
1546 for line_num, line in f.ChangedContents():
1547 match = input_api.re.search(action_re, line)
1548 if match:
[email protected]2f92dec2014-03-07 19:21:521549 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1550 # loaded only once.
1551 if not current_actions:
1552 with open('tools/metrics/actions/actions.xml') as actions_f:
1553 current_actions = actions_f.read()
1554 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081555 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521556 action = 'name="{0}"'.format(action_name)
1557 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081558 return [output_api.PresubmitPromptWarning(
1559 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521560 'tools/metrics/actions/actions.xml. Please run '
1561 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081562 % (f.LocalPath(), line_num, action_name))]
1563 return []
1564
1565
Daniel Cheng13ca61a882017-08-25 15:11:251566def _ImportJSONCommentEater(input_api):
1567 import sys
1568 sys.path = sys.path + [input_api.os_path.join(
1569 input_api.PresubmitLocalPath(),
1570 'tools', 'json_comment_eater')]
1571 import json_comment_eater
1572 return json_comment_eater
1573
1574
[email protected]99171a92014-06-03 08:44:471575def _GetJSONParseError(input_api, filename, eat_comments=True):
1576 try:
1577 contents = input_api.ReadFile(filename)
1578 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:251579 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:131580 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471581
1582 input_api.json.loads(contents)
1583 except ValueError as e:
1584 return e
1585 return None
1586
1587
1588def _GetIDLParseError(input_api, filename):
1589 try:
1590 contents = input_api.ReadFile(filename)
1591 idl_schema = input_api.os_path.join(
1592 input_api.PresubmitLocalPath(),
1593 'tools', 'json_schema_compiler', 'idl_schema.py')
1594 process = input_api.subprocess.Popen(
1595 [input_api.python_executable, idl_schema],
1596 stdin=input_api.subprocess.PIPE,
1597 stdout=input_api.subprocess.PIPE,
1598 stderr=input_api.subprocess.PIPE,
1599 universal_newlines=True)
1600 (_, error) = process.communicate(input=contents)
1601 return error or None
1602 except ValueError as e:
1603 return e
1604
1605
1606def _CheckParseErrors(input_api, output_api):
1607 """Check that IDL and JSON files do not contain syntax errors."""
1608 actions = {
1609 '.idl': _GetIDLParseError,
1610 '.json': _GetJSONParseError,
1611 }
[email protected]99171a92014-06-03 08:44:471612 # Most JSON files are preprocessed and support comments, but these do not.
1613 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491614 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471615 ]
1616 # Only run IDL checker on files in these directories.
1617 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491618 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1619 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471620 ]
1621
1622 def get_action(affected_file):
1623 filename = affected_file.LocalPath()
1624 return actions.get(input_api.os_path.splitext(filename)[1])
1625
[email protected]99171a92014-06-03 08:44:471626 def FilterFile(affected_file):
1627 action = get_action(affected_file)
1628 if not action:
1629 return False
1630 path = affected_file.LocalPath()
1631
Sean Kau46e29bc2017-08-28 16:31:161632 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:471633 return False
1634
1635 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:161636 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:471637 return False
1638 return True
1639
1640 results = []
1641 for affected_file in input_api.AffectedFiles(
1642 file_filter=FilterFile, include_deletes=False):
1643 action = get_action(affected_file)
1644 kwargs = {}
1645 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:161646 _MatchesFile(input_api, json_no_comments_patterns,
1647 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:471648 kwargs['eat_comments'] = False
1649 parse_error = action(input_api,
1650 affected_file.AbsoluteLocalPath(),
1651 **kwargs)
1652 if parse_error:
1653 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1654 (affected_file.LocalPath(), parse_error)))
1655 return results
1656
1657
[email protected]760deea2013-12-10 19:33:491658def _CheckJavaStyle(input_api, output_api):
1659 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471660 import sys
[email protected]760deea2013-12-10 19:33:491661 original_sys_path = sys.path
1662 try:
1663 sys.path = sys.path + [input_api.os_path.join(
1664 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1665 import checkstyle
1666 finally:
1667 # Restore sys.path to what it was before.
1668 sys.path = original_sys_path
1669
1670 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091671 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511672 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491673
1674
Sean Kau46e29bc2017-08-28 16:31:161675def _MatchesFile(input_api, patterns, path):
1676 for pattern in patterns:
1677 if input_api.re.search(pattern, path):
1678 return True
1679 return False
1680
1681
Daniel Cheng7052cdf2017-11-21 19:23:291682def _GetOwnersFilesToCheckForIpcOwners(input_api):
1683 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:171684
Daniel Cheng7052cdf2017-11-21 19:23:291685 Returns:
1686 A dictionary mapping an OWNER file to the list of OWNERS rules it must
1687 contain to cover IPC-related files with noparent reviewer rules.
1688 """
1689 # Whether or not a file affects IPC is (mostly) determined by a simple list
1690 # of filename patterns.
dchenge07de812016-06-20 19:27:171691 file_patterns = [
palmerb19a0932017-01-24 04:00:311692 # Legacy IPC:
dchenge07de812016-06-20 19:27:171693 '*_messages.cc',
1694 '*_messages*.h',
1695 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311696 # Mojo IPC:
dchenge07de812016-06-20 19:27:171697 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:471698 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:171699 '*_struct_traits*.*',
1700 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311701 '*.typemap',
1702 # Android native IPC:
1703 '*.aidl',
1704 # Blink uses a different file naming convention:
1705 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:471706 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:171707 '*StructTraits*.*',
1708 '*TypeConverter*.*',
1709 ]
1710
scottmg7a6ed5ba2016-11-04 18:22:041711 # These third_party directories do not contain IPCs, but contain files
1712 # matching the above patterns, which trigger false positives.
1713 exclude_paths = [
1714 'third_party/crashpad/*',
Nico Weberee3dc9b2017-08-31 17:09:291715 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:041716 ]
1717
dchenge07de812016-06-20 19:27:171718 # Dictionary mapping an OWNERS file path to Patterns.
1719 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1720 # rules ) to a PatternEntry.
1721 # PatternEntry is a dictionary with two keys:
1722 # - 'files': the files that are matched by this pattern
1723 # - 'rules': the per-file rules needed for this pattern
1724 # For example, if we expect OWNERS file to contain rules for *.mojom and
1725 # *_struct_traits*.*, Patterns might look like this:
1726 # {
1727 # '*.mojom': {
1728 # 'files': ...,
1729 # 'rules': [
1730 # 'per-file *.mojom=set noparent',
1731 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1732 # ],
1733 # },
1734 # '*_struct_traits*.*': {
1735 # 'files': ...,
1736 # 'rules': [
1737 # 'per-file *_struct_traits*.*=set noparent',
1738 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1739 # ],
1740 # },
1741 # }
1742 to_check = {}
1743
Daniel Cheng13ca61a882017-08-25 15:11:251744 def AddPatternToCheck(input_file, pattern):
1745 owners_file = input_api.os_path.join(
1746 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
1747 if owners_file not in to_check:
1748 to_check[owners_file] = {}
1749 if pattern not in to_check[owners_file]:
1750 to_check[owners_file][pattern] = {
1751 'files': [],
1752 'rules': [
1753 'per-file %s=set noparent' % pattern,
1754 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1755 ]
1756 }
Vaclav Brozekd5de76a2018-03-17 07:57:501757 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:251758
dchenge07de812016-06-20 19:27:171759 # Iterate through the affected files to see what we actually need to check
1760 # for. We should only nag patch authors about per-file rules if a file in that
1761 # directory would match that pattern. If a directory only contains *.mojom
1762 # files and no *_messages*.h files, we should only nag about rules for
1763 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:251764 for f in input_api.AffectedFiles(include_deletes=False):
1765 # Manifest files don't have a strong naming convention. Instead, scan
1766 # affected files for .json files and see if they look like a manifest.
Sean Kau46e29bc2017-08-28 16:31:161767 if (f.LocalPath().endswith('.json') and
1768 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
1769 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:251770 json_comment_eater = _ImportJSONCommentEater(input_api)
1771 mostly_json_lines = '\n'.join(f.NewContents())
1772 # Comments aren't allowed in strict JSON, so filter them out.
1773 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:431774 try:
1775 json_content = input_api.json.loads(json_lines)
1776 except:
1777 # There's another PRESUBMIT check that already verifies that JSON files
1778 # are not invalid, so no need to emit another warning here.
1779 continue
Daniel Cheng13ca61a882017-08-25 15:11:251780 if 'interface_provider_specs' in json_content:
1781 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:171782 for pattern in file_patterns:
1783 if input_api.fnmatch.fnmatch(
1784 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041785 skip = False
1786 for exclude in exclude_paths:
1787 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1788 skip = True
1789 break
1790 if skip:
1791 continue
Daniel Cheng13ca61a882017-08-25 15:11:251792 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:171793 break
1794
Daniel Cheng7052cdf2017-11-21 19:23:291795 return to_check
1796
1797
1798def _CheckIpcOwners(input_api, output_api):
1799 """Checks that affected files involving IPC have an IPC OWNERS rule."""
1800 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
1801
1802 if to_check:
1803 # If there are any OWNERS files to check, there are IPC-related changes in
1804 # this CL. Auto-CC the review list.
1805 output_api.AppendCC('[email protected]')
1806
1807 # Go through the OWNERS files to check, filtering out rules that are already
1808 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:171809 for owners_file, patterns in to_check.iteritems():
1810 try:
1811 with file(owners_file) as f:
1812 lines = set(f.read().splitlines())
1813 for entry in patterns.itervalues():
1814 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1815 ]
1816 except IOError:
1817 # No OWNERS file, so all the rules are definitely missing.
1818 continue
1819
1820 # All the remaining lines weren't found in OWNERS files, so emit an error.
1821 errors = []
1822 for owners_file, patterns in to_check.iteritems():
1823 missing_lines = []
1824 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:501825 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:171826 missing_lines.extend(entry['rules'])
1827 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1828 if missing_lines:
1829 errors.append(
Daniel Cheng52111692017-06-14 08:00:591830 '%s needs the following lines added:\n\n%s\n\nfor files:\n%s' %
dchenge07de812016-06-20 19:27:171831 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1832
1833 results = []
1834 if errors:
vabrf5ce3bf92016-07-11 14:52:411835 if input_api.is_committing:
1836 output = output_api.PresubmitError
1837 else:
1838 output = output_api.PresubmitPromptWarning
1839 results.append(output(
Daniel Cheng52111692017-06-14 08:00:591840 'Found OWNERS files that need to be updated for IPC security ' +
1841 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:171842 long_text='\n\n'.join(errors)))
1843
1844 return results
1845
1846
jbriance9e12f162016-11-25 07:57:501847def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311848 """Checks that added or removed lines in non third party affected
1849 header files do not lead to new useless class or struct forward
1850 declaration.
jbriance9e12f162016-11-25 07:57:501851 """
1852 results = []
1853 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1854 input_api.re.MULTILINE)
1855 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1856 input_api.re.MULTILINE)
1857 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311858 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:191859 not f.LocalPath().startswith('third_party/blink') and
1860 not f.LocalPath().startswith('third_party\\blink') and
jbriance2c51e821a2016-12-12 08:24:311861 not f.LocalPath().startswith('third_party/WebKit') and
1862 not f.LocalPath().startswith('third_party\\WebKit')):
1863 continue
1864
jbriance9e12f162016-11-25 07:57:501865 if not f.LocalPath().endswith('.h'):
1866 continue
1867
1868 contents = input_api.ReadFile(f)
1869 fwd_decls = input_api.re.findall(class_pattern, contents)
1870 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1871
1872 useless_fwd_decls = []
1873 for decl in fwd_decls:
1874 count = sum(1 for _ in input_api.re.finditer(
1875 r'\b%s\b' % input_api.re.escape(decl), contents))
1876 if count == 1:
1877 useless_fwd_decls.append(decl)
1878
1879 if not useless_fwd_decls:
1880 continue
1881
1882 for line in f.GenerateScmDiff().splitlines():
1883 if (line.startswith('-') and not line.startswith('--') or
1884 line.startswith('+') and not line.startswith('++')):
1885 for decl in useless_fwd_decls:
1886 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1887 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:241888 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:501889 (f.LocalPath(), decl)))
1890 useless_fwd_decls.remove(decl)
1891
1892 return results
1893
1894
dskiba88634f4e2015-08-14 23:03:291895def _CheckAndroidToastUsage(input_api, output_api):
1896 """Checks that code uses org.chromium.ui.widget.Toast instead of
1897 android.widget.Toast (Chromium Toast doesn't force hardware
1898 acceleration on low-end devices, saving memory).
1899 """
1900 toast_import_pattern = input_api.re.compile(
1901 r'^import android\.widget\.Toast;$')
1902
1903 errors = []
1904
1905 sources = lambda affected_file: input_api.FilterSourceFile(
1906 affected_file,
1907 black_list=(_EXCLUDED_PATHS +
1908 _TEST_CODE_EXCLUDED_PATHS +
1909 input_api.DEFAULT_BLACK_LIST +
1910 (r'^chromecast[\\\/].*',
1911 r'^remoting[\\\/].*')),
1912 white_list=(r'.*\.java$',))
1913
1914 for f in input_api.AffectedSourceFiles(sources):
1915 for line_num, line in f.ChangedContents():
1916 if toast_import_pattern.search(line):
1917 errors.append("%s:%d" % (f.LocalPath(), line_num))
1918
1919 results = []
1920
1921 if errors:
1922 results.append(output_api.PresubmitError(
1923 'android.widget.Toast usage is detected. Android toasts use hardware'
1924 ' acceleration, and can be\ncostly on low-end devices. Please use'
1925 ' org.chromium.ui.widget.Toast instead.\n'
1926 'Contact [email protected] if you have any questions.',
1927 errors))
1928
1929 return results
1930
1931
dgnaa68d5e2015-06-10 10:08:221932def _CheckAndroidCrLogUsage(input_api, output_api):
1933 """Checks that new logs using org.chromium.base.Log:
1934 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511935 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221936 """
pkotwicza1dd0b002016-05-16 14:41:041937
torne89540622017-03-24 19:41:301938 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:041939 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:301940 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:041941 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:301942 # WebView license viewer code cannot depend on //base; used in stub APK.
1943 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
1944 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:041945 ]
1946
dgnaa68d5e2015-06-10 10:08:221947 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121948 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1949 class_in_base_pattern = input_api.re.compile(
1950 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1951 has_some_log_import_pattern = input_api.re.compile(
1952 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221953 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121954 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221955 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511956 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221957 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221958
Vincent Scheib16d7b272015-09-15 18:09:071959 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221960 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041961 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1962 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121963
dgnaa68d5e2015-06-10 10:08:221964 tag_decl_errors = []
1965 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121966 tag_errors = []
dgn38736db2015-09-18 19:20:511967 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121968 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221969
1970 for f in input_api.AffectedSourceFiles(sources):
1971 file_content = input_api.ReadFile(f)
1972 has_modified_logs = False
1973
1974 # Per line checks
dgn87d9fb62015-06-12 09:15:121975 if (cr_log_import_pattern.search(file_content) or
1976 (class_in_base_pattern.search(file_content) and
1977 not has_some_log_import_pattern.search(file_content))):
1978 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221979 for line_num, line in f.ChangedContents():
1980
1981 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121982 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221983 if match:
1984 has_modified_logs = True
1985
1986 # Make sure it uses "TAG"
1987 if not match.group('tag') == 'TAG':
1988 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121989 else:
1990 # Report non cr Log function calls in changed lines
1991 for line_num, line in f.ChangedContents():
1992 if log_call_pattern.search(line):
1993 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221994
1995 # Per file checks
1996 if has_modified_logs:
1997 # Make sure the tag is using the "cr" prefix and is not too long
1998 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511999 tag_name = match.group('name') if match else None
2000 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222001 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512002 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222003 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512004 elif '.' in tag_name:
2005 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222006
2007 results = []
2008 if tag_decl_errors:
2009 results.append(output_api.PresubmitPromptWarning(
2010 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512011 '"private static final String TAG = "<package tag>".\n'
2012 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222013 tag_decl_errors))
2014
2015 if tag_length_errors:
2016 results.append(output_api.PresubmitError(
2017 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512018 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222019 tag_length_errors))
2020
2021 if tag_errors:
2022 results.append(output_api.PresubmitPromptWarning(
2023 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2024 tag_errors))
2025
dgn87d9fb62015-06-12 09:15:122026 if util_log_errors:
dgn4401aa52015-04-29 16:26:172027 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122028 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2029 util_log_errors))
2030
dgn38736db2015-09-18 19:20:512031 if tag_with_dot_errors:
2032 results.append(output_api.PresubmitPromptWarning(
2033 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2034 tag_with_dot_errors))
2035
dgn4401aa52015-04-29 16:26:172036 return results
2037
2038
Yoland Yanb92fa522017-08-28 17:37:062039def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2040 """Checks that junit.framework.* is no longer used."""
2041 deprecated_junit_framework_pattern = input_api.re.compile(
2042 r'^import junit\.framework\..*;',
2043 input_api.re.MULTILINE)
2044 sources = lambda x: input_api.FilterSourceFile(
2045 x, white_list=(r'.*\.java$',), black_list=None)
2046 errors = []
2047 for f in input_api.AffectedFiles(sources):
2048 for line_num, line in f.ChangedContents():
2049 if deprecated_junit_framework_pattern.search(line):
2050 errors.append("%s:%d" % (f.LocalPath(), line_num))
2051
2052 results = []
2053 if errors:
2054 results.append(output_api.PresubmitError(
2055 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2056 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2057 ' if you have any question.', errors))
2058 return results
2059
2060
2061def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2062 """Checks that if new Java test classes have inheritance.
2063 Either the new test class is JUnit3 test or it is a JUnit4 test class
2064 with a base class, either case is undesirable.
2065 """
2066 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2067
2068 sources = lambda x: input_api.FilterSourceFile(
2069 x, white_list=(r'.*Test\.java$',), black_list=None)
2070 errors = []
2071 for f in input_api.AffectedFiles(sources):
2072 if not f.OldContents():
2073 class_declaration_start_flag = False
2074 for line_num, line in f.ChangedContents():
2075 if class_declaration_pattern.search(line):
2076 class_declaration_start_flag = True
2077 if class_declaration_start_flag and ' extends ' in line:
2078 errors.append('%s:%d' % (f.LocalPath(), line_num))
2079 if '{' in line:
2080 class_declaration_start_flag = False
2081
2082 results = []
2083 if errors:
2084 results.append(output_api.PresubmitPromptWarning(
2085 'The newly created files include Test classes that inherits from base'
2086 ' class. Please do not use inheritance in JUnit4 tests or add new'
2087 ' JUnit3 tests. Contact [email protected] if you have any'
2088 ' questions.', errors))
2089 return results
2090
yolandyan45001472016-12-21 21:12:422091def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2092 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2093 deprecated_annotation_import_pattern = input_api.re.compile(
2094 r'^import android\.test\.suitebuilder\.annotation\..*;',
2095 input_api.re.MULTILINE)
2096 sources = lambda x: input_api.FilterSourceFile(
2097 x, white_list=(r'.*\.java$',), black_list=None)
2098 errors = []
2099 for f in input_api.AffectedFiles(sources):
2100 for line_num, line in f.ChangedContents():
2101 if deprecated_annotation_import_pattern.search(line):
2102 errors.append("%s:%d" % (f.LocalPath(), line_num))
2103
2104 results = []
2105 if errors:
2106 results.append(output_api.PresubmitError(
2107 'Annotations in android.test.suitebuilder.annotation have been'
2108 ' deprecated since API level 24. Please use android.support.test.filters'
2109 ' from //third_party/android_support_test_runner:runner_java instead.'
2110 ' Contact [email protected] if you have any questions.', errors))
2111 return results
2112
2113
agrieve7b6479d82015-10-07 14:24:222114def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2115 """Checks if MDPI assets are placed in a correct directory."""
2116 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2117 ('/res/drawable/' in f.LocalPath() or
2118 '/res/drawable-ldrtl/' in f.LocalPath()))
2119 errors = []
2120 for f in input_api.AffectedFiles(include_deletes=False,
2121 file_filter=file_filter):
2122 errors.append(' %s' % f.LocalPath())
2123
2124 results = []
2125 if errors:
2126 results.append(output_api.PresubmitError(
2127 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2128 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2129 '/res/drawable-ldrtl/.\n'
2130 'Contact [email protected] if you have questions.', errors))
2131 return results
2132
2133
Nate Fischer535972b2017-09-16 01:06:182134def _CheckAndroidWebkitImports(input_api, output_api):
2135 """Checks that code uses org.chromium.base.Callback instead of
2136 android.widget.ValueCallback except in the WebView glue layer.
2137 """
2138 valuecallback_import_pattern = input_api.re.compile(
2139 r'^import android\.webkit\.ValueCallback;$')
2140
2141 errors = []
2142
2143 sources = lambda affected_file: input_api.FilterSourceFile(
2144 affected_file,
2145 black_list=(_EXCLUDED_PATHS +
2146 _TEST_CODE_EXCLUDED_PATHS +
2147 input_api.DEFAULT_BLACK_LIST +
2148 (r'^android_webview[\\\/]glue[\\\/].*',)),
2149 white_list=(r'.*\.java$',))
2150
2151 for f in input_api.AffectedSourceFiles(sources):
2152 for line_num, line in f.ChangedContents():
2153 if valuecallback_import_pattern.search(line):
2154 errors.append("%s:%d" % (f.LocalPath(), line_num))
2155
2156 results = []
2157
2158 if errors:
2159 results.append(output_api.PresubmitError(
2160 'android.webkit.ValueCallback usage is detected outside of the glue'
2161 ' layer. To stay compatible with the support library, android.webkit.*'
2162 ' classes should only be used inside the glue layer and'
2163 ' org.chromium.base.Callback should be used instead.',
2164 errors))
2165
2166 return results
2167
2168
agrievef32bcc72016-04-04 14:57:402169class PydepsChecker(object):
2170 def __init__(self, input_api, pydeps_files):
2171 self._file_cache = {}
2172 self._input_api = input_api
2173 self._pydeps_files = pydeps_files
2174
2175 def _LoadFile(self, path):
2176 """Returns the list of paths within a .pydeps file relative to //."""
2177 if path not in self._file_cache:
2178 with open(path) as f:
2179 self._file_cache[path] = f.read()
2180 return self._file_cache[path]
2181
2182 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2183 """Returns an interable of paths within the .pydep, relativized to //."""
2184 os_path = self._input_api.os_path
2185 pydeps_dir = os_path.dirname(pydeps_path)
2186 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2187 if not l.startswith('*'))
2188 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2189
2190 def _CreateFilesToPydepsMap(self):
2191 """Returns a map of local_path -> list_of_pydeps."""
2192 ret = {}
2193 for pydep_local_path in self._pydeps_files:
2194 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2195 ret.setdefault(path, []).append(pydep_local_path)
2196 return ret
2197
2198 def ComputeAffectedPydeps(self):
2199 """Returns an iterable of .pydeps files that might need regenerating."""
2200 affected_pydeps = set()
2201 file_to_pydeps_map = None
2202 for f in self._input_api.AffectedFiles(include_deletes=True):
2203 local_path = f.LocalPath()
2204 if local_path == 'DEPS':
2205 return self._pydeps_files
2206 elif local_path.endswith('.pydeps'):
2207 if local_path in self._pydeps_files:
2208 affected_pydeps.add(local_path)
2209 elif local_path.endswith('.py'):
2210 if file_to_pydeps_map is None:
2211 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2212 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2213 return affected_pydeps
2214
2215 def DetermineIfStale(self, pydeps_path):
2216 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412217 import difflib
John Budorick47ca3fe2018-02-10 00:53:102218 import os
2219
agrievef32bcc72016-04-04 14:57:402220 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2221 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102222 env = dict(os.environ)
2223 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402224 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102225 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412226 old_contents = old_pydeps_data[2:]
2227 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402228 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412229 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402230
2231
2232def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2233 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402234 # This check is for Python dependency lists (.pydeps files), and involves
2235 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2236 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282237 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002238 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022239 # TODO(agrieve): Update when there's a better way to detect
2240 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402241 is_android = input_api.os_path.exists('third_party/android_tools')
2242 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2243 results = []
2244 # First, check for new / deleted .pydeps.
2245 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032246 # Check whether we are running the presubmit check for a file in src.
2247 # f.LocalPath is relative to repo (src, or internal repo).
2248 # os_path.exists is relative to src repo.
2249 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2250 # to src and we can conclude that the pydeps is in src.
2251 if input_api.os_path.exists(f.LocalPath()):
2252 if f.LocalPath().endswith('.pydeps'):
2253 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2254 results.append(output_api.PresubmitError(
2255 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2256 'remove %s' % f.LocalPath()))
2257 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2258 results.append(output_api.PresubmitError(
2259 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2260 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402261
2262 if results:
2263 return results
2264
2265 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2266
2267 for pydep_path in checker.ComputeAffectedPydeps():
2268 try:
phajdan.jr0d9878552016-11-04 10:49:412269 result = checker.DetermineIfStale(pydep_path)
2270 if result:
2271 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402272 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412273 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2274 'To regenerate, run:\n\n %s' %
2275 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402276 except input_api.subprocess.CalledProcessError as error:
2277 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2278 long_text=error.output)]
2279
2280 return results
2281
2282
glidere61efad2015-02-18 17:39:432283def _CheckSingletonInHeaders(input_api, output_api):
2284 """Checks to make sure no header files have |Singleton<|."""
2285 def FileFilter(affected_file):
2286 # It's ok for base/memory/singleton.h to have |Singleton<|.
2287 black_list = (_EXCLUDED_PATHS +
2288 input_api.DEFAULT_BLACK_LIST +
Michael Warrese4451492018-03-07 04:42:472289 (r"^base[\\\/]memory[\\\/]singleton\.h$",
2290 r"^net[\\\/]quic[\\\/]platform[\\\/]impl[\\\/]"
2291 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432292 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2293
sergeyu34d21222015-09-16 00:11:442294 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432295 files = []
2296 for f in input_api.AffectedSourceFiles(FileFilter):
2297 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2298 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2299 contents = input_api.ReadFile(f)
2300 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242301 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432302 pattern.search(line)):
2303 files.append(f)
2304 break
2305
2306 if files:
yolandyandaabc6d2016-04-18 18:29:392307 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442308 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432309 'Please move them to an appropriate source file so that the ' +
2310 'template gets instantiated in a single compilation unit.',
2311 files) ]
2312 return []
2313
2314
[email protected]fd20b902014-05-09 02:14:532315_DEPRECATED_CSS = [
2316 # Values
2317 ( "-webkit-box", "flex" ),
2318 ( "-webkit-inline-box", "inline-flex" ),
2319 ( "-webkit-flex", "flex" ),
2320 ( "-webkit-inline-flex", "inline-flex" ),
2321 ( "-webkit-min-content", "min-content" ),
2322 ( "-webkit-max-content", "max-content" ),
2323
2324 # Properties
2325 ( "-webkit-background-clip", "background-clip" ),
2326 ( "-webkit-background-origin", "background-origin" ),
2327 ( "-webkit-background-size", "background-size" ),
2328 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442329 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532330
2331 # Functions
2332 ( "-webkit-gradient", "gradient" ),
2333 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2334 ( "-webkit-linear-gradient", "linear-gradient" ),
2335 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2336 ( "-webkit-radial-gradient", "radial-gradient" ),
2337 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2338]
2339
dbeam1ec68ac2016-12-15 05:22:242340def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532341 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252342 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342343 documentation and iOS CSS for dom distiller
2344 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252345 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532346 results = []
dbeam070cfe62014-10-22 06:44:022347 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:252348 black_list = (_EXCLUDED_PATHS +
2349 _TEST_CODE_EXCLUDED_PATHS +
2350 input_api.DEFAULT_BLACK_LIST +
2351 (r"^chrome/common/extensions/docs",
2352 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342353 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442354 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252355 r"^native_client_sdk"))
2356 file_filter = lambda f: input_api.FilterSourceFile(
2357 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532358 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2359 for line_num, line in fpath.ChangedContents():
2360 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022361 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532362 results.append(output_api.PresubmitError(
2363 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2364 (fpath.LocalPath(), line_num, deprecated_value, value)))
2365 return results
2366
mohan.reddyf21db962014-10-16 12:26:472367
dbeam070cfe62014-10-22 06:44:022368_DEPRECATED_JS = [
2369 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2370 ( "__defineGetter__", "Object.defineProperty" ),
2371 ( "__defineSetter__", "Object.defineProperty" ),
2372]
2373
dbeam1ec68ac2016-12-15 05:22:242374def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022375 """Make sure that we don't use deprecated JS in Chrome code."""
2376 results = []
2377 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2378 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2379 input_api.DEFAULT_BLACK_LIST)
2380 file_filter = lambda f: input_api.FilterSourceFile(
2381 f, white_list=file_inclusion_pattern, black_list=black_list)
2382 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2383 for lnum, line in fpath.ChangedContents():
2384 for (deprecated, replacement) in _DEPRECATED_JS:
2385 if deprecated in line:
2386 results.append(output_api.PresubmitError(
2387 "%s:%d: Use of deprecated JS %s, use %s instead" %
2388 (fpath.LocalPath(), lnum, deprecated, replacement)))
2389 return results
2390
dpapadd651231d82017-07-21 02:44:472391def _CheckForRiskyJsArrowFunction(line_number, line):
2392 if ' => ' in line:
2393 return "line %d, is using an => (arrow) function\n %s\n" % (
2394 line_number, line)
2395 return ''
2396
2397def _CheckForRiskyJsConstLet(input_api, line_number, line):
2398 if input_api.re.match('^\s*(const|let)\s', line):
2399 return "line %d, is using const/let keyword\n %s\n" % (
2400 line_number, line)
2401 return ''
dbeam070cfe62014-10-22 06:44:022402
dbeam1ec68ac2016-12-15 05:22:242403def _CheckForRiskyJsFeatures(input_api, output_api):
2404 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
Steven Bennetts90545f3cb2017-08-14 18:11:002405 # 'ui/webui/resources/cr_components are not allowed on ios'
2406 not_ios_filter = (r".*ui\/webui\/resources\/cr_components.*", )
Steven Bennetts9c7e3c22017-08-02 19:10:572407 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js,
Steven Bennetts90545f3cb2017-08-14 18:11:002408 black_list=not_ios_filter)
dpapadd651231d82017-07-21 02:44:472409 results = []
dbeam1ec68ac2016-12-15 05:22:242410 for f in input_api.AffectedFiles(file_filter=file_filter):
dpapadd651231d82017-07-21 02:44:472411 arrow_error_lines = []
2412 const_let_error_lines = []
dbeam1ec68ac2016-12-15 05:22:242413 for lnum, line in f.ChangedContents():
dpapadd651231d82017-07-21 02:44:472414 arrow_error_lines += filter(None, [
2415 _CheckForRiskyJsArrowFunction(lnum, line),
2416 ])
dbeam1ec68ac2016-12-15 05:22:242417
dpapadd651231d82017-07-21 02:44:472418 const_let_error_lines += filter(None, [
2419 _CheckForRiskyJsConstLet(input_api, lnum, line),
2420 ])
dbeam1ec68ac2016-12-15 05:22:242421
dpapadd651231d82017-07-21 02:44:472422 if arrow_error_lines:
2423 arrow_error_lines = map(
2424 lambda e: "%s:%s" % (f.LocalPath(), e), arrow_error_lines)
2425 results.append(
2426 output_api.PresubmitPromptWarning('\n'.join(arrow_error_lines + [
2427"""
2428Use of => (arrow) operator detected in:
dbeam1ec68ac2016-12-15 05:22:242429%s
2430Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2431https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
dpapadd651231d82017-07-21 02:44:472432""" % f.LocalPath()
2433 ])))
dbeam1ec68ac2016-12-15 05:22:242434
dpapadd651231d82017-07-21 02:44:472435 if const_let_error_lines:
2436 const_let_error_lines = map(
2437 lambda e: "%s:%s" % (f.LocalPath(), e), const_let_error_lines)
2438 results.append(
2439 output_api.PresubmitPromptWarning('\n'.join(const_let_error_lines + [
2440"""
2441Use of const/let keywords detected in:
2442%s
2443Please ensure your code does not run on iOS9 because const/let is not fully
2444supported.
2445https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#let-Block_Scoped-Variables
2446https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#const-Block_Scoped-Constants
2447""" % f.LocalPath()
2448 ])))
2449
2450 return results
dbeam1ec68ac2016-12-15 05:22:242451
rlanday6802cf632017-05-30 17:48:362452def _CheckForRelativeIncludes(input_api, output_api):
2453 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2454 import sys
2455 original_sys_path = sys.path
2456 try:
2457 sys.path = sys.path + [input_api.os_path.join(
2458 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2459 from cpp_checker import CppChecker
2460 finally:
2461 # Restore sys.path to what it was before.
2462 sys.path = original_sys_path
2463
2464 bad_files = {}
2465 for f in input_api.AffectedFiles(include_deletes=False):
2466 if (f.LocalPath().startswith('third_party') and
2467 not f.LocalPath().startswith('third_party/WebKit') and
2468 not f.LocalPath().startswith('third_party\\WebKit')):
2469 continue
2470
2471 if not CppChecker.IsCppFile(f.LocalPath()):
2472 continue
2473
Vaclav Brozekd5de76a2018-03-17 07:57:502474 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362475 if "#include" in line and "../" in line]
2476 if not relative_includes:
2477 continue
2478 bad_files[f.LocalPath()] = relative_includes
2479
2480 if not bad_files:
2481 return []
2482
2483 error_descriptions = []
2484 for file_path, bad_lines in bad_files.iteritems():
2485 error_description = file_path
2486 for line in bad_lines:
2487 error_description += '\n ' + line
2488 error_descriptions.append(error_description)
2489
2490 results = []
2491 results.append(output_api.PresubmitError(
2492 'You added one or more relative #include paths (including "../").\n'
2493 'These shouldn\'t be used because they can be used to include headers\n'
2494 'from code that\'s not correctly specified as a dependency in the\n'
2495 'relevant BUILD.gn file(s).',
2496 error_descriptions))
2497
2498 return results
2499
Takeshi Yoshinoe387aa32017-08-02 13:16:132500
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202501def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2502 if not isinstance(key, ast.Str):
2503 return 'Key at line %d must be a string literal' % key.lineno
2504 if not isinstance(value, ast.Dict):
2505 return 'Value at line %d must be a dict' % value.lineno
2506 if len(value.keys) != 1:
2507 return 'Dict at line %d must have single entry' % value.lineno
2508 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2509 return (
2510 'Entry at line %d must have a string literal \'filepath\' as key' %
2511 value.lineno)
2512 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132513
Takeshi Yoshinoe387aa32017-08-02 13:16:132514
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202515def _CheckWatchlistsEntrySyntax(key, value, ast):
2516 if not isinstance(key, ast.Str):
2517 return 'Key at line %d must be a string literal' % key.lineno
2518 if not isinstance(value, ast.List):
2519 return 'Value at line %d must be a list' % value.lineno
2520 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132521
Takeshi Yoshinoe387aa32017-08-02 13:16:132522
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202523def _CheckWATCHLISTSEntries(wd_dict, w_dict, ast):
2524 mismatch_template = (
2525 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2526 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132527
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202528 i = 0
2529 last_key = ''
2530 while True:
2531 if i >= len(wd_dict.keys):
2532 if i >= len(w_dict.keys):
2533 return None
2534 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2535 elif i >= len(w_dict.keys):
2536 return (
2537 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132538
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202539 wd_key = wd_dict.keys[i]
2540 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132541
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202542 result = _CheckWatchlistDefinitionsEntrySyntax(
2543 wd_key, wd_dict.values[i], ast)
2544 if result is not None:
2545 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132546
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202547 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast)
2548 if result is not None:
2549 return 'Bad entry in WATCHLISTS dict: %s' % result
2550
2551 if wd_key.s != w_key.s:
2552 return mismatch_template % (
2553 '%s at line %d' % (wd_key.s, wd_key.lineno),
2554 '%s at line %d' % (w_key.s, w_key.lineno))
2555
2556 if wd_key.s < last_key:
2557 return (
2558 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2559 (wd_key.lineno, w_key.lineno))
2560 last_key = wd_key.s
2561
2562 i = i + 1
2563
2564
2565def _CheckWATCHLISTSSyntax(expression, ast):
2566 if not isinstance(expression, ast.Expression):
2567 return 'WATCHLISTS file must contain a valid expression'
2568 dictionary = expression.body
2569 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2570 return 'WATCHLISTS file must have single dict with exactly two entries'
2571
2572 first_key = dictionary.keys[0]
2573 first_value = dictionary.values[0]
2574 second_key = dictionary.keys[1]
2575 second_value = dictionary.values[1]
2576
2577 if (not isinstance(first_key, ast.Str) or
2578 first_key.s != 'WATCHLIST_DEFINITIONS' or
2579 not isinstance(first_value, ast.Dict)):
2580 return (
2581 'The first entry of the dict in WATCHLISTS file must be '
2582 'WATCHLIST_DEFINITIONS dict')
2583
2584 if (not isinstance(second_key, ast.Str) or
2585 second_key.s != 'WATCHLISTS' or
2586 not isinstance(second_value, ast.Dict)):
2587 return (
2588 'The second entry of the dict in WATCHLISTS file must be '
2589 'WATCHLISTS dict')
2590
2591 return _CheckWATCHLISTSEntries(first_value, second_value, ast)
Takeshi Yoshinoe387aa32017-08-02 13:16:132592
2593
2594def _CheckWATCHLISTS(input_api, output_api):
2595 for f in input_api.AffectedFiles(include_deletes=False):
2596 if f.LocalPath() == 'WATCHLISTS':
2597 contents = input_api.ReadFile(f, 'r')
2598
2599 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202600 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132601 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202602 # Get an AST tree for it and scan the tree for detailed style checking.
2603 expression = input_api.ast.parse(
2604 contents, filename='WATCHLISTS', mode='eval')
2605 except ValueError as e:
2606 return [output_api.PresubmitError(
2607 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2608 except SyntaxError as e:
2609 return [output_api.PresubmitError(
2610 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2611 except TypeError as e:
2612 return [output_api.PresubmitError(
2613 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132614
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202615 result = _CheckWATCHLISTSSyntax(expression, input_api.ast)
2616 if result is not None:
2617 return [output_api.PresubmitError(result)]
2618 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132619
2620 return []
2621
2622
dgnaa68d5e2015-06-10 10:08:222623def _AndroidSpecificOnUploadChecks(input_api, output_api):
2624 """Groups checks that target android code."""
2625 results = []
dgnaa68d5e2015-06-10 10:08:222626 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222627 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292628 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:062629 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
2630 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:422631 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:182632 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222633 return results
2634
2635
[email protected]22c9bd72011-03-27 16:47:392636def _CommonChecks(input_api, output_api):
2637 """Checks common to both upload and commit."""
2638 results = []
2639 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382640 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542641 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:082642
2643 author = input_api.change.author_email
2644 if author and author not in _KNOWN_ROBOTS:
2645 results.extend(
2646 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
2647
[email protected]55459852011-08-10 15:17:192648 results.extend(
[email protected]760deea2013-12-10 19:33:492649 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542650 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182651 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522652 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222653 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442654 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592655 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062656 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122657 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182658 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222659 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302660 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492661 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032662 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492663 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442664 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272665 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:072666 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542667 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442668 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392669 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552670 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042671 results.extend(
2672 input_api.canned_checks.CheckChangeHasNoTabs(
2673 input_api,
2674 output_api,
2675 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402676 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162677 results.extend(_CheckForAnonymousVariables(input_api, output_api))
Peter Kasting4844e46e2018-02-23 07:27:102678 results.extend(_CheckUniquePtr(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082679 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242680 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2681 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472682 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042683 results.extend(_CheckForIPCRules(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:142684 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232685 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432686 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402687 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152688 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172689 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502690 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242691 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:362692 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:132693 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:432694 results.extend(input_api.RunTests(
2695 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:242696
Vaclav Brozekcdc7defb2018-03-20 09:54:352697 for f in input_api.AffectedFiles():
2698 path, name = input_api.os_path.split(f.LocalPath())
2699 if name == 'PRESUBMIT.py':
2700 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
2701 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2702 input_api, output_api, full_path,
2703 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392704 return results
[email protected]1f7b4172010-01-28 01:17:342705
[email protected]b337cb5b2011-01-23 21:24:052706
[email protected]b8079ae4a2012-12-05 19:56:492707def _CheckPatchFiles(input_api, output_api):
2708 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2709 if f.LocalPath().endswith(('.orig', '.rej'))]
2710 if problems:
2711 return [output_api.PresubmitError(
2712 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032713 else:
2714 return []
[email protected]b8079ae4a2012-12-05 19:56:492715
2716
Kent Tamura5a8755d2017-06-29 23:37:072717def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:212718 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
2719 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
2720 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:072721 include_re = input_api.re.compile(
2722 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
2723 extension_re = input_api.re.compile(r'\.[a-z]+$')
2724 errors = []
2725 for f in input_api.AffectedFiles():
2726 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
2727 continue
2728 found_line_number = None
2729 found_macro = None
2730 for line_num, line in f.ChangedContents():
2731 match = macro_re.search(line)
2732 if match:
2733 found_line_number = line_num
2734 found_macro = match.group(2)
2735 break
2736 if not found_line_number:
2737 continue
2738
2739 found_include = False
2740 for line in f.NewContents():
2741 if include_re.search(line):
2742 found_include = True
2743 break
2744 if found_include:
2745 continue
2746
2747 if not f.LocalPath().endswith('.h'):
2748 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
2749 try:
2750 content = input_api.ReadFile(primary_header_path, 'r')
2751 if include_re.search(content):
2752 continue
2753 except IOError:
2754 pass
2755 errors.append('%s:%d %s macro is used without including build/'
2756 'build_config.h.'
2757 % (f.LocalPath(), found_line_number, found_macro))
2758 if errors:
2759 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
2760 return []
2761
2762
[email protected]b00342e7f2013-03-26 16:21:542763def _DidYouMeanOSMacro(bad_macro):
2764 try:
2765 return {'A': 'OS_ANDROID',
2766 'B': 'OS_BSD',
2767 'C': 'OS_CHROMEOS',
2768 'F': 'OS_FREEBSD',
2769 'L': 'OS_LINUX',
2770 'M': 'OS_MACOSX',
2771 'N': 'OS_NACL',
2772 'O': 'OS_OPENBSD',
2773 'P': 'OS_POSIX',
2774 'S': 'OS_SOLARIS',
2775 'W': 'OS_WIN'}[bad_macro[3].upper()]
2776 except KeyError:
2777 return ''
2778
2779
2780def _CheckForInvalidOSMacrosInFile(input_api, f):
2781 """Check for sensible looking, totally invalid OS macros."""
2782 preprocessor_statement = input_api.re.compile(r'^\s*#')
2783 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2784 results = []
2785 for lnum, line in f.ChangedContents():
2786 if preprocessor_statement.search(line):
2787 for match in os_macro.finditer(line):
2788 if not match.group(1) in _VALID_OS_MACROS:
2789 good = _DidYouMeanOSMacro(match.group(1))
2790 did_you_mean = ' (did you mean %s?)' % good if good else ''
2791 results.append(' %s:%d %s%s' % (f.LocalPath(),
2792 lnum,
2793 match.group(1),
2794 did_you_mean))
2795 return results
2796
2797
2798def _CheckForInvalidOSMacros(input_api, output_api):
2799 """Check all affected files for invalid OS macros."""
2800 bad_macros = []
2801 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472802 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542803 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2804
2805 if not bad_macros:
2806 return []
2807
2808 return [output_api.PresubmitError(
2809 'Possibly invalid OS macro[s] found. Please fix your code\n'
2810 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2811
lliabraa35bab3932014-10-01 12:16:442812
2813def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2814 """Check all affected files for invalid "if defined" macros."""
2815 ALWAYS_DEFINED_MACROS = (
2816 "TARGET_CPU_PPC",
2817 "TARGET_CPU_PPC64",
2818 "TARGET_CPU_68K",
2819 "TARGET_CPU_X86",
2820 "TARGET_CPU_ARM",
2821 "TARGET_CPU_MIPS",
2822 "TARGET_CPU_SPARC",
2823 "TARGET_CPU_ALPHA",
2824 "TARGET_IPHONE_SIMULATOR",
2825 "TARGET_OS_EMBEDDED",
2826 "TARGET_OS_IPHONE",
2827 "TARGET_OS_MAC",
2828 "TARGET_OS_UNIX",
2829 "TARGET_OS_WIN32",
2830 )
2831 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2832 results = []
2833 for lnum, line in f.ChangedContents():
2834 for match in ifdef_macro.finditer(line):
2835 if match.group(1) in ALWAYS_DEFINED_MACROS:
2836 always_defined = ' %s is always defined. ' % match.group(1)
2837 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2838 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2839 lnum,
2840 always_defined,
2841 did_you_mean))
2842 return results
2843
2844
2845def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2846 """Check all affected files for invalid "if defined" macros."""
2847 bad_macros = []
2848 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:212849 if f.LocalPath().startswith('third_party/sqlite/'):
2850 continue
lliabraa35bab3932014-10-01 12:16:442851 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2852 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2853
2854 if not bad_macros:
2855 return []
2856
2857 return [output_api.PresubmitError(
2858 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2859 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2860 bad_macros)]
2861
2862
mlamouria82272622014-09-16 18:45:042863def _CheckForIPCRules(input_api, output_api):
2864 """Check for same IPC rules described in
2865 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2866 """
2867 base_pattern = r'IPC_ENUM_TRAITS\('
2868 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2869 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2870
2871 problems = []
2872 for f in input_api.AffectedSourceFiles(None):
2873 local_path = f.LocalPath()
2874 if not local_path.endswith('.h'):
2875 continue
2876 for line_number, line in f.ChangedContents():
2877 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2878 problems.append(
2879 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2880
2881 if problems:
2882 return [output_api.PresubmitPromptWarning(
2883 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2884 else:
2885 return []
2886
[email protected]b00342e7f2013-03-26 16:21:542887
Daniel Bratell8ba52722018-03-02 16:06:142888def _CheckForIncludeGuards(input_api, output_api):
2889 """Check that header files have proper guards against multiple inclusion.
2890 If a file should not have such guards (and it probably should) then it
2891 should include the string "no-include-guard-because-multiply-included".
2892 """
2893 def is_header_file(f):
2894 return f.LocalPath().endswith('.h')
2895
2896 def replace_special_with_underscore(string):
2897 return input_api.re.sub(r'[\\/.-]', '_', string)
2898
2899 errors = []
2900
2901 for f in input_api.AffectedSourceFiles(is_header_file):
2902 guard_name = None
2903 guard_line_number = None
2904 seen_guard_end = False
2905
2906 file_with_path = input_api.os_path.normpath(f.LocalPath())
2907 base_file_name = input_api.os_path.splitext(
2908 input_api.os_path.basename(file_with_path))[0]
2909 upper_base_file_name = base_file_name.upper()
2910
2911 expected_guard = replace_special_with_underscore(
2912 file_with_path.upper() + '_')
2913 expected_guard_if_blink = base_file_name + '_h'
2914
2915 # For "path/elem/file_name.h" we should really only accept
2916 # PATH_ELEM_FILE_NAME_H_ per coding style or, if Blink,
2917 # file_name_h. Unfortunately there are too many (1000+) files
2918 # with slight deviations from the coding style. Since the most
2919 # important part is that the include guard is there, and that it's
2920 # unique, not the name, this check is forgiving for existing files.
2921 #
2922 # As code becomes more uniform, this could be made stricter.
2923
2924 guard_name_pattern_list = [
2925 # Anything with the right suffix (maybe with an extra _).
2926 r'\w+_H__?',
2927
2928 # To cover include guards with Blink style.
2929 r'\w+_h',
2930
2931 # Anything including the uppercase name of the file.
2932 r'\w*' + input_api.re.escape(replace_special_with_underscore(
2933 upper_base_file_name)) + r'\w*',
2934 ]
2935 guard_name_pattern = '|'.join(guard_name_pattern_list)
2936 guard_pattern = input_api.re.compile(
2937 r'#ifndef\s+(' + guard_name_pattern + ')')
2938
2939 for line_number, line in enumerate(f.NewContents()):
2940 if 'no-include-guard-because-multiply-included' in line:
2941 guard_name = 'DUMMY' # To not trigger check outside the loop.
2942 break
2943
2944 if guard_name is None:
2945 match = guard_pattern.match(line)
2946 if match:
2947 guard_name = match.group(1)
2948 guard_line_number = line_number
2949
2950 # We allow existing files to use slightly wrong include
2951 # guards, but new files should get it right.
2952 if not f.OldContents():
2953 is_in_blink = file_with_path.startswith(input_api.os_path.join(
2954 'third_party', 'WebKit'))
2955 if not (guard_name == expected_guard or
2956 is_in_blink and guard_name == expected_guard_if_blink):
2957 if is_in_blink:
2958 expected_text = "%s or %s" % (expected_guard,
2959 expected_guard_if_blink)
2960 else:
2961 expected_text = expected_guard
2962 errors.append(output_api.PresubmitPromptWarning(
2963 'Header using the wrong include guard name %s' % guard_name,
2964 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell00e1b9bc2018-03-12 13:11:122965 'Expected: %r\nFound: %r' % (expected_text, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:142966 else:
2967 # The line after #ifndef should have a #define of the same name.
2968 if line_number == guard_line_number + 1:
2969 expected_line = '#define %s' % guard_name
2970 if line != expected_line:
2971 errors.append(output_api.PresubmitPromptWarning(
2972 'Missing "%s" for include guard' % expected_line,
2973 ['%s:%d' % (f.LocalPath(), line_number + 1)],
2974 'Expected: %r\nGot: %r' % (expected_line, line)))
2975
2976 if not seen_guard_end and line == '#endif // %s' % guard_name:
2977 seen_guard_end = True
2978 elif seen_guard_end:
2979 if line.strip() != '':
2980 errors.append(output_api.PresubmitPromptWarning(
2981 'Include guard %s not covering the whole file' % (
2982 guard_name), [f.LocalPath()]))
2983 break # Nothing else to check and enough to warn once.
2984
2985 if guard_name is None:
2986 errors.append(output_api.PresubmitPromptWarning(
2987 'Missing include guard %s' % expected_guard,
2988 [f.LocalPath()],
2989 'Missing include guard in %s\n'
2990 'Recommended name: %s\n'
2991 'This check can be disabled by having the string\n'
2992 'no-include-guard-because-multiply-included in the header.' %
2993 (f.LocalPath(), expected_guard)))
2994
2995 return errors
2996
2997
mostynbb639aca52015-01-07 20:31:232998def _CheckForWindowsLineEndings(input_api, output_api):
2999 """Check source code and known ascii text files for Windows style line
3000 endings.
3001 """
earthdok1b5e0ee2015-03-10 15:19:103002 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233003
3004 file_inclusion_pattern = (
3005 known_text_files,
3006 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3007 )
3008
mostynbb639aca52015-01-07 20:31:233009 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533010 source_file_filter = lambda f: input_api.FilterSourceFile(
3011 f, white_list=file_inclusion_pattern, black_list=None)
3012 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503013 include_file = False
3014 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233015 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503016 include_file = True
3017 if include_file:
3018 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233019
3020 if problems:
3021 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3022 'these files to contain Windows style line endings?\n' +
3023 '\n'.join(problems))]
3024
3025 return []
3026
3027
Vaclav Brozekd5de76a2018-03-17 07:57:503028def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133029 """Checks that all source files use SYSLOG properly."""
3030 syslog_files = []
3031 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563032 for line_number, line in f.ChangedContents():
3033 if 'SYSLOG' in line:
3034 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3035
pastarmovj89f7ee12016-09-20 14:58:133036 if syslog_files:
3037 return [output_api.PresubmitPromptWarning(
3038 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3039 ' calls.\nFiles to check:\n', items=syslog_files)]
3040 return []
3041
3042
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193043def _CheckCrbugLinksHaveHttps(input_api, output_api):
Miguel Casas68bdb652017-12-19 16:29:093044 """Checks that crbug(.com) links are correctly prefixed by https://,
3045 unless they come in the accepted form TODO(crbug.com/...)
3046 """
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193047 white_list = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3048 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS)
3049 sources = lambda f: input_api.FilterSourceFile(
3050 f, white_list=white_list, black_list=black_list)
3051
3052 pattern = input_api.re.compile(r'//.*(?<!:\/\/)crbug[.com]*')
Miguel Casas68bdb652017-12-19 16:29:093053 accepted_pattern = input_api.re.compile(r'//.*TODO\(crbug[.com]*');
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193054 problems = []
3055 for f in input_api.AffectedSourceFiles(sources):
3056 for line_num, line in f.ChangedContents():
Miguel Casas68bdb652017-12-19 16:29:093057 if pattern.search(line) and not accepted_pattern.search(line):
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193058 problems.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3059
3060 if problems:
3061 return [output_api.PresubmitPromptWarning(
3062 'Found unprefixed crbug.com URL(s), consider prepending https://\n'+
3063 '\n'.join(problems))]
3064 return []
3065
3066
[email protected]1f7b4172010-01-28 01:17:343067def CheckChangeOnUpload(input_api, output_api):
3068 results = []
3069 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473070 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283071 results.extend(
jam93a6ee792017-02-08 23:59:223072 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193073 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223074 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133075 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163076 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193077 results.extend(_CheckCrbugLinksHaveHttps(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543078 return results
[email protected]ca8d1982009-02-19 16:33:123079
3080
[email protected]1bfb8322014-04-23 01:02:413081def GetTryServerMasterForBot(bot):
3082 """Returns the Try Server master for the given bot.
3083
[email protected]0bb112362014-07-26 04:38:323084 It tries to guess the master from the bot name, but may still fail
3085 and return None. There is no longer a default master.
3086 """
3087 # Potentially ambiguous bot names are listed explicitly.
3088 master_map = {
tandriie5587792016-07-14 00:34:503089 'chromium_presubmit': 'master.tryserver.chromium.linux',
3090 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413091 }
[email protected]0bb112362014-07-26 04:38:323092 master = master_map.get(bot)
3093 if not master:
wnwen4fbaab82016-05-25 12:54:363094 if 'android' in bot:
tandriie5587792016-07-14 00:34:503095 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363096 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503097 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323098 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503099 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323100 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503101 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323102 return master
[email protected]1bfb8322014-04-23 01:02:413103
3104
[email protected]ca8d1982009-02-19 16:33:123105def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543106 results = []
[email protected]1f7b4172010-01-28 01:17:343107 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543108 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273109 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343110 input_api,
3111 output_api,
[email protected]2fdd1f362013-01-16 03:56:033112 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273113
jam93a6ee792017-02-08 23:59:223114 results.extend(
3115 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543116 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3117 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413118 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3119 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543120 return results