blob: 8bbde3dc6a22c0201704557869fc3aee434166c2 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]40d1dbb2012-10-26 07:18:0013 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
14 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2815 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0816 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5417 r"^skia[\\\/].*",
Kent Tamurae9b3a9ec2017-08-31 02:20:1918 r"^third_party[\\\/](WebKit|blink)[\\\/].*",
Mark Mentovaiebb9ddd62017-09-25 17:24:4119 r"^third_party[\\\/]breakpad[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
vapierb2053f542017-03-09 19:46:1026 r"tools[\\\/]md_browser[\\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1427 # Test pages for Maps telemetry tests.
28 r"tools[\\\/]perf[\\\/]page_sets[\\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5429 # Test pages for WebRTC telemetry tests.
30 r"tools[\\\/]perf[\\\/]page_sets[\\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4031)
[email protected]ca8d1982009-02-19 16:33:1232
wnwenbdc444e2016-05-25 13:44:1533
[email protected]06e6d0ff2012-12-11 01:36:4434# Fragment of a regular expression that matches C++ and Objective-C++
35# implementation files.
36_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
37
wnwenbdc444e2016-05-25 13:44:1538
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1939# Fragment of a regular expression that matches C++ and Objective-C++
40# header files.
41_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
42
43
[email protected]06e6d0ff2012-12-11 01:36:4444# Regular expression that matches code only used for test binaries
45# (best effort).
46_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4947 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4448 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4449 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1250 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4451 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4952 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0553 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4954 r'content[\\\/]shell[\\\/].*',
[email protected]7b054982013-11-27 00:44:4755 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4956 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0857 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4958 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4459)
[email protected]ca8d1982009-02-19 16:33:1260
wnwenbdc444e2016-05-25 13:44:1561
[email protected]eea609a2011-11-18 13:10:1262_TEST_ONLY_WARNING = (
63 'You might be calling functions intended only for testing from\n'
64 'production code. It is OK to ignore this warning if you know what\n'
65 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5866 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1267
68
[email protected]cf9b78f2012-11-14 11:40:2869_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4070 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2171 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
72 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2873
wnwenbdc444e2016-05-25 13:44:1574
Eric Stevensona9a980972017-09-23 00:04:4175_BANNED_JAVA_FUNCTIONS = (
76 (
77 'StrictMode.allowThreadDiskReads()',
78 (
79 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
80 'directly.',
81 ),
82 False,
83 ),
84 (
85 'StrictMode.allowThreadDiskWrites()',
86 (
87 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
88 'directly.',
89 ),
90 False,
91 ),
92)
93
[email protected]127f18ec2012-06-16 05:05:5994_BANNED_OBJC_FUNCTIONS = (
95 (
96 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2097 (
98 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5999 'prohibited. Please use CrTrackingArea instead.',
100 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
101 ),
102 False,
103 ),
104 (
[email protected]eaae1972014-04-16 04:17:26105 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20106 (
107 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59108 'instead.',
109 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
110 ),
111 False,
112 ),
113 (
114 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20115 (
116 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59117 'Please use |convertPoint:(point) fromView:nil| instead.',
118 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
119 ),
120 True,
121 ),
122 (
123 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20124 (
125 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59126 'Please use |convertPoint:(point) toView:nil| instead.',
127 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
128 ),
129 True,
130 ),
131 (
132 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20133 (
134 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59135 'Please use |convertRect:(point) fromView:nil| instead.',
136 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
137 ),
138 True,
139 ),
140 (
141 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20142 (
143 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59144 'Please use |convertRect:(point) toView:nil| instead.',
145 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
146 ),
147 True,
148 ),
149 (
150 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20151 (
152 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59153 'Please use |convertSize:(point) fromView:nil| instead.',
154 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
155 ),
156 True,
157 ),
158 (
159 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20160 (
161 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59162 'Please use |convertSize:(point) toView:nil| instead.',
163 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
164 ),
165 True,
166 ),
jif65398702016-10-27 10:19:48167 (
168 r"/\s+UTF8String\s*]",
169 (
170 'The use of -[NSString UTF8String] is dangerous as it can return null',
171 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
172 'Please use |SysNSStringToUTF8| instead.',
173 ),
174 True,
175 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34176 (
177 r'__unsafe_unretained',
178 (
179 'The use of __unsafe_unretained is almost certainly wrong, unless',
180 'when interacting with NSFastEnumeration or NSInvocation.',
181 'Please use __weak in files build with ARC, nothing otherwise.',
182 ),
183 False,
184 ),
[email protected]127f18ec2012-06-16 05:05:59185)
186
Sylvain Defresnea8b73d252018-02-28 15:45:54187_BANNED_IOS_OBJC_FUNCTIONS = (
188 (
189 r'/\bTEST[(]',
190 (
191 'TEST() macro should not be used in Objective-C++ code as it does not ',
192 'drain the autorelease pool at the end of the test. Use TEST_F() ',
193 'macro instead with a fixture inheriting from PlatformTest (or a ',
194 'typedef).'
195 ),
196 True,
197 ),
198 (
199 r'/\btesting::Test\b',
200 (
201 'testing::Test should not be used in Objective-C++ code as it does ',
202 'not drain the autorelease pool at the end of the test. Use ',
203 'PlatformTest instead.'
204 ),
205 True,
206 ),
207)
208
[email protected]127f18ec2012-06-16 05:05:59209
210_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20211 # Make sure that gtest's FRIEND_TEST() macro is not used; the
212 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30213 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20214 (
thomasandersone7caaa9b2017-03-29 19:22:53215 r'\bNULL\b',
216 (
217 'New code should not use NULL. Use nullptr instead.',
218 ),
219 True,
220 (),
221 ),
222 (
[email protected]23e6cbc2012-06-16 18:51:20223 'FRIEND_TEST(',
224 (
[email protected]e3c945502012-06-26 20:01:49225 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20226 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
227 ),
228 False,
[email protected]7345da02012-11-27 14:31:49229 (),
[email protected]23e6cbc2012-06-16 18:51:20230 ),
231 (
thomasanderson4b569052016-09-14 20:15:53232 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
233 (
234 'Chrome clients wishing to select events on X windows should use',
235 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
236 'you are selecting events from the GPU process, or if you are using',
237 'an XDisplay other than gfx::GetXDisplay().',
238 ),
239 True,
240 (
241 r"^ui[\\\/]gl[\\\/].*\.cc$",
242 r"^media[\\\/]gpu[\\\/].*\.cc$",
243 r"^gpu[\\\/].*\.cc$",
244 ),
245 ),
246 (
thomasandersone043e3ce2017-06-08 00:43:20247 r'XInternAtom|xcb_intern_atom',
248 (
thomasanderson11aa41d2017-06-08 22:22:38249 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20250 ),
251 True,
252 (
thomasanderson11aa41d2017-06-08 22:22:38253 r"^gpu[\\\/]ipc[\\\/]service[\\\/]gpu_watchdog_thread\.cc$",
254 r"^remoting[\\\/]host[\\\/]linux[\\\/]x_server_clipboard\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20255 r"^ui[\\\/]gfx[\\\/]x[\\\/]x11_atom_cache\.cc$",
256 ),
257 ),
258 (
tomhudsone2c14d552016-05-26 17:07:46259 'setMatrixClip',
260 (
261 'Overriding setMatrixClip() is prohibited; ',
262 'the base function is deprecated. ',
263 ),
264 True,
265 (),
266 ),
267 (
[email protected]52657f62013-05-20 05:30:31268 'SkRefPtr',
269 (
270 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22271 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31272 ),
273 True,
274 (),
275 ),
276 (
277 'SkAutoRef',
278 (
279 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22280 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31281 ),
282 True,
283 (),
284 ),
285 (
286 'SkAutoTUnref',
287 (
288 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22289 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31290 ),
291 True,
292 (),
293 ),
294 (
295 'SkAutoUnref',
296 (
297 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
298 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22299 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31300 ),
301 True,
302 (),
303 ),
[email protected]d89eec82013-12-03 14:10:59304 (
305 r'/HANDLE_EINTR\(.*close',
306 (
307 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
308 'descriptor will be closed, and it is incorrect to retry the close.',
309 'Either call close directly and ignore its return value, or wrap close',
310 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
311 ),
312 True,
313 (),
314 ),
315 (
316 r'/IGNORE_EINTR\((?!.*close)',
317 (
318 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
319 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
320 ),
321 True,
322 (
323 # Files that #define IGNORE_EINTR.
324 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
325 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
326 ),
327 ),
[email protected]ec5b3f02014-04-04 18:43:43328 (
329 r'/v8::Extension\(',
330 (
331 'Do not introduce new v8::Extensions into the code base, use',
332 'gin::Wrappable instead. See http://crbug.com/334679',
333 ),
334 True,
[email protected]f55c90ee62014-04-12 00:50:03335 (
joaodasilva718f87672014-08-30 09:25:49336 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03337 ),
[email protected]ec5b3f02014-04-04 18:43:43338 ),
skyostilf9469f72015-04-20 10:38:52339 (
jame2d1a952016-04-02 00:27:10340 '#pragma comment(lib,',
341 (
342 'Specify libraries to link with in build files and not in the source.',
343 ),
344 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41345 (
346 r'^third_party[\\\/]abseil-cpp[\\\/].*',
347 ),
jame2d1a952016-04-02 00:27:10348 ),
fdorayc4ac18d2017-05-01 21:39:59349 (
Gabriel Charette7cc6c432018-04-25 20:52:02350 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59351 (
352 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
353 ),
354 False,
355 (),
356 ),
357 (
Gabriel Charette7cc6c432018-04-25 20:52:02358 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59359 (
360 'Consider using THREAD_CHECKER macros instead of the class directly.',
361 ),
362 False,
363 (),
364 ),
dbeamb6f4fde2017-06-15 04:03:06365 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06366 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
367 (
368 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
369 'deprecated (http://crbug.com/634507). Please avoid converting away',
370 'from the Time types in Chromium code, especially if any math is',
371 'being done on time values. For interfacing with platform/library',
372 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
373 'type converter methods instead. For faking TimeXXX values (for unit',
374 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
375 'other use cases, please contact base/time/OWNERS.',
376 ),
377 False,
378 (),
379 ),
380 (
dbeamb6f4fde2017-06-15 04:03:06381 'CallJavascriptFunctionUnsafe',
382 (
383 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
384 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
385 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
386 ),
387 False,
388 (
389 r'^content[\\\/]browser[\\\/]webui[\\\/]web_ui_impl\.(cc|h)$',
390 r'^content[\\\/]public[\\\/]browser[\\\/]web_ui\.h$',
391 r'^content[\\\/]public[\\\/]test[\\\/]test_web_ui\.(cc|h)$',
392 ),
393 ),
dskiba1474c2bfd62017-07-20 02:19:24394 (
395 'leveldb::DB::Open',
396 (
397 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
398 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
399 "Chrome's tracing, making their memory usage visible.",
400 ),
401 True,
402 (
403 r'^third_party/leveldatabase/.*\.(cc|h)$',
404 ),
Gabriel Charette0592c3a2017-07-26 12:02:04405 ),
406 (
Chris Mumfordc38afb62017-10-09 17:55:08407 'leveldb::NewMemEnv',
408 (
409 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58410 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
411 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08412 ),
413 True,
414 (
415 r'^third_party/leveldatabase/.*\.(cc|h)$',
416 ),
417 ),
418 (
Gabriel Charetted9839bc2017-07-29 14:17:47419 'RunLoop::QuitCurrent',
420 (
Robert Liao64b7ab22017-08-04 23:03:43421 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
422 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47423 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41424 False,
Gabriel Charetted9839bc2017-07-29 14:17:47425 (),
Gabriel Charettea44975052017-08-21 23:14:04426 ),
427 (
428 'base::ScopedMockTimeMessageLoopTaskRunner',
429 (
Gabriel Charette87cc1af2018-04-25 20:52:51430 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
431 'ScopedTaskEnvironment::MainThreadType::MOCK_TIME. There are still a',
432 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
433 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
434 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04435 ),
Gabriel Charette87cc1af2018-04-25 20:52:51436 False,
Gabriel Charettea44975052017-08-21 23:14:04437 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57438 ),
439 (
440 r'std::regex',
441 (
442 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02443 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57444 ),
445 True,
446 (),
Francois Doray43670e32017-09-27 12:40:38447 ),
448 (
449 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
450 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
451 (
452 'Use the new API in base/threading/thread_restrictions.h.',
453 ),
454 True,
455 (),
456 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38457 (
458 r'/\bbase::Bind\(',
459 (
Gabriel Charette147335ea2018-03-22 15:59:19460 'Please consider using base::Bind{Once,Repeating} instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02461 'of base::Bind. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38462 ),
463 False,
464 (),
465 ),
466 (
467 r'/\bbase::Callback<',
468 (
Gabriel Charette147335ea2018-03-22 15:59:19469 'Please consider using base::{Once,Repeating}Callback instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02470 'of base::Callback. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38471 ),
472 False,
473 (),
474 ),
475 (
476 r'/\bbase::Closure\b',
477 (
Gabriel Charette147335ea2018-03-22 15:59:19478 'Please consider using base::{Once,Repeating}Closure instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02479 'of base::Closure. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38480 ),
481 False,
482 (),
483 ),
Victor Costan3653df62018-02-08 21:38:16484 (
Gabriel Charette147335ea2018-03-22 15:59:19485 r'RunMessageLoop',
486 (
487 'RunMessageLoop is deprecated, use RunLoop instead.',
488 ),
489 False,
490 (),
491 ),
492 (
493 r'RunThisRunLoop',
494 (
495 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
496 ),
497 False,
498 (),
499 ),
500 (
501 r'RunAllPendingInMessageLoop()',
502 (
503 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
504 "if you're convinced you need this.",
505 ),
506 False,
507 (),
508 ),
509 (
510 r'RunAllPendingInMessageLoop(BrowserThread',
511 (
512 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
513 'BrowserThread::UI, TestBrowserThreadBundle::RunIOThreadUntilIdle',
514 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
515 'async events instead of flushing threads.',
516 ),
517 False,
518 (),
519 ),
520 (
521 r'MessageLoopRunner',
522 (
523 'MessageLoopRunner is deprecated, use RunLoop instead.',
524 ),
525 False,
526 (),
527 ),
528 (
529 r'GetDeferredQuitTaskForRunLoop',
530 (
531 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
532 "gab@ if you found a use case where this is the only solution.",
533 ),
534 False,
535 (),
536 ),
537 (
Victor Costan3653df62018-02-08 21:38:16538 'sqlite3_initialize',
539 (
540 'Instead of sqlite3_initialize, depend on //sql, ',
541 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
542 ),
543 True,
544 (
545 r'^sql/initialization\.(cc|h)$',
546 r'^third_party/sqlite/.*\.(c|cc|h)$',
547 ),
548 ),
Matt Menke7f520a82018-03-28 21:38:37549 (
550 'net::URLFetcher',
551 (
552 'net::URLFetcher should no longer be used in content embedders. ',
553 'Instead, use network::SimpleURLLoader instead, which supports ',
554 'an out-of-process network stack. ',
555 'net::URLFetcher may still be used in binaries that do not embed',
556 'content.',
557 ),
Matt Menke59716d02018-04-05 12:45:53558 False,
Matt Menke7f520a82018-03-28 21:38:37559 (
560 r'^ios[\\\/].*\.(cc|h)$',
561 r'.*[\\\/]ios[\\\/].*\.(cc|h)$',
562 r'.*_ios\.(cc|h)$',
563 r'^net[\\\/].*\.(cc|h)$',
564 r'.*[\\\/]tools[\\\/].*\.(cc|h)$',
565 ),
566 ),
jdoerried7d10ab2018-04-27 10:46:13567 (
568 r'/\barraysize\b',
569 (
570 "arraysize is deprecated, please use base::size(array) instead ",
571 "(https://crbug.com/837308). ",
572 ),
573 False,
574 (),
575 ),
tzik5de2157f2018-05-08 03:42:47576 (
577 r'std::random_shuffle',
578 (
579 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
580 'base::RandomShuffle instead.'
581 ),
582 True,
583 (),
584 ),
[email protected]127f18ec2012-06-16 05:05:59585)
586
wnwenbdc444e2016-05-25 13:44:15587
mlamouria82272622014-09-16 18:45:04588_IPC_ENUM_TRAITS_DEPRECATED = (
589 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50590 'See http://www.chromium.org/Home/chromium-security/education/'
591 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:04592
Stephen Martinis97a394142018-06-07 23:06:05593_LONG_PATH_ERROR = (
594 'Some files included in this CL have file names that are too long (> 200'
595 ' characters). If committed, these files will cause issues on Windows. See'
596 ' https://crbug.com/612667 for more details.'
597)
598
Shenghua Zhangbfaa38b82017-11-16 21:58:02599_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
600 r".*[\\\/]BuildHooksAndroidImpl\.java",
601 r".*[\\\/]LicenseContentProvider\.java",
James Wallace-Leef31ae6c2018-05-01 23:30:20602 r".*[\\\/]PlatformServiceBridgeImpl.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:02603]
[email protected]127f18ec2012-06-16 05:05:59604
Sean Kau46e29bc2017-08-28 16:31:16605# These paths contain test data and other known invalid JSON files.
606_KNOWN_INVALID_JSON_FILE_PATTERNS = [
607 r'test[\\\/]data[\\\/]',
608 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
609 r'^third_party[\\\/]protobuf[\\\/]',
Raphael Kubo da Costa211f3b472017-11-16 00:27:16610 r'^third_party[\\\/]WebKit[\\\/]LayoutTests[\\\/]external[\\\/]wpt[\\\/]',
Alexey Kozyatinskiya42a629f2018-04-17 17:49:38611 r'^third_party[\\\/]blink[\\\/]renderer[\\\/]devtools[\\\/]protocol\.json$',
Sean Kau46e29bc2017-08-28 16:31:16612]
613
614
[email protected]b00342e7f2013-03-26 16:21:54615_VALID_OS_MACROS = (
616 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08617 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54618 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:12619 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:54620 'OS_BSD',
621 'OS_CAT', # For testing.
622 'OS_CHROMEOS',
623 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37624 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54625 'OS_IOS',
626 'OS_LINUX',
627 'OS_MACOSX',
628 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21629 'OS_NACL_NONSFI',
630 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12631 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54632 'OS_OPENBSD',
633 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37634 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54635 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54636 'OS_WIN',
637)
638
639
agrievef32bcc72016-04-04 14:57:40640_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grievea7f1ee902018-05-18 16:17:22641 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:40642 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04643 'build/android/test_wrapper/logdog_wrapper.pydeps',
jbudorick276cc562017-04-29 01:34:58644 'build/secondary/third_party/android_platform/'
645 'development/scripts/stack.pydeps',
agrieve732db3a2016-04-26 19:18:19646 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40647]
648
wnwenbdc444e2016-05-25 13:44:15649
agrievef32bcc72016-04-04 14:57:40650_GENERIC_PYDEPS_FILES = [
John Chencde89192018-01-27 21:18:40651 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22652 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:40653]
654
wnwenbdc444e2016-05-25 13:44:15655
agrievef32bcc72016-04-04 14:57:40656_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
657
658
Eric Boren6fd2b932018-01-25 15:05:08659# Bypass the AUTHORS check for these accounts.
660_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:29661 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
662 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:08663 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
664 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:59665 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:45666 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:59667 ) | set('%[email protected]' % s
Sergiy Byelozyorovf78077a92018-06-14 08:07:11668 for s in ('v8-ci-autoroll-builder',))
Eric Boren6fd2b932018-01-25 15:05:08669
670
[email protected]55459852011-08-10 15:17:19671def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
672 """Attempts to prevent use of functions intended only for testing in
673 non-testing code. For now this is just a best-effort implementation
674 that ignores header files and may have some false positives. A
675 better implementation would probably need a proper C++ parser.
676 """
677 # We only scan .cc files and the like, as the declaration of
678 # for-testing functions in header files are hard to distinguish from
679 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44680 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19681
jochenc0d4808c2015-07-27 09:25:42682 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19683 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09684 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19685 exclusion_pattern = input_api.re.compile(
686 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
687 base_function_pattern, base_function_pattern))
688
689 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44690 black_list = (_EXCLUDED_PATHS +
691 _TEST_CODE_EXCLUDED_PATHS +
692 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19693 return input_api.FilterSourceFile(
694 affected_file,
695 white_list=(file_inclusion_pattern, ),
696 black_list=black_list)
697
698 problems = []
699 for f in input_api.AffectedSourceFiles(FilterFile):
700 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24701 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03702 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46703 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03704 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19705 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03706 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19707
708 if problems:
[email protected]f7051d52013-04-02 18:31:42709 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03710 else:
711 return []
[email protected]55459852011-08-10 15:17:19712
713
Vaclav Brozek7dbc28c2018-03-27 08:35:23714def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
715 """This is a simplified version of
716 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
717 """
718 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
719 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
720 name_pattern = r'ForTest(s|ing)?'
721 # Describes an occurrence of "ForTest*" inside a // comment.
722 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
723 # Catch calls.
724 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
725 # Ignore definitions. (Comments are ignored separately.)
726 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
727
728 problems = []
729 sources = lambda x: input_api.FilterSourceFile(
730 x,
731 black_list=(('(?i).*test', r'.*\/junit\/')
732 + input_api.DEFAULT_BLACK_LIST),
733 white_list=(r'.*\.java$',)
734 )
735 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
736 local_path = f.LocalPath()
737 is_inside_javadoc = False
738 for line_number, line in f.ChangedContents():
739 if is_inside_javadoc and javadoc_end_re.search(line):
740 is_inside_javadoc = False
741 if not is_inside_javadoc and javadoc_start_re.search(line):
742 is_inside_javadoc = True
743 if is_inside_javadoc:
744 continue
745 if (inclusion_re.search(line) and
746 not comment_re.search(line) and
747 not exclusion_re.search(line)):
748 problems.append(
749 '%s:%d\n %s' % (local_path, line_number, line.strip()))
750
751 if problems:
752 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
753 else:
754 return []
755
756
[email protected]10689ca2011-09-02 02:31:54757def _CheckNoIOStreamInHeaders(input_api, output_api):
758 """Checks to make sure no .h files include <iostream>."""
759 files = []
760 pattern = input_api.re.compile(r'^#include\s*<iostream>',
761 input_api.re.MULTILINE)
762 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
763 if not f.LocalPath().endswith('.h'):
764 continue
765 contents = input_api.ReadFile(f)
766 if pattern.search(contents):
767 files.append(f)
768
769 if len(files):
yolandyandaabc6d2016-04-18 18:29:39770 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06771 'Do not #include <iostream> in header files, since it inserts static '
772 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54773 '#include <ostream>. See http://crbug.com/94794',
774 files) ]
775 return []
776
777
[email protected]72df4e782012-06-21 16:28:18778def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52779 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18780 problems = []
781 for f in input_api.AffectedFiles():
782 if (not f.LocalPath().endswith(('.cc', '.mm'))):
783 continue
784
785 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04786 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18787 problems.append(' %s:%d' % (f.LocalPath(), line_num))
788
789 if not problems:
790 return []
791 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
792 '\n'.join(problems))]
793
794
danakj61c1aa22015-10-26 19:55:52795def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57796 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52797 errors = []
798 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
799 input_api.re.MULTILINE)
800 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
801 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
802 continue
803 for lnum, line in f.ChangedContents():
804 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17805 errors.append(output_api.PresubmitError(
806 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57807 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17808 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52809 return errors
810
811
mcasasb7440c282015-02-04 14:52:19812def _FindHistogramNameInLine(histogram_name, line):
813 """Tries to find a histogram name or prefix in a line."""
814 if not "affected-histogram" in line:
815 return histogram_name in line
816 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
817 # the histogram_name.
818 if not '"' in line:
819 return False
820 histogram_prefix = line.split('\"')[1]
821 return histogram_prefix in histogram_name
822
823
824def _CheckUmaHistogramChanges(input_api, output_api):
825 """Check that UMA histogram names in touched lines can still be found in other
826 lines of the patch or in histograms.xml. Note that this check would not catch
827 the reverse: changes in histograms.xml not matched in the code itself."""
828 touched_histograms = []
829 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:47830 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
831 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
832 name_pattern = r'"(.*?)"'
833 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
834 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
835 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
836 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
837 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:17838 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:19839 for f in input_api.AffectedFiles():
840 # If histograms.xml itself is modified, keep the modified lines for later.
841 if f.LocalPath().endswith(('histograms.xml')):
842 histograms_xml_modifications = f.ChangedContents()
843 continue
Vaclav Brozekbdac817c2018-03-24 06:30:47844 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
845 single_line_re = single_line_c_re
846 split_line_prefix_re = split_line_c_prefix_re
847 elif f.LocalPath().endswith(('java')):
848 single_line_re = single_line_java_re
849 split_line_prefix_re = split_line_java_prefix_re
850 else:
mcasasb7440c282015-02-04 14:52:19851 continue
852 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:17853 if last_line_matched_prefix:
854 suffix_found = split_line_suffix_re.search(line)
855 if suffix_found :
856 touched_histograms.append([suffix_found.group(1), f, line_num])
857 last_line_matched_prefix = False
858 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:06859 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:19860 if found:
861 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:17862 continue
863 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:19864
865 # Search for the touched histogram names in the local modifications to
866 # histograms.xml, and, if not found, on the base histograms.xml file.
867 unmatched_histograms = []
868 for histogram_info in touched_histograms:
869 histogram_name_found = False
870 for line_num, line in histograms_xml_modifications:
871 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
872 if histogram_name_found:
873 break
874 if not histogram_name_found:
875 unmatched_histograms.append(histogram_info)
876
eromanb90c82e7e32015-04-01 15:13:49877 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19878 problems = []
879 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49880 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19881 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45882 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19883 histogram_name_found = False
884 for line in histograms_xml:
885 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
886 if histogram_name_found:
887 break
888 if not histogram_name_found:
889 problems.append(' [%s:%d] %s' %
890 (f.LocalPath(), line_num, histogram_name))
891
892 if not problems:
893 return []
894 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
895 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49896 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19897
wnwenbdc444e2016-05-25 13:44:15898
yolandyandaabc6d2016-04-18 18:29:39899def _CheckFlakyTestUsage(input_api, output_api):
900 """Check that FlakyTest annotation is our own instead of the android one"""
901 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
902 files = []
903 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
904 if f.LocalPath().endswith('Test.java'):
905 if pattern.search(input_api.ReadFile(f)):
906 files.append(f)
907 if len(files):
908 return [output_api.PresubmitError(
909 'Use org.chromium.base.test.util.FlakyTest instead of '
910 'android.test.FlakyTest',
911 files)]
912 return []
mcasasb7440c282015-02-04 14:52:19913
wnwenbdc444e2016-05-25 13:44:15914
[email protected]8ea5d4b2011-09-13 21:49:22915def _CheckNoNewWStrings(input_api, output_api):
916 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27917 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22918 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20919 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57920 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34921 '/win/' in f.LocalPath() or
922 'chrome_elf' in f.LocalPath() or
923 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20924 continue
[email protected]8ea5d4b2011-09-13 21:49:22925
[email protected]a11dbe9b2012-08-07 01:32:58926 allowWString = False
[email protected]b5c24292011-11-28 14:38:20927 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58928 if 'presubmit: allow wstring' in line:
929 allowWString = True
930 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27931 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58932 allowWString = False
933 else:
934 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22935
[email protected]55463aa62011-10-12 00:48:27936 if not problems:
937 return []
938 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58939 ' If you are calling a cross-platform API that accepts a wstring, '
940 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27941 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22942
943
[email protected]2a8ac9c2011-10-19 17:20:44944def _CheckNoDEPSGIT(input_api, output_api):
945 """Make sure .DEPS.git is never modified manually."""
946 if any(f.LocalPath().endswith('.DEPS.git') for f in
947 input_api.AffectedFiles()):
948 return [output_api.PresubmitError(
949 'Never commit changes to .DEPS.git. This file is maintained by an\n'
950 'automated system based on what\'s in DEPS and your changes will be\n'
951 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50952 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
953 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:44954 'for more information')]
955 return []
956
957
tandriief664692014-09-23 14:51:47958def _CheckValidHostsInDEPS(input_api, output_api):
959 """Checks that DEPS file deps are from allowed_hosts."""
960 # Run only if DEPS file has been modified to annoy fewer bystanders.
961 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
962 return []
963 # Outsource work to gclient verify
964 try:
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:20965 input_api.subprocess.check_output(['gclient', 'verify'],
966 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:47967 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:20968 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:47969 return [output_api.PresubmitError(
970 'DEPS file must have only git dependencies.',
971 long_text=error.output)]
972
973
[email protected]127f18ec2012-06-16 05:05:59974def _CheckNoBannedFunctions(input_api, output_api):
975 """Make sure that banned functions are not used."""
976 warnings = []
977 errors = []
978
wnwenbdc444e2016-05-25 13:44:15979 def IsBlacklisted(affected_file, blacklist):
980 local_path = affected_file.LocalPath()
981 for item in blacklist:
982 if input_api.re.match(item, local_path):
983 return True
984 return False
985
Sylvain Defresnea8b73d252018-02-28 15:45:54986 def IsIosObcjFile(affected_file):
987 local_path = affected_file.LocalPath()
988 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
989 return False
990 basename = input_api.os_path.basename(local_path)
991 if 'ios' in basename.split('_'):
992 return True
993 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
994 if sep and 'ios' in local_path.split(sep):
995 return True
996 return False
997
wnwenbdc444e2016-05-25 13:44:15998 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
999 matched = False
1000 if func_name[0:1] == '/':
1001 regex = func_name[1:]
1002 if input_api.re.search(regex, line):
1003 matched = True
1004 elif func_name in line:
dchenge07de812016-06-20 19:27:171005 matched = True
wnwenbdc444e2016-05-25 13:44:151006 if matched:
dchenge07de812016-06-20 19:27:171007 problems = warnings
wnwenbdc444e2016-05-25 13:44:151008 if error:
dchenge07de812016-06-20 19:27:171009 problems = errors
wnwenbdc444e2016-05-25 13:44:151010 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1011 for message_line in message:
1012 problems.append(' %s' % message_line)
1013
Eric Stevensona9a980972017-09-23 00:04:411014 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1015 for f in input_api.AffectedFiles(file_filter=file_filter):
1016 for line_num, line in f.ChangedContents():
1017 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1018 CheckForMatch(f, line_num, line, func_name, message, error)
1019
[email protected]127f18ec2012-06-16 05:05:591020 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1021 for f in input_api.AffectedFiles(file_filter=file_filter):
1022 for line_num, line in f.ChangedContents():
1023 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151024 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591025
Sylvain Defresnea8b73d252018-02-28 15:45:541026 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1027 for line_num, line in f.ChangedContents():
1028 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1029 CheckForMatch(f, line_num, line, func_name, message, error)
1030
[email protected]127f18ec2012-06-16 05:05:591031 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1032 for f in input_api.AffectedFiles(file_filter=file_filter):
1033 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491034 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491035 if IsBlacklisted(f, excluded_paths):
1036 continue
wnwenbdc444e2016-05-25 13:44:151037 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591038
1039 result = []
1040 if (warnings):
1041 result.append(output_api.PresubmitPromptWarning(
1042 'Banned functions were used.\n' + '\n'.join(warnings)))
1043 if (errors):
1044 result.append(output_api.PresubmitError(
1045 'Banned functions were used.\n' + '\n'.join(errors)))
1046 return result
1047
1048
[email protected]6c063c62012-07-11 19:11:061049def _CheckNoPragmaOnce(input_api, output_api):
1050 """Make sure that banned functions are not used."""
1051 files = []
1052 pattern = input_api.re.compile(r'^#pragma\s+once',
1053 input_api.re.MULTILINE)
1054 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1055 if not f.LocalPath().endswith('.h'):
1056 continue
1057 contents = input_api.ReadFile(f)
1058 if pattern.search(contents):
1059 files.append(f)
1060
1061 if files:
1062 return [output_api.PresubmitError(
1063 'Do not use #pragma once in header files.\n'
1064 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1065 files)]
1066 return []
1067
[email protected]127f18ec2012-06-16 05:05:591068
[email protected]e7479052012-09-19 00:26:121069def _CheckNoTrinaryTrueFalse(input_api, output_api):
1070 """Checks to make sure we don't introduce use of foo ? true : false."""
1071 problems = []
1072 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1073 for f in input_api.AffectedFiles():
1074 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1075 continue
1076
1077 for line_num, line in f.ChangedContents():
1078 if pattern.match(line):
1079 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1080
1081 if not problems:
1082 return []
1083 return [output_api.PresubmitPromptWarning(
1084 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1085 '\n'.join(problems))]
1086
1087
[email protected]55f9f382012-07-31 11:02:181088def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281089 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181090 change. Breaking - rules is an error, breaking ! rules is a
1091 warning.
1092 """
mohan.reddyf21db962014-10-16 12:26:471093 import sys
[email protected]55f9f382012-07-31 11:02:181094 # We need to wait until we have an input_api object and use this
1095 # roundabout construct to import checkdeps because this file is
1096 # eval-ed and thus doesn't have __file__.
1097 original_sys_path = sys.path
1098 try:
1099 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471100 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181101 import checkdeps
1102 from cpp_checker import CppChecker
Jinsuk Kim5a092672017-10-24 22:42:241103 from java_checker import JavaChecker
rhalavati08acd232017-04-03 07:23:281104 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:181105 from rules import Rule
1106 finally:
1107 # Restore sys.path to what it was before.
1108 sys.path = original_sys_path
1109
1110 added_includes = []
rhalavati08acd232017-04-03 07:23:281111 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241112 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181113 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:281114 if CppChecker.IsCppFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501115 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081116 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
rhalavati08acd232017-04-03 07:23:281117 elif ProtoChecker.IsProtoFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501118 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081119 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241120 elif JavaChecker.IsJavaFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501121 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081122 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181123
[email protected]26385172013-05-09 23:11:351124 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181125
1126 error_descriptions = []
1127 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281128 error_subjects = set()
1129 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181130 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1131 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081132 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181133 description_with_path = '%s\n %s' % (path, rule_description)
1134 if rule_type == Rule.DISALLOW:
1135 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281136 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181137 else:
1138 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281139 warning_subjects.add("#includes")
1140
1141 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1142 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081143 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281144 description_with_path = '%s\n %s' % (path, rule_description)
1145 if rule_type == Rule.DISALLOW:
1146 error_descriptions.append(description_with_path)
1147 error_subjects.add("imports")
1148 else:
1149 warning_descriptions.append(description_with_path)
1150 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181151
Jinsuk Kim5a092672017-10-24 22:42:241152 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021153 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081154 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241155 description_with_path = '%s\n %s' % (path, rule_description)
1156 if rule_type == Rule.DISALLOW:
1157 error_descriptions.append(description_with_path)
1158 error_subjects.add("imports")
1159 else:
1160 warning_descriptions.append(description_with_path)
1161 warning_subjects.add("imports")
1162
[email protected]55f9f382012-07-31 11:02:181163 results = []
1164 if error_descriptions:
1165 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281166 'You added one or more %s that violate checkdeps rules.'
1167 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181168 error_descriptions))
1169 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421170 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281171 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181172 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281173 '%s? See relevant DEPS file(s) for details and contacts.' %
1174 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181175 warning_descriptions))
1176 return results
1177
1178
[email protected]fbcafe5a2012-08-08 15:31:221179def _CheckFilePermissions(input_api, output_api):
1180 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151181 if input_api.platform == 'win32':
1182 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291183 checkperms_tool = input_api.os_path.join(
1184 input_api.PresubmitLocalPath(),
1185 'tools', 'checkperms', 'checkperms.py')
1186 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471187 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391188 with input_api.CreateTemporaryFile() as file_list:
1189 for f in input_api.AffectedFiles():
1190 # checkperms.py file/directory arguments must be relative to the
1191 # repository.
1192 file_list.write(f.LocalPath() + '\n')
1193 file_list.close()
1194 args += ['--file-list', file_list.name]
1195 try:
1196 input_api.subprocess.check_output(args)
1197 return []
1198 except input_api.subprocess.CalledProcessError as error:
1199 return [output_api.PresubmitError(
1200 'checkperms.py failed:',
1201 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221202
1203
robertocn832f5992017-01-04 19:01:301204def _CheckTeamTags(input_api, output_api):
1205 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1206 checkteamtags_tool = input_api.os_path.join(
1207 input_api.PresubmitLocalPath(),
1208 'tools', 'checkteamtags', 'checkteamtags.py')
1209 args = [input_api.python_executable, checkteamtags_tool,
1210 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221211 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301212 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1213 'OWNERS']
1214 try:
1215 if files:
1216 input_api.subprocess.check_output(args + files)
1217 return []
1218 except input_api.subprocess.CalledProcessError as error:
1219 return [output_api.PresubmitError(
1220 'checkteamtags.py failed:',
1221 long_text=error.output)]
1222
1223
[email protected]c8278b32012-10-30 20:35:491224def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1225 """Makes sure we don't include ui/aura/window_property.h
1226 in header files.
1227 """
1228 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1229 errors = []
1230 for f in input_api.AffectedFiles():
1231 if not f.LocalPath().endswith('.h'):
1232 continue
1233 for line_num, line in f.ChangedContents():
1234 if pattern.match(line):
1235 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1236
1237 results = []
1238 if errors:
1239 results.append(output_api.PresubmitError(
1240 'Header files should not include ui/aura/window_property.h', errors))
1241 return results
1242
1243
[email protected]70ca77752012-11-20 03:45:031244def _CheckForVersionControlConflictsInFile(input_api, f):
1245 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1246 errors = []
1247 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:231248 if f.LocalPath().endswith('.md'):
1249 # First-level headers in markdown look a lot like version control
1250 # conflict markers. http://daringfireball.net/projects/markdown/basics
1251 continue
[email protected]70ca77752012-11-20 03:45:031252 if pattern.match(line):
1253 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1254 return errors
1255
1256
1257def _CheckForVersionControlConflicts(input_api, output_api):
1258 """Usually this is not intentional and will cause a compile failure."""
1259 errors = []
1260 for f in input_api.AffectedFiles():
1261 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1262
1263 results = []
1264 if errors:
1265 results.append(output_api.PresubmitError(
1266 'Version control conflict markers found, please resolve.', errors))
1267 return results
1268
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201269
estadee17314a02017-01-12 16:22:161270def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1271 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1272 errors = []
1273 for f in input_api.AffectedFiles():
1274 for line_num, line in f.ChangedContents():
1275 if pattern.search(line):
1276 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1277
1278 results = []
1279 if errors:
1280 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501281 'Found Google support URL addressed by answer number. Please replace '
1282 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161283 return results
1284
[email protected]70ca77752012-11-20 03:45:031285
[email protected]06e6d0ff2012-12-11 01:36:441286def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1287 def FilterFile(affected_file):
1288 """Filter function for use with input_api.AffectedSourceFiles,
1289 below. This filters out everything except non-test files from
1290 top-level directories that generally speaking should not hard-code
1291 service URLs (e.g. src/android_webview/, src/content/ and others).
1292 """
1293 return input_api.FilterSourceFile(
1294 affected_file,
[email protected]78bb39d62012-12-11 15:11:561295 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:441296 black_list=(_EXCLUDED_PATHS +
1297 _TEST_CODE_EXCLUDED_PATHS +
1298 input_api.DEFAULT_BLACK_LIST))
1299
reillyi38965732015-11-16 18:27:331300 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1301 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461302 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1303 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441304 problems = [] # items are (filename, line_number, line)
1305 for f in input_api.AffectedSourceFiles(FilterFile):
1306 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461307 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441308 problems.append((f.LocalPath(), line_num, line))
1309
1310 if problems:
[email protected]f7051d52013-04-02 18:31:421311 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441312 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581313 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441314 [' %s:%d: %s' % (
1315 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031316 else:
1317 return []
[email protected]06e6d0ff2012-12-11 01:36:441318
1319
[email protected]d2530012013-01-25 16:39:271320def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1321 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311322 The native_client_sdk directory is excluded because it has auto-generated PNG
1323 files for documentation.
[email protected]d2530012013-01-25 16:39:271324 """
[email protected]d2530012013-01-25 16:39:271325 errors = []
binji0dcdf342014-12-12 18:32:311326 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
1327 black_list = (r'^native_client_sdk[\\\/]',)
1328 file_filter = lambda f: input_api.FilterSourceFile(
1329 f, white_list=white_list, black_list=black_list)
1330 for f in input_api.AffectedFiles(include_deletes=False,
1331 file_filter=file_filter):
1332 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271333
1334 results = []
1335 if errors:
1336 results.append(output_api.PresubmitError(
1337 'The name of PNG files should not have abbreviations. \n'
1338 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1339 'Contact [email protected] if you have questions.', errors))
1340 return results
1341
1342
Daniel Cheng4dcdb6b2017-04-13 08:30:171343def _ExtractAddRulesFromParsedDeps(parsed_deps):
1344 """Extract the rules that add dependencies from a parsed DEPS file.
1345
1346 Args:
1347 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1348 add_rules = set()
1349 add_rules.update([
1350 rule[1:] for rule in parsed_deps.get('include_rules', [])
1351 if rule.startswith('+') or rule.startswith('!')
1352 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501353 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171354 {}).iteritems():
1355 add_rules.update([
1356 rule[1:] for rule in rules
1357 if rule.startswith('+') or rule.startswith('!')
1358 ])
1359 return add_rules
1360
1361
1362def _ParseDeps(contents):
1363 """Simple helper for parsing DEPS files."""
1364 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171365 class _VarImpl:
1366
1367 def __init__(self, local_scope):
1368 self._local_scope = local_scope
1369
1370 def Lookup(self, var_name):
1371 """Implements the Var syntax."""
1372 try:
1373 return self._local_scope['vars'][var_name]
1374 except KeyError:
1375 raise Exception('Var is not defined: %s' % var_name)
1376
1377 local_scope = {}
1378 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171379 'Var': _VarImpl(local_scope).Lookup,
1380 }
1381 exec contents in global_scope, local_scope
1382 return local_scope
1383
1384
1385def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081386 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411387 a set of DEPS entries that we should look up.
1388
1389 For a directory (rather than a specific filename) we fake a path to
1390 a specific filename by adding /DEPS. This is chosen as a file that
1391 will seldom or never be subject to per-file include_rules.
1392 """
[email protected]2b438d62013-11-14 17:54:141393 # We ignore deps entries on auto-generated directories.
1394 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081395
Daniel Cheng4dcdb6b2017-04-13 08:30:171396 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1397 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1398
1399 added_deps = new_deps.difference(old_deps)
1400
[email protected]2b438d62013-11-14 17:54:141401 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171402 for added_dep in added_deps:
1403 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1404 continue
1405 # Assume that a rule that ends in .h is a rule for a specific file.
1406 if added_dep.endswith('.h'):
1407 results.add(added_dep)
1408 else:
1409 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081410 return results
1411
1412
[email protected]e871964c2013-05-13 14:14:551413def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1414 """When a dependency prefixed with + is added to a DEPS file, we
1415 want to make sure that the change is reviewed by an OWNER of the
1416 target file or directory, to avoid layering violations from being
1417 introduced. This check verifies that this happens.
1418 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171419 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241420
1421 file_filter = lambda f: not input_api.re.match(
Kent Tamurae9b3a9ec2017-08-31 02:20:191422 r"^third_party[\\\/](WebKit|blink)[\\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241423 for f in input_api.AffectedFiles(include_deletes=False,
1424 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551425 filename = input_api.os_path.basename(f.LocalPath())
1426 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171427 virtual_depended_on_files.update(_CalculateAddedDeps(
1428 input_api.os_path,
1429 '\n'.join(f.OldContents()),
1430 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551431
[email protected]e871964c2013-05-13 14:14:551432 if not virtual_depended_on_files:
1433 return []
1434
1435 if input_api.is_committing:
1436 if input_api.tbr:
1437 return [output_api.PresubmitNotifyResult(
1438 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271439 if input_api.dry_run:
1440 return [output_api.PresubmitNotifyResult(
1441 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551442 if not input_api.change.issue:
1443 return [output_api.PresubmitError(
1444 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401445 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551446 output = output_api.PresubmitError
1447 else:
1448 output = output_api.PresubmitNotifyResult
1449
1450 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501451 owner_email, reviewers = (
1452 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1453 input_api,
1454 owners_db.email_regexp,
1455 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551456
1457 owner_email = owner_email or input_api.change.author_email
1458
[email protected]de4f7d22013-05-23 14:27:461459 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511460 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461461 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551462 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1463 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411464
1465 # We strip the /DEPS part that was added by
1466 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1467 # directory.
1468 def StripDeps(path):
1469 start_deps = path.rfind('/DEPS')
1470 if start_deps != -1:
1471 return path[:start_deps]
1472 else:
1473 return path
1474 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551475 for path in missing_files]
1476
1477 if unapproved_dependencies:
1478 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151479 output('You need LGTM from owners of depends-on paths in DEPS that were '
1480 'modified in this CL:\n %s' %
1481 '\n '.join(sorted(unapproved_dependencies)))]
1482 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1483 output_list.append(output(
1484 'Suggested missing target path OWNERS:\n %s' %
1485 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551486 return output_list
1487
1488 return []
1489
1490
[email protected]85218562013-11-22 07:41:401491def _CheckSpamLogging(input_api, output_api):
1492 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1493 black_list = (_EXCLUDED_PATHS +
1494 _TEST_CODE_EXCLUDED_PATHS +
1495 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501496 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191497 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481498 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461499 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121500 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1501 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581502 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161503 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031504 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151505 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1506 r"^chromecast[\\\/]",
1507 r"^cloud_print[\\\/]",
manzagop85e629e2017-05-09 22:11:481508 r"^components[\\\/]browser_watcher[\\\/]"
1509 r"dump_stability_report_main_win.cc$",
jochen34415e52015-07-10 08:34:311510 r"^components[\\\/]html_viewer[\\\/]"
1511 r"web_test_delegate_impl\.cc$",
Samuel Huang577ef6c2018-03-13 18:19:341512 r"^components[\\\/]zucchini[\\\/].*",
peter80739bb2015-10-20 11:17:461513 # TODO(peter): Remove this exception. https://crbug.com/534537
1514 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1515 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251516 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1517 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241518 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111519 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151520 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111521 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521522 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501523 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361524 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311525 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131526 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001527 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441528 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451529 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021530 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351531 r"dump_file_system.cc$",
1532 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401533 source_file_filter = lambda x: input_api.FilterSourceFile(
1534 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1535
thomasanderson625d3932017-03-29 07:16:581536 log_info = set([])
1537 printf = set([])
[email protected]85218562013-11-22 07:41:401538
1539 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581540 for _, line in f.ChangedContents():
1541 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1542 log_info.add(f.LocalPath())
1543 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1544 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371545
thomasanderson625d3932017-03-29 07:16:581546 if input_api.re.search(r"\bprintf\(", line):
1547 printf.add(f.LocalPath())
1548 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1549 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401550
1551 if log_info:
1552 return [output_api.PresubmitError(
1553 'These files spam the console log with LOG(INFO):',
1554 items=log_info)]
1555 if printf:
1556 return [output_api.PresubmitError(
1557 'These files spam the console log with printf/fprintf:',
1558 items=printf)]
1559 return []
1560
1561
[email protected]49aa76a2013-12-04 06:59:161562def _CheckForAnonymousVariables(input_api, output_api):
1563 """These types are all expected to hold locks while in scope and
1564 so should never be anonymous (which causes them to be immediately
1565 destroyed)."""
1566 they_who_must_be_named = [
1567 'base::AutoLock',
1568 'base::AutoReset',
1569 'base::AutoUnlock',
1570 'SkAutoAlphaRestore',
1571 'SkAutoBitmapShaderInstall',
1572 'SkAutoBlitterChoose',
1573 'SkAutoBounderCommit',
1574 'SkAutoCallProc',
1575 'SkAutoCanvasRestore',
1576 'SkAutoCommentBlock',
1577 'SkAutoDescriptor',
1578 'SkAutoDisableDirectionCheck',
1579 'SkAutoDisableOvalCheck',
1580 'SkAutoFree',
1581 'SkAutoGlyphCache',
1582 'SkAutoHDC',
1583 'SkAutoLockColors',
1584 'SkAutoLockPixels',
1585 'SkAutoMalloc',
1586 'SkAutoMaskFreeImage',
1587 'SkAutoMutexAcquire',
1588 'SkAutoPathBoundsUpdate',
1589 'SkAutoPDFRelease',
1590 'SkAutoRasterClipValidate',
1591 'SkAutoRef',
1592 'SkAutoTime',
1593 'SkAutoTrace',
1594 'SkAutoUnref',
1595 ]
1596 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1597 # bad: base::AutoLock(lock.get());
1598 # not bad: base::AutoLock lock(lock.get());
1599 bad_pattern = input_api.re.compile(anonymous)
1600 # good: new base::AutoLock(lock.get())
1601 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1602 errors = []
1603
1604 for f in input_api.AffectedFiles():
1605 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1606 continue
1607 for linenum, line in f.ChangedContents():
1608 if bad_pattern.search(line) and not good_pattern.search(line):
1609 errors.append('%s:%d' % (f.LocalPath(), linenum))
1610
1611 if errors:
1612 return [output_api.PresubmitError(
1613 'These lines create anonymous variables that need to be named:',
1614 items=errors)]
1615 return []
1616
1617
Peter Kasting4844e46e2018-02-23 07:27:101618def _CheckUniquePtr(input_api, output_api):
1619 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1620 sources = lambda affected_file: input_api.FilterSourceFile(
1621 affected_file,
1622 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1623 input_api.DEFAULT_BLACK_LIST),
1624 white_list=(file_inclusion_pattern,))
Vaclav Brozeka54c528b2018-04-06 19:23:551625
1626 # Pattern to capture a single "<...>" block of template arguments. It can
1627 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
1628 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
1629 # latter would likely require counting that < and > match, which is not
1630 # expressible in regular languages. Should the need arise, one can introduce
1631 # limited counting (matching up to a total number of nesting depth), which
1632 # should cover all practical cases for already a low nesting limit.
1633 template_arg_pattern = (
1634 r'<[^>]*' # Opening block of <.
1635 r'>([^<]*>)?') # Closing block of >.
1636 # Prefix expressing that whatever follows is not already inside a <...>
1637 # block.
1638 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:101639 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:551640 not_inside_template_arg_pattern
1641 + r'\bstd::unique_ptr'
1642 + template_arg_pattern
1643 + r'\(\)')
1644
1645 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
1646 template_arg_no_array_pattern = (
1647 r'<[^>]*[^]]' # Opening block of <.
1648 r'>([^(<]*[^]]>)?') # Closing block of >.
1649 # Prefix saying that what follows is the start of an expression.
1650 start_of_expr_pattern = r'(=|\breturn|^)\s*'
1651 # Suffix saying that what follows are call parentheses with a non-empty list
1652 # of arguments.
1653 nonempty_arg_list_pattern = r'\(([^)]|$)'
1654 return_construct_pattern = input_api.re.compile(
1655 start_of_expr_pattern
1656 + r'std::unique_ptr'
1657 + template_arg_no_array_pattern
1658 + nonempty_arg_list_pattern)
1659
Vaclav Brozek851d9602018-04-04 16:13:051660 problems_constructor = []
1661 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:101662 for f in input_api.AffectedSourceFiles(sources):
1663 for line_number, line in f.ChangedContents():
1664 # Disallow:
1665 # return std::unique_ptr<T>(foo);
1666 # bar = std::unique_ptr<T>(foo);
1667 # But allow:
1668 # return std::unique_ptr<T[]>(foo);
1669 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozek851d9602018-04-04 16:13:051670 local_path = f.LocalPath()
Peter Kasting4844e46e2018-02-23 07:27:101671 if return_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051672 problems_constructor.append(
1673 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:101674 # Disallow:
1675 # std::unique_ptr<T>()
1676 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051677 problems_nullptr.append(
1678 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1679
1680 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:161681 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:051682 errors.append(output_api.PresubmitError(
1683 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161684 problems_nullptr))
1685 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:051686 errors.append(output_api.PresubmitError(
1687 'The following files use explicit std::unique_ptr constructor.'
1688 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161689 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:101690 return errors
1691
1692
[email protected]999261d2014-03-03 20:08:081693def _CheckUserActionUpdate(input_api, output_api):
1694 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521695 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081696 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521697 # If actions.xml is already included in the changelist, the PRESUBMIT
1698 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081699 return []
1700
[email protected]999261d2014-03-03 20:08:081701 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1702 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521703 current_actions = None
[email protected]999261d2014-03-03 20:08:081704 for f in input_api.AffectedFiles(file_filter=file_filter):
1705 for line_num, line in f.ChangedContents():
1706 match = input_api.re.search(action_re, line)
1707 if match:
[email protected]2f92dec2014-03-07 19:21:521708 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1709 # loaded only once.
1710 if not current_actions:
1711 with open('tools/metrics/actions/actions.xml') as actions_f:
1712 current_actions = actions_f.read()
1713 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081714 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521715 action = 'name="{0}"'.format(action_name)
1716 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081717 return [output_api.PresubmitPromptWarning(
1718 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521719 'tools/metrics/actions/actions.xml. Please run '
1720 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081721 % (f.LocalPath(), line_num, action_name))]
1722 return []
1723
1724
Daniel Cheng13ca61a882017-08-25 15:11:251725def _ImportJSONCommentEater(input_api):
1726 import sys
1727 sys.path = sys.path + [input_api.os_path.join(
1728 input_api.PresubmitLocalPath(),
1729 'tools', 'json_comment_eater')]
1730 import json_comment_eater
1731 return json_comment_eater
1732
1733
[email protected]99171a92014-06-03 08:44:471734def _GetJSONParseError(input_api, filename, eat_comments=True):
1735 try:
1736 contents = input_api.ReadFile(filename)
1737 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:251738 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:131739 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471740
1741 input_api.json.loads(contents)
1742 except ValueError as e:
1743 return e
1744 return None
1745
1746
1747def _GetIDLParseError(input_api, filename):
1748 try:
1749 contents = input_api.ReadFile(filename)
1750 idl_schema = input_api.os_path.join(
1751 input_api.PresubmitLocalPath(),
1752 'tools', 'json_schema_compiler', 'idl_schema.py')
1753 process = input_api.subprocess.Popen(
1754 [input_api.python_executable, idl_schema],
1755 stdin=input_api.subprocess.PIPE,
1756 stdout=input_api.subprocess.PIPE,
1757 stderr=input_api.subprocess.PIPE,
1758 universal_newlines=True)
1759 (_, error) = process.communicate(input=contents)
1760 return error or None
1761 except ValueError as e:
1762 return e
1763
1764
1765def _CheckParseErrors(input_api, output_api):
1766 """Check that IDL and JSON files do not contain syntax errors."""
1767 actions = {
1768 '.idl': _GetIDLParseError,
1769 '.json': _GetJSONParseError,
1770 }
[email protected]99171a92014-06-03 08:44:471771 # Most JSON files are preprocessed and support comments, but these do not.
1772 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491773 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471774 ]
1775 # Only run IDL checker on files in these directories.
1776 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491777 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1778 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471779 ]
1780
1781 def get_action(affected_file):
1782 filename = affected_file.LocalPath()
1783 return actions.get(input_api.os_path.splitext(filename)[1])
1784
[email protected]99171a92014-06-03 08:44:471785 def FilterFile(affected_file):
1786 action = get_action(affected_file)
1787 if not action:
1788 return False
1789 path = affected_file.LocalPath()
1790
Sean Kau46e29bc2017-08-28 16:31:161791 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:471792 return False
1793
1794 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:161795 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:471796 return False
1797 return True
1798
1799 results = []
1800 for affected_file in input_api.AffectedFiles(
1801 file_filter=FilterFile, include_deletes=False):
1802 action = get_action(affected_file)
1803 kwargs = {}
1804 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:161805 _MatchesFile(input_api, json_no_comments_patterns,
1806 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:471807 kwargs['eat_comments'] = False
1808 parse_error = action(input_api,
1809 affected_file.AbsoluteLocalPath(),
1810 **kwargs)
1811 if parse_error:
1812 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1813 (affected_file.LocalPath(), parse_error)))
1814 return results
1815
1816
[email protected]760deea2013-12-10 19:33:491817def _CheckJavaStyle(input_api, output_api):
1818 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471819 import sys
[email protected]760deea2013-12-10 19:33:491820 original_sys_path = sys.path
1821 try:
1822 sys.path = sys.path + [input_api.os_path.join(
1823 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1824 import checkstyle
1825 finally:
1826 # Restore sys.path to what it was before.
1827 sys.path = original_sys_path
1828
1829 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091830 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511831 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491832
1833
Sean Kau46e29bc2017-08-28 16:31:161834def _MatchesFile(input_api, patterns, path):
1835 for pattern in patterns:
1836 if input_api.re.search(pattern, path):
1837 return True
1838 return False
1839
1840
Daniel Cheng7052cdf2017-11-21 19:23:291841def _GetOwnersFilesToCheckForIpcOwners(input_api):
1842 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:171843
Daniel Cheng7052cdf2017-11-21 19:23:291844 Returns:
1845 A dictionary mapping an OWNER file to the list of OWNERS rules it must
1846 contain to cover IPC-related files with noparent reviewer rules.
1847 """
1848 # Whether or not a file affects IPC is (mostly) determined by a simple list
1849 # of filename patterns.
dchenge07de812016-06-20 19:27:171850 file_patterns = [
palmerb19a0932017-01-24 04:00:311851 # Legacy IPC:
dchenge07de812016-06-20 19:27:171852 '*_messages.cc',
1853 '*_messages*.h',
1854 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311855 # Mojo IPC:
dchenge07de812016-06-20 19:27:171856 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:471857 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:171858 '*_struct_traits*.*',
1859 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311860 '*.typemap',
1861 # Android native IPC:
1862 '*.aidl',
1863 # Blink uses a different file naming convention:
1864 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:471865 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:171866 '*StructTraits*.*',
1867 '*TypeConverter*.*',
1868 ]
1869
scottmg7a6ed5ba2016-11-04 18:22:041870 # These third_party directories do not contain IPCs, but contain files
1871 # matching the above patterns, which trigger false positives.
1872 exclude_paths = [
1873 'third_party/crashpad/*',
Daniel Chengebe635e2018-07-13 12:36:061874 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:291875 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:041876 ]
1877
dchenge07de812016-06-20 19:27:171878 # Dictionary mapping an OWNERS file path to Patterns.
1879 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1880 # rules ) to a PatternEntry.
1881 # PatternEntry is a dictionary with two keys:
1882 # - 'files': the files that are matched by this pattern
1883 # - 'rules': the per-file rules needed for this pattern
1884 # For example, if we expect OWNERS file to contain rules for *.mojom and
1885 # *_struct_traits*.*, Patterns might look like this:
1886 # {
1887 # '*.mojom': {
1888 # 'files': ...,
1889 # 'rules': [
1890 # 'per-file *.mojom=set noparent',
1891 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1892 # ],
1893 # },
1894 # '*_struct_traits*.*': {
1895 # 'files': ...,
1896 # 'rules': [
1897 # 'per-file *_struct_traits*.*=set noparent',
1898 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1899 # ],
1900 # },
1901 # }
1902 to_check = {}
1903
Daniel Cheng13ca61a882017-08-25 15:11:251904 def AddPatternToCheck(input_file, pattern):
1905 owners_file = input_api.os_path.join(
1906 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
1907 if owners_file not in to_check:
1908 to_check[owners_file] = {}
1909 if pattern not in to_check[owners_file]:
1910 to_check[owners_file][pattern] = {
1911 'files': [],
1912 'rules': [
1913 'per-file %s=set noparent' % pattern,
1914 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1915 ]
1916 }
Vaclav Brozekd5de76a2018-03-17 07:57:501917 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:251918
dchenge07de812016-06-20 19:27:171919 # Iterate through the affected files to see what we actually need to check
1920 # for. We should only nag patch authors about per-file rules if a file in that
1921 # directory would match that pattern. If a directory only contains *.mojom
1922 # files and no *_messages*.h files, we should only nag about rules for
1923 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:251924 for f in input_api.AffectedFiles(include_deletes=False):
1925 # Manifest files don't have a strong naming convention. Instead, scan
1926 # affected files for .json files and see if they look like a manifest.
Sean Kau46e29bc2017-08-28 16:31:161927 if (f.LocalPath().endswith('.json') and
1928 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
1929 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:251930 json_comment_eater = _ImportJSONCommentEater(input_api)
1931 mostly_json_lines = '\n'.join(f.NewContents())
1932 # Comments aren't allowed in strict JSON, so filter them out.
1933 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:431934 try:
1935 json_content = input_api.json.loads(json_lines)
1936 except:
1937 # There's another PRESUBMIT check that already verifies that JSON files
1938 # are not invalid, so no need to emit another warning here.
1939 continue
Daniel Cheng13ca61a882017-08-25 15:11:251940 if 'interface_provider_specs' in json_content:
1941 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:171942 for pattern in file_patterns:
1943 if input_api.fnmatch.fnmatch(
1944 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041945 skip = False
1946 for exclude in exclude_paths:
1947 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1948 skip = True
1949 break
1950 if skip:
1951 continue
Daniel Cheng13ca61a882017-08-25 15:11:251952 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:171953 break
1954
Daniel Cheng7052cdf2017-11-21 19:23:291955 return to_check
1956
1957
1958def _CheckIpcOwners(input_api, output_api):
1959 """Checks that affected files involving IPC have an IPC OWNERS rule."""
1960 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
1961
1962 if to_check:
1963 # If there are any OWNERS files to check, there are IPC-related changes in
1964 # this CL. Auto-CC the review list.
1965 output_api.AppendCC('[email protected]')
1966
1967 # Go through the OWNERS files to check, filtering out rules that are already
1968 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:171969 for owners_file, patterns in to_check.iteritems():
1970 try:
1971 with file(owners_file) as f:
1972 lines = set(f.read().splitlines())
1973 for entry in patterns.itervalues():
1974 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1975 ]
1976 except IOError:
1977 # No OWNERS file, so all the rules are definitely missing.
1978 continue
1979
1980 # All the remaining lines weren't found in OWNERS files, so emit an error.
1981 errors = []
1982 for owners_file, patterns in to_check.iteritems():
1983 missing_lines = []
1984 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:501985 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:171986 missing_lines.extend(entry['rules'])
1987 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1988 if missing_lines:
1989 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:051990 'Because of the presence of files:\n%s\n\n'
1991 '%s needs the following %d lines added:\n\n%s' %
1992 ('\n'.join(files), owners_file, len(missing_lines),
1993 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:171994
1995 results = []
1996 if errors:
vabrf5ce3bf92016-07-11 14:52:411997 if input_api.is_committing:
1998 output = output_api.PresubmitError
1999 else:
2000 output = output_api.PresubmitPromptWarning
2001 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592002 'Found OWNERS files that need to be updated for IPC security ' +
2003 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172004 long_text='\n\n'.join(errors)))
2005
2006 return results
2007
2008
jbriance9e12f162016-11-25 07:57:502009def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312010 """Checks that added or removed lines in non third party affected
2011 header files do not lead to new useless class or struct forward
2012 declaration.
jbriance9e12f162016-11-25 07:57:502013 """
2014 results = []
2015 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2016 input_api.re.MULTILINE)
2017 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2018 input_api.re.MULTILINE)
2019 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312020 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192021 not f.LocalPath().startswith('third_party/blink') and
2022 not f.LocalPath().startswith('third_party\\blink') and
jbriance2c51e821a2016-12-12 08:24:312023 not f.LocalPath().startswith('third_party/WebKit') and
2024 not f.LocalPath().startswith('third_party\\WebKit')):
2025 continue
2026
jbriance9e12f162016-11-25 07:57:502027 if not f.LocalPath().endswith('.h'):
2028 continue
2029
2030 contents = input_api.ReadFile(f)
2031 fwd_decls = input_api.re.findall(class_pattern, contents)
2032 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2033
2034 useless_fwd_decls = []
2035 for decl in fwd_decls:
2036 count = sum(1 for _ in input_api.re.finditer(
2037 r'\b%s\b' % input_api.re.escape(decl), contents))
2038 if count == 1:
2039 useless_fwd_decls.append(decl)
2040
2041 if not useless_fwd_decls:
2042 continue
2043
2044 for line in f.GenerateScmDiff().splitlines():
2045 if (line.startswith('-') and not line.startswith('--') or
2046 line.startswith('+') and not line.startswith('++')):
2047 for decl in useless_fwd_decls:
2048 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2049 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242050 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502051 (f.LocalPath(), decl)))
2052 useless_fwd_decls.remove(decl)
2053
2054 return results
2055
2056
dskiba88634f4e2015-08-14 23:03:292057def _CheckAndroidToastUsage(input_api, output_api):
2058 """Checks that code uses org.chromium.ui.widget.Toast instead of
2059 android.widget.Toast (Chromium Toast doesn't force hardware
2060 acceleration on low-end devices, saving memory).
2061 """
2062 toast_import_pattern = input_api.re.compile(
2063 r'^import android\.widget\.Toast;$')
2064
2065 errors = []
2066
2067 sources = lambda affected_file: input_api.FilterSourceFile(
2068 affected_file,
2069 black_list=(_EXCLUDED_PATHS +
2070 _TEST_CODE_EXCLUDED_PATHS +
2071 input_api.DEFAULT_BLACK_LIST +
2072 (r'^chromecast[\\\/].*',
2073 r'^remoting[\\\/].*')),
2074 white_list=(r'.*\.java$',))
2075
2076 for f in input_api.AffectedSourceFiles(sources):
2077 for line_num, line in f.ChangedContents():
2078 if toast_import_pattern.search(line):
2079 errors.append("%s:%d" % (f.LocalPath(), line_num))
2080
2081 results = []
2082
2083 if errors:
2084 results.append(output_api.PresubmitError(
2085 'android.widget.Toast usage is detected. Android toasts use hardware'
2086 ' acceleration, and can be\ncostly on low-end devices. Please use'
2087 ' org.chromium.ui.widget.Toast instead.\n'
2088 'Contact [email protected] if you have any questions.',
2089 errors))
2090
2091 return results
2092
2093
dgnaa68d5e2015-06-10 10:08:222094def _CheckAndroidCrLogUsage(input_api, output_api):
2095 """Checks that new logs using org.chromium.base.Log:
2096 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512097 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222098 """
pkotwicza1dd0b002016-05-16 14:41:042099
torne89540622017-03-24 19:41:302100 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042101 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302102 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:042103 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:302104 # WebView license viewer code cannot depend on //base; used in stub APK.
2105 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
2106 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:042107 ]
2108
dgnaa68d5e2015-06-10 10:08:222109 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122110 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2111 class_in_base_pattern = input_api.re.compile(
2112 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2113 has_some_log_import_pattern = input_api.re.compile(
2114 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222115 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122116 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222117 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512118 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222119 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222120
Vincent Scheib16d7b272015-09-15 18:09:072121 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222122 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:042123 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
2124 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122125
dgnaa68d5e2015-06-10 10:08:222126 tag_decl_errors = []
2127 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122128 tag_errors = []
dgn38736db2015-09-18 19:20:512129 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122130 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222131
2132 for f in input_api.AffectedSourceFiles(sources):
2133 file_content = input_api.ReadFile(f)
2134 has_modified_logs = False
2135
2136 # Per line checks
dgn87d9fb62015-06-12 09:15:122137 if (cr_log_import_pattern.search(file_content) or
2138 (class_in_base_pattern.search(file_content) and
2139 not has_some_log_import_pattern.search(file_content))):
2140 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222141 for line_num, line in f.ChangedContents():
2142
2143 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122144 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222145 if match:
2146 has_modified_logs = True
2147
2148 # Make sure it uses "TAG"
2149 if not match.group('tag') == 'TAG':
2150 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122151 else:
2152 # Report non cr Log function calls in changed lines
2153 for line_num, line in f.ChangedContents():
2154 if log_call_pattern.search(line):
2155 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222156
2157 # Per file checks
2158 if has_modified_logs:
2159 # Make sure the tag is using the "cr" prefix and is not too long
2160 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512161 tag_name = match.group('name') if match else None
2162 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222163 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512164 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222165 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512166 elif '.' in tag_name:
2167 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222168
2169 results = []
2170 if tag_decl_errors:
2171 results.append(output_api.PresubmitPromptWarning(
2172 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512173 '"private static final String TAG = "<package tag>".\n'
2174 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222175 tag_decl_errors))
2176
2177 if tag_length_errors:
2178 results.append(output_api.PresubmitError(
2179 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512180 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222181 tag_length_errors))
2182
2183 if tag_errors:
2184 results.append(output_api.PresubmitPromptWarning(
2185 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2186 tag_errors))
2187
dgn87d9fb62015-06-12 09:15:122188 if util_log_errors:
dgn4401aa52015-04-29 16:26:172189 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122190 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2191 util_log_errors))
2192
dgn38736db2015-09-18 19:20:512193 if tag_with_dot_errors:
2194 results.append(output_api.PresubmitPromptWarning(
2195 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2196 tag_with_dot_errors))
2197
dgn4401aa52015-04-29 16:26:172198 return results
2199
2200
Yoland Yanb92fa522017-08-28 17:37:062201def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2202 """Checks that junit.framework.* is no longer used."""
2203 deprecated_junit_framework_pattern = input_api.re.compile(
2204 r'^import junit\.framework\..*;',
2205 input_api.re.MULTILINE)
2206 sources = lambda x: input_api.FilterSourceFile(
2207 x, white_list=(r'.*\.java$',), black_list=None)
2208 errors = []
2209 for f in input_api.AffectedFiles(sources):
2210 for line_num, line in f.ChangedContents():
2211 if deprecated_junit_framework_pattern.search(line):
2212 errors.append("%s:%d" % (f.LocalPath(), line_num))
2213
2214 results = []
2215 if errors:
2216 results.append(output_api.PresubmitError(
2217 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2218 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2219 ' if you have any question.', errors))
2220 return results
2221
2222
2223def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2224 """Checks that if new Java test classes have inheritance.
2225 Either the new test class is JUnit3 test or it is a JUnit4 test class
2226 with a base class, either case is undesirable.
2227 """
2228 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2229
2230 sources = lambda x: input_api.FilterSourceFile(
2231 x, white_list=(r'.*Test\.java$',), black_list=None)
2232 errors = []
2233 for f in input_api.AffectedFiles(sources):
2234 if not f.OldContents():
2235 class_declaration_start_flag = False
2236 for line_num, line in f.ChangedContents():
2237 if class_declaration_pattern.search(line):
2238 class_declaration_start_flag = True
2239 if class_declaration_start_flag and ' extends ' in line:
2240 errors.append('%s:%d' % (f.LocalPath(), line_num))
2241 if '{' in line:
2242 class_declaration_start_flag = False
2243
2244 results = []
2245 if errors:
2246 results.append(output_api.PresubmitPromptWarning(
2247 'The newly created files include Test classes that inherits from base'
2248 ' class. Please do not use inheritance in JUnit4 tests or add new'
2249 ' JUnit3 tests. Contact [email protected] if you have any'
2250 ' questions.', errors))
2251 return results
2252
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202253
yolandyan45001472016-12-21 21:12:422254def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2255 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2256 deprecated_annotation_import_pattern = input_api.re.compile(
2257 r'^import android\.test\.suitebuilder\.annotation\..*;',
2258 input_api.re.MULTILINE)
2259 sources = lambda x: input_api.FilterSourceFile(
2260 x, white_list=(r'.*\.java$',), black_list=None)
2261 errors = []
2262 for f in input_api.AffectedFiles(sources):
2263 for line_num, line in f.ChangedContents():
2264 if deprecated_annotation_import_pattern.search(line):
2265 errors.append("%s:%d" % (f.LocalPath(), line_num))
2266
2267 results = []
2268 if errors:
2269 results.append(output_api.PresubmitError(
2270 'Annotations in android.test.suitebuilder.annotation have been'
2271 ' deprecated since API level 24. Please use android.support.test.filters'
2272 ' from //third_party/android_support_test_runner:runner_java instead.'
2273 ' Contact [email protected] if you have any questions.', errors))
2274 return results
2275
2276
agrieve7b6479d82015-10-07 14:24:222277def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2278 """Checks if MDPI assets are placed in a correct directory."""
2279 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2280 ('/res/drawable/' in f.LocalPath() or
2281 '/res/drawable-ldrtl/' in f.LocalPath()))
2282 errors = []
2283 for f in input_api.AffectedFiles(include_deletes=False,
2284 file_filter=file_filter):
2285 errors.append(' %s' % f.LocalPath())
2286
2287 results = []
2288 if errors:
2289 results.append(output_api.PresubmitError(
2290 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2291 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2292 '/res/drawable-ldrtl/.\n'
2293 'Contact [email protected] if you have questions.', errors))
2294 return results
2295
2296
Nate Fischer535972b2017-09-16 01:06:182297def _CheckAndroidWebkitImports(input_api, output_api):
2298 """Checks that code uses org.chromium.base.Callback instead of
2299 android.widget.ValueCallback except in the WebView glue layer.
2300 """
2301 valuecallback_import_pattern = input_api.re.compile(
2302 r'^import android\.webkit\.ValueCallback;$')
2303
2304 errors = []
2305
2306 sources = lambda affected_file: input_api.FilterSourceFile(
2307 affected_file,
2308 black_list=(_EXCLUDED_PATHS +
2309 _TEST_CODE_EXCLUDED_PATHS +
2310 input_api.DEFAULT_BLACK_LIST +
2311 (r'^android_webview[\\\/]glue[\\\/].*',)),
2312 white_list=(r'.*\.java$',))
2313
2314 for f in input_api.AffectedSourceFiles(sources):
2315 for line_num, line in f.ChangedContents():
2316 if valuecallback_import_pattern.search(line):
2317 errors.append("%s:%d" % (f.LocalPath(), line_num))
2318
2319 results = []
2320
2321 if errors:
2322 results.append(output_api.PresubmitError(
2323 'android.webkit.ValueCallback usage is detected outside of the glue'
2324 ' layer. To stay compatible with the support library, android.webkit.*'
2325 ' classes should only be used inside the glue layer and'
2326 ' org.chromium.base.Callback should be used instead.',
2327 errors))
2328
2329 return results
2330
2331
agrievef32bcc72016-04-04 14:57:402332class PydepsChecker(object):
2333 def __init__(self, input_api, pydeps_files):
2334 self._file_cache = {}
2335 self._input_api = input_api
2336 self._pydeps_files = pydeps_files
2337
2338 def _LoadFile(self, path):
2339 """Returns the list of paths within a .pydeps file relative to //."""
2340 if path not in self._file_cache:
2341 with open(path) as f:
2342 self._file_cache[path] = f.read()
2343 return self._file_cache[path]
2344
2345 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2346 """Returns an interable of paths within the .pydep, relativized to //."""
2347 os_path = self._input_api.os_path
2348 pydeps_dir = os_path.dirname(pydeps_path)
2349 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2350 if not l.startswith('*'))
2351 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2352
2353 def _CreateFilesToPydepsMap(self):
2354 """Returns a map of local_path -> list_of_pydeps."""
2355 ret = {}
2356 for pydep_local_path in self._pydeps_files:
2357 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2358 ret.setdefault(path, []).append(pydep_local_path)
2359 return ret
2360
2361 def ComputeAffectedPydeps(self):
2362 """Returns an iterable of .pydeps files that might need regenerating."""
2363 affected_pydeps = set()
2364 file_to_pydeps_map = None
2365 for f in self._input_api.AffectedFiles(include_deletes=True):
2366 local_path = f.LocalPath()
2367 if local_path == 'DEPS':
2368 return self._pydeps_files
2369 elif local_path.endswith('.pydeps'):
2370 if local_path in self._pydeps_files:
2371 affected_pydeps.add(local_path)
2372 elif local_path.endswith('.py'):
2373 if file_to_pydeps_map is None:
2374 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2375 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2376 return affected_pydeps
2377
2378 def DetermineIfStale(self, pydeps_path):
2379 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412380 import difflib
John Budorick47ca3fe2018-02-10 00:53:102381 import os
2382
agrievef32bcc72016-04-04 14:57:402383 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2384 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102385 env = dict(os.environ)
2386 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402387 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102388 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412389 old_contents = old_pydeps_data[2:]
2390 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402391 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412392 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402393
2394
2395def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2396 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402397 # This check is for Python dependency lists (.pydeps files), and involves
2398 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2399 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282400 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002401 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022402 # TODO(agrieve): Update when there's a better way to detect
2403 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402404 is_android = input_api.os_path.exists('third_party/android_tools')
2405 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2406 results = []
2407 # First, check for new / deleted .pydeps.
2408 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032409 # Check whether we are running the presubmit check for a file in src.
2410 # f.LocalPath is relative to repo (src, or internal repo).
2411 # os_path.exists is relative to src repo.
2412 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2413 # to src and we can conclude that the pydeps is in src.
2414 if input_api.os_path.exists(f.LocalPath()):
2415 if f.LocalPath().endswith('.pydeps'):
2416 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2417 results.append(output_api.PresubmitError(
2418 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2419 'remove %s' % f.LocalPath()))
2420 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2421 results.append(output_api.PresubmitError(
2422 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2423 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402424
2425 if results:
2426 return results
2427
2428 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2429
2430 for pydep_path in checker.ComputeAffectedPydeps():
2431 try:
phajdan.jr0d9878552016-11-04 10:49:412432 result = checker.DetermineIfStale(pydep_path)
2433 if result:
2434 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402435 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412436 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2437 'To regenerate, run:\n\n %s' %
2438 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402439 except input_api.subprocess.CalledProcessError as error:
2440 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2441 long_text=error.output)]
2442
2443 return results
2444
2445
glidere61efad2015-02-18 17:39:432446def _CheckSingletonInHeaders(input_api, output_api):
2447 """Checks to make sure no header files have |Singleton<|."""
2448 def FileFilter(affected_file):
2449 # It's ok for base/memory/singleton.h to have |Singleton<|.
2450 black_list = (_EXCLUDED_PATHS +
2451 input_api.DEFAULT_BLACK_LIST +
Michael Warrese4451492018-03-07 04:42:472452 (r"^base[\\\/]memory[\\\/]singleton\.h$",
2453 r"^net[\\\/]quic[\\\/]platform[\\\/]impl[\\\/]"
2454 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432455 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2456
sergeyu34d21222015-09-16 00:11:442457 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432458 files = []
2459 for f in input_api.AffectedSourceFiles(FileFilter):
2460 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2461 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2462 contents = input_api.ReadFile(f)
2463 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242464 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432465 pattern.search(line)):
2466 files.append(f)
2467 break
2468
2469 if files:
yolandyandaabc6d2016-04-18 18:29:392470 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442471 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432472 'Please move them to an appropriate source file so that the ' +
2473 'template gets instantiated in a single compilation unit.',
2474 files) ]
2475 return []
2476
2477
[email protected]fd20b902014-05-09 02:14:532478_DEPRECATED_CSS = [
2479 # Values
2480 ( "-webkit-box", "flex" ),
2481 ( "-webkit-inline-box", "inline-flex" ),
2482 ( "-webkit-flex", "flex" ),
2483 ( "-webkit-inline-flex", "inline-flex" ),
2484 ( "-webkit-min-content", "min-content" ),
2485 ( "-webkit-max-content", "max-content" ),
2486
2487 # Properties
2488 ( "-webkit-background-clip", "background-clip" ),
2489 ( "-webkit-background-origin", "background-origin" ),
2490 ( "-webkit-background-size", "background-size" ),
2491 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442492 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532493
2494 # Functions
2495 ( "-webkit-gradient", "gradient" ),
2496 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2497 ( "-webkit-linear-gradient", "linear-gradient" ),
2498 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2499 ( "-webkit-radial-gradient", "radial-gradient" ),
2500 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2501]
2502
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202503
dbeam1ec68ac2016-12-15 05:22:242504def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532505 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252506 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342507 documentation and iOS CSS for dom distiller
2508 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252509 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532510 results = []
dbeam070cfe62014-10-22 06:44:022511 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:252512 black_list = (_EXCLUDED_PATHS +
2513 _TEST_CODE_EXCLUDED_PATHS +
2514 input_api.DEFAULT_BLACK_LIST +
2515 (r"^chrome/common/extensions/docs",
2516 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342517 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442518 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252519 r"^native_client_sdk"))
2520 file_filter = lambda f: input_api.FilterSourceFile(
2521 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532522 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2523 for line_num, line in fpath.ChangedContents():
2524 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022525 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532526 results.append(output_api.PresubmitError(
2527 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2528 (fpath.LocalPath(), line_num, deprecated_value, value)))
2529 return results
2530
mohan.reddyf21db962014-10-16 12:26:472531
dbeam070cfe62014-10-22 06:44:022532_DEPRECATED_JS = [
2533 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2534 ( "__defineGetter__", "Object.defineProperty" ),
2535 ( "__defineSetter__", "Object.defineProperty" ),
2536]
2537
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202538
dbeam1ec68ac2016-12-15 05:22:242539def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022540 """Make sure that we don't use deprecated JS in Chrome code."""
2541 results = []
2542 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2543 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2544 input_api.DEFAULT_BLACK_LIST)
2545 file_filter = lambda f: input_api.FilterSourceFile(
2546 f, white_list=file_inclusion_pattern, black_list=black_list)
2547 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2548 for lnum, line in fpath.ChangedContents():
2549 for (deprecated, replacement) in _DEPRECATED_JS:
2550 if deprecated in line:
2551 results.append(output_api.PresubmitError(
2552 "%s:%d: Use of deprecated JS %s, use %s instead" %
2553 (fpath.LocalPath(), lnum, deprecated, replacement)))
2554 return results
2555
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202556
dpapadd651231d82017-07-21 02:44:472557def _CheckForRiskyJsArrowFunction(line_number, line):
2558 if ' => ' in line:
2559 return "line %d, is using an => (arrow) function\n %s\n" % (
2560 line_number, line)
2561 return ''
2562
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202563
dpapadd651231d82017-07-21 02:44:472564def _CheckForRiskyJsConstLet(input_api, line_number, line):
2565 if input_api.re.match('^\s*(const|let)\s', line):
2566 return "line %d, is using const/let keyword\n %s\n" % (
2567 line_number, line)
2568 return ''
dbeam070cfe62014-10-22 06:44:022569
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202570
dbeam1ec68ac2016-12-15 05:22:242571def _CheckForRiskyJsFeatures(input_api, output_api):
2572 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
Steven Bennetts90545f3cb2017-08-14 18:11:002573 # 'ui/webui/resources/cr_components are not allowed on ios'
2574 not_ios_filter = (r".*ui\/webui\/resources\/cr_components.*", )
Steven Bennetts9c7e3c22017-08-02 19:10:572575 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js,
Steven Bennetts90545f3cb2017-08-14 18:11:002576 black_list=not_ios_filter)
dpapadd651231d82017-07-21 02:44:472577 results = []
dbeam1ec68ac2016-12-15 05:22:242578 for f in input_api.AffectedFiles(file_filter=file_filter):
dpapadd651231d82017-07-21 02:44:472579 arrow_error_lines = []
2580 const_let_error_lines = []
dbeam1ec68ac2016-12-15 05:22:242581 for lnum, line in f.ChangedContents():
dpapadd651231d82017-07-21 02:44:472582 arrow_error_lines += filter(None, [
2583 _CheckForRiskyJsArrowFunction(lnum, line),
2584 ])
dbeam1ec68ac2016-12-15 05:22:242585
dpapadd651231d82017-07-21 02:44:472586 const_let_error_lines += filter(None, [
2587 _CheckForRiskyJsConstLet(input_api, lnum, line),
2588 ])
dbeam1ec68ac2016-12-15 05:22:242589
dpapadd651231d82017-07-21 02:44:472590 if arrow_error_lines:
2591 arrow_error_lines = map(
2592 lambda e: "%s:%s" % (f.LocalPath(), e), arrow_error_lines)
2593 results.append(
2594 output_api.PresubmitPromptWarning('\n'.join(arrow_error_lines + [
2595"""
2596Use of => (arrow) operator detected in:
dbeam1ec68ac2016-12-15 05:22:242597%s
2598Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2599https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
dpapadd651231d82017-07-21 02:44:472600""" % f.LocalPath()
2601 ])))
dbeam1ec68ac2016-12-15 05:22:242602
dpapadd651231d82017-07-21 02:44:472603 if const_let_error_lines:
2604 const_let_error_lines = map(
2605 lambda e: "%s:%s" % (f.LocalPath(), e), const_let_error_lines)
2606 results.append(
2607 output_api.PresubmitPromptWarning('\n'.join(const_let_error_lines + [
2608"""
2609Use of const/let keywords detected in:
2610%s
2611Please ensure your code does not run on iOS9 because const/let is not fully
2612supported.
2613https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#let-Block_Scoped-Variables
2614https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#const-Block_Scoped-Constants
2615""" % f.LocalPath()
2616 ])))
2617
2618 return results
dbeam1ec68ac2016-12-15 05:22:242619
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202620
rlanday6802cf632017-05-30 17:48:362621def _CheckForRelativeIncludes(input_api, output_api):
2622 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2623 import sys
2624 original_sys_path = sys.path
2625 try:
2626 sys.path = sys.path + [input_api.os_path.join(
2627 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2628 from cpp_checker import CppChecker
2629 finally:
2630 # Restore sys.path to what it was before.
2631 sys.path = original_sys_path
2632
2633 bad_files = {}
2634 for f in input_api.AffectedFiles(include_deletes=False):
2635 if (f.LocalPath().startswith('third_party') and
2636 not f.LocalPath().startswith('third_party/WebKit') and
2637 not f.LocalPath().startswith('third_party\\WebKit')):
2638 continue
2639
2640 if not CppChecker.IsCppFile(f.LocalPath()):
2641 continue
2642
Vaclav Brozekd5de76a2018-03-17 07:57:502643 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362644 if "#include" in line and "../" in line]
2645 if not relative_includes:
2646 continue
2647 bad_files[f.LocalPath()] = relative_includes
2648
2649 if not bad_files:
2650 return []
2651
2652 error_descriptions = []
2653 for file_path, bad_lines in bad_files.iteritems():
2654 error_description = file_path
2655 for line in bad_lines:
2656 error_description += '\n ' + line
2657 error_descriptions.append(error_description)
2658
2659 results = []
2660 results.append(output_api.PresubmitError(
2661 'You added one or more relative #include paths (including "../").\n'
2662 'These shouldn\'t be used because they can be used to include headers\n'
2663 'from code that\'s not correctly specified as a dependency in the\n'
2664 'relevant BUILD.gn file(s).',
2665 error_descriptions))
2666
2667 return results
2668
Takeshi Yoshinoe387aa32017-08-02 13:16:132669
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202670def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2671 if not isinstance(key, ast.Str):
2672 return 'Key at line %d must be a string literal' % key.lineno
2673 if not isinstance(value, ast.Dict):
2674 return 'Value at line %d must be a dict' % value.lineno
2675 if len(value.keys) != 1:
2676 return 'Dict at line %d must have single entry' % value.lineno
2677 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2678 return (
2679 'Entry at line %d must have a string literal \'filepath\' as key' %
2680 value.lineno)
2681 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132682
Takeshi Yoshinoe387aa32017-08-02 13:16:132683
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202684def _CheckWatchlistsEntrySyntax(key, value, ast):
2685 if not isinstance(key, ast.Str):
2686 return 'Key at line %d must be a string literal' % key.lineno
2687 if not isinstance(value, ast.List):
2688 return 'Value at line %d must be a list' % value.lineno
2689 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132690
Takeshi Yoshinoe387aa32017-08-02 13:16:132691
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202692def _CheckWATCHLISTSEntries(wd_dict, w_dict, ast):
2693 mismatch_template = (
2694 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2695 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132696
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202697 i = 0
2698 last_key = ''
2699 while True:
2700 if i >= len(wd_dict.keys):
2701 if i >= len(w_dict.keys):
2702 return None
2703 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2704 elif i >= len(w_dict.keys):
2705 return (
2706 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132707
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202708 wd_key = wd_dict.keys[i]
2709 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132710
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202711 result = _CheckWatchlistDefinitionsEntrySyntax(
2712 wd_key, wd_dict.values[i], ast)
2713 if result is not None:
2714 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132715
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202716 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast)
2717 if result is not None:
2718 return 'Bad entry in WATCHLISTS dict: %s' % result
2719
2720 if wd_key.s != w_key.s:
2721 return mismatch_template % (
2722 '%s at line %d' % (wd_key.s, wd_key.lineno),
2723 '%s at line %d' % (w_key.s, w_key.lineno))
2724
2725 if wd_key.s < last_key:
2726 return (
2727 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2728 (wd_key.lineno, w_key.lineno))
2729 last_key = wd_key.s
2730
2731 i = i + 1
2732
2733
2734def _CheckWATCHLISTSSyntax(expression, ast):
2735 if not isinstance(expression, ast.Expression):
2736 return 'WATCHLISTS file must contain a valid expression'
2737 dictionary = expression.body
2738 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2739 return 'WATCHLISTS file must have single dict with exactly two entries'
2740
2741 first_key = dictionary.keys[0]
2742 first_value = dictionary.values[0]
2743 second_key = dictionary.keys[1]
2744 second_value = dictionary.values[1]
2745
2746 if (not isinstance(first_key, ast.Str) or
2747 first_key.s != 'WATCHLIST_DEFINITIONS' or
2748 not isinstance(first_value, ast.Dict)):
2749 return (
2750 'The first entry of the dict in WATCHLISTS file must be '
2751 'WATCHLIST_DEFINITIONS dict')
2752
2753 if (not isinstance(second_key, ast.Str) or
2754 second_key.s != 'WATCHLISTS' or
2755 not isinstance(second_value, ast.Dict)):
2756 return (
2757 'The second entry of the dict in WATCHLISTS file must be '
2758 'WATCHLISTS dict')
2759
2760 return _CheckWATCHLISTSEntries(first_value, second_value, ast)
Takeshi Yoshinoe387aa32017-08-02 13:16:132761
2762
2763def _CheckWATCHLISTS(input_api, output_api):
2764 for f in input_api.AffectedFiles(include_deletes=False):
2765 if f.LocalPath() == 'WATCHLISTS':
2766 contents = input_api.ReadFile(f, 'r')
2767
2768 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202769 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132770 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202771 # Get an AST tree for it and scan the tree for detailed style checking.
2772 expression = input_api.ast.parse(
2773 contents, filename='WATCHLISTS', mode='eval')
2774 except ValueError as e:
2775 return [output_api.PresubmitError(
2776 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2777 except SyntaxError as e:
2778 return [output_api.PresubmitError(
2779 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2780 except TypeError as e:
2781 return [output_api.PresubmitError(
2782 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132783
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202784 result = _CheckWATCHLISTSSyntax(expression, input_api.ast)
2785 if result is not None:
2786 return [output_api.PresubmitError(result)]
2787 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132788
2789 return []
2790
2791
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192792def _CheckNewHeaderWithoutGnChange(input_api, output_api):
2793 """Checks that newly added header files have corresponding GN changes.
2794 Note that this is only a heuristic. To be precise, run script:
2795 build/check_gn_headers.py.
2796 """
2797
2798 def headers(f):
2799 return input_api.FilterSourceFile(
2800 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
2801
2802 new_headers = []
2803 for f in input_api.AffectedSourceFiles(headers):
2804 if f.Action() != 'A':
2805 continue
2806 new_headers.append(f.LocalPath())
2807
2808 def gn_files(f):
2809 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
2810
2811 all_gn_changed_contents = ''
2812 for f in input_api.AffectedSourceFiles(gn_files):
2813 for _, line in f.ChangedContents():
2814 all_gn_changed_contents += line
2815
2816 problems = []
2817 for header in new_headers:
2818 basename = input_api.os_path.basename(header)
2819 if basename not in all_gn_changed_contents:
2820 problems.append(header)
2821
2822 if problems:
2823 return [output_api.PresubmitPromptWarning(
2824 'Missing GN changes for new header files', items=sorted(problems),
2825 long_text='Please double check whether newly added header files need '
2826 'corresponding changes in gn or gni files.\nThis checking is only a '
2827 'heuristic. Run build/check_gn_headers.py to be precise.\n'
2828 'Read https://crbug.com/661774 for more info.')]
2829 return []
2830
2831
dgnaa68d5e2015-06-10 10:08:222832def _AndroidSpecificOnUploadChecks(input_api, output_api):
2833 """Groups checks that target android code."""
2834 results = []
dgnaa68d5e2015-06-10 10:08:222835 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222836 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292837 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:062838 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
2839 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:422840 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:182841 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222842 return results
2843
2844
[email protected]22c9bd72011-03-27 16:47:392845def _CommonChecks(input_api, output_api):
2846 """Checks common to both upload and commit."""
2847 results = []
2848 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382849 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542850 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:082851
2852 author = input_api.change.author_email
2853 if author and author not in _KNOWN_ROBOTS:
2854 results.extend(
2855 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
2856
[email protected]55459852011-08-10 15:17:192857 results.extend(
[email protected]760deea2013-12-10 19:33:492858 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:232859 results.extend(
2860 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542861 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182862 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522863 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222864 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442865 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592866 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062867 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122868 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182869 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222870 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302871 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492872 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032873 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492874 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442875 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272876 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:072877 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542878 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442879 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392880 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552881 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042882 results.extend(
2883 input_api.canned_checks.CheckChangeHasNoTabs(
2884 input_api,
2885 output_api,
2886 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402887 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162888 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082889 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242890 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2891 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472892 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042893 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:052894 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:142895 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232896 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432897 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402898 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152899 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172900 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502901 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242902 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:362903 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:132904 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:432905 results.extend(input_api.RunTests(
2906 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:142907 results.extend(_CheckTranslationScreenshots(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242908
Vaclav Brozekcdc7defb2018-03-20 09:54:352909 for f in input_api.AffectedFiles():
2910 path, name = input_api.os_path.split(f.LocalPath())
2911 if name == 'PRESUBMIT.py':
2912 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:002913 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
2914 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:072915 # The PRESUBMIT.py file (and the directory containing it) might
2916 # have been affected by being moved or removed, so only try to
2917 # run the tests if they still exist.
2918 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2919 input_api, output_api, full_path,
2920 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392921 return results
[email protected]1f7b4172010-01-28 01:17:342922
[email protected]b337cb5b2011-01-23 21:24:052923
[email protected]b8079ae4a2012-12-05 19:56:492924def _CheckPatchFiles(input_api, output_api):
2925 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2926 if f.LocalPath().endswith(('.orig', '.rej'))]
2927 if problems:
2928 return [output_api.PresubmitError(
2929 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032930 else:
2931 return []
[email protected]b8079ae4a2012-12-05 19:56:492932
2933
Kent Tamura5a8755d2017-06-29 23:37:072934def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:212935 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
2936 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
2937 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:072938 include_re = input_api.re.compile(
2939 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
2940 extension_re = input_api.re.compile(r'\.[a-z]+$')
2941 errors = []
2942 for f in input_api.AffectedFiles():
2943 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
2944 continue
2945 found_line_number = None
2946 found_macro = None
2947 for line_num, line in f.ChangedContents():
2948 match = macro_re.search(line)
2949 if match:
2950 found_line_number = line_num
2951 found_macro = match.group(2)
2952 break
2953 if not found_line_number:
2954 continue
2955
2956 found_include = False
2957 for line in f.NewContents():
2958 if include_re.search(line):
2959 found_include = True
2960 break
2961 if found_include:
2962 continue
2963
2964 if not f.LocalPath().endswith('.h'):
2965 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
2966 try:
2967 content = input_api.ReadFile(primary_header_path, 'r')
2968 if include_re.search(content):
2969 continue
2970 except IOError:
2971 pass
2972 errors.append('%s:%d %s macro is used without including build/'
2973 'build_config.h.'
2974 % (f.LocalPath(), found_line_number, found_macro))
2975 if errors:
2976 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
2977 return []
2978
2979
[email protected]b00342e7f2013-03-26 16:21:542980def _DidYouMeanOSMacro(bad_macro):
2981 try:
2982 return {'A': 'OS_ANDROID',
2983 'B': 'OS_BSD',
2984 'C': 'OS_CHROMEOS',
2985 'F': 'OS_FREEBSD',
2986 'L': 'OS_LINUX',
2987 'M': 'OS_MACOSX',
2988 'N': 'OS_NACL',
2989 'O': 'OS_OPENBSD',
2990 'P': 'OS_POSIX',
2991 'S': 'OS_SOLARIS',
2992 'W': 'OS_WIN'}[bad_macro[3].upper()]
2993 except KeyError:
2994 return ''
2995
2996
2997def _CheckForInvalidOSMacrosInFile(input_api, f):
2998 """Check for sensible looking, totally invalid OS macros."""
2999 preprocessor_statement = input_api.re.compile(r'^\s*#')
3000 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
3001 results = []
3002 for lnum, line in f.ChangedContents():
3003 if preprocessor_statement.search(line):
3004 for match in os_macro.finditer(line):
3005 if not match.group(1) in _VALID_OS_MACROS:
3006 good = _DidYouMeanOSMacro(match.group(1))
3007 did_you_mean = ' (did you mean %s?)' % good if good else ''
3008 results.append(' %s:%d %s%s' % (f.LocalPath(),
3009 lnum,
3010 match.group(1),
3011 did_you_mean))
3012 return results
3013
3014
3015def _CheckForInvalidOSMacros(input_api, output_api):
3016 """Check all affected files for invalid OS macros."""
3017 bad_macros = []
3018 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:473019 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:543020 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
3021
3022 if not bad_macros:
3023 return []
3024
3025 return [output_api.PresubmitError(
3026 'Possibly invalid OS macro[s] found. Please fix your code\n'
3027 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
3028
lliabraa35bab3932014-10-01 12:16:443029
3030def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
3031 """Check all affected files for invalid "if defined" macros."""
3032 ALWAYS_DEFINED_MACROS = (
3033 "TARGET_CPU_PPC",
3034 "TARGET_CPU_PPC64",
3035 "TARGET_CPU_68K",
3036 "TARGET_CPU_X86",
3037 "TARGET_CPU_ARM",
3038 "TARGET_CPU_MIPS",
3039 "TARGET_CPU_SPARC",
3040 "TARGET_CPU_ALPHA",
3041 "TARGET_IPHONE_SIMULATOR",
3042 "TARGET_OS_EMBEDDED",
3043 "TARGET_OS_IPHONE",
3044 "TARGET_OS_MAC",
3045 "TARGET_OS_UNIX",
3046 "TARGET_OS_WIN32",
3047 )
3048 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
3049 results = []
3050 for lnum, line in f.ChangedContents():
3051 for match in ifdef_macro.finditer(line):
3052 if match.group(1) in ALWAYS_DEFINED_MACROS:
3053 always_defined = ' %s is always defined. ' % match.group(1)
3054 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
3055 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
3056 lnum,
3057 always_defined,
3058 did_you_mean))
3059 return results
3060
3061
3062def _CheckForInvalidIfDefinedMacros(input_api, output_api):
3063 """Check all affected files for invalid "if defined" macros."""
3064 bad_macros = []
3065 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:213066 if f.LocalPath().startswith('third_party/sqlite/'):
3067 continue
lliabraa35bab3932014-10-01 12:16:443068 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3069 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3070
3071 if not bad_macros:
3072 return []
3073
3074 return [output_api.PresubmitError(
3075 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3076 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3077 bad_macros)]
3078
3079
mlamouria82272622014-09-16 18:45:043080def _CheckForIPCRules(input_api, output_api):
3081 """Check for same IPC rules described in
3082 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3083 """
3084 base_pattern = r'IPC_ENUM_TRAITS\('
3085 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3086 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3087
3088 problems = []
3089 for f in input_api.AffectedSourceFiles(None):
3090 local_path = f.LocalPath()
3091 if not local_path.endswith('.h'):
3092 continue
3093 for line_number, line in f.ChangedContents():
3094 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3095 problems.append(
3096 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3097
3098 if problems:
3099 return [output_api.PresubmitPromptWarning(
3100 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
3101 else:
3102 return []
3103
[email protected]b00342e7f2013-03-26 16:21:543104
Stephen Martinis97a394142018-06-07 23:06:053105def _CheckForLongPathnames(input_api, output_api):
3106 """Check to make sure no files being submitted have long paths.
3107 This causes issues on Windows.
3108 """
3109 problems = []
3110 for f in input_api.AffectedSourceFiles(None):
3111 local_path = f.LocalPath()
3112 # Windows has a path limit of 260 characters. Limit path length to 200 so
3113 # that we have some extra for the prefix on dev machines and the bots.
3114 if len(local_path) > 200:
3115 problems.append(local_path)
3116
3117 if problems:
3118 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
3119 else:
3120 return []
3121
3122
Daniel Bratell8ba52722018-03-02 16:06:143123def _CheckForIncludeGuards(input_api, output_api):
3124 """Check that header files have proper guards against multiple inclusion.
3125 If a file should not have such guards (and it probably should) then it
3126 should include the string "no-include-guard-because-multiply-included".
3127 """
Daniel Bratell6a75baef62018-06-04 10:04:453128 def is_chromium_header_file(f):
3129 # We only check header files under the control of the Chromium
3130 # project. That is, those outside third_party apart from
3131 # third_party/blink.
3132 file_with_path = input_api.os_path.normpath(f.LocalPath())
3133 return (file_with_path.endswith('.h') and
3134 (not file_with_path.startswith('third_party') or
3135 file_with_path.startswith(
3136 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:143137
3138 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:343139 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:143140
3141 errors = []
3142
Daniel Bratell6a75baef62018-06-04 10:04:453143 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:143144 guard_name = None
3145 guard_line_number = None
3146 seen_guard_end = False
3147
3148 file_with_path = input_api.os_path.normpath(f.LocalPath())
3149 base_file_name = input_api.os_path.splitext(
3150 input_api.os_path.basename(file_with_path))[0]
3151 upper_base_file_name = base_file_name.upper()
3152
3153 expected_guard = replace_special_with_underscore(
3154 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:143155
3156 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:573157 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
3158 # are too many (1000+) files with slight deviations from the
3159 # coding style. The most important part is that the include guard
3160 # is there, and that it's unique, not the name so this check is
3161 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:143162 #
3163 # As code becomes more uniform, this could be made stricter.
3164
3165 guard_name_pattern_list = [
3166 # Anything with the right suffix (maybe with an extra _).
3167 r'\w+_H__?',
3168
Daniel Bratell39b5b062018-05-16 18:09:573169 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:143170 r'\w+_h',
3171
3172 # Anything including the uppercase name of the file.
3173 r'\w*' + input_api.re.escape(replace_special_with_underscore(
3174 upper_base_file_name)) + r'\w*',
3175 ]
3176 guard_name_pattern = '|'.join(guard_name_pattern_list)
3177 guard_pattern = input_api.re.compile(
3178 r'#ifndef\s+(' + guard_name_pattern + ')')
3179
3180 for line_number, line in enumerate(f.NewContents()):
3181 if 'no-include-guard-because-multiply-included' in line:
3182 guard_name = 'DUMMY' # To not trigger check outside the loop.
3183 break
3184
3185 if guard_name is None:
3186 match = guard_pattern.match(line)
3187 if match:
3188 guard_name = match.group(1)
3189 guard_line_number = line_number
3190
Daniel Bratell39b5b062018-05-16 18:09:573191 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:453192 # don't match the chromium style guide, but new files should
3193 # get it right.
3194 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:573195 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:143196 errors.append(output_api.PresubmitPromptWarning(
3197 'Header using the wrong include guard name %s' % guard_name,
3198 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:573199 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:143200 else:
3201 # The line after #ifndef should have a #define of the same name.
3202 if line_number == guard_line_number + 1:
3203 expected_line = '#define %s' % guard_name
3204 if line != expected_line:
3205 errors.append(output_api.PresubmitPromptWarning(
3206 'Missing "%s" for include guard' % expected_line,
3207 ['%s:%d' % (f.LocalPath(), line_number + 1)],
3208 'Expected: %r\nGot: %r' % (expected_line, line)))
3209
3210 if not seen_guard_end and line == '#endif // %s' % guard_name:
3211 seen_guard_end = True
3212 elif seen_guard_end:
3213 if line.strip() != '':
3214 errors.append(output_api.PresubmitPromptWarning(
3215 'Include guard %s not covering the whole file' % (
3216 guard_name), [f.LocalPath()]))
3217 break # Nothing else to check and enough to warn once.
3218
3219 if guard_name is None:
3220 errors.append(output_api.PresubmitPromptWarning(
3221 'Missing include guard %s' % expected_guard,
3222 [f.LocalPath()],
3223 'Missing include guard in %s\n'
3224 'Recommended name: %s\n'
3225 'This check can be disabled by having the string\n'
3226 'no-include-guard-because-multiply-included in the header.' %
3227 (f.LocalPath(), expected_guard)))
3228
3229 return errors
3230
3231
mostynbb639aca52015-01-07 20:31:233232def _CheckForWindowsLineEndings(input_api, output_api):
3233 """Check source code and known ascii text files for Windows style line
3234 endings.
3235 """
earthdok1b5e0ee2015-03-10 15:19:103236 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233237
3238 file_inclusion_pattern = (
3239 known_text_files,
3240 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3241 )
3242
mostynbb639aca52015-01-07 20:31:233243 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533244 source_file_filter = lambda f: input_api.FilterSourceFile(
3245 f, white_list=file_inclusion_pattern, black_list=None)
3246 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503247 include_file = False
3248 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233249 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503250 include_file = True
3251 if include_file:
3252 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233253
3254 if problems:
3255 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3256 'these files to contain Windows style line endings?\n' +
3257 '\n'.join(problems))]
3258
3259 return []
3260
3261
Vaclav Brozekd5de76a2018-03-17 07:57:503262def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133263 """Checks that all source files use SYSLOG properly."""
3264 syslog_files = []
3265 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563266 for line_number, line in f.ChangedContents():
3267 if 'SYSLOG' in line:
3268 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3269
pastarmovj89f7ee12016-09-20 14:58:133270 if syslog_files:
3271 return [output_api.PresubmitPromptWarning(
3272 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3273 ' calls.\nFiles to check:\n', items=syslog_files)]
3274 return []
3275
3276
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193277def _CheckCrbugLinksHaveHttps(input_api, output_api):
Miguel Casas68bdb652017-12-19 16:29:093278 """Checks that crbug(.com) links are correctly prefixed by https://,
3279 unless they come in the accepted form TODO(crbug.com/...)
3280 """
Wei-Yin Chen (陳威尹)b1ce35492018-07-31 02:37:013281 white_list = (r'.+%s' % _IMPLEMENTATION_EXTENSIONS, )
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193282 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS)
3283 sources = lambda f: input_api.FilterSourceFile(
3284 f, white_list=white_list, black_list=black_list)
3285
3286 pattern = input_api.re.compile(r'//.*(?<!:\/\/)crbug[.com]*')
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203287 accepted_pattern = input_api.re.compile(r'//.*TODO\(crbug[.com]*')
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193288 problems = []
3289 for f in input_api.AffectedSourceFiles(sources):
3290 for line_num, line in f.ChangedContents():
Miguel Casas68bdb652017-12-19 16:29:093291 if pattern.search(line) and not accepted_pattern.search(line):
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193292 problems.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3293
3294 if problems:
3295 return [output_api.PresubmitPromptWarning(
3296 'Found unprefixed crbug.com URL(s), consider prepending https://\n'+
3297 '\n'.join(problems))]
3298 return []
3299
3300
[email protected]1f7b4172010-01-28 01:17:343301def CheckChangeOnUpload(input_api, output_api):
3302 results = []
3303 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473304 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283305 results.extend(
jam93a6ee792017-02-08 23:59:223306 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193307 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223308 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133309 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163310 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193311 results.extend(_CheckCrbugLinksHaveHttps(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:533312 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193313 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543314 return results
[email protected]ca8d1982009-02-19 16:33:123315
3316
[email protected]1bfb8322014-04-23 01:02:413317def GetTryServerMasterForBot(bot):
3318 """Returns the Try Server master for the given bot.
3319
[email protected]0bb112362014-07-26 04:38:323320 It tries to guess the master from the bot name, but may still fail
3321 and return None. There is no longer a default master.
3322 """
3323 # Potentially ambiguous bot names are listed explicitly.
3324 master_map = {
tandriie5587792016-07-14 00:34:503325 'chromium_presubmit': 'master.tryserver.chromium.linux',
3326 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413327 }
[email protected]0bb112362014-07-26 04:38:323328 master = master_map.get(bot)
3329 if not master:
wnwen4fbaab82016-05-25 12:54:363330 if 'android' in bot:
tandriie5587792016-07-14 00:34:503331 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363332 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503333 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323334 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503335 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323336 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503337 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323338 return master
[email protected]1bfb8322014-04-23 01:02:413339
3340
[email protected]ca8d1982009-02-19 16:33:123341def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543342 results = []
[email protected]1f7b4172010-01-28 01:17:343343 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543344 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273345 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343346 input_api,
3347 output_api,
[email protected]2fdd1f362013-01-16 03:56:033348 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273349
jam93a6ee792017-02-08 23:59:223350 results.extend(
3351 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543352 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3353 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413354 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3355 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543356 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143357
3358
3359def _CheckTranslationScreenshots(input_api, output_api):
3360 PART_FILE_TAG = "part"
3361 import os
3362 import sys
3363 from io import StringIO
3364
3365 try:
3366 old_sys_path = sys.path
3367 sys.path = sys.path + [input_api.os_path.join(
3368 input_api.PresubmitLocalPath(), 'tools', 'grit')]
3369 import grit.grd_reader
3370 import grit.node.message
3371 import grit.util
3372 finally:
3373 sys.path = old_sys_path
3374
3375 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
3376 """Load the grd file and return a dict of message ids to messages.
3377
3378 Ignores any nested grdp files pointed by <part> tag.
3379 """
3380 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
3381 stop_after=None, first_ids_file=None,
3382 debug=False, defines=None,
3383 tags_to_ignore=set([PART_FILE_TAG]))
3384 return {
3385 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
3386 grit.node.message.MessageNode)
3387 }
3388
3389 def _GetGrdpMessagesFromString(grdp_string):
3390 """Parses the contents of a grdp file given in grdp_string.
3391
3392 grd_reader can't parse grdp files directly. Instead, this creates a
3393 temporary directory with a grd file pointing to the grdp file, and loads the
3394 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
3395 """
3396 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
3397 <grit latest_public_release="1" current_release="1">
3398 <release seq="1">
3399 <messages>
3400 <part file="sub.grdp" />
3401 </messages>
3402 </release>
3403 </grit>
3404 """
3405 with grit.util.TempDir({'main.grd': WRAPPER,
3406 'sub.grdp': grdp_string}) as temp_dir:
3407 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
3408
3409 new_or_added_paths = set(f.LocalPath()
3410 for f in input_api.AffectedFiles()
3411 if (f.Action() == 'A' or f.Action() == 'M'))
3412 removed_paths = set(f.LocalPath()
3413 for f in input_api.AffectedFiles(include_deletes=True)
3414 if f.Action() == 'D')
3415
3416 affected_grds = [f for f in input_api.AffectedFiles()
3417 if (f.LocalPath().endswith('.grd') or
3418 f.LocalPath().endswith('.grdp'))]
3419 affected_png_paths = [f.AbsoluteLocalPath()
3420 for f in input_api.AffectedFiles()
3421 if (f.LocalPath().endswith('.png'))]
3422
3423 # Check for screenshots. Developers can upload screenshots using
3424 # tools/translation/upload_screenshots.py which finds and uploads
3425 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
3426 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
3427 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
3428 #
3429 # The logic here is as follows:
3430 #
3431 # - If the CL has a .png file under the screenshots directory for a grd
3432 # file, warn the developer. Actual images should never be checked into the
3433 # Chrome repo.
3434 #
3435 # - If the CL contains modified or new messages in grd files and doesn't
3436 # contain the corresponding .sha1 files, warn the developer to add images
3437 # and upload them via tools/translation/upload_screenshots.py.
3438 #
3439 # - If the CL contains modified or new messages in grd files and the
3440 # corresponding .sha1 files, everything looks good.
3441 #
3442 # - If the CL contains removed messages in grd files but the corresponding
3443 # .sha1 files aren't removed, warn the developer to remove them.
3444 unnecessary_screenshots = []
3445 missing_sha1 = []
3446 unnecessary_sha1_files = []
3447
3448
3449 def _CheckScreenshotAdded(screenshots_dir, message_id):
3450 sha1_path = input_api.os_path.join(
3451 screenshots_dir, message_id + '.png.sha1')
3452 if sha1_path not in new_or_added_paths:
3453 missing_sha1.append(sha1_path)
3454
3455
3456 def _CheckScreenshotRemoved(screenshots_dir, message_id):
3457 sha1_path = input_api.os_path.join(
3458 screenshots_dir, message_id + '.png.sha1')
3459 if sha1_path not in removed_paths:
3460 unnecessary_sha1_files.append(sha1_path)
3461
3462
3463 for f in affected_grds:
3464 file_path = f.LocalPath()
3465 old_id_to_msg_map = {}
3466 new_id_to_msg_map = {}
3467 if file_path.endswith('.grdp'):
3468 if f.OldContents():
3469 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393470 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143471 if f.NewContents():
3472 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393473 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143474 else:
3475 if f.OldContents():
3476 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393477 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143478 if f.NewContents():
3479 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393480 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143481
3482 # Compute added, removed and modified message IDs.
3483 old_ids = set(old_id_to_msg_map)
3484 new_ids = set(new_id_to_msg_map)
3485 added_ids = new_ids - old_ids
3486 removed_ids = old_ids - new_ids
3487 modified_ids = set([])
3488 for key in old_ids.intersection(new_ids):
3489 if (old_id_to_msg_map[key].FormatXml()
3490 != new_id_to_msg_map[key].FormatXml()):
3491 modified_ids.add(key)
3492
3493 grd_name, ext = input_api.os_path.splitext(
3494 input_api.os_path.basename(file_path))
3495 screenshots_dir = input_api.os_path.join(
3496 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
3497
3498 # Check the screenshot directory for .png files. Warn if there is any.
3499 for png_path in affected_png_paths:
3500 if png_path.startswith(screenshots_dir):
3501 unnecessary_screenshots.append(png_path)
3502
3503 for added_id in added_ids:
3504 _CheckScreenshotAdded(screenshots_dir, added_id)
3505
3506 for modified_id in modified_ids:
3507 _CheckScreenshotAdded(screenshots_dir, modified_id)
3508
3509 for removed_id in removed_ids:
3510 _CheckScreenshotRemoved(screenshots_dir, removed_id)
3511
3512 results = []
3513 if unnecessary_screenshots:
3514 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393515 'Do not include actual screenshots in the changelist. Run '
3516 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143517 sorted(unnecessary_screenshots)))
3518
3519 if missing_sha1:
3520 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393521 'You are adding or modifying UI strings.\n'
3522 'To ensure the best translations, take screenshots of the relevant UI '
3523 '(https://g.co/chrome/translation) and add these files to your '
3524 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143525
3526 if unnecessary_sha1_files:
3527 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393528 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143529 sorted(unnecessary_sha1_files)))
3530
3531 return results