blob: 3cf3d7a9846e3186f190c89bc6399b6063da35ce [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d19842009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]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]ca8d19842009-02-19 16:33:1232
wnwenbdc444e2016-05-25 13:44:1533
[email protected]06e6d0ff2012-12-11 01:36:4434# Fragment of a regular expression that matches C++ and Objective-C++
35# implementation files.
36_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
37
wnwenbdc444e2016-05-25 13:44:1538
[email protected]06e6d0ff2012-12-11 01:36:4439# Regular expression that matches code only used for test binaries
40# (best effort).
41_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4942 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4443 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
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]ca8d19842009-02-19 16:33:1255
wnwenbdc444e2016-05-25 13:44:1556
[email protected]eea609a2011-11-18 13:10:1257_TEST_ONLY_WARNING = (
58 'You might be calling functions intended only for testing from\n'
59 'production code. It is OK to ignore this warning if you know what\n'
60 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5861 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1262
63
[email protected]cf9b78f2012-11-14 11:40:2864_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4065 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2166 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
67 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2868
wnwenbdc444e2016-05-25 13:44:1569
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)
1774 json_content = input_api.json.loads(json_lines)
1775 if 'interface_provider_specs' in json_content:
1776 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:171777 for pattern in file_patterns:
1778 if input_api.fnmatch.fnmatch(
1779 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041780 skip = False
1781 for exclude in exclude_paths:
1782 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1783 skip = True
1784 break
1785 if skip:
1786 continue
Daniel Cheng13ca61a882017-08-25 15:11:251787 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:171788 break
1789
Daniel Cheng7052cdf2017-11-21 19:23:291790 return to_check
1791
1792
1793def _CheckIpcOwners(input_api, output_api):
1794 """Checks that affected files involving IPC have an IPC OWNERS rule."""
1795 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
1796
1797 if to_check:
1798 # If there are any OWNERS files to check, there are IPC-related changes in
1799 # this CL. Auto-CC the review list.
1800 output_api.AppendCC('[email protected]')
1801
1802 # Go through the OWNERS files to check, filtering out rules that are already
1803 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:171804 for owners_file, patterns in to_check.iteritems():
1805 try:
1806 with file(owners_file) as f:
1807 lines = set(f.read().splitlines())
1808 for entry in patterns.itervalues():
1809 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1810 ]
1811 except IOError:
1812 # No OWNERS file, so all the rules are definitely missing.
1813 continue
1814
1815 # All the remaining lines weren't found in OWNERS files, so emit an error.
1816 errors = []
1817 for owners_file, patterns in to_check.iteritems():
1818 missing_lines = []
1819 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:501820 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:171821 missing_lines.extend(entry['rules'])
1822 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1823 if missing_lines:
1824 errors.append(
Daniel Cheng52111692017-06-14 08:00:591825 '%s needs the following lines added:\n\n%s\n\nfor files:\n%s' %
dchenge07de812016-06-20 19:27:171826 (owners_file, '\n'.join(missing_lines), '\n'.join(files)))
1827
1828 results = []
1829 if errors:
vabrf5ce3bf92016-07-11 14:52:411830 if input_api.is_committing:
1831 output = output_api.PresubmitError
1832 else:
1833 output = output_api.PresubmitPromptWarning
1834 results.append(output(
Daniel Cheng52111692017-06-14 08:00:591835 'Found OWNERS files that need to be updated for IPC security ' +
1836 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:171837 long_text='\n\n'.join(errors)))
1838
1839 return results
1840
1841
jbriance9e12f162016-11-25 07:57:501842def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311843 """Checks that added or removed lines in non third party affected
1844 header files do not lead to new useless class or struct forward
1845 declaration.
jbriance9e12f162016-11-25 07:57:501846 """
1847 results = []
1848 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1849 input_api.re.MULTILINE)
1850 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
1851 input_api.re.MULTILINE)
1852 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:311853 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:191854 not f.LocalPath().startswith('third_party/blink') and
1855 not f.LocalPath().startswith('third_party\\blink') and
jbriance2c51e821a2016-12-12 08:24:311856 not f.LocalPath().startswith('third_party/WebKit') and
1857 not f.LocalPath().startswith('third_party\\WebKit')):
1858 continue
1859
jbriance9e12f162016-11-25 07:57:501860 if not f.LocalPath().endswith('.h'):
1861 continue
1862
1863 contents = input_api.ReadFile(f)
1864 fwd_decls = input_api.re.findall(class_pattern, contents)
1865 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
1866
1867 useless_fwd_decls = []
1868 for decl in fwd_decls:
1869 count = sum(1 for _ in input_api.re.finditer(
1870 r'\b%s\b' % input_api.re.escape(decl), contents))
1871 if count == 1:
1872 useless_fwd_decls.append(decl)
1873
1874 if not useless_fwd_decls:
1875 continue
1876
1877 for line in f.GenerateScmDiff().splitlines():
1878 if (line.startswith('-') and not line.startswith('--') or
1879 line.startswith('+') and not line.startswith('++')):
1880 for decl in useless_fwd_decls:
1881 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
1882 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:241883 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:501884 (f.LocalPath(), decl)))
1885 useless_fwd_decls.remove(decl)
1886
1887 return results
1888
1889
dskiba88634f4e2015-08-14 23:03:291890def _CheckAndroidToastUsage(input_api, output_api):
1891 """Checks that code uses org.chromium.ui.widget.Toast instead of
1892 android.widget.Toast (Chromium Toast doesn't force hardware
1893 acceleration on low-end devices, saving memory).
1894 """
1895 toast_import_pattern = input_api.re.compile(
1896 r'^import android\.widget\.Toast;$')
1897
1898 errors = []
1899
1900 sources = lambda affected_file: input_api.FilterSourceFile(
1901 affected_file,
1902 black_list=(_EXCLUDED_PATHS +
1903 _TEST_CODE_EXCLUDED_PATHS +
1904 input_api.DEFAULT_BLACK_LIST +
1905 (r'^chromecast[\\\/].*',
1906 r'^remoting[\\\/].*')),
1907 white_list=(r'.*\.java$',))
1908
1909 for f in input_api.AffectedSourceFiles(sources):
1910 for line_num, line in f.ChangedContents():
1911 if toast_import_pattern.search(line):
1912 errors.append("%s:%d" % (f.LocalPath(), line_num))
1913
1914 results = []
1915
1916 if errors:
1917 results.append(output_api.PresubmitError(
1918 'android.widget.Toast usage is detected. Android toasts use hardware'
1919 ' acceleration, and can be\ncostly on low-end devices. Please use'
1920 ' org.chromium.ui.widget.Toast instead.\n'
1921 'Contact [email protected] if you have any questions.',
1922 errors))
1923
1924 return results
1925
1926
dgnaa68d5e2015-06-10 10:08:221927def _CheckAndroidCrLogUsage(input_api, output_api):
1928 """Checks that new logs using org.chromium.base.Log:
1929 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:511930 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:221931 """
pkotwicza1dd0b002016-05-16 14:41:041932
torne89540622017-03-24 19:41:301933 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:041934 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:301935 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:041936 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:301937 # WebView license viewer code cannot depend on //base; used in stub APK.
1938 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
1939 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:041940 ]
1941
dgnaa68d5e2015-06-10 10:08:221942 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:121943 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
1944 class_in_base_pattern = input_api.re.compile(
1945 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
1946 has_some_log_import_pattern = input_api.re.compile(
1947 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221948 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:121949 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:221950 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:511951 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:221952 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:221953
Vincent Scheib16d7b272015-09-15 18:09:071954 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:221955 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:041956 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
1957 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:121958
dgnaa68d5e2015-06-10 10:08:221959 tag_decl_errors = []
1960 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:121961 tag_errors = []
dgn38736db2015-09-18 19:20:511962 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:121963 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:221964
1965 for f in input_api.AffectedSourceFiles(sources):
1966 file_content = input_api.ReadFile(f)
1967 has_modified_logs = False
1968
1969 # Per line checks
dgn87d9fb62015-06-12 09:15:121970 if (cr_log_import_pattern.search(file_content) or
1971 (class_in_base_pattern.search(file_content) and
1972 not has_some_log_import_pattern.search(file_content))):
1973 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:221974 for line_num, line in f.ChangedContents():
1975
1976 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:121977 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:221978 if match:
1979 has_modified_logs = True
1980
1981 # Make sure it uses "TAG"
1982 if not match.group('tag') == 'TAG':
1983 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:121984 else:
1985 # Report non cr Log function calls in changed lines
1986 for line_num, line in f.ChangedContents():
1987 if log_call_pattern.search(line):
1988 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:221989
1990 # Per file checks
1991 if has_modified_logs:
1992 # Make sure the tag is using the "cr" prefix and is not too long
1993 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:511994 tag_name = match.group('name') if match else None
1995 if not tag_name:
dgnaa68d5e2015-06-10 10:08:221996 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511997 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:221998 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:511999 elif '.' in tag_name:
2000 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222001
2002 results = []
2003 if tag_decl_errors:
2004 results.append(output_api.PresubmitPromptWarning(
2005 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512006 '"private static final String TAG = "<package tag>".\n'
2007 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222008 tag_decl_errors))
2009
2010 if tag_length_errors:
2011 results.append(output_api.PresubmitError(
2012 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512013 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222014 tag_length_errors))
2015
2016 if tag_errors:
2017 results.append(output_api.PresubmitPromptWarning(
2018 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2019 tag_errors))
2020
dgn87d9fb62015-06-12 09:15:122021 if util_log_errors:
dgn4401aa52015-04-29 16:26:172022 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122023 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2024 util_log_errors))
2025
dgn38736db2015-09-18 19:20:512026 if tag_with_dot_errors:
2027 results.append(output_api.PresubmitPromptWarning(
2028 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2029 tag_with_dot_errors))
2030
dgn4401aa52015-04-29 16:26:172031 return results
2032
2033
Yoland Yanb92fa522017-08-28 17:37:062034def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2035 """Checks that junit.framework.* is no longer used."""
2036 deprecated_junit_framework_pattern = input_api.re.compile(
2037 r'^import junit\.framework\..*;',
2038 input_api.re.MULTILINE)
2039 sources = lambda x: input_api.FilterSourceFile(
2040 x, white_list=(r'.*\.java$',), black_list=None)
2041 errors = []
2042 for f in input_api.AffectedFiles(sources):
2043 for line_num, line in f.ChangedContents():
2044 if deprecated_junit_framework_pattern.search(line):
2045 errors.append("%s:%d" % (f.LocalPath(), line_num))
2046
2047 results = []
2048 if errors:
2049 results.append(output_api.PresubmitError(
2050 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2051 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2052 ' if you have any question.', errors))
2053 return results
2054
2055
2056def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2057 """Checks that if new Java test classes have inheritance.
2058 Either the new test class is JUnit3 test or it is a JUnit4 test class
2059 with a base class, either case is undesirable.
2060 """
2061 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2062
2063 sources = lambda x: input_api.FilterSourceFile(
2064 x, white_list=(r'.*Test\.java$',), black_list=None)
2065 errors = []
2066 for f in input_api.AffectedFiles(sources):
2067 if not f.OldContents():
2068 class_declaration_start_flag = False
2069 for line_num, line in f.ChangedContents():
2070 if class_declaration_pattern.search(line):
2071 class_declaration_start_flag = True
2072 if class_declaration_start_flag and ' extends ' in line:
2073 errors.append('%s:%d' % (f.LocalPath(), line_num))
2074 if '{' in line:
2075 class_declaration_start_flag = False
2076
2077 results = []
2078 if errors:
2079 results.append(output_api.PresubmitPromptWarning(
2080 'The newly created files include Test classes that inherits from base'
2081 ' class. Please do not use inheritance in JUnit4 tests or add new'
2082 ' JUnit3 tests. Contact [email protected] if you have any'
2083 ' questions.', errors))
2084 return results
2085
yolandyan45001472016-12-21 21:12:422086def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2087 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2088 deprecated_annotation_import_pattern = input_api.re.compile(
2089 r'^import android\.test\.suitebuilder\.annotation\..*;',
2090 input_api.re.MULTILINE)
2091 sources = lambda x: input_api.FilterSourceFile(
2092 x, white_list=(r'.*\.java$',), black_list=None)
2093 errors = []
2094 for f in input_api.AffectedFiles(sources):
2095 for line_num, line in f.ChangedContents():
2096 if deprecated_annotation_import_pattern.search(line):
2097 errors.append("%s:%d" % (f.LocalPath(), line_num))
2098
2099 results = []
2100 if errors:
2101 results.append(output_api.PresubmitError(
2102 'Annotations in android.test.suitebuilder.annotation have been'
2103 ' deprecated since API level 24. Please use android.support.test.filters'
2104 ' from //third_party/android_support_test_runner:runner_java instead.'
2105 ' Contact [email protected] if you have any questions.', errors))
2106 return results
2107
2108
agrieve7b6479d82015-10-07 14:24:222109def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2110 """Checks if MDPI assets are placed in a correct directory."""
2111 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2112 ('/res/drawable/' in f.LocalPath() or
2113 '/res/drawable-ldrtl/' in f.LocalPath()))
2114 errors = []
2115 for f in input_api.AffectedFiles(include_deletes=False,
2116 file_filter=file_filter):
2117 errors.append(' %s' % f.LocalPath())
2118
2119 results = []
2120 if errors:
2121 results.append(output_api.PresubmitError(
2122 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2123 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2124 '/res/drawable-ldrtl/.\n'
2125 'Contact [email protected] if you have questions.', errors))
2126 return results
2127
2128
Nate Fischer535972b2017-09-16 01:06:182129def _CheckAndroidWebkitImports(input_api, output_api):
2130 """Checks that code uses org.chromium.base.Callback instead of
2131 android.widget.ValueCallback except in the WebView glue layer.
2132 """
2133 valuecallback_import_pattern = input_api.re.compile(
2134 r'^import android\.webkit\.ValueCallback;$')
2135
2136 errors = []
2137
2138 sources = lambda affected_file: input_api.FilterSourceFile(
2139 affected_file,
2140 black_list=(_EXCLUDED_PATHS +
2141 _TEST_CODE_EXCLUDED_PATHS +
2142 input_api.DEFAULT_BLACK_LIST +
2143 (r'^android_webview[\\\/]glue[\\\/].*',)),
2144 white_list=(r'.*\.java$',))
2145
2146 for f in input_api.AffectedSourceFiles(sources):
2147 for line_num, line in f.ChangedContents():
2148 if valuecallback_import_pattern.search(line):
2149 errors.append("%s:%d" % (f.LocalPath(), line_num))
2150
2151 results = []
2152
2153 if errors:
2154 results.append(output_api.PresubmitError(
2155 'android.webkit.ValueCallback usage is detected outside of the glue'
2156 ' layer. To stay compatible with the support library, android.webkit.*'
2157 ' classes should only be used inside the glue layer and'
2158 ' org.chromium.base.Callback should be used instead.',
2159 errors))
2160
2161 return results
2162
2163
agrievef32bcc72016-04-04 14:57:402164class PydepsChecker(object):
2165 def __init__(self, input_api, pydeps_files):
2166 self._file_cache = {}
2167 self._input_api = input_api
2168 self._pydeps_files = pydeps_files
2169
2170 def _LoadFile(self, path):
2171 """Returns the list of paths within a .pydeps file relative to //."""
2172 if path not in self._file_cache:
2173 with open(path) as f:
2174 self._file_cache[path] = f.read()
2175 return self._file_cache[path]
2176
2177 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2178 """Returns an interable of paths within the .pydep, relativized to //."""
2179 os_path = self._input_api.os_path
2180 pydeps_dir = os_path.dirname(pydeps_path)
2181 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2182 if not l.startswith('*'))
2183 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2184
2185 def _CreateFilesToPydepsMap(self):
2186 """Returns a map of local_path -> list_of_pydeps."""
2187 ret = {}
2188 for pydep_local_path in self._pydeps_files:
2189 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2190 ret.setdefault(path, []).append(pydep_local_path)
2191 return ret
2192
2193 def ComputeAffectedPydeps(self):
2194 """Returns an iterable of .pydeps files that might need regenerating."""
2195 affected_pydeps = set()
2196 file_to_pydeps_map = None
2197 for f in self._input_api.AffectedFiles(include_deletes=True):
2198 local_path = f.LocalPath()
2199 if local_path == 'DEPS':
2200 return self._pydeps_files
2201 elif local_path.endswith('.pydeps'):
2202 if local_path in self._pydeps_files:
2203 affected_pydeps.add(local_path)
2204 elif local_path.endswith('.py'):
2205 if file_to_pydeps_map is None:
2206 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2207 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2208 return affected_pydeps
2209
2210 def DetermineIfStale(self, pydeps_path):
2211 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412212 import difflib
John Budorick47ca3fe2018-02-10 00:53:102213 import os
2214
agrievef32bcc72016-04-04 14:57:402215 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2216 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102217 env = dict(os.environ)
2218 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402219 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102220 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412221 old_contents = old_pydeps_data[2:]
2222 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402223 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412224 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402225
2226
2227def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2228 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402229 # This check is for Python dependency lists (.pydeps files), and involves
2230 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2231 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282232 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002233 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022234 # TODO(agrieve): Update when there's a better way to detect
2235 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402236 is_android = input_api.os_path.exists('third_party/android_tools')
2237 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2238 results = []
2239 # First, check for new / deleted .pydeps.
2240 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032241 # Check whether we are running the presubmit check for a file in src.
2242 # f.LocalPath is relative to repo (src, or internal repo).
2243 # os_path.exists is relative to src repo.
2244 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2245 # to src and we can conclude that the pydeps is in src.
2246 if input_api.os_path.exists(f.LocalPath()):
2247 if f.LocalPath().endswith('.pydeps'):
2248 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2249 results.append(output_api.PresubmitError(
2250 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2251 'remove %s' % f.LocalPath()))
2252 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2253 results.append(output_api.PresubmitError(
2254 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2255 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402256
2257 if results:
2258 return results
2259
2260 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2261
2262 for pydep_path in checker.ComputeAffectedPydeps():
2263 try:
phajdan.jr0d9878552016-11-04 10:49:412264 result = checker.DetermineIfStale(pydep_path)
2265 if result:
2266 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402267 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412268 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2269 'To regenerate, run:\n\n %s' %
2270 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402271 except input_api.subprocess.CalledProcessError as error:
2272 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2273 long_text=error.output)]
2274
2275 return results
2276
2277
glidere61efad2015-02-18 17:39:432278def _CheckSingletonInHeaders(input_api, output_api):
2279 """Checks to make sure no header files have |Singleton<|."""
2280 def FileFilter(affected_file):
2281 # It's ok for base/memory/singleton.h to have |Singleton<|.
2282 black_list = (_EXCLUDED_PATHS +
2283 input_api.DEFAULT_BLACK_LIST +
Michael Warrese4451492018-03-07 04:42:472284 (r"^base[\\\/]memory[\\\/]singleton\.h$",
2285 r"^net[\\\/]quic[\\\/]platform[\\\/]impl[\\\/]"
2286 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432287 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2288
sergeyu34d21222015-09-16 00:11:442289 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432290 files = []
2291 for f in input_api.AffectedSourceFiles(FileFilter):
2292 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2293 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2294 contents = input_api.ReadFile(f)
2295 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242296 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432297 pattern.search(line)):
2298 files.append(f)
2299 break
2300
2301 if files:
yolandyandaabc6d2016-04-18 18:29:392302 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442303 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432304 'Please move them to an appropriate source file so that the ' +
2305 'template gets instantiated in a single compilation unit.',
2306 files) ]
2307 return []
2308
2309
[email protected]fd20b902014-05-09 02:14:532310_DEPRECATED_CSS = [
2311 # Values
2312 ( "-webkit-box", "flex" ),
2313 ( "-webkit-inline-box", "inline-flex" ),
2314 ( "-webkit-flex", "flex" ),
2315 ( "-webkit-inline-flex", "inline-flex" ),
2316 ( "-webkit-min-content", "min-content" ),
2317 ( "-webkit-max-content", "max-content" ),
2318
2319 # Properties
2320 ( "-webkit-background-clip", "background-clip" ),
2321 ( "-webkit-background-origin", "background-origin" ),
2322 ( "-webkit-background-size", "background-size" ),
2323 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442324 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532325
2326 # Functions
2327 ( "-webkit-gradient", "gradient" ),
2328 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2329 ( "-webkit-linear-gradient", "linear-gradient" ),
2330 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2331 ( "-webkit-radial-gradient", "radial-gradient" ),
2332 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2333]
2334
dbeam1ec68ac2016-12-15 05:22:242335def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532336 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252337 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342338 documentation and iOS CSS for dom distiller
2339 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252340 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532341 results = []
dbeam070cfe62014-10-22 06:44:022342 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:252343 black_list = (_EXCLUDED_PATHS +
2344 _TEST_CODE_EXCLUDED_PATHS +
2345 input_api.DEFAULT_BLACK_LIST +
2346 (r"^chrome/common/extensions/docs",
2347 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342348 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442349 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252350 r"^native_client_sdk"))
2351 file_filter = lambda f: input_api.FilterSourceFile(
2352 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532353 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2354 for line_num, line in fpath.ChangedContents():
2355 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022356 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532357 results.append(output_api.PresubmitError(
2358 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2359 (fpath.LocalPath(), line_num, deprecated_value, value)))
2360 return results
2361
mohan.reddyf21db962014-10-16 12:26:472362
dbeam070cfe62014-10-22 06:44:022363_DEPRECATED_JS = [
2364 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2365 ( "__defineGetter__", "Object.defineProperty" ),
2366 ( "__defineSetter__", "Object.defineProperty" ),
2367]
2368
dbeam1ec68ac2016-12-15 05:22:242369def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022370 """Make sure that we don't use deprecated JS in Chrome code."""
2371 results = []
2372 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2373 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2374 input_api.DEFAULT_BLACK_LIST)
2375 file_filter = lambda f: input_api.FilterSourceFile(
2376 f, white_list=file_inclusion_pattern, black_list=black_list)
2377 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2378 for lnum, line in fpath.ChangedContents():
2379 for (deprecated, replacement) in _DEPRECATED_JS:
2380 if deprecated in line:
2381 results.append(output_api.PresubmitError(
2382 "%s:%d: Use of deprecated JS %s, use %s instead" %
2383 (fpath.LocalPath(), lnum, deprecated, replacement)))
2384 return results
2385
dpapadd651231d82017-07-21 02:44:472386def _CheckForRiskyJsArrowFunction(line_number, line):
2387 if ' => ' in line:
2388 return "line %d, is using an => (arrow) function\n %s\n" % (
2389 line_number, line)
2390 return ''
2391
2392def _CheckForRiskyJsConstLet(input_api, line_number, line):
2393 if input_api.re.match('^\s*(const|let)\s', line):
2394 return "line %d, is using const/let keyword\n %s\n" % (
2395 line_number, line)
2396 return ''
dbeam070cfe62014-10-22 06:44:022397
dbeam1ec68ac2016-12-15 05:22:242398def _CheckForRiskyJsFeatures(input_api, output_api):
2399 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
Steven Bennetts90545f3cb2017-08-14 18:11:002400 # 'ui/webui/resources/cr_components are not allowed on ios'
2401 not_ios_filter = (r".*ui\/webui\/resources\/cr_components.*", )
Steven Bennetts9c7e3c22017-08-02 19:10:572402 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js,
Steven Bennetts90545f3cb2017-08-14 18:11:002403 black_list=not_ios_filter)
dpapadd651231d82017-07-21 02:44:472404 results = []
dbeam1ec68ac2016-12-15 05:22:242405 for f in input_api.AffectedFiles(file_filter=file_filter):
dpapadd651231d82017-07-21 02:44:472406 arrow_error_lines = []
2407 const_let_error_lines = []
dbeam1ec68ac2016-12-15 05:22:242408 for lnum, line in f.ChangedContents():
dpapadd651231d82017-07-21 02:44:472409 arrow_error_lines += filter(None, [
2410 _CheckForRiskyJsArrowFunction(lnum, line),
2411 ])
dbeam1ec68ac2016-12-15 05:22:242412
dpapadd651231d82017-07-21 02:44:472413 const_let_error_lines += filter(None, [
2414 _CheckForRiskyJsConstLet(input_api, lnum, line),
2415 ])
dbeam1ec68ac2016-12-15 05:22:242416
dpapadd651231d82017-07-21 02:44:472417 if arrow_error_lines:
2418 arrow_error_lines = map(
2419 lambda e: "%s:%s" % (f.LocalPath(), e), arrow_error_lines)
2420 results.append(
2421 output_api.PresubmitPromptWarning('\n'.join(arrow_error_lines + [
2422"""
2423Use of => (arrow) operator detected in:
dbeam1ec68ac2016-12-15 05:22:242424%s
2425Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2426https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
dpapadd651231d82017-07-21 02:44:472427""" % f.LocalPath()
2428 ])))
dbeam1ec68ac2016-12-15 05:22:242429
dpapadd651231d82017-07-21 02:44:472430 if const_let_error_lines:
2431 const_let_error_lines = map(
2432 lambda e: "%s:%s" % (f.LocalPath(), e), const_let_error_lines)
2433 results.append(
2434 output_api.PresubmitPromptWarning('\n'.join(const_let_error_lines + [
2435"""
2436Use of const/let keywords detected in:
2437%s
2438Please ensure your code does not run on iOS9 because const/let is not fully
2439supported.
2440https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#let-Block_Scoped-Variables
2441https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#const-Block_Scoped-Constants
2442""" % f.LocalPath()
2443 ])))
2444
2445 return results
dbeam1ec68ac2016-12-15 05:22:242446
rlanday6802cf632017-05-30 17:48:362447def _CheckForRelativeIncludes(input_api, output_api):
2448 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2449 import sys
2450 original_sys_path = sys.path
2451 try:
2452 sys.path = sys.path + [input_api.os_path.join(
2453 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2454 from cpp_checker import CppChecker
2455 finally:
2456 # Restore sys.path to what it was before.
2457 sys.path = original_sys_path
2458
2459 bad_files = {}
2460 for f in input_api.AffectedFiles(include_deletes=False):
2461 if (f.LocalPath().startswith('third_party') and
2462 not f.LocalPath().startswith('third_party/WebKit') and
2463 not f.LocalPath().startswith('third_party\\WebKit')):
2464 continue
2465
2466 if not CppChecker.IsCppFile(f.LocalPath()):
2467 continue
2468
Vaclav Brozekd5de76a2018-03-17 07:57:502469 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362470 if "#include" in line and "../" in line]
2471 if not relative_includes:
2472 continue
2473 bad_files[f.LocalPath()] = relative_includes
2474
2475 if not bad_files:
2476 return []
2477
2478 error_descriptions = []
2479 for file_path, bad_lines in bad_files.iteritems():
2480 error_description = file_path
2481 for line in bad_lines:
2482 error_description += '\n ' + line
2483 error_descriptions.append(error_description)
2484
2485 results = []
2486 results.append(output_api.PresubmitError(
2487 'You added one or more relative #include paths (including "../").\n'
2488 'These shouldn\'t be used because they can be used to include headers\n'
2489 'from code that\'s not correctly specified as a dependency in the\n'
2490 'relevant BUILD.gn file(s).',
2491 error_descriptions))
2492
2493 return results
2494
Takeshi Yoshinoe387aa32017-08-02 13:16:132495
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202496def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2497 if not isinstance(key, ast.Str):
2498 return 'Key at line %d must be a string literal' % key.lineno
2499 if not isinstance(value, ast.Dict):
2500 return 'Value at line %d must be a dict' % value.lineno
2501 if len(value.keys) != 1:
2502 return 'Dict at line %d must have single entry' % value.lineno
2503 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2504 return (
2505 'Entry at line %d must have a string literal \'filepath\' as key' %
2506 value.lineno)
2507 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132508
Takeshi Yoshinoe387aa32017-08-02 13:16:132509
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202510def _CheckWatchlistsEntrySyntax(key, value, ast):
2511 if not isinstance(key, ast.Str):
2512 return 'Key at line %d must be a string literal' % key.lineno
2513 if not isinstance(value, ast.List):
2514 return 'Value at line %d must be a list' % value.lineno
2515 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132516
Takeshi Yoshinoe387aa32017-08-02 13:16:132517
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202518def _CheckWATCHLISTSEntries(wd_dict, w_dict, ast):
2519 mismatch_template = (
2520 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2521 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132522
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202523 i = 0
2524 last_key = ''
2525 while True:
2526 if i >= len(wd_dict.keys):
2527 if i >= len(w_dict.keys):
2528 return None
2529 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2530 elif i >= len(w_dict.keys):
2531 return (
2532 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132533
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202534 wd_key = wd_dict.keys[i]
2535 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132536
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202537 result = _CheckWatchlistDefinitionsEntrySyntax(
2538 wd_key, wd_dict.values[i], ast)
2539 if result is not None:
2540 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132541
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202542 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast)
2543 if result is not None:
2544 return 'Bad entry in WATCHLISTS dict: %s' % result
2545
2546 if wd_key.s != w_key.s:
2547 return mismatch_template % (
2548 '%s at line %d' % (wd_key.s, wd_key.lineno),
2549 '%s at line %d' % (w_key.s, w_key.lineno))
2550
2551 if wd_key.s < last_key:
2552 return (
2553 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2554 (wd_key.lineno, w_key.lineno))
2555 last_key = wd_key.s
2556
2557 i = i + 1
2558
2559
2560def _CheckWATCHLISTSSyntax(expression, ast):
2561 if not isinstance(expression, ast.Expression):
2562 return 'WATCHLISTS file must contain a valid expression'
2563 dictionary = expression.body
2564 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2565 return 'WATCHLISTS file must have single dict with exactly two entries'
2566
2567 first_key = dictionary.keys[0]
2568 first_value = dictionary.values[0]
2569 second_key = dictionary.keys[1]
2570 second_value = dictionary.values[1]
2571
2572 if (not isinstance(first_key, ast.Str) or
2573 first_key.s != 'WATCHLIST_DEFINITIONS' or
2574 not isinstance(first_value, ast.Dict)):
2575 return (
2576 'The first entry of the dict in WATCHLISTS file must be '
2577 'WATCHLIST_DEFINITIONS dict')
2578
2579 if (not isinstance(second_key, ast.Str) or
2580 second_key.s != 'WATCHLISTS' or
2581 not isinstance(second_value, ast.Dict)):
2582 return (
2583 'The second entry of the dict in WATCHLISTS file must be '
2584 'WATCHLISTS dict')
2585
2586 return _CheckWATCHLISTSEntries(first_value, second_value, ast)
Takeshi Yoshinoe387aa32017-08-02 13:16:132587
2588
2589def _CheckWATCHLISTS(input_api, output_api):
2590 for f in input_api.AffectedFiles(include_deletes=False):
2591 if f.LocalPath() == 'WATCHLISTS':
2592 contents = input_api.ReadFile(f, 'r')
2593
2594 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202595 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132596 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202597 # Get an AST tree for it and scan the tree for detailed style checking.
2598 expression = input_api.ast.parse(
2599 contents, filename='WATCHLISTS', mode='eval')
2600 except ValueError as e:
2601 return [output_api.PresubmitError(
2602 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2603 except SyntaxError as e:
2604 return [output_api.PresubmitError(
2605 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2606 except TypeError as e:
2607 return [output_api.PresubmitError(
2608 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132609
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202610 result = _CheckWATCHLISTSSyntax(expression, input_api.ast)
2611 if result is not None:
2612 return [output_api.PresubmitError(result)]
2613 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132614
2615 return []
2616
2617
dgnaa68d5e2015-06-10 10:08:222618def _AndroidSpecificOnUploadChecks(input_api, output_api):
2619 """Groups checks that target android code."""
2620 results = []
dgnaa68d5e2015-06-10 10:08:222621 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222622 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292623 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:062624 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
2625 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:422626 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:182627 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222628 return results
2629
2630
[email protected]22c9bd72011-03-27 16:47:392631def _CommonChecks(input_api, output_api):
2632 """Checks common to both upload and commit."""
2633 results = []
2634 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382635 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542636 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:082637
2638 author = input_api.change.author_email
2639 if author and author not in _KNOWN_ROBOTS:
2640 results.extend(
2641 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
2642
[email protected]55459852011-08-10 15:17:192643 results.extend(
[email protected]760deea2013-12-10 19:33:492644 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542645 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182646 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522647 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222648 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442649 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592650 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062651 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122652 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182653 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222654 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302655 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492656 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032657 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492658 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442659 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272660 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:072661 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542662 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442663 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392664 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552665 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042666 results.extend(
2667 input_api.canned_checks.CheckChangeHasNoTabs(
2668 input_api,
2669 output_api,
2670 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402671 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162672 results.extend(_CheckForAnonymousVariables(input_api, output_api))
Peter Kasting4844e46e2018-02-23 07:27:102673 results.extend(_CheckUniquePtr(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082674 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242675 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2676 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472677 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042678 results.extend(_CheckForIPCRules(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:142679 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232680 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432681 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402682 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152683 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172684 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502685 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242686 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:362687 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:132688 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:432689 results.extend(input_api.RunTests(
2690 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:242691
Vaclav Brozekcdc7defb2018-03-20 09:54:352692 for f in input_api.AffectedFiles():
2693 path, name = input_api.os_path.split(f.LocalPath())
2694 if name == 'PRESUBMIT.py':
2695 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
2696 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2697 input_api, output_api, full_path,
2698 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392699 return results
[email protected]1f7b4172010-01-28 01:17:342700
[email protected]b337cb5b2011-01-23 21:24:052701
[email protected]b8079ae4a2012-12-05 19:56:492702def _CheckPatchFiles(input_api, output_api):
2703 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2704 if f.LocalPath().endswith(('.orig', '.rej'))]
2705 if problems:
2706 return [output_api.PresubmitError(
2707 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032708 else:
2709 return []
[email protected]b8079ae4a2012-12-05 19:56:492710
2711
Kent Tamura5a8755d2017-06-29 23:37:072712def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:212713 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
2714 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
2715 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:072716 include_re = input_api.re.compile(
2717 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
2718 extension_re = input_api.re.compile(r'\.[a-z]+$')
2719 errors = []
2720 for f in input_api.AffectedFiles():
2721 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
2722 continue
2723 found_line_number = None
2724 found_macro = None
2725 for line_num, line in f.ChangedContents():
2726 match = macro_re.search(line)
2727 if match:
2728 found_line_number = line_num
2729 found_macro = match.group(2)
2730 break
2731 if not found_line_number:
2732 continue
2733
2734 found_include = False
2735 for line in f.NewContents():
2736 if include_re.search(line):
2737 found_include = True
2738 break
2739 if found_include:
2740 continue
2741
2742 if not f.LocalPath().endswith('.h'):
2743 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
2744 try:
2745 content = input_api.ReadFile(primary_header_path, 'r')
2746 if include_re.search(content):
2747 continue
2748 except IOError:
2749 pass
2750 errors.append('%s:%d %s macro is used without including build/'
2751 'build_config.h.'
2752 % (f.LocalPath(), found_line_number, found_macro))
2753 if errors:
2754 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
2755 return []
2756
2757
[email protected]b00342e7f2013-03-26 16:21:542758def _DidYouMeanOSMacro(bad_macro):
2759 try:
2760 return {'A': 'OS_ANDROID',
2761 'B': 'OS_BSD',
2762 'C': 'OS_CHROMEOS',
2763 'F': 'OS_FREEBSD',
2764 'L': 'OS_LINUX',
2765 'M': 'OS_MACOSX',
2766 'N': 'OS_NACL',
2767 'O': 'OS_OPENBSD',
2768 'P': 'OS_POSIX',
2769 'S': 'OS_SOLARIS',
2770 'W': 'OS_WIN'}[bad_macro[3].upper()]
2771 except KeyError:
2772 return ''
2773
2774
2775def _CheckForInvalidOSMacrosInFile(input_api, f):
2776 """Check for sensible looking, totally invalid OS macros."""
2777 preprocessor_statement = input_api.re.compile(r'^\s*#')
2778 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2779 results = []
2780 for lnum, line in f.ChangedContents():
2781 if preprocessor_statement.search(line):
2782 for match in os_macro.finditer(line):
2783 if not match.group(1) in _VALID_OS_MACROS:
2784 good = _DidYouMeanOSMacro(match.group(1))
2785 did_you_mean = ' (did you mean %s?)' % good if good else ''
2786 results.append(' %s:%d %s%s' % (f.LocalPath(),
2787 lnum,
2788 match.group(1),
2789 did_you_mean))
2790 return results
2791
2792
2793def _CheckForInvalidOSMacros(input_api, output_api):
2794 """Check all affected files for invalid OS macros."""
2795 bad_macros = []
2796 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472797 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542798 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2799
2800 if not bad_macros:
2801 return []
2802
2803 return [output_api.PresubmitError(
2804 'Possibly invalid OS macro[s] found. Please fix your code\n'
2805 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2806
lliabraa35bab3932014-10-01 12:16:442807
2808def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2809 """Check all affected files for invalid "if defined" macros."""
2810 ALWAYS_DEFINED_MACROS = (
2811 "TARGET_CPU_PPC",
2812 "TARGET_CPU_PPC64",
2813 "TARGET_CPU_68K",
2814 "TARGET_CPU_X86",
2815 "TARGET_CPU_ARM",
2816 "TARGET_CPU_MIPS",
2817 "TARGET_CPU_SPARC",
2818 "TARGET_CPU_ALPHA",
2819 "TARGET_IPHONE_SIMULATOR",
2820 "TARGET_OS_EMBEDDED",
2821 "TARGET_OS_IPHONE",
2822 "TARGET_OS_MAC",
2823 "TARGET_OS_UNIX",
2824 "TARGET_OS_WIN32",
2825 )
2826 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2827 results = []
2828 for lnum, line in f.ChangedContents():
2829 for match in ifdef_macro.finditer(line):
2830 if match.group(1) in ALWAYS_DEFINED_MACROS:
2831 always_defined = ' %s is always defined. ' % match.group(1)
2832 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2833 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2834 lnum,
2835 always_defined,
2836 did_you_mean))
2837 return results
2838
2839
2840def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2841 """Check all affected files for invalid "if defined" macros."""
2842 bad_macros = []
2843 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:212844 if f.LocalPath().startswith('third_party/sqlite/'):
2845 continue
lliabraa35bab3932014-10-01 12:16:442846 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
2847 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
2848
2849 if not bad_macros:
2850 return []
2851
2852 return [output_api.PresubmitError(
2853 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
2854 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
2855 bad_macros)]
2856
2857
mlamouria82272622014-09-16 18:45:042858def _CheckForIPCRules(input_api, output_api):
2859 """Check for same IPC rules described in
2860 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
2861 """
2862 base_pattern = r'IPC_ENUM_TRAITS\('
2863 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
2864 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
2865
2866 problems = []
2867 for f in input_api.AffectedSourceFiles(None):
2868 local_path = f.LocalPath()
2869 if not local_path.endswith('.h'):
2870 continue
2871 for line_number, line in f.ChangedContents():
2872 if inclusion_pattern.search(line) and not comment_pattern.search(line):
2873 problems.append(
2874 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2875
2876 if problems:
2877 return [output_api.PresubmitPromptWarning(
2878 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
2879 else:
2880 return []
2881
[email protected]b00342e7f2013-03-26 16:21:542882
Daniel Bratell8ba52722018-03-02 16:06:142883def _CheckForIncludeGuards(input_api, output_api):
2884 """Check that header files have proper guards against multiple inclusion.
2885 If a file should not have such guards (and it probably should) then it
2886 should include the string "no-include-guard-because-multiply-included".
2887 """
2888 def is_header_file(f):
2889 return f.LocalPath().endswith('.h')
2890
2891 def replace_special_with_underscore(string):
2892 return input_api.re.sub(r'[\\/.-]', '_', string)
2893
2894 errors = []
2895
2896 for f in input_api.AffectedSourceFiles(is_header_file):
2897 guard_name = None
2898 guard_line_number = None
2899 seen_guard_end = False
2900
2901 file_with_path = input_api.os_path.normpath(f.LocalPath())
2902 base_file_name = input_api.os_path.splitext(
2903 input_api.os_path.basename(file_with_path))[0]
2904 upper_base_file_name = base_file_name.upper()
2905
2906 expected_guard = replace_special_with_underscore(
2907 file_with_path.upper() + '_')
2908 expected_guard_if_blink = base_file_name + '_h'
2909
2910 # For "path/elem/file_name.h" we should really only accept
2911 # PATH_ELEM_FILE_NAME_H_ per coding style or, if Blink,
2912 # file_name_h. Unfortunately there are too many (1000+) files
2913 # with slight deviations from the coding style. Since the most
2914 # important part is that the include guard is there, and that it's
2915 # unique, not the name, this check is forgiving for existing files.
2916 #
2917 # As code becomes more uniform, this could be made stricter.
2918
2919 guard_name_pattern_list = [
2920 # Anything with the right suffix (maybe with an extra _).
2921 r'\w+_H__?',
2922
2923 # To cover include guards with Blink style.
2924 r'\w+_h',
2925
2926 # Anything including the uppercase name of the file.
2927 r'\w*' + input_api.re.escape(replace_special_with_underscore(
2928 upper_base_file_name)) + r'\w*',
2929 ]
2930 guard_name_pattern = '|'.join(guard_name_pattern_list)
2931 guard_pattern = input_api.re.compile(
2932 r'#ifndef\s+(' + guard_name_pattern + ')')
2933
2934 for line_number, line in enumerate(f.NewContents()):
2935 if 'no-include-guard-because-multiply-included' in line:
2936 guard_name = 'DUMMY' # To not trigger check outside the loop.
2937 break
2938
2939 if guard_name is None:
2940 match = guard_pattern.match(line)
2941 if match:
2942 guard_name = match.group(1)
2943 guard_line_number = line_number
2944
2945 # We allow existing files to use slightly wrong include
2946 # guards, but new files should get it right.
2947 if not f.OldContents():
2948 is_in_blink = file_with_path.startswith(input_api.os_path.join(
2949 'third_party', 'WebKit'))
2950 if not (guard_name == expected_guard or
2951 is_in_blink and guard_name == expected_guard_if_blink):
2952 if is_in_blink:
2953 expected_text = "%s or %s" % (expected_guard,
2954 expected_guard_if_blink)
2955 else:
2956 expected_text = expected_guard
2957 errors.append(output_api.PresubmitPromptWarning(
2958 'Header using the wrong include guard name %s' % guard_name,
2959 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell00e1b9bc2018-03-12 13:11:122960 'Expected: %r\nFound: %r' % (expected_text, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:142961 else:
2962 # The line after #ifndef should have a #define of the same name.
2963 if line_number == guard_line_number + 1:
2964 expected_line = '#define %s' % guard_name
2965 if line != expected_line:
2966 errors.append(output_api.PresubmitPromptWarning(
2967 'Missing "%s" for include guard' % expected_line,
2968 ['%s:%d' % (f.LocalPath(), line_number + 1)],
2969 'Expected: %r\nGot: %r' % (expected_line, line)))
2970
2971 if not seen_guard_end and line == '#endif // %s' % guard_name:
2972 seen_guard_end = True
2973 elif seen_guard_end:
2974 if line.strip() != '':
2975 errors.append(output_api.PresubmitPromptWarning(
2976 'Include guard %s not covering the whole file' % (
2977 guard_name), [f.LocalPath()]))
2978 break # Nothing else to check and enough to warn once.
2979
2980 if guard_name is None:
2981 errors.append(output_api.PresubmitPromptWarning(
2982 'Missing include guard %s' % expected_guard,
2983 [f.LocalPath()],
2984 'Missing include guard in %s\n'
2985 'Recommended name: %s\n'
2986 'This check can be disabled by having the string\n'
2987 'no-include-guard-because-multiply-included in the header.' %
2988 (f.LocalPath(), expected_guard)))
2989
2990 return errors
2991
2992
mostynbb639aca52015-01-07 20:31:232993def _CheckForWindowsLineEndings(input_api, output_api):
2994 """Check source code and known ascii text files for Windows style line
2995 endings.
2996 """
earthdok1b5e0ee2015-03-10 15:19:102997 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:232998
2999 file_inclusion_pattern = (
3000 known_text_files,
3001 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3002 )
3003
mostynbb639aca52015-01-07 20:31:233004 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533005 source_file_filter = lambda f: input_api.FilterSourceFile(
3006 f, white_list=file_inclusion_pattern, black_list=None)
3007 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503008 include_file = False
3009 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233010 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503011 include_file = True
3012 if include_file:
3013 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233014
3015 if problems:
3016 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3017 'these files to contain Windows style line endings?\n' +
3018 '\n'.join(problems))]
3019
3020 return []
3021
3022
Vaclav Brozekd5de76a2018-03-17 07:57:503023def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133024 """Checks that all source files use SYSLOG properly."""
3025 syslog_files = []
3026 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563027 for line_number, line in f.ChangedContents():
3028 if 'SYSLOG' in line:
3029 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3030
pastarmovj89f7ee12016-09-20 14:58:133031 if syslog_files:
3032 return [output_api.PresubmitPromptWarning(
3033 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3034 ' calls.\nFiles to check:\n', items=syslog_files)]
3035 return []
3036
3037
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193038def _CheckCrbugLinksHaveHttps(input_api, output_api):
Miguel Casas68bdb652017-12-19 16:29:093039 """Checks that crbug(.com) links are correctly prefixed by https://,
3040 unless they come in the accepted form TODO(crbug.com/...)
3041 """
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193042 white_list = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3043 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS)
3044 sources = lambda f: input_api.FilterSourceFile(
3045 f, white_list=white_list, black_list=black_list)
3046
3047 pattern = input_api.re.compile(r'//.*(?<!:\/\/)crbug[.com]*')
Miguel Casas68bdb652017-12-19 16:29:093048 accepted_pattern = input_api.re.compile(r'//.*TODO\(crbug[.com]*');
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193049 problems = []
3050 for f in input_api.AffectedSourceFiles(sources):
3051 for line_num, line in f.ChangedContents():
Miguel Casas68bdb652017-12-19 16:29:093052 if pattern.search(line) and not accepted_pattern.search(line):
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193053 problems.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3054
3055 if problems:
3056 return [output_api.PresubmitPromptWarning(
3057 'Found unprefixed crbug.com URL(s), consider prepending https://\n'+
3058 '\n'.join(problems))]
3059 return []
3060
3061
[email protected]1f7b4172010-01-28 01:17:343062def CheckChangeOnUpload(input_api, output_api):
3063 results = []
3064 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473065 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283066 results.extend(
jam93a6ee792017-02-08 23:59:223067 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193068 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223069 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133070 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163071 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193072 results.extend(_CheckCrbugLinksHaveHttps(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543073 return results
[email protected]ca8d19842009-02-19 16:33:123074
3075
[email protected]1bfb8322014-04-23 01:02:413076def GetTryServerMasterForBot(bot):
3077 """Returns the Try Server master for the given bot.
3078
[email protected]0bb112362014-07-26 04:38:323079 It tries to guess the master from the bot name, but may still fail
3080 and return None. There is no longer a default master.
3081 """
3082 # Potentially ambiguous bot names are listed explicitly.
3083 master_map = {
tandriie5587792016-07-14 00:34:503084 'chromium_presubmit': 'master.tryserver.chromium.linux',
3085 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413086 }
[email protected]0bb112362014-07-26 04:38:323087 master = master_map.get(bot)
3088 if not master:
wnwen4fbaab82016-05-25 12:54:363089 if 'android' in bot:
tandriie5587792016-07-14 00:34:503090 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363091 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503092 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323093 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503094 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323095 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503096 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323097 return master
[email protected]1bfb8322014-04-23 01:02:413098
3099
[email protected]ca8d19842009-02-19 16:33:123100def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543101 results = []
[email protected]1f7b4172010-01-28 01:17:343102 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543103 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273104 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343105 input_api,
3106 output_api,
[email protected]2fdd1f362013-01-16 03:56:033107 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273108
jam93a6ee792017-02-08 23:59:223109 results.extend(
3110 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543111 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3112 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413113 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3114 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543115 return results