blob: ccfebcf35cf752bd2fdc18e443897ea20dba9203 [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 = (
Egor Paskoce145c42018-09-28 19:31:0413 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
14 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
15 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
16 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
17 r"^skia[\\/].*",
18 r"^third_party[\\/](WebKit|blink)[\\/].*",
19 r"^third_party[\\/]breakpad[\\/].*",
20 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5421 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
Egor Paskoce145c42018-09-28 19:31:0423 r".+[\\/]pnacl_shim\.c$",
24 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
25 r"^chrome[\\/]browser[\\/]resources[\\/]pdf[\\/]index.js",
26 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1427 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0428 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5429 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0430 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 = (
Egor Paskoce145c42018-09-28 19:31:0447 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,
Egor Paskoce145c42018-09-28 19:31:0452 r'.*[\\/](test|tool(s)?)[\\/].*',
[email protected]ef070cc2013-05-03 11:53:0553 # content_shell is used for running layout tests.
Egor Paskoce145c42018-09-28 19:31:0454 r'content[\\/]shell[\\/].*',
[email protected]7b054982013-11-27 00:44:4755 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0456 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0857 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0458 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 (
Egor Paskoce145c42018-09-28 19:31:04241 r"^ui[\\/]gl[\\/].*\.cc$",
242 r"^media[\\/]gpu[\\/].*\.cc$",
243 r"^gpu[\\/].*\.cc$",
thomasanderson4b569052016-09-14 20:15:53244 ),
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 (
Egor Paskoce145c42018-09-28 19:31:04253 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
254 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
255 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20256 ),
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.
Egor Paskoce145c42018-09-28 19:31:04324 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
325 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59326 ),
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 (
Egor Paskoce145c42018-09-28 19:31:04336 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 (
Egor Paskoce145c42018-09-28 19:31:04346 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41347 ),
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 (
Egor Paskoce145c42018-09-28 19:31:04389 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)$',
dbeamb6f4fde2017-06-15 04:03:06392 ),
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 ),
Gabriel Charette04b138f2018-08-06 00:03:22454 False,
Francois Doray43670e32017-09-27 12:40:38455 (),
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 (
Egor Paskoce145c42018-09-28 19:31:04560 r'^ios[\\/].*\.(cc|h)$',
561 r'.*[\\/]ios[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:37562 r'.*_ios\.(cc|h)$',
Egor Paskoce145c42018-09-28 19:31:04563 r'^net[\\/].*\.(cc|h)$',
564 r'.*[\\/]tools[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:37565 ),
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 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24585 (
586 'ios/web/public/test/http_server',
587 (
588 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
589 ),
590 False,
591 (),
592 ),
[email protected]127f18ec2012-06-16 05:05:59593)
594
wnwenbdc444e2016-05-25 13:44:15595
mlamouria82272622014-09-16 18:45:04596_IPC_ENUM_TRAITS_DEPRECATED = (
597 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50598 'See http://www.chromium.org/Home/chromium-security/education/'
599 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:04600
Stephen Martinis97a394142018-06-07 23:06:05601_LONG_PATH_ERROR = (
602 'Some files included in this CL have file names that are too long (> 200'
603 ' characters). If committed, these files will cause issues on Windows. See'
604 ' https://crbug.com/612667 for more details.'
605)
606
Shenghua Zhangbfaa38b82017-11-16 21:58:02607_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:04608 r".*[\\/]BuildHooksAndroidImpl\.java",
609 r".*[\\/]LicenseContentProvider\.java",
610 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:28611 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:02612]
[email protected]127f18ec2012-06-16 05:05:59613
Sean Kau46e29bc2017-08-28 16:31:16614# These paths contain test data and other known invalid JSON files.
615_KNOWN_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:04616 r'test[\\/]data[\\/]',
617 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
618 r'^third_party[\\/]protobuf[\\/]',
619 r'^third_party[\\/]WebKit[\\/]LayoutTests[\\/]external[\\/]wpt[\\/]',
620 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Sean Kau46e29bc2017-08-28 16:31:16621]
622
623
[email protected]b00342e7f2013-03-26 16:21:54624_VALID_OS_MACROS = (
625 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08626 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54627 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:12628 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:54629 'OS_BSD',
630 'OS_CAT', # For testing.
631 'OS_CHROMEOS',
632 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37633 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54634 'OS_IOS',
635 'OS_LINUX',
636 'OS_MACOSX',
637 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21638 'OS_NACL_NONSFI',
639 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12640 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54641 'OS_OPENBSD',
642 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37643 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54644 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54645 'OS_WIN',
646)
647
648
agrievef32bcc72016-04-04 14:57:40649_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:39650 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36651 'base/android/jni_generator/jni_generator.pydeps',
652 'base/android/jni_generator/jni_registration_generator.pydeps',
653 'build/android/gyp/aar.pydeps',
654 'build/android/gyp/aidl.pydeps',
655 'build/android/gyp/apkbuilder.pydeps',
656 'build/android/gyp/app_bundle_to_apks.pydeps',
657 'build/android/gyp/bytecode_processor.pydeps',
658 'build/android/gyp/compile_resources.pydeps',
659 'build/android/gyp/create_bundle_wrapper_script.pydeps',
660 'build/android/gyp/copy_ex.pydeps',
661 'build/android/gyp/create_app_bundle.pydeps',
662 'build/android/gyp/create_apk_operations_script.pydeps',
663 'build/android/gyp/create_dist_jar.pydeps',
664 'build/android/gyp/create_java_binary_script.pydeps',
665 'build/android/gyp/create_stack_script.pydeps',
666 'build/android/gyp/create_test_runner_script.pydeps',
667 'build/android/gyp/create_tool_wrapper.pydeps',
668 'build/android/gyp/desugar.pydeps',
669 'build/android/gyp/dex.pydeps',
670 'build/android/gyp/dist_aar.pydeps',
671 'build/android/gyp/emma_instr.pydeps',
672 'build/android/gyp/filter_zip.pydeps',
673 'build/android/gyp/gcc_preprocess.pydeps',
674 'build/android/gyp/generate_proguarded_module_jar.pydeps',
675 'build/android/gyp/ijar.pydeps',
676 'build/android/gyp/java_cpp_enum.pydeps',
677 'build/android/gyp/javac.pydeps',
678 'build/android/gyp/jinja_template.pydeps',
679 'build/android/gyp/lint.pydeps',
680 'build/android/gyp/main_dex_list.pydeps',
681 'build/android/gyp/merge_jar_info_files.pydeps',
682 'build/android/gyp/merge_manifest.pydeps',
683 'build/android/gyp/prepare_resources.pydeps',
684 'build/android/gyp/proguard.pydeps',
685 'build/android/gyp/write_build_config.pydeps',
686 'build/android/gyp/write_ordered_libraries.pydeps',
687 'build/android/incremental_install/generate_android_manifest.pydeps',
688 'build/android/incremental_install/write_installer_json.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22689 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:40690 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04691 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36692 'build/protoc_java.pydeps',
jbudorick276cc562017-04-29 01:34:58693 'build/secondary/third_party/android_platform/'
694 'development/scripts/stack.pydeps',
agrieve732db3a2016-04-26 19:18:19695 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40696]
697
wnwenbdc444e2016-05-25 13:44:15698
agrievef32bcc72016-04-04 14:57:40699_GENERIC_PYDEPS_FILES = [
John Chencde89192018-01-27 21:18:40700 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Cole Winstanley7045a1b2018-08-27 23:37:29701 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22702 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:40703]
704
wnwenbdc444e2016-05-25 13:44:15705
agrievef32bcc72016-04-04 14:57:40706_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
707
708
Eric Boren6fd2b932018-01-25 15:05:08709# Bypass the AUTHORS check for these accounts.
710_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:29711 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
712 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:08713 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
Eric Boren57cc805b2018-08-20 17:28:32714 'spirv', 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:59715 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:45716 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:59717 ) | set('%[email protected]' % s
Eric Boren835d71f2018-09-07 21:09:04718 for s in ('v8-ci-autoroll-builder',)
719 ) | set('%[email protected]' % s
720 for s in ('chromium-autoroll',)
721 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:30722 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:08723
724
[email protected]55459852011-08-10 15:17:19725def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
726 """Attempts to prevent use of functions intended only for testing in
727 non-testing code. For now this is just a best-effort implementation
728 that ignores header files and may have some false positives. A
729 better implementation would probably need a proper C++ parser.
730 """
731 # We only scan .cc files and the like, as the declaration of
732 # for-testing functions in header files are hard to distinguish from
733 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49734 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:19735
jochenc0d4808c2015-07-27 09:25:42736 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19737 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09738 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19739 exclusion_pattern = input_api.re.compile(
740 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
741 base_function_pattern, base_function_pattern))
742
743 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44744 black_list = (_EXCLUDED_PATHS +
745 _TEST_CODE_EXCLUDED_PATHS +
746 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19747 return input_api.FilterSourceFile(
748 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49749 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:19750 black_list=black_list)
751
752 problems = []
753 for f in input_api.AffectedSourceFiles(FilterFile):
754 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24755 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03756 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46757 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03758 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19759 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03760 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19761
762 if problems:
[email protected]f7051d52013-04-02 18:31:42763 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03764 else:
765 return []
[email protected]55459852011-08-10 15:17:19766
767
Vaclav Brozek7dbc28c2018-03-27 08:35:23768def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
769 """This is a simplified version of
770 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
771 """
772 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
773 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
774 name_pattern = r'ForTest(s|ing)?'
775 # Describes an occurrence of "ForTest*" inside a // comment.
776 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
777 # Catch calls.
778 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
779 # Ignore definitions. (Comments are ignored separately.)
780 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
781
782 problems = []
783 sources = lambda x: input_api.FilterSourceFile(
784 x,
785 black_list=(('(?i).*test', r'.*\/junit\/')
786 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49787 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:23788 )
789 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
790 local_path = f.LocalPath()
791 is_inside_javadoc = False
792 for line_number, line in f.ChangedContents():
793 if is_inside_javadoc and javadoc_end_re.search(line):
794 is_inside_javadoc = False
795 if not is_inside_javadoc and javadoc_start_re.search(line):
796 is_inside_javadoc = True
797 if is_inside_javadoc:
798 continue
799 if (inclusion_re.search(line) and
800 not comment_re.search(line) and
801 not exclusion_re.search(line)):
802 problems.append(
803 '%s:%d\n %s' % (local_path, line_number, line.strip()))
804
805 if problems:
806 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
807 else:
808 return []
809
810
[email protected]10689ca2011-09-02 02:31:54811def _CheckNoIOStreamInHeaders(input_api, output_api):
812 """Checks to make sure no .h files include <iostream>."""
813 files = []
814 pattern = input_api.re.compile(r'^#include\s*<iostream>',
815 input_api.re.MULTILINE)
816 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
817 if not f.LocalPath().endswith('.h'):
818 continue
819 contents = input_api.ReadFile(f)
820 if pattern.search(contents):
821 files.append(f)
822
823 if len(files):
yolandyandaabc6d2016-04-18 18:29:39824 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06825 'Do not #include <iostream> in header files, since it inserts static '
826 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54827 '#include <ostream>. See http://crbug.com/94794',
828 files) ]
829 return []
830
Danil Chapovalov3518f362018-08-11 16:13:43831def _CheckNoStrCatRedefines(input_api, output_api):
832 """Checks no windows headers with StrCat redefined are included directly."""
833 files = []
834 pattern_deny = input_api.re.compile(
835 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
836 input_api.re.MULTILINE)
837 pattern_allow = input_api.re.compile(
838 r'^#include\s"base/win/windows_defines.inc"',
839 input_api.re.MULTILINE)
840 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
841 contents = input_api.ReadFile(f)
842 if pattern_deny.search(contents) and not pattern_allow.search(contents):
843 files.append(f.LocalPath())
844
845 if len(files):
846 return [output_api.PresubmitError(
847 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
848 'directly since they pollute code with StrCat macro. Instead, '
849 'include matching header from base/win. See http://crbug.com/856536',
850 files) ]
851 return []
852
[email protected]10689ca2011-09-02 02:31:54853
[email protected]72df4e782012-06-21 16:28:18854def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52855 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18856 problems = []
857 for f in input_api.AffectedFiles():
858 if (not f.LocalPath().endswith(('.cc', '.mm'))):
859 continue
860
861 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04862 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18863 problems.append(' %s:%d' % (f.LocalPath(), line_num))
864
865 if not problems:
866 return []
867 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
868 '\n'.join(problems))]
869
Dominic Battre033531052018-09-24 15:45:34870def _CheckNoDISABLETypoInTests(input_api, output_api):
871 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
872
873 This test warns if somebody tries to disable a test with the DISABLE_ prefix
874 instead of DISABLED_. To filter false positives, reports are only generated
875 if a corresponding MAYBE_ line exists.
876 """
877 problems = []
878
879 # The following two patterns are looked for in tandem - is a test labeled
880 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
881 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
882 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
883
884 # This is for the case that a test is disabled on all platforms.
885 full_disable_pattern = input_api.re.compile(
886 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
887 input_api.re.MULTILINE)
888
Katie Df13948e2018-09-25 07:33:44889 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:34890 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
891 continue
892
893 # Search for MABYE_, DISABLE_ pairs.
894 disable_lines = {} # Maps of test name to line number.
895 maybe_lines = {}
896 for line_num, line in f.ChangedContents():
897 disable_match = disable_pattern.search(line)
898 if disable_match:
899 disable_lines[disable_match.group(1)] = line_num
900 maybe_match = maybe_pattern.search(line)
901 if maybe_match:
902 maybe_lines[maybe_match.group(1)] = line_num
903
904 # Search for DISABLE_ occurrences within a TEST() macro.
905 disable_tests = set(disable_lines.keys())
906 maybe_tests = set(maybe_lines.keys())
907 for test in disable_tests.intersection(maybe_tests):
908 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
909
910 contents = input_api.ReadFile(f)
911 full_disable_match = full_disable_pattern.search(contents)
912 if full_disable_match:
913 problems.append(' %s' % f.LocalPath())
914
915 if not problems:
916 return []
917 return [
918 output_api.PresubmitPromptWarning(
919 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
920 '\n'.join(problems))
921 ]
922
[email protected]72df4e782012-06-21 16:28:18923
danakj61c1aa22015-10-26 19:55:52924def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57925 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52926 errors = []
927 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
928 input_api.re.MULTILINE)
929 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
930 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
931 continue
932 for lnum, line in f.ChangedContents():
933 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17934 errors.append(output_api.PresubmitError(
935 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57936 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17937 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52938 return errors
939
940
mcasasb7440c282015-02-04 14:52:19941def _FindHistogramNameInLine(histogram_name, line):
942 """Tries to find a histogram name or prefix in a line."""
943 if not "affected-histogram" in line:
944 return histogram_name in line
945 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
946 # the histogram_name.
947 if not '"' in line:
948 return False
949 histogram_prefix = line.split('\"')[1]
950 return histogram_prefix in histogram_name
951
952
953def _CheckUmaHistogramChanges(input_api, output_api):
954 """Check that UMA histogram names in touched lines can still be found in other
955 lines of the patch or in histograms.xml. Note that this check would not catch
956 the reverse: changes in histograms.xml not matched in the code itself."""
957 touched_histograms = []
958 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:47959 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
960 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
961 name_pattern = r'"(.*?)"'
962 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
963 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
964 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
965 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
966 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:17967 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:19968 for f in input_api.AffectedFiles():
969 # If histograms.xml itself is modified, keep the modified lines for later.
970 if f.LocalPath().endswith(('histograms.xml')):
971 histograms_xml_modifications = f.ChangedContents()
972 continue
Vaclav Brozekbdac817c2018-03-24 06:30:47973 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
974 single_line_re = single_line_c_re
975 split_line_prefix_re = split_line_c_prefix_re
976 elif f.LocalPath().endswith(('java')):
977 single_line_re = single_line_java_re
978 split_line_prefix_re = split_line_java_prefix_re
979 else:
mcasasb7440c282015-02-04 14:52:19980 continue
981 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:17982 if last_line_matched_prefix:
983 suffix_found = split_line_suffix_re.search(line)
984 if suffix_found :
985 touched_histograms.append([suffix_found.group(1), f, line_num])
986 last_line_matched_prefix = False
987 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:06988 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:19989 if found:
990 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:17991 continue
992 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:19993
994 # Search for the touched histogram names in the local modifications to
995 # histograms.xml, and, if not found, on the base histograms.xml file.
996 unmatched_histograms = []
997 for histogram_info in touched_histograms:
998 histogram_name_found = False
999 for line_num, line in histograms_xml_modifications:
1000 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
1001 if histogram_name_found:
1002 break
1003 if not histogram_name_found:
1004 unmatched_histograms.append(histogram_info)
1005
eromanb90c82e7e32015-04-01 15:13:491006 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191007 problems = []
1008 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491009 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191010 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451011 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191012 histogram_name_found = False
1013 for line in histograms_xml:
1014 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
1015 if histogram_name_found:
1016 break
1017 if not histogram_name_found:
1018 problems.append(' [%s:%d] %s' %
1019 (f.LocalPath(), line_num, histogram_name))
1020
1021 if not problems:
1022 return []
1023 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1024 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491025 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191026
wnwenbdc444e2016-05-25 13:44:151027
yolandyandaabc6d2016-04-18 18:29:391028def _CheckFlakyTestUsage(input_api, output_api):
1029 """Check that FlakyTest annotation is our own instead of the android one"""
1030 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1031 files = []
1032 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1033 if f.LocalPath().endswith('Test.java'):
1034 if pattern.search(input_api.ReadFile(f)):
1035 files.append(f)
1036 if len(files):
1037 return [output_api.PresubmitError(
1038 'Use org.chromium.base.test.util.FlakyTest instead of '
1039 'android.test.FlakyTest',
1040 files)]
1041 return []
mcasasb7440c282015-02-04 14:52:191042
wnwenbdc444e2016-05-25 13:44:151043
[email protected]8ea5d4b2011-09-13 21:49:221044def _CheckNoNewWStrings(input_api, output_api):
1045 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271046 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221047 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201048 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571049 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341050 '/win/' in f.LocalPath() or
1051 'chrome_elf' in f.LocalPath() or
1052 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201053 continue
[email protected]8ea5d4b2011-09-13 21:49:221054
[email protected]a11dbe9b2012-08-07 01:32:581055 allowWString = False
[email protected]b5c24292011-11-28 14:38:201056 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581057 if 'presubmit: allow wstring' in line:
1058 allowWString = True
1059 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271060 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581061 allowWString = False
1062 else:
1063 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221064
[email protected]55463aa62011-10-12 00:48:271065 if not problems:
1066 return []
1067 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581068 ' If you are calling a cross-platform API that accepts a wstring, '
1069 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271070 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221071
1072
[email protected]2a8ac9c2011-10-19 17:20:441073def _CheckNoDEPSGIT(input_api, output_api):
1074 """Make sure .DEPS.git is never modified manually."""
1075 if any(f.LocalPath().endswith('.DEPS.git') for f in
1076 input_api.AffectedFiles()):
1077 return [output_api.PresubmitError(
1078 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1079 'automated system based on what\'s in DEPS and your changes will be\n'
1080 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501081 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1082 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441083 'for more information')]
1084 return []
1085
1086
tandriief664692014-09-23 14:51:471087def _CheckValidHostsInDEPS(input_api, output_api):
1088 """Checks that DEPS file deps are from allowed_hosts."""
1089 # Run only if DEPS file has been modified to annoy fewer bystanders.
1090 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1091 return []
1092 # Outsource work to gclient verify
1093 try:
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201094 input_api.subprocess.check_output(['gclient', 'verify'],
1095 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471096 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201097 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471098 return [output_api.PresubmitError(
1099 'DEPS file must have only git dependencies.',
1100 long_text=error.output)]
1101
1102
[email protected]127f18ec2012-06-16 05:05:591103def _CheckNoBannedFunctions(input_api, output_api):
1104 """Make sure that banned functions are not used."""
1105 warnings = []
1106 errors = []
1107
wnwenbdc444e2016-05-25 13:44:151108 def IsBlacklisted(affected_file, blacklist):
1109 local_path = affected_file.LocalPath()
1110 for item in blacklist:
1111 if input_api.re.match(item, local_path):
1112 return True
1113 return False
1114
Sylvain Defresnea8b73d252018-02-28 15:45:541115 def IsIosObcjFile(affected_file):
1116 local_path = affected_file.LocalPath()
1117 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1118 return False
1119 basename = input_api.os_path.basename(local_path)
1120 if 'ios' in basename.split('_'):
1121 return True
1122 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1123 if sep and 'ios' in local_path.split(sep):
1124 return True
1125 return False
1126
wnwenbdc444e2016-05-25 13:44:151127 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
1128 matched = False
1129 if func_name[0:1] == '/':
1130 regex = func_name[1:]
1131 if input_api.re.search(regex, line):
1132 matched = True
1133 elif func_name in line:
dchenge07de812016-06-20 19:27:171134 matched = True
wnwenbdc444e2016-05-25 13:44:151135 if matched:
dchenge07de812016-06-20 19:27:171136 problems = warnings
wnwenbdc444e2016-05-25 13:44:151137 if error:
dchenge07de812016-06-20 19:27:171138 problems = errors
wnwenbdc444e2016-05-25 13:44:151139 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1140 for message_line in message:
1141 problems.append(' %s' % message_line)
1142
Eric Stevensona9a980972017-09-23 00:04:411143 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1144 for f in input_api.AffectedFiles(file_filter=file_filter):
1145 for line_num, line in f.ChangedContents():
1146 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1147 CheckForMatch(f, line_num, line, func_name, message, error)
1148
[email protected]127f18ec2012-06-16 05:05:591149 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1150 for f in input_api.AffectedFiles(file_filter=file_filter):
1151 for line_num, line in f.ChangedContents():
1152 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151153 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591154
Sylvain Defresnea8b73d252018-02-28 15:45:541155 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1156 for line_num, line in f.ChangedContents():
1157 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1158 CheckForMatch(f, line_num, line, func_name, message, error)
1159
[email protected]127f18ec2012-06-16 05:05:591160 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1161 for f in input_api.AffectedFiles(file_filter=file_filter):
1162 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491163 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491164 if IsBlacklisted(f, excluded_paths):
1165 continue
wnwenbdc444e2016-05-25 13:44:151166 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591167
1168 result = []
1169 if (warnings):
1170 result.append(output_api.PresubmitPromptWarning(
1171 'Banned functions were used.\n' + '\n'.join(warnings)))
1172 if (errors):
1173 result.append(output_api.PresubmitError(
1174 'Banned functions were used.\n' + '\n'.join(errors)))
1175 return result
1176
1177
[email protected]6c063c62012-07-11 19:11:061178def _CheckNoPragmaOnce(input_api, output_api):
1179 """Make sure that banned functions are not used."""
1180 files = []
1181 pattern = input_api.re.compile(r'^#pragma\s+once',
1182 input_api.re.MULTILINE)
1183 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1184 if not f.LocalPath().endswith('.h'):
1185 continue
1186 contents = input_api.ReadFile(f)
1187 if pattern.search(contents):
1188 files.append(f)
1189
1190 if files:
1191 return [output_api.PresubmitError(
1192 'Do not use #pragma once in header files.\n'
1193 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1194 files)]
1195 return []
1196
[email protected]127f18ec2012-06-16 05:05:591197
[email protected]e7479052012-09-19 00:26:121198def _CheckNoTrinaryTrueFalse(input_api, output_api):
1199 """Checks to make sure we don't introduce use of foo ? true : false."""
1200 problems = []
1201 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1202 for f in input_api.AffectedFiles():
1203 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1204 continue
1205
1206 for line_num, line in f.ChangedContents():
1207 if pattern.match(line):
1208 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1209
1210 if not problems:
1211 return []
1212 return [output_api.PresubmitPromptWarning(
1213 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1214 '\n'.join(problems))]
1215
1216
[email protected]55f9f382012-07-31 11:02:181217def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281218 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181219 change. Breaking - rules is an error, breaking ! rules is a
1220 warning.
1221 """
mohan.reddyf21db962014-10-16 12:26:471222 import sys
[email protected]55f9f382012-07-31 11:02:181223 # We need to wait until we have an input_api object and use this
1224 # roundabout construct to import checkdeps because this file is
1225 # eval-ed and thus doesn't have __file__.
1226 original_sys_path = sys.path
1227 try:
1228 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471229 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181230 import checkdeps
1231 from cpp_checker import CppChecker
Jinsuk Kim5a092672017-10-24 22:42:241232 from java_checker import JavaChecker
rhalavati08acd232017-04-03 07:23:281233 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:181234 from rules import Rule
1235 finally:
1236 # Restore sys.path to what it was before.
1237 sys.path = original_sys_path
1238
1239 added_includes = []
rhalavati08acd232017-04-03 07:23:281240 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241241 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181242 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:281243 if CppChecker.IsCppFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501244 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081245 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
rhalavati08acd232017-04-03 07:23:281246 elif ProtoChecker.IsProtoFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501247 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081248 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241249 elif JavaChecker.IsJavaFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501250 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081251 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181252
[email protected]26385172013-05-09 23:11:351253 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181254
1255 error_descriptions = []
1256 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281257 error_subjects = set()
1258 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181259 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1260 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081261 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181262 description_with_path = '%s\n %s' % (path, rule_description)
1263 if rule_type == Rule.DISALLOW:
1264 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281265 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181266 else:
1267 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281268 warning_subjects.add("#includes")
1269
1270 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1271 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081272 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281273 description_with_path = '%s\n %s' % (path, rule_description)
1274 if rule_type == Rule.DISALLOW:
1275 error_descriptions.append(description_with_path)
1276 error_subjects.add("imports")
1277 else:
1278 warning_descriptions.append(description_with_path)
1279 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181280
Jinsuk Kim5a092672017-10-24 22:42:241281 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021282 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081283 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241284 description_with_path = '%s\n %s' % (path, rule_description)
1285 if rule_type == Rule.DISALLOW:
1286 error_descriptions.append(description_with_path)
1287 error_subjects.add("imports")
1288 else:
1289 warning_descriptions.append(description_with_path)
1290 warning_subjects.add("imports")
1291
[email protected]55f9f382012-07-31 11:02:181292 results = []
1293 if error_descriptions:
1294 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281295 'You added one or more %s that violate checkdeps rules.'
1296 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181297 error_descriptions))
1298 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421299 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281300 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181301 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281302 '%s? See relevant DEPS file(s) for details and contacts.' %
1303 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181304 warning_descriptions))
1305 return results
1306
1307
[email protected]fbcafe5a2012-08-08 15:31:221308def _CheckFilePermissions(input_api, output_api):
1309 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151310 if input_api.platform == 'win32':
1311 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291312 checkperms_tool = input_api.os_path.join(
1313 input_api.PresubmitLocalPath(),
1314 'tools', 'checkperms', 'checkperms.py')
1315 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471316 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391317 with input_api.CreateTemporaryFile() as file_list:
1318 for f in input_api.AffectedFiles():
1319 # checkperms.py file/directory arguments must be relative to the
1320 # repository.
1321 file_list.write(f.LocalPath() + '\n')
1322 file_list.close()
1323 args += ['--file-list', file_list.name]
1324 try:
1325 input_api.subprocess.check_output(args)
1326 return []
1327 except input_api.subprocess.CalledProcessError as error:
1328 return [output_api.PresubmitError(
1329 'checkperms.py failed:',
1330 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221331
1332
robertocn832f5992017-01-04 19:01:301333def _CheckTeamTags(input_api, output_api):
1334 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1335 checkteamtags_tool = input_api.os_path.join(
1336 input_api.PresubmitLocalPath(),
1337 'tools', 'checkteamtags', 'checkteamtags.py')
1338 args = [input_api.python_executable, checkteamtags_tool,
1339 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221340 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301341 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1342 'OWNERS']
1343 try:
1344 if files:
1345 input_api.subprocess.check_output(args + files)
1346 return []
1347 except input_api.subprocess.CalledProcessError as error:
1348 return [output_api.PresubmitError(
1349 'checkteamtags.py failed:',
1350 long_text=error.output)]
1351
1352
[email protected]c8278b32012-10-30 20:35:491353def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1354 """Makes sure we don't include ui/aura/window_property.h
1355 in header files.
1356 """
1357 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1358 errors = []
1359 for f in input_api.AffectedFiles():
1360 if not f.LocalPath().endswith('.h'):
1361 continue
1362 for line_num, line in f.ChangedContents():
1363 if pattern.match(line):
1364 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1365
1366 results = []
1367 if errors:
1368 results.append(output_api.PresubmitError(
1369 'Header files should not include ui/aura/window_property.h', errors))
1370 return results
1371
1372
[email protected]70ca77752012-11-20 03:45:031373def _CheckForVersionControlConflictsInFile(input_api, f):
1374 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1375 errors = []
1376 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:231377 if f.LocalPath().endswith('.md'):
1378 # First-level headers in markdown look a lot like version control
1379 # conflict markers. http://daringfireball.net/projects/markdown/basics
1380 continue
[email protected]70ca77752012-11-20 03:45:031381 if pattern.match(line):
1382 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1383 return errors
1384
1385
1386def _CheckForVersionControlConflicts(input_api, output_api):
1387 """Usually this is not intentional and will cause a compile failure."""
1388 errors = []
1389 for f in input_api.AffectedFiles():
1390 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1391
1392 results = []
1393 if errors:
1394 results.append(output_api.PresubmitError(
1395 'Version control conflict markers found, please resolve.', errors))
1396 return results
1397
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201398
estadee17314a02017-01-12 16:22:161399def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1400 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1401 errors = []
1402 for f in input_api.AffectedFiles():
1403 for line_num, line in f.ChangedContents():
1404 if pattern.search(line):
1405 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1406
1407 results = []
1408 if errors:
1409 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501410 'Found Google support URL addressed by answer number. Please replace '
1411 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161412 return results
1413
[email protected]70ca77752012-11-20 03:45:031414
[email protected]06e6d0ff2012-12-11 01:36:441415def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1416 def FilterFile(affected_file):
1417 """Filter function for use with input_api.AffectedSourceFiles,
1418 below. This filters out everything except non-test files from
1419 top-level directories that generally speaking should not hard-code
1420 service URLs (e.g. src/android_webview/, src/content/ and others).
1421 """
1422 return input_api.FilterSourceFile(
1423 affected_file,
Egor Paskoce145c42018-09-28 19:31:041424 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:441425 black_list=(_EXCLUDED_PATHS +
1426 _TEST_CODE_EXCLUDED_PATHS +
1427 input_api.DEFAULT_BLACK_LIST))
1428
reillyi38965732015-11-16 18:27:331429 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1430 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461431 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1432 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441433 problems = [] # items are (filename, line_number, line)
1434 for f in input_api.AffectedSourceFiles(FilterFile):
1435 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461436 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441437 problems.append((f.LocalPath(), line_num, line))
1438
1439 if problems:
[email protected]f7051d52013-04-02 18:31:421440 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441441 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581442 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441443 [' %s:%d: %s' % (
1444 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031445 else:
1446 return []
[email protected]06e6d0ff2012-12-11 01:36:441447
1448
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491449# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:271450def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1451 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311452 The native_client_sdk directory is excluded because it has auto-generated PNG
1453 files for documentation.
[email protected]d2530012013-01-25 16:39:271454 """
[email protected]d2530012013-01-25 16:39:271455 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491456 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:041457 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:311458 file_filter = lambda f: input_api.FilterSourceFile(
1459 f, white_list=white_list, black_list=black_list)
1460 for f in input_api.AffectedFiles(include_deletes=False,
1461 file_filter=file_filter):
1462 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271463
1464 results = []
1465 if errors:
1466 results.append(output_api.PresubmitError(
1467 'The name of PNG files should not have abbreviations. \n'
1468 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1469 'Contact [email protected] if you have questions.', errors))
1470 return results
1471
1472
Daniel Cheng4dcdb6b2017-04-13 08:30:171473def _ExtractAddRulesFromParsedDeps(parsed_deps):
1474 """Extract the rules that add dependencies from a parsed DEPS file.
1475
1476 Args:
1477 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1478 add_rules = set()
1479 add_rules.update([
1480 rule[1:] for rule in parsed_deps.get('include_rules', [])
1481 if rule.startswith('+') or rule.startswith('!')
1482 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501483 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171484 {}).iteritems():
1485 add_rules.update([
1486 rule[1:] for rule in rules
1487 if rule.startswith('+') or rule.startswith('!')
1488 ])
1489 return add_rules
1490
1491
1492def _ParseDeps(contents):
1493 """Simple helper for parsing DEPS files."""
1494 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171495 class _VarImpl:
1496
1497 def __init__(self, local_scope):
1498 self._local_scope = local_scope
1499
1500 def Lookup(self, var_name):
1501 """Implements the Var syntax."""
1502 try:
1503 return self._local_scope['vars'][var_name]
1504 except KeyError:
1505 raise Exception('Var is not defined: %s' % var_name)
1506
1507 local_scope = {}
1508 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171509 'Var': _VarImpl(local_scope).Lookup,
1510 }
1511 exec contents in global_scope, local_scope
1512 return local_scope
1513
1514
1515def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081516 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411517 a set of DEPS entries that we should look up.
1518
1519 For a directory (rather than a specific filename) we fake a path to
1520 a specific filename by adding /DEPS. This is chosen as a file that
1521 will seldom or never be subject to per-file include_rules.
1522 """
[email protected]2b438d62013-11-14 17:54:141523 # We ignore deps entries on auto-generated directories.
1524 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081525
Daniel Cheng4dcdb6b2017-04-13 08:30:171526 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1527 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1528
1529 added_deps = new_deps.difference(old_deps)
1530
[email protected]2b438d62013-11-14 17:54:141531 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171532 for added_dep in added_deps:
1533 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1534 continue
1535 # Assume that a rule that ends in .h is a rule for a specific file.
1536 if added_dep.endswith('.h'):
1537 results.add(added_dep)
1538 else:
1539 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081540 return results
1541
1542
[email protected]e871964c2013-05-13 14:14:551543def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1544 """When a dependency prefixed with + is added to a DEPS file, we
1545 want to make sure that the change is reviewed by an OWNER of the
1546 target file or directory, to avoid layering violations from being
1547 introduced. This check verifies that this happens.
1548 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171549 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241550
1551 file_filter = lambda f: not input_api.re.match(
Egor Paskoce145c42018-09-28 19:31:041552 r"^third_party[\\/](WebKit|blink)[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241553 for f in input_api.AffectedFiles(include_deletes=False,
1554 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551555 filename = input_api.os_path.basename(f.LocalPath())
1556 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171557 virtual_depended_on_files.update(_CalculateAddedDeps(
1558 input_api.os_path,
1559 '\n'.join(f.OldContents()),
1560 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551561
[email protected]e871964c2013-05-13 14:14:551562 if not virtual_depended_on_files:
1563 return []
1564
1565 if input_api.is_committing:
1566 if input_api.tbr:
1567 return [output_api.PresubmitNotifyResult(
1568 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271569 if input_api.dry_run:
1570 return [output_api.PresubmitNotifyResult(
1571 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551572 if not input_api.change.issue:
1573 return [output_api.PresubmitError(
1574 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401575 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551576 output = output_api.PresubmitError
1577 else:
1578 output = output_api.PresubmitNotifyResult
1579
1580 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501581 owner_email, reviewers = (
1582 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1583 input_api,
1584 owners_db.email_regexp,
1585 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551586
1587 owner_email = owner_email or input_api.change.author_email
1588
[email protected]de4f7d22013-05-23 14:27:461589 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511590 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461591 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551592 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1593 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411594
1595 # We strip the /DEPS part that was added by
1596 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1597 # directory.
1598 def StripDeps(path):
1599 start_deps = path.rfind('/DEPS')
1600 if start_deps != -1:
1601 return path[:start_deps]
1602 else:
1603 return path
1604 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551605 for path in missing_files]
1606
1607 if unapproved_dependencies:
1608 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151609 output('You need LGTM from owners of depends-on paths in DEPS that were '
1610 'modified in this CL:\n %s' %
1611 '\n '.join(sorted(unapproved_dependencies)))]
1612 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1613 output_list.append(output(
1614 'Suggested missing target path OWNERS:\n %s' %
1615 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551616 return output_list
1617
1618 return []
1619
1620
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491621# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:401622def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491623 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:401624 black_list = (_EXCLUDED_PATHS +
1625 _TEST_CODE_EXCLUDED_PATHS +
1626 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:041627 (r"^base[\\/]logging\.h$",
1628 r"^base[\\/]logging\.cc$",
1629 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
1630 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
1631 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:121632 r"startup_browser_creator\.cc$",
Egor Paskoce145c42018-09-28 19:31:041633 r"^chrome[\\/]installer[\\/]setup[\\/].*",
1634 r"^chrome[\\/]chrome_cleaner[\\/].*",
1635 r"chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031636 r"diagnostics_writer\.cc$",
Egor Paskoce145c42018-09-28 19:31:041637 r"^chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
1638 r"^chromecast[\\/]",
1639 r"^cloud_print[\\/]",
1640 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:481641 r"dump_stability_report_main_win.cc$",
Egor Paskoce145c42018-09-28 19:31:041642 r"^components[\\/]html_viewer[\\/]"
jochen34415e52015-07-10 08:34:311643 r"web_test_delegate_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041644 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:461645 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:041646 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:461647 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041648 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:251649 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:041650 r"^courgette[\\/]courgette_minimal_tool\.cc$",
1651 r"^courgette[\\/]courgette_tool\.cc$",
1652 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
1653 r"^ipc[\\/]ipc_logging\.cc$",
1654 r"^native_client_sdk[\\/]",
1655 r"^remoting[\\/]base[\\/]logging\.h$",
1656 r"^remoting[\\/]host[\\/].*",
1657 r"^sandbox[\\/]linux[\\/].*",
1658 r"^tools[\\/]",
1659 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
1660 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
1661 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
1662 r"^storage[\\/]browser[\\/]fileapi[\\/]" +
skyostil87681be82016-12-19 12:46:351663 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:041664 r"^headless[\\/]app[\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401665 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491666 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:401667
thomasanderson625d3932017-03-29 07:16:581668 log_info = set([])
1669 printf = set([])
[email protected]85218562013-11-22 07:41:401670
1671 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581672 for _, line in f.ChangedContents():
1673 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1674 log_info.add(f.LocalPath())
1675 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1676 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371677
thomasanderson625d3932017-03-29 07:16:581678 if input_api.re.search(r"\bprintf\(", line):
1679 printf.add(f.LocalPath())
1680 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1681 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401682
1683 if log_info:
1684 return [output_api.PresubmitError(
1685 'These files spam the console log with LOG(INFO):',
1686 items=log_info)]
1687 if printf:
1688 return [output_api.PresubmitError(
1689 'These files spam the console log with printf/fprintf:',
1690 items=printf)]
1691 return []
1692
1693
[email protected]49aa76a2013-12-04 06:59:161694def _CheckForAnonymousVariables(input_api, output_api):
1695 """These types are all expected to hold locks while in scope and
1696 so should never be anonymous (which causes them to be immediately
1697 destroyed)."""
1698 they_who_must_be_named = [
1699 'base::AutoLock',
1700 'base::AutoReset',
1701 'base::AutoUnlock',
1702 'SkAutoAlphaRestore',
1703 'SkAutoBitmapShaderInstall',
1704 'SkAutoBlitterChoose',
1705 'SkAutoBounderCommit',
1706 'SkAutoCallProc',
1707 'SkAutoCanvasRestore',
1708 'SkAutoCommentBlock',
1709 'SkAutoDescriptor',
1710 'SkAutoDisableDirectionCheck',
1711 'SkAutoDisableOvalCheck',
1712 'SkAutoFree',
1713 'SkAutoGlyphCache',
1714 'SkAutoHDC',
1715 'SkAutoLockColors',
1716 'SkAutoLockPixels',
1717 'SkAutoMalloc',
1718 'SkAutoMaskFreeImage',
1719 'SkAutoMutexAcquire',
1720 'SkAutoPathBoundsUpdate',
1721 'SkAutoPDFRelease',
1722 'SkAutoRasterClipValidate',
1723 'SkAutoRef',
1724 'SkAutoTime',
1725 'SkAutoTrace',
1726 'SkAutoUnref',
1727 ]
1728 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1729 # bad: base::AutoLock(lock.get());
1730 # not bad: base::AutoLock lock(lock.get());
1731 bad_pattern = input_api.re.compile(anonymous)
1732 # good: new base::AutoLock(lock.get())
1733 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1734 errors = []
1735
1736 for f in input_api.AffectedFiles():
1737 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1738 continue
1739 for linenum, line in f.ChangedContents():
1740 if bad_pattern.search(line) and not good_pattern.search(line):
1741 errors.append('%s:%d' % (f.LocalPath(), linenum))
1742
1743 if errors:
1744 return [output_api.PresubmitError(
1745 'These lines create anonymous variables that need to be named:',
1746 items=errors)]
1747 return []
1748
1749
Peter Kasting4844e46e2018-02-23 07:27:101750def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:531751 # Returns whether |template_str| is of the form <T, U...> for some types T
1752 # and U. Assumes that |template_str| is already in the form <...>.
1753 def HasMoreThanOneArg(template_str):
1754 # Level of <...> nesting.
1755 nesting = 0
1756 for c in template_str:
1757 if c == '<':
1758 nesting += 1
1759 elif c == '>':
1760 nesting -= 1
1761 elif c == ',' and nesting == 1:
1762 return True
1763 return False
1764
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491765 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:101766 sources = lambda affected_file: input_api.FilterSourceFile(
1767 affected_file,
1768 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1769 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491770 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:551771
1772 # Pattern to capture a single "<...>" block of template arguments. It can
1773 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
1774 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
1775 # latter would likely require counting that < and > match, which is not
1776 # expressible in regular languages. Should the need arise, one can introduce
1777 # limited counting (matching up to a total number of nesting depth), which
1778 # should cover all practical cases for already a low nesting limit.
1779 template_arg_pattern = (
1780 r'<[^>]*' # Opening block of <.
1781 r'>([^<]*>)?') # Closing block of >.
1782 # Prefix expressing that whatever follows is not already inside a <...>
1783 # block.
1784 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:101785 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:551786 not_inside_template_arg_pattern
1787 + r'\bstd::unique_ptr'
1788 + template_arg_pattern
1789 + r'\(\)')
1790
1791 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
1792 template_arg_no_array_pattern = (
1793 r'<[^>]*[^]]' # Opening block of <.
1794 r'>([^(<]*[^]]>)?') # Closing block of >.
1795 # Prefix saying that what follows is the start of an expression.
1796 start_of_expr_pattern = r'(=|\breturn|^)\s*'
1797 # Suffix saying that what follows are call parentheses with a non-empty list
1798 # of arguments.
1799 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:531800 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:551801 return_construct_pattern = input_api.re.compile(
1802 start_of_expr_pattern
1803 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:531804 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:551805 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:531806 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:551807 + nonempty_arg_list_pattern)
1808
Vaclav Brozek851d9602018-04-04 16:13:051809 problems_constructor = []
1810 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:101811 for f in input_api.AffectedSourceFiles(sources):
1812 for line_number, line in f.ChangedContents():
1813 # Disallow:
1814 # return std::unique_ptr<T>(foo);
1815 # bar = std::unique_ptr<T>(foo);
1816 # But allow:
1817 # return std::unique_ptr<T[]>(foo);
1818 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:531819 # And also allow cases when the second template argument is present. Those
1820 # cases cannot be handled by std::make_unique:
1821 # return std::unique_ptr<T, U>(foo);
1822 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:051823 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:531824 return_construct_result = return_construct_pattern.search(line)
1825 if return_construct_result and not HasMoreThanOneArg(
1826 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:051827 problems_constructor.append(
1828 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:101829 # Disallow:
1830 # std::unique_ptr<T>()
1831 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051832 problems_nullptr.append(
1833 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1834
1835 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:161836 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:051837 errors.append(output_api.PresubmitError(
1838 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161839 problems_nullptr))
1840 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:051841 errors.append(output_api.PresubmitError(
1842 'The following files use explicit std::unique_ptr constructor.'
1843 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161844 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:101845 return errors
1846
1847
[email protected]999261d2014-03-03 20:08:081848def _CheckUserActionUpdate(input_api, output_api):
1849 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521850 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081851 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521852 # If actions.xml is already included in the changelist, the PRESUBMIT
1853 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081854 return []
1855
[email protected]999261d2014-03-03 20:08:081856 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1857 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521858 current_actions = None
[email protected]999261d2014-03-03 20:08:081859 for f in input_api.AffectedFiles(file_filter=file_filter):
1860 for line_num, line in f.ChangedContents():
1861 match = input_api.re.search(action_re, line)
1862 if match:
[email protected]2f92dec2014-03-07 19:21:521863 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1864 # loaded only once.
1865 if not current_actions:
1866 with open('tools/metrics/actions/actions.xml') as actions_f:
1867 current_actions = actions_f.read()
1868 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081869 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521870 action = 'name="{0}"'.format(action_name)
1871 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081872 return [output_api.PresubmitPromptWarning(
1873 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521874 'tools/metrics/actions/actions.xml. Please run '
1875 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081876 % (f.LocalPath(), line_num, action_name))]
1877 return []
1878
1879
Daniel Cheng13ca61a882017-08-25 15:11:251880def _ImportJSONCommentEater(input_api):
1881 import sys
1882 sys.path = sys.path + [input_api.os_path.join(
1883 input_api.PresubmitLocalPath(),
1884 'tools', 'json_comment_eater')]
1885 import json_comment_eater
1886 return json_comment_eater
1887
1888
[email protected]99171a92014-06-03 08:44:471889def _GetJSONParseError(input_api, filename, eat_comments=True):
1890 try:
1891 contents = input_api.ReadFile(filename)
1892 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:251893 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:131894 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471895
1896 input_api.json.loads(contents)
1897 except ValueError as e:
1898 return e
1899 return None
1900
1901
1902def _GetIDLParseError(input_api, filename):
1903 try:
1904 contents = input_api.ReadFile(filename)
1905 idl_schema = input_api.os_path.join(
1906 input_api.PresubmitLocalPath(),
1907 'tools', 'json_schema_compiler', 'idl_schema.py')
1908 process = input_api.subprocess.Popen(
1909 [input_api.python_executable, idl_schema],
1910 stdin=input_api.subprocess.PIPE,
1911 stdout=input_api.subprocess.PIPE,
1912 stderr=input_api.subprocess.PIPE,
1913 universal_newlines=True)
1914 (_, error) = process.communicate(input=contents)
1915 return error or None
1916 except ValueError as e:
1917 return e
1918
1919
1920def _CheckParseErrors(input_api, output_api):
1921 """Check that IDL and JSON files do not contain syntax errors."""
1922 actions = {
1923 '.idl': _GetIDLParseError,
1924 '.json': _GetJSONParseError,
1925 }
[email protected]99171a92014-06-03 08:44:471926 # Most JSON files are preprocessed and support comments, but these do not.
1927 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:041928 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:471929 ]
1930 # Only run IDL checker on files in these directories.
1931 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:041932 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
1933 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:471934 ]
1935
1936 def get_action(affected_file):
1937 filename = affected_file.LocalPath()
1938 return actions.get(input_api.os_path.splitext(filename)[1])
1939
[email protected]99171a92014-06-03 08:44:471940 def FilterFile(affected_file):
1941 action = get_action(affected_file)
1942 if not action:
1943 return False
1944 path = affected_file.LocalPath()
1945
Sean Kau46e29bc2017-08-28 16:31:161946 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:471947 return False
1948
1949 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:161950 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:471951 return False
1952 return True
1953
1954 results = []
1955 for affected_file in input_api.AffectedFiles(
1956 file_filter=FilterFile, include_deletes=False):
1957 action = get_action(affected_file)
1958 kwargs = {}
1959 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:161960 _MatchesFile(input_api, json_no_comments_patterns,
1961 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:471962 kwargs['eat_comments'] = False
1963 parse_error = action(input_api,
1964 affected_file.AbsoluteLocalPath(),
1965 **kwargs)
1966 if parse_error:
1967 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1968 (affected_file.LocalPath(), parse_error)))
1969 return results
1970
1971
[email protected]760deea2013-12-10 19:33:491972def _CheckJavaStyle(input_api, output_api):
1973 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471974 import sys
[email protected]760deea2013-12-10 19:33:491975 original_sys_path = sys.path
1976 try:
1977 sys.path = sys.path + [input_api.os_path.join(
1978 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1979 import checkstyle
1980 finally:
1981 # Restore sys.path to what it was before.
1982 sys.path = original_sys_path
1983
1984 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091985 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511986 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491987
1988
Sean Kau46e29bc2017-08-28 16:31:161989def _MatchesFile(input_api, patterns, path):
1990 for pattern in patterns:
1991 if input_api.re.search(pattern, path):
1992 return True
1993 return False
1994
1995
Daniel Cheng7052cdf2017-11-21 19:23:291996def _GetOwnersFilesToCheckForIpcOwners(input_api):
1997 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:171998
Daniel Cheng7052cdf2017-11-21 19:23:291999 Returns:
2000 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2001 contain to cover IPC-related files with noparent reviewer rules.
2002 """
2003 # Whether or not a file affects IPC is (mostly) determined by a simple list
2004 # of filename patterns.
dchenge07de812016-06-20 19:27:172005 file_patterns = [
palmerb19a0932017-01-24 04:00:312006 # Legacy IPC:
dchenge07de812016-06-20 19:27:172007 '*_messages.cc',
2008 '*_messages*.h',
2009 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312010 # Mojo IPC:
dchenge07de812016-06-20 19:27:172011 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472012 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172013 '*_struct_traits*.*',
2014 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312015 '*.typemap',
2016 # Android native IPC:
2017 '*.aidl',
2018 # Blink uses a different file naming convention:
2019 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472020 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172021 '*StructTraits*.*',
2022 '*TypeConverter*.*',
2023 ]
2024
scottmg7a6ed5ba2016-11-04 18:22:042025 # These third_party directories do not contain IPCs, but contain files
2026 # matching the above patterns, which trigger false positives.
2027 exclude_paths = [
2028 'third_party/crashpad/*',
Andres Medinae684cf42018-08-27 18:48:232029 'third_party/protobuf/benchmarks/python/*',
Daniel Chengebe635e2018-07-13 12:36:062030 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:292031 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:042032 ]
2033
dchenge07de812016-06-20 19:27:172034 # Dictionary mapping an OWNERS file path to Patterns.
2035 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2036 # rules ) to a PatternEntry.
2037 # PatternEntry is a dictionary with two keys:
2038 # - 'files': the files that are matched by this pattern
2039 # - 'rules': the per-file rules needed for this pattern
2040 # For example, if we expect OWNERS file to contain rules for *.mojom and
2041 # *_struct_traits*.*, Patterns might look like this:
2042 # {
2043 # '*.mojom': {
2044 # 'files': ...,
2045 # 'rules': [
2046 # 'per-file *.mojom=set noparent',
2047 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2048 # ],
2049 # },
2050 # '*_struct_traits*.*': {
2051 # 'files': ...,
2052 # 'rules': [
2053 # 'per-file *_struct_traits*.*=set noparent',
2054 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2055 # ],
2056 # },
2057 # }
2058 to_check = {}
2059
Daniel Cheng13ca61a882017-08-25 15:11:252060 def AddPatternToCheck(input_file, pattern):
2061 owners_file = input_api.os_path.join(
2062 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2063 if owners_file not in to_check:
2064 to_check[owners_file] = {}
2065 if pattern not in to_check[owners_file]:
2066 to_check[owners_file][pattern] = {
2067 'files': [],
2068 'rules': [
2069 'per-file %s=set noparent' % pattern,
2070 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2071 ]
2072 }
Vaclav Brozekd5de76a2018-03-17 07:57:502073 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252074
dchenge07de812016-06-20 19:27:172075 # Iterate through the affected files to see what we actually need to check
2076 # for. We should only nag patch authors about per-file rules if a file in that
2077 # directory would match that pattern. If a directory only contains *.mojom
2078 # files and no *_messages*.h files, we should only nag about rules for
2079 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252080 for f in input_api.AffectedFiles(include_deletes=False):
2081 # Manifest files don't have a strong naming convention. Instead, scan
2082 # affected files for .json files and see if they look like a manifest.
Sean Kau46e29bc2017-08-28 16:31:162083 if (f.LocalPath().endswith('.json') and
2084 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
2085 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:252086 json_comment_eater = _ImportJSONCommentEater(input_api)
2087 mostly_json_lines = '\n'.join(f.NewContents())
2088 # Comments aren't allowed in strict JSON, so filter them out.
2089 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:432090 try:
2091 json_content = input_api.json.loads(json_lines)
2092 except:
2093 # There's another PRESUBMIT check that already verifies that JSON files
2094 # are not invalid, so no need to emit another warning here.
2095 continue
Daniel Cheng13ca61a882017-08-25 15:11:252096 if 'interface_provider_specs' in json_content:
2097 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172098 for pattern in file_patterns:
2099 if input_api.fnmatch.fnmatch(
2100 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042101 skip = False
2102 for exclude in exclude_paths:
2103 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2104 skip = True
2105 break
2106 if skip:
2107 continue
Daniel Cheng13ca61a882017-08-25 15:11:252108 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172109 break
2110
Daniel Cheng7052cdf2017-11-21 19:23:292111 return to_check
2112
2113
2114def _CheckIpcOwners(input_api, output_api):
2115 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2116 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2117
2118 if to_check:
2119 # If there are any OWNERS files to check, there are IPC-related changes in
2120 # this CL. Auto-CC the review list.
2121 output_api.AppendCC('[email protected]')
2122
2123 # Go through the OWNERS files to check, filtering out rules that are already
2124 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172125 for owners_file, patterns in to_check.iteritems():
2126 try:
2127 with file(owners_file) as f:
2128 lines = set(f.read().splitlines())
2129 for entry in patterns.itervalues():
2130 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2131 ]
2132 except IOError:
2133 # No OWNERS file, so all the rules are definitely missing.
2134 continue
2135
2136 # All the remaining lines weren't found in OWNERS files, so emit an error.
2137 errors = []
2138 for owners_file, patterns in to_check.iteritems():
2139 missing_lines = []
2140 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502141 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172142 missing_lines.extend(entry['rules'])
2143 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2144 if missing_lines:
2145 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052146 'Because of the presence of files:\n%s\n\n'
2147 '%s needs the following %d lines added:\n\n%s' %
2148 ('\n'.join(files), owners_file, len(missing_lines),
2149 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172150
2151 results = []
2152 if errors:
vabrf5ce3bf92016-07-11 14:52:412153 if input_api.is_committing:
2154 output = output_api.PresubmitError
2155 else:
2156 output = output_api.PresubmitPromptWarning
2157 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592158 'Found OWNERS files that need to be updated for IPC security ' +
2159 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172160 long_text='\n\n'.join(errors)))
2161
2162 return results
2163
2164
jbriance9e12f162016-11-25 07:57:502165def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312166 """Checks that added or removed lines in non third party affected
2167 header files do not lead to new useless class or struct forward
2168 declaration.
jbriance9e12f162016-11-25 07:57:502169 """
2170 results = []
2171 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2172 input_api.re.MULTILINE)
2173 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2174 input_api.re.MULTILINE)
2175 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312176 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192177 not f.LocalPath().startswith('third_party/blink') and
2178 not f.LocalPath().startswith('third_party\\blink') and
jbriance2c51e821a2016-12-12 08:24:312179 not f.LocalPath().startswith('third_party/WebKit') and
2180 not f.LocalPath().startswith('third_party\\WebKit')):
2181 continue
2182
jbriance9e12f162016-11-25 07:57:502183 if not f.LocalPath().endswith('.h'):
2184 continue
2185
2186 contents = input_api.ReadFile(f)
2187 fwd_decls = input_api.re.findall(class_pattern, contents)
2188 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2189
2190 useless_fwd_decls = []
2191 for decl in fwd_decls:
2192 count = sum(1 for _ in input_api.re.finditer(
2193 r'\b%s\b' % input_api.re.escape(decl), contents))
2194 if count == 1:
2195 useless_fwd_decls.append(decl)
2196
2197 if not useless_fwd_decls:
2198 continue
2199
2200 for line in f.GenerateScmDiff().splitlines():
2201 if (line.startswith('-') and not line.startswith('--') or
2202 line.startswith('+') and not line.startswith('++')):
2203 for decl in useless_fwd_decls:
2204 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2205 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242206 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502207 (f.LocalPath(), decl)))
2208 useless_fwd_decls.remove(decl)
2209
2210 return results
2211
2212
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492213# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:292214def _CheckAndroidToastUsage(input_api, output_api):
2215 """Checks that code uses org.chromium.ui.widget.Toast instead of
2216 android.widget.Toast (Chromium Toast doesn't force hardware
2217 acceleration on low-end devices, saving memory).
2218 """
2219 toast_import_pattern = input_api.re.compile(
2220 r'^import android\.widget\.Toast;$')
2221
2222 errors = []
2223
2224 sources = lambda affected_file: input_api.FilterSourceFile(
2225 affected_file,
2226 black_list=(_EXCLUDED_PATHS +
2227 _TEST_CODE_EXCLUDED_PATHS +
2228 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042229 (r'^chromecast[\\/].*',
2230 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492231 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:292232
2233 for f in input_api.AffectedSourceFiles(sources):
2234 for line_num, line in f.ChangedContents():
2235 if toast_import_pattern.search(line):
2236 errors.append("%s:%d" % (f.LocalPath(), line_num))
2237
2238 results = []
2239
2240 if errors:
2241 results.append(output_api.PresubmitError(
2242 'android.widget.Toast usage is detected. Android toasts use hardware'
2243 ' acceleration, and can be\ncostly on low-end devices. Please use'
2244 ' org.chromium.ui.widget.Toast instead.\n'
2245 'Contact [email protected] if you have any questions.',
2246 errors))
2247
2248 return results
2249
2250
dgnaa68d5e2015-06-10 10:08:222251def _CheckAndroidCrLogUsage(input_api, output_api):
2252 """Checks that new logs using org.chromium.base.Log:
2253 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512254 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222255 """
pkotwicza1dd0b002016-05-16 14:41:042256
torne89540622017-03-24 19:41:302257 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042258 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302259 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:042260 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:302261 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:042262 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
2263 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:092264 # The customtabs_benchmark is a small app that does not depend on Chromium
2265 # java pieces.
Egor Paskoce145c42018-09-28 19:31:042266 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:042267 ]
2268
dgnaa68d5e2015-06-10 10:08:222269 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122270 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2271 class_in_base_pattern = input_api.re.compile(
2272 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2273 has_some_log_import_pattern = input_api.re.compile(
2274 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222275 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122276 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222277 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512278 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222279 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222280
Vincent Scheib16d7b272015-09-15 18:09:072281 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222282 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492283 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:042284 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122285
dgnaa68d5e2015-06-10 10:08:222286 tag_decl_errors = []
2287 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122288 tag_errors = []
dgn38736db2015-09-18 19:20:512289 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122290 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222291
2292 for f in input_api.AffectedSourceFiles(sources):
2293 file_content = input_api.ReadFile(f)
2294 has_modified_logs = False
2295
2296 # Per line checks
dgn87d9fb62015-06-12 09:15:122297 if (cr_log_import_pattern.search(file_content) or
2298 (class_in_base_pattern.search(file_content) and
2299 not has_some_log_import_pattern.search(file_content))):
2300 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222301 for line_num, line in f.ChangedContents():
2302
2303 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122304 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222305 if match:
2306 has_modified_logs = True
2307
2308 # Make sure it uses "TAG"
2309 if not match.group('tag') == 'TAG':
2310 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122311 else:
2312 # Report non cr Log function calls in changed lines
2313 for line_num, line in f.ChangedContents():
2314 if log_call_pattern.search(line):
2315 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222316
2317 # Per file checks
2318 if has_modified_logs:
2319 # Make sure the tag is using the "cr" prefix and is not too long
2320 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512321 tag_name = match.group('name') if match else None
2322 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222323 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512324 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222325 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512326 elif '.' in tag_name:
2327 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222328
2329 results = []
2330 if tag_decl_errors:
2331 results.append(output_api.PresubmitPromptWarning(
2332 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512333 '"private static final String TAG = "<package tag>".\n'
2334 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222335 tag_decl_errors))
2336
2337 if tag_length_errors:
2338 results.append(output_api.PresubmitError(
2339 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512340 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222341 tag_length_errors))
2342
2343 if tag_errors:
2344 results.append(output_api.PresubmitPromptWarning(
2345 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2346 tag_errors))
2347
dgn87d9fb62015-06-12 09:15:122348 if util_log_errors:
dgn4401aa52015-04-29 16:26:172349 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122350 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2351 util_log_errors))
2352
dgn38736db2015-09-18 19:20:512353 if tag_with_dot_errors:
2354 results.append(output_api.PresubmitPromptWarning(
2355 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2356 tag_with_dot_errors))
2357
dgn4401aa52015-04-29 16:26:172358 return results
2359
2360
Yoland Yanb92fa522017-08-28 17:37:062361def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2362 """Checks that junit.framework.* is no longer used."""
2363 deprecated_junit_framework_pattern = input_api.re.compile(
2364 r'^import junit\.framework\..*;',
2365 input_api.re.MULTILINE)
2366 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492367 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062368 errors = []
2369 for f in input_api.AffectedFiles(sources):
2370 for line_num, line in f.ChangedContents():
2371 if deprecated_junit_framework_pattern.search(line):
2372 errors.append("%s:%d" % (f.LocalPath(), line_num))
2373
2374 results = []
2375 if errors:
2376 results.append(output_api.PresubmitError(
2377 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2378 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2379 ' if you have any question.', errors))
2380 return results
2381
2382
2383def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2384 """Checks that if new Java test classes have inheritance.
2385 Either the new test class is JUnit3 test or it is a JUnit4 test class
2386 with a base class, either case is undesirable.
2387 """
2388 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2389
2390 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492391 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062392 errors = []
2393 for f in input_api.AffectedFiles(sources):
2394 if not f.OldContents():
2395 class_declaration_start_flag = False
2396 for line_num, line in f.ChangedContents():
2397 if class_declaration_pattern.search(line):
2398 class_declaration_start_flag = True
2399 if class_declaration_start_flag and ' extends ' in line:
2400 errors.append('%s:%d' % (f.LocalPath(), line_num))
2401 if '{' in line:
2402 class_declaration_start_flag = False
2403
2404 results = []
2405 if errors:
2406 results.append(output_api.PresubmitPromptWarning(
2407 'The newly created files include Test classes that inherits from base'
2408 ' class. Please do not use inheritance in JUnit4 tests or add new'
2409 ' JUnit3 tests. Contact [email protected] if you have any'
2410 ' questions.', errors))
2411 return results
2412
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202413
yolandyan45001472016-12-21 21:12:422414def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2415 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2416 deprecated_annotation_import_pattern = input_api.re.compile(
2417 r'^import android\.test\.suitebuilder\.annotation\..*;',
2418 input_api.re.MULTILINE)
2419 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492420 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:422421 errors = []
2422 for f in input_api.AffectedFiles(sources):
2423 for line_num, line in f.ChangedContents():
2424 if deprecated_annotation_import_pattern.search(line):
2425 errors.append("%s:%d" % (f.LocalPath(), line_num))
2426
2427 results = []
2428 if errors:
2429 results.append(output_api.PresubmitError(
2430 'Annotations in android.test.suitebuilder.annotation have been'
2431 ' deprecated since API level 24. Please use android.support.test.filters'
2432 ' from //third_party/android_support_test_runner:runner_java instead.'
2433 ' Contact [email protected] if you have any questions.', errors))
2434 return results
2435
2436
agrieve7b6479d82015-10-07 14:24:222437def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2438 """Checks if MDPI assets are placed in a correct directory."""
2439 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2440 ('/res/drawable/' in f.LocalPath() or
2441 '/res/drawable-ldrtl/' in f.LocalPath()))
2442 errors = []
2443 for f in input_api.AffectedFiles(include_deletes=False,
2444 file_filter=file_filter):
2445 errors.append(' %s' % f.LocalPath())
2446
2447 results = []
2448 if errors:
2449 results.append(output_api.PresubmitError(
2450 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2451 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2452 '/res/drawable-ldrtl/.\n'
2453 'Contact [email protected] if you have questions.', errors))
2454 return results
2455
2456
Nate Fischer535972b2017-09-16 01:06:182457def _CheckAndroidWebkitImports(input_api, output_api):
2458 """Checks that code uses org.chromium.base.Callback instead of
2459 android.widget.ValueCallback except in the WebView glue layer.
2460 """
2461 valuecallback_import_pattern = input_api.re.compile(
2462 r'^import android\.webkit\.ValueCallback;$')
2463
2464 errors = []
2465
2466 sources = lambda affected_file: input_api.FilterSourceFile(
2467 affected_file,
2468 black_list=(_EXCLUDED_PATHS +
2469 _TEST_CODE_EXCLUDED_PATHS +
2470 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042471 (r'^android_webview[\\/]glue[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492472 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:182473
2474 for f in input_api.AffectedSourceFiles(sources):
2475 for line_num, line in f.ChangedContents():
2476 if valuecallback_import_pattern.search(line):
2477 errors.append("%s:%d" % (f.LocalPath(), line_num))
2478
2479 results = []
2480
2481 if errors:
2482 results.append(output_api.PresubmitError(
2483 'android.webkit.ValueCallback usage is detected outside of the glue'
2484 ' layer. To stay compatible with the support library, android.webkit.*'
2485 ' classes should only be used inside the glue layer and'
2486 ' org.chromium.base.Callback should be used instead.',
2487 errors))
2488
2489 return results
2490
2491
agrievef32bcc72016-04-04 14:57:402492class PydepsChecker(object):
2493 def __init__(self, input_api, pydeps_files):
2494 self._file_cache = {}
2495 self._input_api = input_api
2496 self._pydeps_files = pydeps_files
2497
2498 def _LoadFile(self, path):
2499 """Returns the list of paths within a .pydeps file relative to //."""
2500 if path not in self._file_cache:
2501 with open(path) as f:
2502 self._file_cache[path] = f.read()
2503 return self._file_cache[path]
2504
2505 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2506 """Returns an interable of paths within the .pydep, relativized to //."""
2507 os_path = self._input_api.os_path
2508 pydeps_dir = os_path.dirname(pydeps_path)
2509 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2510 if not l.startswith('*'))
2511 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2512
2513 def _CreateFilesToPydepsMap(self):
2514 """Returns a map of local_path -> list_of_pydeps."""
2515 ret = {}
2516 for pydep_local_path in self._pydeps_files:
2517 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2518 ret.setdefault(path, []).append(pydep_local_path)
2519 return ret
2520
2521 def ComputeAffectedPydeps(self):
2522 """Returns an iterable of .pydeps files that might need regenerating."""
2523 affected_pydeps = set()
2524 file_to_pydeps_map = None
2525 for f in self._input_api.AffectedFiles(include_deletes=True):
2526 local_path = f.LocalPath()
2527 if local_path == 'DEPS':
2528 return self._pydeps_files
2529 elif local_path.endswith('.pydeps'):
2530 if local_path in self._pydeps_files:
2531 affected_pydeps.add(local_path)
2532 elif local_path.endswith('.py'):
2533 if file_to_pydeps_map is None:
2534 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2535 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2536 return affected_pydeps
2537
2538 def DetermineIfStale(self, pydeps_path):
2539 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412540 import difflib
John Budorick47ca3fe2018-02-10 00:53:102541 import os
2542
agrievef32bcc72016-04-04 14:57:402543 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2544 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102545 env = dict(os.environ)
2546 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402547 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102548 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412549 old_contents = old_pydeps_data[2:]
2550 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402551 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412552 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402553
2554
2555def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2556 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402557 # This check is for Python dependency lists (.pydeps files), and involves
2558 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2559 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282560 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002561 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022562 # TODO(agrieve): Update when there's a better way to detect
2563 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402564 is_android = input_api.os_path.exists('third_party/android_tools')
2565 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2566 results = []
2567 # First, check for new / deleted .pydeps.
2568 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032569 # Check whether we are running the presubmit check for a file in src.
2570 # f.LocalPath is relative to repo (src, or internal repo).
2571 # os_path.exists is relative to src repo.
2572 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2573 # to src and we can conclude that the pydeps is in src.
2574 if input_api.os_path.exists(f.LocalPath()):
2575 if f.LocalPath().endswith('.pydeps'):
2576 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2577 results.append(output_api.PresubmitError(
2578 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2579 'remove %s' % f.LocalPath()))
2580 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2581 results.append(output_api.PresubmitError(
2582 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2583 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402584
2585 if results:
2586 return results
2587
2588 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2589
2590 for pydep_path in checker.ComputeAffectedPydeps():
2591 try:
phajdan.jr0d9878552016-11-04 10:49:412592 result = checker.DetermineIfStale(pydep_path)
2593 if result:
2594 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402595 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412596 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2597 'To regenerate, run:\n\n %s' %
2598 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402599 except input_api.subprocess.CalledProcessError as error:
2600 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2601 long_text=error.output)]
2602
2603 return results
2604
2605
glidere61efad2015-02-18 17:39:432606def _CheckSingletonInHeaders(input_api, output_api):
2607 """Checks to make sure no header files have |Singleton<|."""
2608 def FileFilter(affected_file):
2609 # It's ok for base/memory/singleton.h to have |Singleton<|.
2610 black_list = (_EXCLUDED_PATHS +
2611 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042612 (r"^base[\\/]memory[\\/]singleton\.h$",
2613 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:472614 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432615 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2616
sergeyu34d21222015-09-16 00:11:442617 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432618 files = []
2619 for f in input_api.AffectedSourceFiles(FileFilter):
2620 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2621 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2622 contents = input_api.ReadFile(f)
2623 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242624 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432625 pattern.search(line)):
2626 files.append(f)
2627 break
2628
2629 if files:
yolandyandaabc6d2016-04-18 18:29:392630 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442631 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432632 'Please move them to an appropriate source file so that the ' +
2633 'template gets instantiated in a single compilation unit.',
2634 files) ]
2635 return []
2636
2637
[email protected]fd20b902014-05-09 02:14:532638_DEPRECATED_CSS = [
2639 # Values
2640 ( "-webkit-box", "flex" ),
2641 ( "-webkit-inline-box", "inline-flex" ),
2642 ( "-webkit-flex", "flex" ),
2643 ( "-webkit-inline-flex", "inline-flex" ),
2644 ( "-webkit-min-content", "min-content" ),
2645 ( "-webkit-max-content", "max-content" ),
2646
2647 # Properties
2648 ( "-webkit-background-clip", "background-clip" ),
2649 ( "-webkit-background-origin", "background-origin" ),
2650 ( "-webkit-background-size", "background-size" ),
2651 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442652 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532653
2654 # Functions
2655 ( "-webkit-gradient", "gradient" ),
2656 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2657 ( "-webkit-linear-gradient", "linear-gradient" ),
2658 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2659 ( "-webkit-radial-gradient", "radial-gradient" ),
2660 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2661]
2662
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202663
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492664# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242665def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532666 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252667 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342668 documentation and iOS CSS for dom distiller
2669 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252670 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532671 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492672 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:252673 black_list = (_EXCLUDED_PATHS +
2674 _TEST_CODE_EXCLUDED_PATHS +
2675 input_api.DEFAULT_BLACK_LIST +
2676 (r"^chrome/common/extensions/docs",
2677 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342678 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442679 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252680 r"^native_client_sdk"))
2681 file_filter = lambda f: input_api.FilterSourceFile(
2682 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532683 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2684 for line_num, line in fpath.ChangedContents():
2685 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022686 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532687 results.append(output_api.PresubmitError(
2688 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2689 (fpath.LocalPath(), line_num, deprecated_value, value)))
2690 return results
2691
mohan.reddyf21db962014-10-16 12:26:472692
dbeam070cfe62014-10-22 06:44:022693_DEPRECATED_JS = [
2694 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2695 ( "__defineGetter__", "Object.defineProperty" ),
2696 ( "__defineSetter__", "Object.defineProperty" ),
2697]
2698
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202699
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492700# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242701def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022702 """Make sure that we don't use deprecated JS in Chrome code."""
2703 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492704 file_inclusion_pattern = [r".+\.js$"] # TODO(dbeam): .html?
dbeam070cfe62014-10-22 06:44:022705 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2706 input_api.DEFAULT_BLACK_LIST)
2707 file_filter = lambda f: input_api.FilterSourceFile(
2708 f, white_list=file_inclusion_pattern, black_list=black_list)
2709 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2710 for lnum, line in fpath.ChangedContents():
2711 for (deprecated, replacement) in _DEPRECATED_JS:
2712 if deprecated in line:
2713 results.append(output_api.PresubmitError(
2714 "%s:%d: Use of deprecated JS %s, use %s instead" %
2715 (fpath.LocalPath(), lnum, deprecated, replacement)))
2716 return results
2717
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202718
dpapadd651231d82017-07-21 02:44:472719def _CheckForRiskyJsArrowFunction(line_number, line):
2720 if ' => ' in line:
2721 return "line %d, is using an => (arrow) function\n %s\n" % (
2722 line_number, line)
2723 return ''
2724
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202725
dpapadd651231d82017-07-21 02:44:472726def _CheckForRiskyJsConstLet(input_api, line_number, line):
2727 if input_api.re.match('^\s*(const|let)\s', line):
2728 return "line %d, is using const/let keyword\n %s\n" % (
2729 line_number, line)
2730 return ''
dbeam070cfe62014-10-22 06:44:022731
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202732
dbeam1ec68ac2016-12-15 05:22:242733def _CheckForRiskyJsFeatures(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492734 maybe_ios_js = [r"^(ios|components|ui\/webui\/resources)\/.+\.js$"]
Steven Bennetts90545f3cb2017-08-14 18:11:002735 # 'ui/webui/resources/cr_components are not allowed on ios'
2736 not_ios_filter = (r".*ui\/webui\/resources\/cr_components.*", )
Steven Bennetts9c7e3c22017-08-02 19:10:572737 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js,
Steven Bennetts90545f3cb2017-08-14 18:11:002738 black_list=not_ios_filter)
dpapadd651231d82017-07-21 02:44:472739 results = []
dbeam1ec68ac2016-12-15 05:22:242740 for f in input_api.AffectedFiles(file_filter=file_filter):
dpapadd651231d82017-07-21 02:44:472741 arrow_error_lines = []
2742 const_let_error_lines = []
dbeam1ec68ac2016-12-15 05:22:242743 for lnum, line in f.ChangedContents():
dpapadd651231d82017-07-21 02:44:472744 arrow_error_lines += filter(None, [
2745 _CheckForRiskyJsArrowFunction(lnum, line),
2746 ])
dbeam1ec68ac2016-12-15 05:22:242747
dpapadd651231d82017-07-21 02:44:472748 const_let_error_lines += filter(None, [
2749 _CheckForRiskyJsConstLet(input_api, lnum, line),
2750 ])
dbeam1ec68ac2016-12-15 05:22:242751
dpapadd651231d82017-07-21 02:44:472752 if arrow_error_lines:
2753 arrow_error_lines = map(
2754 lambda e: "%s:%s" % (f.LocalPath(), e), arrow_error_lines)
2755 results.append(
2756 output_api.PresubmitPromptWarning('\n'.join(arrow_error_lines + [
2757"""
2758Use of => (arrow) operator detected in:
dbeam1ec68ac2016-12-15 05:22:242759%s
2760Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
Dan Beamdd2470c2018-10-03 00:07:222761https://chromium.googlesource.com/chromium/src/+/master/styleguide/web/es6.md#Arrow-Functions
dpapadd651231d82017-07-21 02:44:472762""" % f.LocalPath()
2763 ])))
dbeam1ec68ac2016-12-15 05:22:242764
dpapadd651231d82017-07-21 02:44:472765 if const_let_error_lines:
2766 const_let_error_lines = map(
2767 lambda e: "%s:%s" % (f.LocalPath(), e), const_let_error_lines)
2768 results.append(
2769 output_api.PresubmitPromptWarning('\n'.join(const_let_error_lines + [
2770"""
2771Use of const/let keywords detected in:
2772%s
2773Please ensure your code does not run on iOS9 because const/let is not fully
2774supported.
Dan Beamdd2470c2018-10-03 00:07:222775https://chromium.googlesource.com/chromium/src/+/master/styleguide/web/es6.md#let-Block_Scoped-Variables
2776https://chromium.googlesource.com/chromium/src/+/master/styleguide/web/es6.md#const-Block_Scoped-Constants
dpapadd651231d82017-07-21 02:44:472777""" % f.LocalPath()
2778 ])))
2779
2780 return results
dbeam1ec68ac2016-12-15 05:22:242781
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202782
rlanday6802cf632017-05-30 17:48:362783def _CheckForRelativeIncludes(input_api, output_api):
2784 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2785 import sys
2786 original_sys_path = sys.path
2787 try:
2788 sys.path = sys.path + [input_api.os_path.join(
2789 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2790 from cpp_checker import CppChecker
2791 finally:
2792 # Restore sys.path to what it was before.
2793 sys.path = original_sys_path
2794
2795 bad_files = {}
2796 for f in input_api.AffectedFiles(include_deletes=False):
2797 if (f.LocalPath().startswith('third_party') and
2798 not f.LocalPath().startswith('third_party/WebKit') and
2799 not f.LocalPath().startswith('third_party\\WebKit')):
2800 continue
2801
2802 if not CppChecker.IsCppFile(f.LocalPath()):
2803 continue
2804
Vaclav Brozekd5de76a2018-03-17 07:57:502805 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362806 if "#include" in line and "../" in line]
2807 if not relative_includes:
2808 continue
2809 bad_files[f.LocalPath()] = relative_includes
2810
2811 if not bad_files:
2812 return []
2813
2814 error_descriptions = []
2815 for file_path, bad_lines in bad_files.iteritems():
2816 error_description = file_path
2817 for line in bad_lines:
2818 error_description += '\n ' + line
2819 error_descriptions.append(error_description)
2820
2821 results = []
2822 results.append(output_api.PresubmitError(
2823 'You added one or more relative #include paths (including "../").\n'
2824 'These shouldn\'t be used because they can be used to include headers\n'
2825 'from code that\'s not correctly specified as a dependency in the\n'
2826 'relevant BUILD.gn file(s).',
2827 error_descriptions))
2828
2829 return results
2830
Takeshi Yoshinoe387aa32017-08-02 13:16:132831
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202832def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2833 if not isinstance(key, ast.Str):
2834 return 'Key at line %d must be a string literal' % key.lineno
2835 if not isinstance(value, ast.Dict):
2836 return 'Value at line %d must be a dict' % value.lineno
2837 if len(value.keys) != 1:
2838 return 'Dict at line %d must have single entry' % value.lineno
2839 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2840 return (
2841 'Entry at line %d must have a string literal \'filepath\' as key' %
2842 value.lineno)
2843 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132844
Takeshi Yoshinoe387aa32017-08-02 13:16:132845
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202846def _CheckWatchlistsEntrySyntax(key, value, ast):
2847 if not isinstance(key, ast.Str):
2848 return 'Key at line %d must be a string literal' % key.lineno
2849 if not isinstance(value, ast.List):
2850 return 'Value at line %d must be a list' % value.lineno
2851 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132852
Takeshi Yoshinoe387aa32017-08-02 13:16:132853
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202854def _CheckWATCHLISTSEntries(wd_dict, w_dict, ast):
2855 mismatch_template = (
2856 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2857 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132858
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202859 i = 0
2860 last_key = ''
2861 while True:
2862 if i >= len(wd_dict.keys):
2863 if i >= len(w_dict.keys):
2864 return None
2865 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2866 elif i >= len(w_dict.keys):
2867 return (
2868 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132869
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202870 wd_key = wd_dict.keys[i]
2871 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132872
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202873 result = _CheckWatchlistDefinitionsEntrySyntax(
2874 wd_key, wd_dict.values[i], ast)
2875 if result is not None:
2876 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132877
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202878 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast)
2879 if result is not None:
2880 return 'Bad entry in WATCHLISTS dict: %s' % result
2881
2882 if wd_key.s != w_key.s:
2883 return mismatch_template % (
2884 '%s at line %d' % (wd_key.s, wd_key.lineno),
2885 '%s at line %d' % (w_key.s, w_key.lineno))
2886
2887 if wd_key.s < last_key:
2888 return (
2889 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2890 (wd_key.lineno, w_key.lineno))
2891 last_key = wd_key.s
2892
2893 i = i + 1
2894
2895
2896def _CheckWATCHLISTSSyntax(expression, ast):
2897 if not isinstance(expression, ast.Expression):
2898 return 'WATCHLISTS file must contain a valid expression'
2899 dictionary = expression.body
2900 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2901 return 'WATCHLISTS file must have single dict with exactly two entries'
2902
2903 first_key = dictionary.keys[0]
2904 first_value = dictionary.values[0]
2905 second_key = dictionary.keys[1]
2906 second_value = dictionary.values[1]
2907
2908 if (not isinstance(first_key, ast.Str) or
2909 first_key.s != 'WATCHLIST_DEFINITIONS' or
2910 not isinstance(first_value, ast.Dict)):
2911 return (
2912 'The first entry of the dict in WATCHLISTS file must be '
2913 'WATCHLIST_DEFINITIONS dict')
2914
2915 if (not isinstance(second_key, ast.Str) or
2916 second_key.s != 'WATCHLISTS' or
2917 not isinstance(second_value, ast.Dict)):
2918 return (
2919 'The second entry of the dict in WATCHLISTS file must be '
2920 'WATCHLISTS dict')
2921
2922 return _CheckWATCHLISTSEntries(first_value, second_value, ast)
Takeshi Yoshinoe387aa32017-08-02 13:16:132923
2924
2925def _CheckWATCHLISTS(input_api, output_api):
2926 for f in input_api.AffectedFiles(include_deletes=False):
2927 if f.LocalPath() == 'WATCHLISTS':
2928 contents = input_api.ReadFile(f, 'r')
2929
2930 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202931 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132932 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202933 # Get an AST tree for it and scan the tree for detailed style checking.
2934 expression = input_api.ast.parse(
2935 contents, filename='WATCHLISTS', mode='eval')
2936 except ValueError as e:
2937 return [output_api.PresubmitError(
2938 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2939 except SyntaxError as e:
2940 return [output_api.PresubmitError(
2941 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2942 except TypeError as e:
2943 return [output_api.PresubmitError(
2944 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132945
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202946 result = _CheckWATCHLISTSSyntax(expression, input_api.ast)
2947 if result is not None:
2948 return [output_api.PresubmitError(result)]
2949 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132950
2951 return []
2952
2953
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192954def _CheckNewHeaderWithoutGnChange(input_api, output_api):
2955 """Checks that newly added header files have corresponding GN changes.
2956 Note that this is only a heuristic. To be precise, run script:
2957 build/check_gn_headers.py.
2958 """
2959
2960 def headers(f):
2961 return input_api.FilterSourceFile(
2962 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
2963
2964 new_headers = []
2965 for f in input_api.AffectedSourceFiles(headers):
2966 if f.Action() != 'A':
2967 continue
2968 new_headers.append(f.LocalPath())
2969
2970 def gn_files(f):
2971 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
2972
2973 all_gn_changed_contents = ''
2974 for f in input_api.AffectedSourceFiles(gn_files):
2975 for _, line in f.ChangedContents():
2976 all_gn_changed_contents += line
2977
2978 problems = []
2979 for header in new_headers:
2980 basename = input_api.os_path.basename(header)
2981 if basename not in all_gn_changed_contents:
2982 problems.append(header)
2983
2984 if problems:
2985 return [output_api.PresubmitPromptWarning(
2986 'Missing GN changes for new header files', items=sorted(problems),
2987 long_text='Please double check whether newly added header files need '
2988 'corresponding changes in gn or gni files.\nThis checking is only a '
2989 'heuristic. Run build/check_gn_headers.py to be precise.\n'
2990 'Read https://crbug.com/661774 for more info.')]
2991 return []
2992
2993
Michael Giuffridad3bc8672018-10-25 22:48:022994def _CheckCorrectProductNameInMessages(input_api, output_api):
2995 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
2996
2997 This assumes we won't intentionally reference one product from the other
2998 product.
2999 """
3000 all_problems = []
3001 test_cases = [{
3002 "filename_postfix": "google_chrome_strings.grd",
3003 "correct_name": "Chrome",
3004 "incorrect_name": "Chromium",
3005 }, {
3006 "filename_postfix": "chromium_strings.grd",
3007 "correct_name": "Chromium",
3008 "incorrect_name": "Chrome",
3009 }]
3010
3011 for test_case in test_cases:
3012 problems = []
3013 filename_filter = lambda x: x.LocalPath().endswith(
3014 test_case["filename_postfix"])
3015
3016 # Check each new line. Can yield false positives in multiline comments, but
3017 # easier than trying to parse the XML because messages can have nested
3018 # children, and associating message elements with affected lines is hard.
3019 for f in input_api.AffectedSourceFiles(filename_filter):
3020 for line_num, line in f.ChangedContents():
3021 if "<message" in line or "<!--" in line or "-->" in line:
3022 continue
3023 if test_case["incorrect_name"] in line:
3024 problems.append(
3025 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
3026
3027 if problems:
3028 message = (
3029 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
3030 % (test_case["correct_name"], test_case["correct_name"],
3031 test_case["incorrect_name"]))
3032 all_problems.append(
3033 output_api.PresubmitPromptWarning(message, items=problems))
3034
3035 return all_problems
3036
3037
dgnaa68d5e2015-06-10 10:08:223038def _AndroidSpecificOnUploadChecks(input_api, output_api):
3039 """Groups checks that target android code."""
3040 results = []
dgnaa68d5e2015-06-10 10:08:223041 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:223042 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:293043 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:063044 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
3045 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:423046 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:183047 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223048 return results
3049
3050
[email protected]22c9bd72011-03-27 16:47:393051def _CommonChecks(input_api, output_api):
3052 """Checks common to both upload and commit."""
3053 results = []
3054 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:383055 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:543056 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:083057
3058 author = input_api.change.author_email
3059 if author and author not in _KNOWN_ROBOTS:
3060 results.extend(
3061 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
3062
[email protected]55459852011-08-10 15:17:193063 results.extend(
[email protected]760deea2013-12-10 19:33:493064 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:233065 results.extend(
3066 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:543067 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:183068 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:343069 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:523070 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:223071 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:443072 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:593073 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:063074 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:123075 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:183076 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:223077 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:303078 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:493079 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:033080 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:493081 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:443082 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:273083 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:073084 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:543085 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:443086 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:393087 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:553088 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:043089 results.extend(
3090 input_api.canned_checks.CheckChangeHasNoTabs(
3091 input_api,
3092 output_api,
3093 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:403094 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:163095 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:083096 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:243097 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
3098 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:473099 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:043100 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:053101 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:143102 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:233103 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:433104 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:403105 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:153106 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:173107 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:503108 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:243109 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:363110 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:133111 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:433112 results.extend(input_api.RunTests(
3113 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143114 results.extend(_CheckTranslationScreenshots(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:023115 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:243116
Vaclav Brozekcdc7defb2018-03-20 09:54:353117 for f in input_api.AffectedFiles():
3118 path, name = input_api.os_path.split(f.LocalPath())
3119 if name == 'PRESUBMIT.py':
3120 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:003121 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
3122 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:073123 # The PRESUBMIT.py file (and the directory containing it) might
3124 # have been affected by being moved or removed, so only try to
3125 # run the tests if they still exist.
3126 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
3127 input_api, output_api, full_path,
3128 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:393129 return results
[email protected]1f7b4172010-01-28 01:17:343130
[email protected]b337cb5b2011-01-23 21:24:053131
[email protected]b8079ae4a2012-12-05 19:56:493132def _CheckPatchFiles(input_api, output_api):
3133 problems = [f.LocalPath() for f in input_api.AffectedFiles()
3134 if f.LocalPath().endswith(('.orig', '.rej'))]
3135 if problems:
3136 return [output_api.PresubmitError(
3137 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:033138 else:
3139 return []
[email protected]b8079ae4a2012-12-05 19:56:493140
3141
Kent Tamura5a8755d2017-06-29 23:37:073142def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:213143 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
3144 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
3145 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:073146 include_re = input_api.re.compile(
3147 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
3148 extension_re = input_api.re.compile(r'\.[a-z]+$')
3149 errors = []
3150 for f in input_api.AffectedFiles():
3151 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
3152 continue
3153 found_line_number = None
3154 found_macro = None
3155 for line_num, line in f.ChangedContents():
3156 match = macro_re.search(line)
3157 if match:
3158 found_line_number = line_num
3159 found_macro = match.group(2)
3160 break
3161 if not found_line_number:
3162 continue
3163
3164 found_include = False
3165 for line in f.NewContents():
3166 if include_re.search(line):
3167 found_include = True
3168 break
3169 if found_include:
3170 continue
3171
3172 if not f.LocalPath().endswith('.h'):
3173 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
3174 try:
3175 content = input_api.ReadFile(primary_header_path, 'r')
3176 if include_re.search(content):
3177 continue
3178 except IOError:
3179 pass
3180 errors.append('%s:%d %s macro is used without including build/'
3181 'build_config.h.'
3182 % (f.LocalPath(), found_line_number, found_macro))
3183 if errors:
3184 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
3185 return []
3186
3187
[email protected]b00342e7f2013-03-26 16:21:543188def _DidYouMeanOSMacro(bad_macro):
3189 try:
3190 return {'A': 'OS_ANDROID',
3191 'B': 'OS_BSD',
3192 'C': 'OS_CHROMEOS',
3193 'F': 'OS_FREEBSD',
3194 'L': 'OS_LINUX',
3195 'M': 'OS_MACOSX',
3196 'N': 'OS_NACL',
3197 'O': 'OS_OPENBSD',
3198 'P': 'OS_POSIX',
3199 'S': 'OS_SOLARIS',
3200 'W': 'OS_WIN'}[bad_macro[3].upper()]
3201 except KeyError:
3202 return ''
3203
3204
3205def _CheckForInvalidOSMacrosInFile(input_api, f):
3206 """Check for sensible looking, totally invalid OS macros."""
3207 preprocessor_statement = input_api.re.compile(r'^\s*#')
3208 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
3209 results = []
3210 for lnum, line in f.ChangedContents():
3211 if preprocessor_statement.search(line):
3212 for match in os_macro.finditer(line):
3213 if not match.group(1) in _VALID_OS_MACROS:
3214 good = _DidYouMeanOSMacro(match.group(1))
3215 did_you_mean = ' (did you mean %s?)' % good if good else ''
3216 results.append(' %s:%d %s%s' % (f.LocalPath(),
3217 lnum,
3218 match.group(1),
3219 did_you_mean))
3220 return results
3221
3222
3223def _CheckForInvalidOSMacros(input_api, output_api):
3224 """Check all affected files for invalid OS macros."""
3225 bad_macros = []
3226 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:473227 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:543228 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
3229
3230 if not bad_macros:
3231 return []
3232
3233 return [output_api.PresubmitError(
3234 'Possibly invalid OS macro[s] found. Please fix your code\n'
3235 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
3236
lliabraa35bab3932014-10-01 12:16:443237
3238def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
3239 """Check all affected files for invalid "if defined" macros."""
3240 ALWAYS_DEFINED_MACROS = (
3241 "TARGET_CPU_PPC",
3242 "TARGET_CPU_PPC64",
3243 "TARGET_CPU_68K",
3244 "TARGET_CPU_X86",
3245 "TARGET_CPU_ARM",
3246 "TARGET_CPU_MIPS",
3247 "TARGET_CPU_SPARC",
3248 "TARGET_CPU_ALPHA",
3249 "TARGET_IPHONE_SIMULATOR",
3250 "TARGET_OS_EMBEDDED",
3251 "TARGET_OS_IPHONE",
3252 "TARGET_OS_MAC",
3253 "TARGET_OS_UNIX",
3254 "TARGET_OS_WIN32",
3255 )
3256 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
3257 results = []
3258 for lnum, line in f.ChangedContents():
3259 for match in ifdef_macro.finditer(line):
3260 if match.group(1) in ALWAYS_DEFINED_MACROS:
3261 always_defined = ' %s is always defined. ' % match.group(1)
3262 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
3263 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
3264 lnum,
3265 always_defined,
3266 did_you_mean))
3267 return results
3268
3269
3270def _CheckForInvalidIfDefinedMacros(input_api, output_api):
3271 """Check all affected files for invalid "if defined" macros."""
3272 bad_macros = []
3273 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:213274 if f.LocalPath().startswith('third_party/sqlite/'):
3275 continue
lliabraa35bab3932014-10-01 12:16:443276 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3277 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3278
3279 if not bad_macros:
3280 return []
3281
3282 return [output_api.PresubmitError(
3283 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3284 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3285 bad_macros)]
3286
3287
mlamouria82272622014-09-16 18:45:043288def _CheckForIPCRules(input_api, output_api):
3289 """Check for same IPC rules described in
3290 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3291 """
3292 base_pattern = r'IPC_ENUM_TRAITS\('
3293 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3294 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3295
3296 problems = []
3297 for f in input_api.AffectedSourceFiles(None):
3298 local_path = f.LocalPath()
3299 if not local_path.endswith('.h'):
3300 continue
3301 for line_number, line in f.ChangedContents():
3302 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3303 problems.append(
3304 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3305
3306 if problems:
3307 return [output_api.PresubmitPromptWarning(
3308 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
3309 else:
3310 return []
3311
[email protected]b00342e7f2013-03-26 16:21:543312
Stephen Martinis97a394142018-06-07 23:06:053313def _CheckForLongPathnames(input_api, output_api):
3314 """Check to make sure no files being submitted have long paths.
3315 This causes issues on Windows.
3316 """
3317 problems = []
3318 for f in input_api.AffectedSourceFiles(None):
3319 local_path = f.LocalPath()
3320 # Windows has a path limit of 260 characters. Limit path length to 200 so
3321 # that we have some extra for the prefix on dev machines and the bots.
3322 if len(local_path) > 200:
3323 problems.append(local_path)
3324
3325 if problems:
3326 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
3327 else:
3328 return []
3329
3330
Daniel Bratell8ba52722018-03-02 16:06:143331def _CheckForIncludeGuards(input_api, output_api):
3332 """Check that header files have proper guards against multiple inclusion.
3333 If a file should not have such guards (and it probably should) then it
3334 should include the string "no-include-guard-because-multiply-included".
3335 """
Daniel Bratell6a75baef62018-06-04 10:04:453336 def is_chromium_header_file(f):
3337 # We only check header files under the control of the Chromium
3338 # project. That is, those outside third_party apart from
3339 # third_party/blink.
3340 file_with_path = input_api.os_path.normpath(f.LocalPath())
3341 return (file_with_path.endswith('.h') and
3342 (not file_with_path.startswith('third_party') or
3343 file_with_path.startswith(
3344 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:143345
3346 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:343347 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:143348
3349 errors = []
3350
Daniel Bratell6a75baef62018-06-04 10:04:453351 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:143352 guard_name = None
3353 guard_line_number = None
3354 seen_guard_end = False
3355
3356 file_with_path = input_api.os_path.normpath(f.LocalPath())
3357 base_file_name = input_api.os_path.splitext(
3358 input_api.os_path.basename(file_with_path))[0]
3359 upper_base_file_name = base_file_name.upper()
3360
3361 expected_guard = replace_special_with_underscore(
3362 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:143363
3364 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:573365 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
3366 # are too many (1000+) files with slight deviations from the
3367 # coding style. The most important part is that the include guard
3368 # is there, and that it's unique, not the name so this check is
3369 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:143370 #
3371 # As code becomes more uniform, this could be made stricter.
3372
3373 guard_name_pattern_list = [
3374 # Anything with the right suffix (maybe with an extra _).
3375 r'\w+_H__?',
3376
Daniel Bratell39b5b062018-05-16 18:09:573377 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:143378 r'\w+_h',
3379
3380 # Anything including the uppercase name of the file.
3381 r'\w*' + input_api.re.escape(replace_special_with_underscore(
3382 upper_base_file_name)) + r'\w*',
3383 ]
3384 guard_name_pattern = '|'.join(guard_name_pattern_list)
3385 guard_pattern = input_api.re.compile(
3386 r'#ifndef\s+(' + guard_name_pattern + ')')
3387
3388 for line_number, line in enumerate(f.NewContents()):
3389 if 'no-include-guard-because-multiply-included' in line:
3390 guard_name = 'DUMMY' # To not trigger check outside the loop.
3391 break
3392
3393 if guard_name is None:
3394 match = guard_pattern.match(line)
3395 if match:
3396 guard_name = match.group(1)
3397 guard_line_number = line_number
3398
Daniel Bratell39b5b062018-05-16 18:09:573399 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:453400 # don't match the chromium style guide, but new files should
3401 # get it right.
3402 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:573403 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:143404 errors.append(output_api.PresubmitPromptWarning(
3405 'Header using the wrong include guard name %s' % guard_name,
3406 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:573407 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:143408 else:
3409 # The line after #ifndef should have a #define of the same name.
3410 if line_number == guard_line_number + 1:
3411 expected_line = '#define %s' % guard_name
3412 if line != expected_line:
3413 errors.append(output_api.PresubmitPromptWarning(
3414 'Missing "%s" for include guard' % expected_line,
3415 ['%s:%d' % (f.LocalPath(), line_number + 1)],
3416 'Expected: %r\nGot: %r' % (expected_line, line)))
3417
3418 if not seen_guard_end and line == '#endif // %s' % guard_name:
3419 seen_guard_end = True
3420 elif seen_guard_end:
3421 if line.strip() != '':
3422 errors.append(output_api.PresubmitPromptWarning(
3423 'Include guard %s not covering the whole file' % (
3424 guard_name), [f.LocalPath()]))
3425 break # Nothing else to check and enough to warn once.
3426
3427 if guard_name is None:
3428 errors.append(output_api.PresubmitPromptWarning(
3429 'Missing include guard %s' % expected_guard,
3430 [f.LocalPath()],
3431 'Missing include guard in %s\n'
3432 'Recommended name: %s\n'
3433 'This check can be disabled by having the string\n'
3434 'no-include-guard-because-multiply-included in the header.' %
3435 (f.LocalPath(), expected_guard)))
3436
3437 return errors
3438
3439
mostynbb639aca52015-01-07 20:31:233440def _CheckForWindowsLineEndings(input_api, output_api):
3441 """Check source code and known ascii text files for Windows style line
3442 endings.
3443 """
earthdok1b5e0ee2015-03-10 15:19:103444 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233445
3446 file_inclusion_pattern = (
3447 known_text_files,
3448 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3449 )
3450
mostynbb639aca52015-01-07 20:31:233451 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533452 source_file_filter = lambda f: input_api.FilterSourceFile(
3453 f, white_list=file_inclusion_pattern, black_list=None)
3454 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503455 include_file = False
3456 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233457 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503458 include_file = True
3459 if include_file:
3460 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233461
3462 if problems:
3463 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3464 'these files to contain Windows style line endings?\n' +
3465 '\n'.join(problems))]
3466
3467 return []
3468
3469
Vaclav Brozekd5de76a2018-03-17 07:57:503470def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133471 """Checks that all source files use SYSLOG properly."""
3472 syslog_files = []
3473 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563474 for line_number, line in f.ChangedContents():
3475 if 'SYSLOG' in line:
3476 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3477
pastarmovj89f7ee12016-09-20 14:58:133478 if syslog_files:
3479 return [output_api.PresubmitPromptWarning(
3480 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3481 ' calls.\nFiles to check:\n', items=syslog_files)]
3482 return []
3483
3484
[email protected]1f7b4172010-01-28 01:17:343485def CheckChangeOnUpload(input_api, output_api):
3486 results = []
3487 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473488 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283489 results.extend(
jam93a6ee792017-02-08 23:59:223490 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193491 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223492 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133493 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163494 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:533495 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193496 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543497 return results
[email protected]ca8d1982009-02-19 16:33:123498
3499
[email protected]1bfb8322014-04-23 01:02:413500def GetTryServerMasterForBot(bot):
3501 """Returns the Try Server master for the given bot.
3502
[email protected]0bb112362014-07-26 04:38:323503 It tries to guess the master from the bot name, but may still fail
3504 and return None. There is no longer a default master.
3505 """
3506 # Potentially ambiguous bot names are listed explicitly.
3507 master_map = {
tandriie5587792016-07-14 00:34:503508 'chromium_presubmit': 'master.tryserver.chromium.linux',
3509 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413510 }
[email protected]0bb112362014-07-26 04:38:323511 master = master_map.get(bot)
3512 if not master:
wnwen4fbaab82016-05-25 12:54:363513 if 'android' in bot:
tandriie5587792016-07-14 00:34:503514 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363515 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503516 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323517 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503518 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323519 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503520 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323521 return master
[email protected]1bfb8322014-04-23 01:02:413522
3523
[email protected]ca8d1982009-02-19 16:33:123524def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543525 results = []
[email protected]1f7b4172010-01-28 01:17:343526 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543527 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273528 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343529 input_api,
3530 output_api,
[email protected]2fdd1f362013-01-16 03:56:033531 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273532
jam93a6ee792017-02-08 23:59:223533 results.extend(
3534 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543535 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3536 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413537 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3538 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543539 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143540
3541
3542def _CheckTranslationScreenshots(input_api, output_api):
3543 PART_FILE_TAG = "part"
3544 import os
3545 import sys
3546 from io import StringIO
3547
3548 try:
3549 old_sys_path = sys.path
3550 sys.path = sys.path + [input_api.os_path.join(
3551 input_api.PresubmitLocalPath(), 'tools', 'grit')]
3552 import grit.grd_reader
3553 import grit.node.message
3554 import grit.util
3555 finally:
3556 sys.path = old_sys_path
3557
3558 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
3559 """Load the grd file and return a dict of message ids to messages.
3560
3561 Ignores any nested grdp files pointed by <part> tag.
3562 """
3563 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
3564 stop_after=None, first_ids_file=None,
3565 debug=False, defines=None,
3566 tags_to_ignore=set([PART_FILE_TAG]))
3567 return {
3568 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
3569 grit.node.message.MessageNode)
3570 }
3571
3572 def _GetGrdpMessagesFromString(grdp_string):
3573 """Parses the contents of a grdp file given in grdp_string.
3574
3575 grd_reader can't parse grdp files directly. Instead, this creates a
3576 temporary directory with a grd file pointing to the grdp file, and loads the
3577 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
3578 """
3579 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
3580 <grit latest_public_release="1" current_release="1">
3581 <release seq="1">
3582 <messages>
3583 <part file="sub.grdp" />
3584 </messages>
3585 </release>
3586 </grit>
3587 """
3588 with grit.util.TempDir({'main.grd': WRAPPER,
3589 'sub.grdp': grdp_string}) as temp_dir:
3590 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
3591
3592 new_or_added_paths = set(f.LocalPath()
3593 for f in input_api.AffectedFiles()
3594 if (f.Action() == 'A' or f.Action() == 'M'))
3595 removed_paths = set(f.LocalPath()
3596 for f in input_api.AffectedFiles(include_deletes=True)
3597 if f.Action() == 'D')
3598
3599 affected_grds = [f for f in input_api.AffectedFiles()
3600 if (f.LocalPath().endswith('.grd') or
3601 f.LocalPath().endswith('.grdp'))]
3602 affected_png_paths = [f.AbsoluteLocalPath()
3603 for f in input_api.AffectedFiles()
3604 if (f.LocalPath().endswith('.png'))]
3605
3606 # Check for screenshots. Developers can upload screenshots using
3607 # tools/translation/upload_screenshots.py which finds and uploads
3608 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
3609 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
3610 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
3611 #
3612 # The logic here is as follows:
3613 #
3614 # - If the CL has a .png file under the screenshots directory for a grd
3615 # file, warn the developer. Actual images should never be checked into the
3616 # Chrome repo.
3617 #
3618 # - If the CL contains modified or new messages in grd files and doesn't
3619 # contain the corresponding .sha1 files, warn the developer to add images
3620 # and upload them via tools/translation/upload_screenshots.py.
3621 #
3622 # - If the CL contains modified or new messages in grd files and the
3623 # corresponding .sha1 files, everything looks good.
3624 #
3625 # - If the CL contains removed messages in grd files but the corresponding
3626 # .sha1 files aren't removed, warn the developer to remove them.
3627 unnecessary_screenshots = []
3628 missing_sha1 = []
3629 unnecessary_sha1_files = []
3630
3631
3632 def _CheckScreenshotAdded(screenshots_dir, message_id):
3633 sha1_path = input_api.os_path.join(
3634 screenshots_dir, message_id + '.png.sha1')
3635 if sha1_path not in new_or_added_paths:
3636 missing_sha1.append(sha1_path)
3637
3638
3639 def _CheckScreenshotRemoved(screenshots_dir, message_id):
3640 sha1_path = input_api.os_path.join(
3641 screenshots_dir, message_id + '.png.sha1')
3642 if sha1_path not in removed_paths:
3643 unnecessary_sha1_files.append(sha1_path)
3644
3645
3646 for f in affected_grds:
3647 file_path = f.LocalPath()
3648 old_id_to_msg_map = {}
3649 new_id_to_msg_map = {}
3650 if file_path.endswith('.grdp'):
3651 if f.OldContents():
3652 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393653 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143654 if f.NewContents():
3655 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393656 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143657 else:
3658 if f.OldContents():
3659 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393660 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143661 if f.NewContents():
3662 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393663 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143664
3665 # Compute added, removed and modified message IDs.
3666 old_ids = set(old_id_to_msg_map)
3667 new_ids = set(new_id_to_msg_map)
3668 added_ids = new_ids - old_ids
3669 removed_ids = old_ids - new_ids
3670 modified_ids = set([])
3671 for key in old_ids.intersection(new_ids):
3672 if (old_id_to_msg_map[key].FormatXml()
3673 != new_id_to_msg_map[key].FormatXml()):
3674 modified_ids.add(key)
3675
3676 grd_name, ext = input_api.os_path.splitext(
3677 input_api.os_path.basename(file_path))
3678 screenshots_dir = input_api.os_path.join(
3679 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
3680
3681 # Check the screenshot directory for .png files. Warn if there is any.
3682 for png_path in affected_png_paths:
3683 if png_path.startswith(screenshots_dir):
3684 unnecessary_screenshots.append(png_path)
3685
3686 for added_id in added_ids:
3687 _CheckScreenshotAdded(screenshots_dir, added_id)
3688
3689 for modified_id in modified_ids:
3690 _CheckScreenshotAdded(screenshots_dir, modified_id)
3691
3692 for removed_id in removed_ids:
3693 _CheckScreenshotRemoved(screenshots_dir, removed_id)
3694
3695 results = []
3696 if unnecessary_screenshots:
3697 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393698 'Do not include actual screenshots in the changelist. Run '
3699 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143700 sorted(unnecessary_screenshots)))
3701
3702 if missing_sha1:
3703 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393704 'You are adding or modifying UI strings.\n'
3705 'To ensure the best translations, take screenshots of the relevant UI '
3706 '(https://g.co/chrome/translation) and add these files to your '
3707 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143708
3709 if unnecessary_sha1_files:
3710 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393711 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143712 sorted(unnecessary_sha1_files)))
3713
3714 return results