blob: 38a306d39714ddcac3c0c2ad4dd55370bcc6b5e4 [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[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4918 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0419 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 (
tzik3f295992018-12-04 20:32:23346 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04347 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41348 ),
jame2d1a952016-04-02 00:27:10349 ),
fdorayc4ac18d2017-05-01 21:39:59350 (
Gabriel Charette7cc6c432018-04-25 20:52:02351 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59352 (
353 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
354 ),
355 False,
356 (),
357 ),
358 (
Gabriel Charette7cc6c432018-04-25 20:52:02359 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59360 (
361 'Consider using THREAD_CHECKER macros instead of the class directly.',
362 ),
363 False,
364 (),
365 ),
dbeamb6f4fde2017-06-15 04:03:06366 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06367 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
368 (
369 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
370 'deprecated (http://crbug.com/634507). Please avoid converting away',
371 'from the Time types in Chromium code, especially if any math is',
372 'being done on time values. For interfacing with platform/library',
373 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
374 'type converter methods instead. For faking TimeXXX values (for unit',
375 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
376 'other use cases, please contact base/time/OWNERS.',
377 ),
378 False,
379 (),
380 ),
381 (
dbeamb6f4fde2017-06-15 04:03:06382 'CallJavascriptFunctionUnsafe',
383 (
384 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
385 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
386 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
387 ),
388 False,
389 (
Egor Paskoce145c42018-09-28 19:31:04390 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
391 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
392 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06393 ),
394 ),
dskiba1474c2bfd62017-07-20 02:19:24395 (
396 'leveldb::DB::Open',
397 (
398 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
399 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
400 "Chrome's tracing, making their memory usage visible.",
401 ),
402 True,
403 (
404 r'^third_party/leveldatabase/.*\.(cc|h)$',
405 ),
Gabriel Charette0592c3a2017-07-26 12:02:04406 ),
407 (
Chris Mumfordc38afb62017-10-09 17:55:08408 'leveldb::NewMemEnv',
409 (
410 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58411 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
412 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08413 ),
414 True,
415 (
416 r'^third_party/leveldatabase/.*\.(cc|h)$',
417 ),
418 ),
419 (
Gabriel Charetted9839bc2017-07-29 14:17:47420 'RunLoop::QuitCurrent',
421 (
Robert Liao64b7ab22017-08-04 23:03:43422 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
423 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47424 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41425 False,
Gabriel Charetted9839bc2017-07-29 14:17:47426 (),
Gabriel Charettea44975052017-08-21 23:14:04427 ),
428 (
429 'base::ScopedMockTimeMessageLoopTaskRunner',
430 (
Gabriel Charette87cc1af2018-04-25 20:52:51431 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
432 'ScopedTaskEnvironment::MainThreadType::MOCK_TIME. There are still a',
433 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
434 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
435 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04436 ),
Gabriel Charette87cc1af2018-04-25 20:52:51437 False,
Gabriel Charettea44975052017-08-21 23:14:04438 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57439 ),
440 (
441 r'std::regex',
442 (
443 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02444 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57445 ),
446 True,
447 (),
Francois Doray43670e32017-09-27 12:40:38448 ),
449 (
450 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
451 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
452 (
453 'Use the new API in base/threading/thread_restrictions.h.',
454 ),
Gabriel Charette04b138f2018-08-06 00:03:22455 False,
Francois Doray43670e32017-09-27 12:40:38456 (),
457 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38458 (
459 r'/\bbase::Bind\(',
460 (
Gabriel Charette147335ea2018-03-22 15:59:19461 'Please consider using base::Bind{Once,Repeating} instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02462 'of base::Bind. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38463 ),
464 False,
465 (),
466 ),
467 (
468 r'/\bbase::Callback<',
469 (
Gabriel Charette147335ea2018-03-22 15:59:19470 'Please consider using base::{Once,Repeating}Callback instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02471 'of base::Callback. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38472 ),
473 False,
474 (),
475 ),
476 (
477 r'/\bbase::Closure\b',
478 (
Gabriel Charette147335ea2018-03-22 15:59:19479 'Please consider using base::{Once,Repeating}Closure instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02480 'of base::Closure. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38481 ),
482 False,
483 (),
484 ),
Victor Costan3653df62018-02-08 21:38:16485 (
Gabriel Charette147335ea2018-03-22 15:59:19486 r'RunMessageLoop',
487 (
488 'RunMessageLoop is deprecated, use RunLoop instead.',
489 ),
490 False,
491 (),
492 ),
493 (
494 r'RunThisRunLoop',
495 (
496 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
497 ),
498 False,
499 (),
500 ),
501 (
502 r'RunAllPendingInMessageLoop()',
503 (
504 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
505 "if you're convinced you need this.",
506 ),
507 False,
508 (),
509 ),
510 (
511 r'RunAllPendingInMessageLoop(BrowserThread',
512 (
513 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
514 'BrowserThread::UI, TestBrowserThreadBundle::RunIOThreadUntilIdle',
515 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
516 'async events instead of flushing threads.',
517 ),
518 False,
519 (),
520 ),
521 (
522 r'MessageLoopRunner',
523 (
524 'MessageLoopRunner is deprecated, use RunLoop instead.',
525 ),
526 False,
527 (),
528 ),
529 (
530 r'GetDeferredQuitTaskForRunLoop',
531 (
532 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
533 "gab@ if you found a use case where this is the only solution.",
534 ),
535 False,
536 (),
537 ),
538 (
Victor Costan3653df62018-02-08 21:38:16539 'sqlite3_initialize',
540 (
541 'Instead of sqlite3_initialize, depend on //sql, ',
542 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
543 ),
544 True,
545 (
546 r'^sql/initialization\.(cc|h)$',
547 r'^third_party/sqlite/.*\.(c|cc|h)$',
548 ),
549 ),
Matt Menke7f520a82018-03-28 21:38:37550 (
551 'net::URLFetcher',
552 (
553 'net::URLFetcher should no longer be used in content embedders. ',
554 'Instead, use network::SimpleURLLoader instead, which supports ',
555 'an out-of-process network stack. ',
556 'net::URLFetcher may still be used in binaries that do not embed',
557 'content.',
558 ),
Matt Menke59716d02018-04-05 12:45:53559 False,
Matt Menke7f520a82018-03-28 21:38:37560 (
Egor Paskoce145c42018-09-28 19:31:04561 r'^ios[\\/].*\.(cc|h)$',
562 r'.*[\\/]ios[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:37563 r'.*_ios\.(cc|h)$',
Egor Paskoce145c42018-09-28 19:31:04564 r'^net[\\/].*\.(cc|h)$',
565 r'.*[\\/]tools[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:37566 ),
567 ),
jdoerried7d10ab2018-04-27 10:46:13568 (
tzik5de2157f2018-05-08 03:42:47569 r'std::random_shuffle',
570 (
571 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
572 'base::RandomShuffle instead.'
573 ),
574 True,
575 (),
576 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24577 (
578 'ios/web/public/test/http_server',
579 (
580 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
581 ),
582 False,
583 (),
584 ),
[email protected]127f18ec2012-06-16 05:05:59585)
586
wnwenbdc444e2016-05-25 13:44:15587
mlamouria82272622014-09-16 18:45:04588_IPC_ENUM_TRAITS_DEPRECATED = (
589 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50590 'See http://www.chromium.org/Home/chromium-security/education/'
591 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:04592
Stephen Martinis97a394142018-06-07 23:06:05593_LONG_PATH_ERROR = (
594 'Some files included in this CL have file names that are too long (> 200'
595 ' characters). If committed, these files will cause issues on Windows. See'
596 ' https://crbug.com/612667 for more details.'
597)
598
Shenghua Zhangbfaa38b82017-11-16 21:58:02599_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:04600 r".*[\\/]BuildHooksAndroidImpl\.java",
601 r".*[\\/]LicenseContentProvider\.java",
602 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:28603 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:02604]
[email protected]127f18ec2012-06-16 05:05:59605
Sean Kau46e29bc2017-08-28 16:31:16606# These paths contain test data and other known invalid JSON files.
607_KNOWN_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:04608 r'test[\\/]data[\\/]',
609 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
610 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:04611 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:43612 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:16613]
614
615
[email protected]b00342e7f2013-03-26 16:21:54616_VALID_OS_MACROS = (
617 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08618 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54619 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:12620 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:54621 'OS_BSD',
622 'OS_CAT', # For testing.
623 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:04624 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:54625 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37626 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54627 'OS_IOS',
628 'OS_LINUX',
629 'OS_MACOSX',
630 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21631 'OS_NACL_NONSFI',
632 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12633 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54634 'OS_OPENBSD',
635 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37636 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54637 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54638 'OS_WIN',
639)
640
641
agrievef32bcc72016-04-04 14:57:40642_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:39643 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36644 'base/android/jni_generator/jni_generator.pydeps',
645 'base/android/jni_generator/jni_registration_generator.pydeps',
646 'build/android/gyp/aar.pydeps',
647 'build/android/gyp/aidl.pydeps',
648 'build/android/gyp/apkbuilder.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36649 'build/android/gyp/bytecode_processor.pydeps',
650 'build/android/gyp/compile_resources.pydeps',
651 'build/android/gyp/create_bundle_wrapper_script.pydeps',
652 'build/android/gyp/copy_ex.pydeps',
653 'build/android/gyp/create_app_bundle.pydeps',
654 'build/android/gyp/create_apk_operations_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36655 'build/android/gyp/create_java_binary_script.pydeps',
656 'build/android/gyp/create_stack_script.pydeps',
657 'build/android/gyp/create_test_runner_script.pydeps',
658 'build/android/gyp/create_tool_wrapper.pydeps',
659 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:59660 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36661 'build/android/gyp/dex.pydeps',
662 'build/android/gyp/dist_aar.pydeps',
663 'build/android/gyp/emma_instr.pydeps',
664 'build/android/gyp/filter_zip.pydeps',
665 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:36666 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36667 'build/android/gyp/ijar.pydeps',
668 'build/android/gyp/java_cpp_enum.pydeps',
669 'build/android/gyp/javac.pydeps',
670 'build/android/gyp/jinja_template.pydeps',
671 'build/android/gyp/lint.pydeps',
672 'build/android/gyp/main_dex_list.pydeps',
673 'build/android/gyp/merge_jar_info_files.pydeps',
674 'build/android/gyp/merge_manifest.pydeps',
675 'build/android/gyp/prepare_resources.pydeps',
676 'build/android/gyp/proguard.pydeps',
677 'build/android/gyp/write_build_config.pydeps',
678 'build/android/gyp/write_ordered_libraries.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:56679 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36680 'build/android/incremental_install/generate_android_manifest.pydeps',
681 'build/android/incremental_install/write_installer_json.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22682 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:40683 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04684 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36685 'build/protoc_java.pydeps',
Sam Maier3599daa2018-11-26 18:02:59686 ('build/secondary/third_party/android_platform/'
687 'development/scripts/stack.pydeps'),
agrieve732db3a2016-04-26 19:18:19688 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40689]
690
wnwenbdc444e2016-05-25 13:44:15691
agrievef32bcc72016-04-04 14:57:40692_GENERIC_PYDEPS_FILES = [
John Chencde89192018-01-27 21:18:40693 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Cole Winstanley7045a1b2018-08-27 23:37:29694 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22695 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:40696]
697
wnwenbdc444e2016-05-25 13:44:15698
agrievef32bcc72016-04-04 14:57:40699_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
700
701
Eric Boren6fd2b932018-01-25 15:05:08702# Bypass the AUTHORS check for these accounts.
703_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:29704 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
705 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:08706 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
Eric Boren57cc805b2018-08-20 17:28:32707 'spirv', 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:59708 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:45709 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:59710 ) | set('%[email protected]' % s
Robert Ma7f024172018-11-01 20:59:22711 for s in ('v8-ci-autoroll-builder', 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:04712 ) | set('%[email protected]' % s
713 for s in ('chromium-autoroll',)
714 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:30715 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:08716
717
[email protected]55459852011-08-10 15:17:19718def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
719 """Attempts to prevent use of functions intended only for testing in
720 non-testing code. For now this is just a best-effort implementation
721 that ignores header files and may have some false positives. A
722 better implementation would probably need a proper C++ parser.
723 """
724 # We only scan .cc files and the like, as the declaration of
725 # for-testing functions in header files are hard to distinguish from
726 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49727 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:19728
jochenc0d4808c2015-07-27 09:25:42729 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19730 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09731 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19732 exclusion_pattern = input_api.re.compile(
733 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
734 base_function_pattern, base_function_pattern))
735
736 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44737 black_list = (_EXCLUDED_PATHS +
738 _TEST_CODE_EXCLUDED_PATHS +
739 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19740 return input_api.FilterSourceFile(
741 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49742 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:19743 black_list=black_list)
744
745 problems = []
746 for f in input_api.AffectedSourceFiles(FilterFile):
747 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24748 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03749 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46750 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03751 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19752 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03753 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19754
755 if problems:
[email protected]f7051d52013-04-02 18:31:42756 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03757 else:
758 return []
[email protected]55459852011-08-10 15:17:19759
760
Vaclav Brozek7dbc28c2018-03-27 08:35:23761def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
762 """This is a simplified version of
763 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
764 """
765 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
766 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
767 name_pattern = r'ForTest(s|ing)?'
768 # Describes an occurrence of "ForTest*" inside a // comment.
769 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
770 # Catch calls.
771 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
772 # Ignore definitions. (Comments are ignored separately.)
773 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
774
775 problems = []
776 sources = lambda x: input_api.FilterSourceFile(
777 x,
778 black_list=(('(?i).*test', r'.*\/junit\/')
779 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49780 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:23781 )
782 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
783 local_path = f.LocalPath()
784 is_inside_javadoc = False
785 for line_number, line in f.ChangedContents():
786 if is_inside_javadoc and javadoc_end_re.search(line):
787 is_inside_javadoc = False
788 if not is_inside_javadoc and javadoc_start_re.search(line):
789 is_inside_javadoc = True
790 if is_inside_javadoc:
791 continue
792 if (inclusion_re.search(line) and
793 not comment_re.search(line) and
794 not exclusion_re.search(line)):
795 problems.append(
796 '%s:%d\n %s' % (local_path, line_number, line.strip()))
797
798 if problems:
799 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
800 else:
801 return []
802
803
[email protected]10689ca2011-09-02 02:31:54804def _CheckNoIOStreamInHeaders(input_api, output_api):
805 """Checks to make sure no .h files include <iostream>."""
806 files = []
807 pattern = input_api.re.compile(r'^#include\s*<iostream>',
808 input_api.re.MULTILINE)
809 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
810 if not f.LocalPath().endswith('.h'):
811 continue
812 contents = input_api.ReadFile(f)
813 if pattern.search(contents):
814 files.append(f)
815
816 if len(files):
yolandyandaabc6d2016-04-18 18:29:39817 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06818 'Do not #include <iostream> in header files, since it inserts static '
819 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54820 '#include <ostream>. See http://crbug.com/94794',
821 files) ]
822 return []
823
Danil Chapovalov3518f362018-08-11 16:13:43824def _CheckNoStrCatRedefines(input_api, output_api):
825 """Checks no windows headers with StrCat redefined are included directly."""
826 files = []
827 pattern_deny = input_api.re.compile(
828 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
829 input_api.re.MULTILINE)
830 pattern_allow = input_api.re.compile(
831 r'^#include\s"base/win/windows_defines.inc"',
832 input_api.re.MULTILINE)
833 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
834 contents = input_api.ReadFile(f)
835 if pattern_deny.search(contents) and not pattern_allow.search(contents):
836 files.append(f.LocalPath())
837
838 if len(files):
839 return [output_api.PresubmitError(
840 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
841 'directly since they pollute code with StrCat macro. Instead, '
842 'include matching header from base/win. See http://crbug.com/856536',
843 files) ]
844 return []
845
[email protected]10689ca2011-09-02 02:31:54846
[email protected]72df4e782012-06-21 16:28:18847def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52848 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18849 problems = []
850 for f in input_api.AffectedFiles():
851 if (not f.LocalPath().endswith(('.cc', '.mm'))):
852 continue
853
854 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04855 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18856 problems.append(' %s:%d' % (f.LocalPath(), line_num))
857
858 if not problems:
859 return []
860 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
861 '\n'.join(problems))]
862
Dominic Battre033531052018-09-24 15:45:34863def _CheckNoDISABLETypoInTests(input_api, output_api):
864 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
865
866 This test warns if somebody tries to disable a test with the DISABLE_ prefix
867 instead of DISABLED_. To filter false positives, reports are only generated
868 if a corresponding MAYBE_ line exists.
869 """
870 problems = []
871
872 # The following two patterns are looked for in tandem - is a test labeled
873 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
874 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
875 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
876
877 # This is for the case that a test is disabled on all platforms.
878 full_disable_pattern = input_api.re.compile(
879 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
880 input_api.re.MULTILINE)
881
Katie Df13948e2018-09-25 07:33:44882 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:34883 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
884 continue
885
886 # Search for MABYE_, DISABLE_ pairs.
887 disable_lines = {} # Maps of test name to line number.
888 maybe_lines = {}
889 for line_num, line in f.ChangedContents():
890 disable_match = disable_pattern.search(line)
891 if disable_match:
892 disable_lines[disable_match.group(1)] = line_num
893 maybe_match = maybe_pattern.search(line)
894 if maybe_match:
895 maybe_lines[maybe_match.group(1)] = line_num
896
897 # Search for DISABLE_ occurrences within a TEST() macro.
898 disable_tests = set(disable_lines.keys())
899 maybe_tests = set(maybe_lines.keys())
900 for test in disable_tests.intersection(maybe_tests):
901 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
902
903 contents = input_api.ReadFile(f)
904 full_disable_match = full_disable_pattern.search(contents)
905 if full_disable_match:
906 problems.append(' %s' % f.LocalPath())
907
908 if not problems:
909 return []
910 return [
911 output_api.PresubmitPromptWarning(
912 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
913 '\n'.join(problems))
914 ]
915
[email protected]72df4e782012-06-21 16:28:18916
danakj61c1aa22015-10-26 19:55:52917def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57918 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52919 errors = []
920 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
921 input_api.re.MULTILINE)
922 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
923 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
924 continue
925 for lnum, line in f.ChangedContents():
926 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17927 errors.append(output_api.PresubmitError(
928 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57929 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17930 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52931 return errors
932
933
mcasasb7440c282015-02-04 14:52:19934def _FindHistogramNameInLine(histogram_name, line):
935 """Tries to find a histogram name or prefix in a line."""
936 if not "affected-histogram" in line:
937 return histogram_name in line
938 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
939 # the histogram_name.
940 if not '"' in line:
941 return False
942 histogram_prefix = line.split('\"')[1]
943 return histogram_prefix in histogram_name
944
945
946def _CheckUmaHistogramChanges(input_api, output_api):
947 """Check that UMA histogram names in touched lines can still be found in other
948 lines of the patch or in histograms.xml. Note that this check would not catch
949 the reverse: changes in histograms.xml not matched in the code itself."""
950 touched_histograms = []
951 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:47952 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
953 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
954 name_pattern = r'"(.*?)"'
955 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
956 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
957 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
958 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
959 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:17960 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:19961 for f in input_api.AffectedFiles():
962 # If histograms.xml itself is modified, keep the modified lines for later.
963 if f.LocalPath().endswith(('histograms.xml')):
964 histograms_xml_modifications = f.ChangedContents()
965 continue
Vaclav Brozekbdac817c2018-03-24 06:30:47966 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
967 single_line_re = single_line_c_re
968 split_line_prefix_re = split_line_c_prefix_re
969 elif f.LocalPath().endswith(('java')):
970 single_line_re = single_line_java_re
971 split_line_prefix_re = split_line_java_prefix_re
972 else:
mcasasb7440c282015-02-04 14:52:19973 continue
974 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:17975 if last_line_matched_prefix:
976 suffix_found = split_line_suffix_re.search(line)
977 if suffix_found :
978 touched_histograms.append([suffix_found.group(1), f, line_num])
979 last_line_matched_prefix = False
980 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:06981 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:19982 if found:
983 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:17984 continue
985 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:19986
987 # Search for the touched histogram names in the local modifications to
988 # histograms.xml, and, if not found, on the base histograms.xml file.
989 unmatched_histograms = []
990 for histogram_info in touched_histograms:
991 histogram_name_found = False
992 for line_num, line in histograms_xml_modifications:
993 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
994 if histogram_name_found:
995 break
996 if not histogram_name_found:
997 unmatched_histograms.append(histogram_info)
998
eromanb90c82e7e32015-04-01 15:13:49999 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191000 problems = []
1001 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491002 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191003 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451004 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191005 histogram_name_found = False
1006 for line in histograms_xml:
1007 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
1008 if histogram_name_found:
1009 break
1010 if not histogram_name_found:
1011 problems.append(' [%s:%d] %s' %
1012 (f.LocalPath(), line_num, histogram_name))
1013
1014 if not problems:
1015 return []
1016 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1017 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491018 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191019
wnwenbdc444e2016-05-25 13:44:151020
yolandyandaabc6d2016-04-18 18:29:391021def _CheckFlakyTestUsage(input_api, output_api):
1022 """Check that FlakyTest annotation is our own instead of the android one"""
1023 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1024 files = []
1025 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1026 if f.LocalPath().endswith('Test.java'):
1027 if pattern.search(input_api.ReadFile(f)):
1028 files.append(f)
1029 if len(files):
1030 return [output_api.PresubmitError(
1031 'Use org.chromium.base.test.util.FlakyTest instead of '
1032 'android.test.FlakyTest',
1033 files)]
1034 return []
mcasasb7440c282015-02-04 14:52:191035
wnwenbdc444e2016-05-25 13:44:151036
[email protected]8ea5d4b2011-09-13 21:49:221037def _CheckNoNewWStrings(input_api, output_api):
1038 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271039 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221040 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201041 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571042 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341043 '/win/' in f.LocalPath() or
1044 'chrome_elf' in f.LocalPath() or
1045 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201046 continue
[email protected]8ea5d4b2011-09-13 21:49:221047
[email protected]a11dbe9b2012-08-07 01:32:581048 allowWString = False
[email protected]b5c24292011-11-28 14:38:201049 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581050 if 'presubmit: allow wstring' in line:
1051 allowWString = True
1052 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271053 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581054 allowWString = False
1055 else:
1056 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221057
[email protected]55463aa62011-10-12 00:48:271058 if not problems:
1059 return []
1060 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581061 ' If you are calling a cross-platform API that accepts a wstring, '
1062 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271063 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221064
1065
[email protected]2a8ac9c2011-10-19 17:20:441066def _CheckNoDEPSGIT(input_api, output_api):
1067 """Make sure .DEPS.git is never modified manually."""
1068 if any(f.LocalPath().endswith('.DEPS.git') for f in
1069 input_api.AffectedFiles()):
1070 return [output_api.PresubmitError(
1071 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1072 'automated system based on what\'s in DEPS and your changes will be\n'
1073 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501074 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1075 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441076 'for more information')]
1077 return []
1078
1079
tandriief664692014-09-23 14:51:471080def _CheckValidHostsInDEPS(input_api, output_api):
1081 """Checks that DEPS file deps are from allowed_hosts."""
1082 # Run only if DEPS file has been modified to annoy fewer bystanders.
1083 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1084 return []
1085 # Outsource work to gclient verify
1086 try:
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201087 input_api.subprocess.check_output(['gclient', 'verify'],
1088 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471089 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201090 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471091 return [output_api.PresubmitError(
1092 'DEPS file must have only git dependencies.',
1093 long_text=error.output)]
1094
1095
[email protected]127f18ec2012-06-16 05:05:591096def _CheckNoBannedFunctions(input_api, output_api):
1097 """Make sure that banned functions are not used."""
1098 warnings = []
1099 errors = []
1100
wnwenbdc444e2016-05-25 13:44:151101 def IsBlacklisted(affected_file, blacklist):
1102 local_path = affected_file.LocalPath()
1103 for item in blacklist:
1104 if input_api.re.match(item, local_path):
1105 return True
1106 return False
1107
Sylvain Defresnea8b73d252018-02-28 15:45:541108 def IsIosObcjFile(affected_file):
1109 local_path = affected_file.LocalPath()
1110 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1111 return False
1112 basename = input_api.os_path.basename(local_path)
1113 if 'ios' in basename.split('_'):
1114 return True
1115 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1116 if sep and 'ios' in local_path.split(sep):
1117 return True
1118 return False
1119
wnwenbdc444e2016-05-25 13:44:151120 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
1121 matched = False
1122 if func_name[0:1] == '/':
1123 regex = func_name[1:]
1124 if input_api.re.search(regex, line):
1125 matched = True
1126 elif func_name in line:
dchenge07de812016-06-20 19:27:171127 matched = True
wnwenbdc444e2016-05-25 13:44:151128 if matched:
dchenge07de812016-06-20 19:27:171129 problems = warnings
wnwenbdc444e2016-05-25 13:44:151130 if error:
dchenge07de812016-06-20 19:27:171131 problems = errors
wnwenbdc444e2016-05-25 13:44:151132 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1133 for message_line in message:
1134 problems.append(' %s' % message_line)
1135
Eric Stevensona9a980972017-09-23 00:04:411136 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1137 for f in input_api.AffectedFiles(file_filter=file_filter):
1138 for line_num, line in f.ChangedContents():
1139 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1140 CheckForMatch(f, line_num, line, func_name, message, error)
1141
[email protected]127f18ec2012-06-16 05:05:591142 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1143 for f in input_api.AffectedFiles(file_filter=file_filter):
1144 for line_num, line in f.ChangedContents():
1145 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151146 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591147
Sylvain Defresnea8b73d252018-02-28 15:45:541148 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1149 for line_num, line in f.ChangedContents():
1150 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1151 CheckForMatch(f, line_num, line, func_name, message, error)
1152
[email protected]127f18ec2012-06-16 05:05:591153 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1154 for f in input_api.AffectedFiles(file_filter=file_filter):
1155 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491156 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491157 if IsBlacklisted(f, excluded_paths):
1158 continue
wnwenbdc444e2016-05-25 13:44:151159 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591160
1161 result = []
1162 if (warnings):
1163 result.append(output_api.PresubmitPromptWarning(
1164 'Banned functions were used.\n' + '\n'.join(warnings)))
1165 if (errors):
1166 result.append(output_api.PresubmitError(
1167 'Banned functions were used.\n' + '\n'.join(errors)))
1168 return result
1169
1170
[email protected]6c063c62012-07-11 19:11:061171def _CheckNoPragmaOnce(input_api, output_api):
1172 """Make sure that banned functions are not used."""
1173 files = []
1174 pattern = input_api.re.compile(r'^#pragma\s+once',
1175 input_api.re.MULTILINE)
1176 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1177 if not f.LocalPath().endswith('.h'):
1178 continue
1179 contents = input_api.ReadFile(f)
1180 if pattern.search(contents):
1181 files.append(f)
1182
1183 if files:
1184 return [output_api.PresubmitError(
1185 'Do not use #pragma once in header files.\n'
1186 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1187 files)]
1188 return []
1189
[email protected]127f18ec2012-06-16 05:05:591190
[email protected]e7479052012-09-19 00:26:121191def _CheckNoTrinaryTrueFalse(input_api, output_api):
1192 """Checks to make sure we don't introduce use of foo ? true : false."""
1193 problems = []
1194 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1195 for f in input_api.AffectedFiles():
1196 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1197 continue
1198
1199 for line_num, line in f.ChangedContents():
1200 if pattern.match(line):
1201 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1202
1203 if not problems:
1204 return []
1205 return [output_api.PresubmitPromptWarning(
1206 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1207 '\n'.join(problems))]
1208
1209
[email protected]55f9f382012-07-31 11:02:181210def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281211 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181212 change. Breaking - rules is an error, breaking ! rules is a
1213 warning.
1214 """
mohan.reddyf21db962014-10-16 12:26:471215 import sys
[email protected]55f9f382012-07-31 11:02:181216 # We need to wait until we have an input_api object and use this
1217 # roundabout construct to import checkdeps because this file is
1218 # eval-ed and thus doesn't have __file__.
1219 original_sys_path = sys.path
1220 try:
1221 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471222 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181223 import checkdeps
1224 from cpp_checker import CppChecker
Jinsuk Kim5a092672017-10-24 22:42:241225 from java_checker import JavaChecker
rhalavati08acd232017-04-03 07:23:281226 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:181227 from rules import Rule
1228 finally:
1229 # Restore sys.path to what it was before.
1230 sys.path = original_sys_path
1231
1232 added_includes = []
rhalavati08acd232017-04-03 07:23:281233 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241234 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181235 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:281236 if CppChecker.IsCppFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501237 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081238 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
rhalavati08acd232017-04-03 07:23:281239 elif ProtoChecker.IsProtoFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501240 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081241 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241242 elif JavaChecker.IsJavaFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501243 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081244 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181245
[email protected]26385172013-05-09 23:11:351246 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181247
1248 error_descriptions = []
1249 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281250 error_subjects = set()
1251 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181252 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1253 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081254 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181255 description_with_path = '%s\n %s' % (path, rule_description)
1256 if rule_type == Rule.DISALLOW:
1257 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281258 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181259 else:
1260 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281261 warning_subjects.add("#includes")
1262
1263 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1264 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081265 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281266 description_with_path = '%s\n %s' % (path, rule_description)
1267 if rule_type == Rule.DISALLOW:
1268 error_descriptions.append(description_with_path)
1269 error_subjects.add("imports")
1270 else:
1271 warning_descriptions.append(description_with_path)
1272 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181273
Jinsuk Kim5a092672017-10-24 22:42:241274 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021275 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081276 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241277 description_with_path = '%s\n %s' % (path, rule_description)
1278 if rule_type == Rule.DISALLOW:
1279 error_descriptions.append(description_with_path)
1280 error_subjects.add("imports")
1281 else:
1282 warning_descriptions.append(description_with_path)
1283 warning_subjects.add("imports")
1284
[email protected]55f9f382012-07-31 11:02:181285 results = []
1286 if error_descriptions:
1287 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281288 'You added one or more %s that violate checkdeps rules.'
1289 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181290 error_descriptions))
1291 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421292 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281293 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181294 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281295 '%s? See relevant DEPS file(s) for details and contacts.' %
1296 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181297 warning_descriptions))
1298 return results
1299
1300
[email protected]fbcafe5a2012-08-08 15:31:221301def _CheckFilePermissions(input_api, output_api):
1302 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151303 if input_api.platform == 'win32':
1304 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291305 checkperms_tool = input_api.os_path.join(
1306 input_api.PresubmitLocalPath(),
1307 'tools', 'checkperms', 'checkperms.py')
1308 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471309 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391310 with input_api.CreateTemporaryFile() as file_list:
1311 for f in input_api.AffectedFiles():
1312 # checkperms.py file/directory arguments must be relative to the
1313 # repository.
1314 file_list.write(f.LocalPath() + '\n')
1315 file_list.close()
1316 args += ['--file-list', file_list.name]
1317 try:
1318 input_api.subprocess.check_output(args)
1319 return []
1320 except input_api.subprocess.CalledProcessError as error:
1321 return [output_api.PresubmitError(
1322 'checkperms.py failed:',
1323 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221324
1325
robertocn832f5992017-01-04 19:01:301326def _CheckTeamTags(input_api, output_api):
1327 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1328 checkteamtags_tool = input_api.os_path.join(
1329 input_api.PresubmitLocalPath(),
1330 'tools', 'checkteamtags', 'checkteamtags.py')
1331 args = [input_api.python_executable, checkteamtags_tool,
1332 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221333 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301334 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1335 'OWNERS']
1336 try:
1337 if files:
1338 input_api.subprocess.check_output(args + files)
1339 return []
1340 except input_api.subprocess.CalledProcessError as error:
1341 return [output_api.PresubmitError(
1342 'checkteamtags.py failed:',
1343 long_text=error.output)]
1344
1345
[email protected]c8278b32012-10-30 20:35:491346def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1347 """Makes sure we don't include ui/aura/window_property.h
1348 in header files.
1349 """
1350 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1351 errors = []
1352 for f in input_api.AffectedFiles():
1353 if not f.LocalPath().endswith('.h'):
1354 continue
1355 for line_num, line in f.ChangedContents():
1356 if pattern.match(line):
1357 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1358
1359 results = []
1360 if errors:
1361 results.append(output_api.PresubmitError(
1362 'Header files should not include ui/aura/window_property.h', errors))
1363 return results
1364
1365
[email protected]70ca77752012-11-20 03:45:031366def _CheckForVersionControlConflictsInFile(input_api, f):
1367 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1368 errors = []
1369 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:231370 if f.LocalPath().endswith('.md'):
1371 # First-level headers in markdown look a lot like version control
1372 # conflict markers. http://daringfireball.net/projects/markdown/basics
1373 continue
[email protected]70ca77752012-11-20 03:45:031374 if pattern.match(line):
1375 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1376 return errors
1377
1378
1379def _CheckForVersionControlConflicts(input_api, output_api):
1380 """Usually this is not intentional and will cause a compile failure."""
1381 errors = []
1382 for f in input_api.AffectedFiles():
1383 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1384
1385 results = []
1386 if errors:
1387 results.append(output_api.PresubmitError(
1388 'Version control conflict markers found, please resolve.', errors))
1389 return results
1390
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201391
estadee17314a02017-01-12 16:22:161392def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1393 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1394 errors = []
1395 for f in input_api.AffectedFiles():
1396 for line_num, line in f.ChangedContents():
1397 if pattern.search(line):
1398 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1399
1400 results = []
1401 if errors:
1402 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501403 'Found Google support URL addressed by answer number. Please replace '
1404 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161405 return results
1406
[email protected]70ca77752012-11-20 03:45:031407
[email protected]06e6d0ff2012-12-11 01:36:441408def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1409 def FilterFile(affected_file):
1410 """Filter function for use with input_api.AffectedSourceFiles,
1411 below. This filters out everything except non-test files from
1412 top-level directories that generally speaking should not hard-code
1413 service URLs (e.g. src/android_webview/, src/content/ and others).
1414 """
1415 return input_api.FilterSourceFile(
1416 affected_file,
Egor Paskoce145c42018-09-28 19:31:041417 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:441418 black_list=(_EXCLUDED_PATHS +
1419 _TEST_CODE_EXCLUDED_PATHS +
1420 input_api.DEFAULT_BLACK_LIST))
1421
reillyi38965732015-11-16 18:27:331422 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1423 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461424 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1425 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441426 problems = [] # items are (filename, line_number, line)
1427 for f in input_api.AffectedSourceFiles(FilterFile):
1428 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461429 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441430 problems.append((f.LocalPath(), line_num, line))
1431
1432 if problems:
[email protected]f7051d52013-04-02 18:31:421433 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441434 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581435 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441436 [' %s:%d: %s' % (
1437 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031438 else:
1439 return []
[email protected]06e6d0ff2012-12-11 01:36:441440
1441
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491442# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:271443def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1444 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311445 The native_client_sdk directory is excluded because it has auto-generated PNG
1446 files for documentation.
[email protected]d2530012013-01-25 16:39:271447 """
[email protected]d2530012013-01-25 16:39:271448 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491449 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:041450 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:311451 file_filter = lambda f: input_api.FilterSourceFile(
1452 f, white_list=white_list, black_list=black_list)
1453 for f in input_api.AffectedFiles(include_deletes=False,
1454 file_filter=file_filter):
1455 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271456
1457 results = []
1458 if errors:
1459 results.append(output_api.PresubmitError(
1460 'The name of PNG files should not have abbreviations. \n'
1461 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1462 'Contact [email protected] if you have questions.', errors))
1463 return results
1464
1465
Daniel Cheng4dcdb6b2017-04-13 08:30:171466def _ExtractAddRulesFromParsedDeps(parsed_deps):
1467 """Extract the rules that add dependencies from a parsed DEPS file.
1468
1469 Args:
1470 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1471 add_rules = set()
1472 add_rules.update([
1473 rule[1:] for rule in parsed_deps.get('include_rules', [])
1474 if rule.startswith('+') or rule.startswith('!')
1475 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501476 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171477 {}).iteritems():
1478 add_rules.update([
1479 rule[1:] for rule in rules
1480 if rule.startswith('+') or rule.startswith('!')
1481 ])
1482 return add_rules
1483
1484
1485def _ParseDeps(contents):
1486 """Simple helper for parsing DEPS files."""
1487 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171488 class _VarImpl:
1489
1490 def __init__(self, local_scope):
1491 self._local_scope = local_scope
1492
1493 def Lookup(self, var_name):
1494 """Implements the Var syntax."""
1495 try:
1496 return self._local_scope['vars'][var_name]
1497 except KeyError:
1498 raise Exception('Var is not defined: %s' % var_name)
1499
1500 local_scope = {}
1501 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171502 'Var': _VarImpl(local_scope).Lookup,
1503 }
1504 exec contents in global_scope, local_scope
1505 return local_scope
1506
1507
1508def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081509 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411510 a set of DEPS entries that we should look up.
1511
1512 For a directory (rather than a specific filename) we fake a path to
1513 a specific filename by adding /DEPS. This is chosen as a file that
1514 will seldom or never be subject to per-file include_rules.
1515 """
[email protected]2b438d62013-11-14 17:54:141516 # We ignore deps entries on auto-generated directories.
1517 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081518
Daniel Cheng4dcdb6b2017-04-13 08:30:171519 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1520 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1521
1522 added_deps = new_deps.difference(old_deps)
1523
[email protected]2b438d62013-11-14 17:54:141524 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171525 for added_dep in added_deps:
1526 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1527 continue
1528 # Assume that a rule that ends in .h is a rule for a specific file.
1529 if added_dep.endswith('.h'):
1530 results.add(added_dep)
1531 else:
1532 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081533 return results
1534
1535
[email protected]e871964c2013-05-13 14:14:551536def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1537 """When a dependency prefixed with + is added to a DEPS file, we
1538 want to make sure that the change is reviewed by an OWNER of the
1539 target file or directory, to avoid layering violations from being
1540 introduced. This check verifies that this happens.
1541 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171542 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241543
1544 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:491545 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241546 for f in input_api.AffectedFiles(include_deletes=False,
1547 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551548 filename = input_api.os_path.basename(f.LocalPath())
1549 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171550 virtual_depended_on_files.update(_CalculateAddedDeps(
1551 input_api.os_path,
1552 '\n'.join(f.OldContents()),
1553 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551554
[email protected]e871964c2013-05-13 14:14:551555 if not virtual_depended_on_files:
1556 return []
1557
1558 if input_api.is_committing:
1559 if input_api.tbr:
1560 return [output_api.PresubmitNotifyResult(
1561 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271562 if input_api.dry_run:
1563 return [output_api.PresubmitNotifyResult(
1564 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551565 if not input_api.change.issue:
1566 return [output_api.PresubmitError(
1567 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401568 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551569 output = output_api.PresubmitError
1570 else:
1571 output = output_api.PresubmitNotifyResult
1572
1573 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501574 owner_email, reviewers = (
1575 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1576 input_api,
1577 owners_db.email_regexp,
1578 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551579
1580 owner_email = owner_email or input_api.change.author_email
1581
[email protected]de4f7d22013-05-23 14:27:461582 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511583 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461584 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551585 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1586 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411587
1588 # We strip the /DEPS part that was added by
1589 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1590 # directory.
1591 def StripDeps(path):
1592 start_deps = path.rfind('/DEPS')
1593 if start_deps != -1:
1594 return path[:start_deps]
1595 else:
1596 return path
1597 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551598 for path in missing_files]
1599
1600 if unapproved_dependencies:
1601 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151602 output('You need LGTM from owners of depends-on paths in DEPS that were '
1603 'modified in this CL:\n %s' %
1604 '\n '.join(sorted(unapproved_dependencies)))]
1605 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1606 output_list.append(output(
1607 'Suggested missing target path OWNERS:\n %s' %
1608 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551609 return output_list
1610
1611 return []
1612
1613
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491614# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:401615def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491616 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:401617 black_list = (_EXCLUDED_PATHS +
1618 _TEST_CODE_EXCLUDED_PATHS +
1619 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:041620 (r"^base[\\/]logging\.h$",
1621 r"^base[\\/]logging\.cc$",
1622 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
1623 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
1624 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:121625 r"startup_browser_creator\.cc$",
Egor Paskoce145c42018-09-28 19:31:041626 r"^chrome[\\/]installer[\\/]setup[\\/].*",
1627 r"^chrome[\\/]chrome_cleaner[\\/].*",
1628 r"chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031629 r"diagnostics_writer\.cc$",
Egor Paskoce145c42018-09-28 19:31:041630 r"^chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
1631 r"^chromecast[\\/]",
1632 r"^cloud_print[\\/]",
1633 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:481634 r"dump_stability_report_main_win.cc$",
Egor Paskoce145c42018-09-28 19:31:041635 r"^components[\\/]html_viewer[\\/]"
jochen34415e52015-07-10 08:34:311636 r"web_test_delegate_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041637 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:461638 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:041639 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:461640 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041641 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:251642 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:041643 r"^courgette[\\/]courgette_minimal_tool\.cc$",
1644 r"^courgette[\\/]courgette_tool\.cc$",
1645 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331646 r"^fuchsia[\\/]browser[\\/]frame_impl.cc$",
1647 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:041648 r"^ipc[\\/]ipc_logging\.cc$",
1649 r"^native_client_sdk[\\/]",
1650 r"^remoting[\\/]base[\\/]logging\.h$",
1651 r"^remoting[\\/]host[\\/].*",
1652 r"^sandbox[\\/]linux[\\/].*",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331653 r"^storage[\\/]browser[\\/]fileapi[\\/]" +
1654 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:041655 r"^tools[\\/]",
1656 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
1657 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331658 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]"))
[email protected]85218562013-11-22 07:41:401659 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491660 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:401661
thomasanderson625d3932017-03-29 07:16:581662 log_info = set([])
1663 printf = set([])
[email protected]85218562013-11-22 07:41:401664
1665 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581666 for _, line in f.ChangedContents():
1667 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1668 log_info.add(f.LocalPath())
1669 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1670 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371671
thomasanderson625d3932017-03-29 07:16:581672 if input_api.re.search(r"\bprintf\(", line):
1673 printf.add(f.LocalPath())
1674 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1675 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401676
1677 if log_info:
1678 return [output_api.PresubmitError(
1679 'These files spam the console log with LOG(INFO):',
1680 items=log_info)]
1681 if printf:
1682 return [output_api.PresubmitError(
1683 'These files spam the console log with printf/fprintf:',
1684 items=printf)]
1685 return []
1686
1687
[email protected]49aa76a2013-12-04 06:59:161688def _CheckForAnonymousVariables(input_api, output_api):
1689 """These types are all expected to hold locks while in scope and
1690 so should never be anonymous (which causes them to be immediately
1691 destroyed)."""
1692 they_who_must_be_named = [
1693 'base::AutoLock',
1694 'base::AutoReset',
1695 'base::AutoUnlock',
1696 'SkAutoAlphaRestore',
1697 'SkAutoBitmapShaderInstall',
1698 'SkAutoBlitterChoose',
1699 'SkAutoBounderCommit',
1700 'SkAutoCallProc',
1701 'SkAutoCanvasRestore',
1702 'SkAutoCommentBlock',
1703 'SkAutoDescriptor',
1704 'SkAutoDisableDirectionCheck',
1705 'SkAutoDisableOvalCheck',
1706 'SkAutoFree',
1707 'SkAutoGlyphCache',
1708 'SkAutoHDC',
1709 'SkAutoLockColors',
1710 'SkAutoLockPixels',
1711 'SkAutoMalloc',
1712 'SkAutoMaskFreeImage',
1713 'SkAutoMutexAcquire',
1714 'SkAutoPathBoundsUpdate',
1715 'SkAutoPDFRelease',
1716 'SkAutoRasterClipValidate',
1717 'SkAutoRef',
1718 'SkAutoTime',
1719 'SkAutoTrace',
1720 'SkAutoUnref',
1721 ]
1722 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1723 # bad: base::AutoLock(lock.get());
1724 # not bad: base::AutoLock lock(lock.get());
1725 bad_pattern = input_api.re.compile(anonymous)
1726 # good: new base::AutoLock(lock.get())
1727 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1728 errors = []
1729
1730 for f in input_api.AffectedFiles():
1731 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1732 continue
1733 for linenum, line in f.ChangedContents():
1734 if bad_pattern.search(line) and not good_pattern.search(line):
1735 errors.append('%s:%d' % (f.LocalPath(), linenum))
1736
1737 if errors:
1738 return [output_api.PresubmitError(
1739 'These lines create anonymous variables that need to be named:',
1740 items=errors)]
1741 return []
1742
1743
Peter Kasting4844e46e2018-02-23 07:27:101744def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:531745 # Returns whether |template_str| is of the form <T, U...> for some types T
1746 # and U. Assumes that |template_str| is already in the form <...>.
1747 def HasMoreThanOneArg(template_str):
1748 # Level of <...> nesting.
1749 nesting = 0
1750 for c in template_str:
1751 if c == '<':
1752 nesting += 1
1753 elif c == '>':
1754 nesting -= 1
1755 elif c == ',' and nesting == 1:
1756 return True
1757 return False
1758
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491759 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:101760 sources = lambda affected_file: input_api.FilterSourceFile(
1761 affected_file,
1762 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1763 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491764 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:551765
1766 # Pattern to capture a single "<...>" block of template arguments. It can
1767 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
1768 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
1769 # latter would likely require counting that < and > match, which is not
1770 # expressible in regular languages. Should the need arise, one can introduce
1771 # limited counting (matching up to a total number of nesting depth), which
1772 # should cover all practical cases for already a low nesting limit.
1773 template_arg_pattern = (
1774 r'<[^>]*' # Opening block of <.
1775 r'>([^<]*>)?') # Closing block of >.
1776 # Prefix expressing that whatever follows is not already inside a <...>
1777 # block.
1778 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:101779 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:551780 not_inside_template_arg_pattern
1781 + r'\bstd::unique_ptr'
1782 + template_arg_pattern
1783 + r'\(\)')
1784
1785 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
1786 template_arg_no_array_pattern = (
1787 r'<[^>]*[^]]' # Opening block of <.
1788 r'>([^(<]*[^]]>)?') # Closing block of >.
1789 # Prefix saying that what follows is the start of an expression.
1790 start_of_expr_pattern = r'(=|\breturn|^)\s*'
1791 # Suffix saying that what follows are call parentheses with a non-empty list
1792 # of arguments.
1793 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:531794 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:551795 return_construct_pattern = input_api.re.compile(
1796 start_of_expr_pattern
1797 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:531798 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:551799 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:531800 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:551801 + nonempty_arg_list_pattern)
1802
Vaclav Brozek851d9602018-04-04 16:13:051803 problems_constructor = []
1804 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:101805 for f in input_api.AffectedSourceFiles(sources):
1806 for line_number, line in f.ChangedContents():
1807 # Disallow:
1808 # return std::unique_ptr<T>(foo);
1809 # bar = std::unique_ptr<T>(foo);
1810 # But allow:
1811 # return std::unique_ptr<T[]>(foo);
1812 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:531813 # And also allow cases when the second template argument is present. Those
1814 # cases cannot be handled by std::make_unique:
1815 # return std::unique_ptr<T, U>(foo);
1816 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:051817 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:531818 return_construct_result = return_construct_pattern.search(line)
1819 if return_construct_result and not HasMoreThanOneArg(
1820 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:051821 problems_constructor.append(
1822 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:101823 # Disallow:
1824 # std::unique_ptr<T>()
1825 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051826 problems_nullptr.append(
1827 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1828
1829 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:161830 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:051831 errors.append(output_api.PresubmitError(
1832 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161833 problems_nullptr))
1834 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:051835 errors.append(output_api.PresubmitError(
1836 'The following files use explicit std::unique_ptr constructor.'
1837 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161838 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:101839 return errors
1840
1841
[email protected]999261d2014-03-03 20:08:081842def _CheckUserActionUpdate(input_api, output_api):
1843 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521844 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081845 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521846 # If actions.xml is already included in the changelist, the PRESUBMIT
1847 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081848 return []
1849
[email protected]999261d2014-03-03 20:08:081850 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1851 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521852 current_actions = None
[email protected]999261d2014-03-03 20:08:081853 for f in input_api.AffectedFiles(file_filter=file_filter):
1854 for line_num, line in f.ChangedContents():
1855 match = input_api.re.search(action_re, line)
1856 if match:
[email protected]2f92dec2014-03-07 19:21:521857 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1858 # loaded only once.
1859 if not current_actions:
1860 with open('tools/metrics/actions/actions.xml') as actions_f:
1861 current_actions = actions_f.read()
1862 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081863 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521864 action = 'name="{0}"'.format(action_name)
1865 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081866 return [output_api.PresubmitPromptWarning(
1867 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521868 'tools/metrics/actions/actions.xml. Please run '
1869 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081870 % (f.LocalPath(), line_num, action_name))]
1871 return []
1872
1873
Daniel Cheng13ca61a882017-08-25 15:11:251874def _ImportJSONCommentEater(input_api):
1875 import sys
1876 sys.path = sys.path + [input_api.os_path.join(
1877 input_api.PresubmitLocalPath(),
1878 'tools', 'json_comment_eater')]
1879 import json_comment_eater
1880 return json_comment_eater
1881
1882
[email protected]99171a92014-06-03 08:44:471883def _GetJSONParseError(input_api, filename, eat_comments=True):
1884 try:
1885 contents = input_api.ReadFile(filename)
1886 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:251887 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:131888 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471889
1890 input_api.json.loads(contents)
1891 except ValueError as e:
1892 return e
1893 return None
1894
1895
1896def _GetIDLParseError(input_api, filename):
1897 try:
1898 contents = input_api.ReadFile(filename)
1899 idl_schema = input_api.os_path.join(
1900 input_api.PresubmitLocalPath(),
1901 'tools', 'json_schema_compiler', 'idl_schema.py')
1902 process = input_api.subprocess.Popen(
1903 [input_api.python_executable, idl_schema],
1904 stdin=input_api.subprocess.PIPE,
1905 stdout=input_api.subprocess.PIPE,
1906 stderr=input_api.subprocess.PIPE,
1907 universal_newlines=True)
1908 (_, error) = process.communicate(input=contents)
1909 return error or None
1910 except ValueError as e:
1911 return e
1912
1913
1914def _CheckParseErrors(input_api, output_api):
1915 """Check that IDL and JSON files do not contain syntax errors."""
1916 actions = {
1917 '.idl': _GetIDLParseError,
1918 '.json': _GetJSONParseError,
1919 }
[email protected]99171a92014-06-03 08:44:471920 # Most JSON files are preprocessed and support comments, but these do not.
1921 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:041922 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:471923 ]
1924 # Only run IDL checker on files in these directories.
1925 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:041926 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
1927 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:471928 ]
1929
1930 def get_action(affected_file):
1931 filename = affected_file.LocalPath()
1932 return actions.get(input_api.os_path.splitext(filename)[1])
1933
[email protected]99171a92014-06-03 08:44:471934 def FilterFile(affected_file):
1935 action = get_action(affected_file)
1936 if not action:
1937 return False
1938 path = affected_file.LocalPath()
1939
Sean Kau46e29bc2017-08-28 16:31:161940 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:471941 return False
1942
1943 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:161944 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:471945 return False
1946 return True
1947
1948 results = []
1949 for affected_file in input_api.AffectedFiles(
1950 file_filter=FilterFile, include_deletes=False):
1951 action = get_action(affected_file)
1952 kwargs = {}
1953 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:161954 _MatchesFile(input_api, json_no_comments_patterns,
1955 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:471956 kwargs['eat_comments'] = False
1957 parse_error = action(input_api,
1958 affected_file.AbsoluteLocalPath(),
1959 **kwargs)
1960 if parse_error:
1961 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1962 (affected_file.LocalPath(), parse_error)))
1963 return results
1964
1965
[email protected]760deea2013-12-10 19:33:491966def _CheckJavaStyle(input_api, output_api):
1967 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471968 import sys
[email protected]760deea2013-12-10 19:33:491969 original_sys_path = sys.path
1970 try:
1971 sys.path = sys.path + [input_api.os_path.join(
1972 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1973 import checkstyle
1974 finally:
1975 # Restore sys.path to what it was before.
1976 sys.path = original_sys_path
1977
1978 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091979 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511980 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491981
1982
Sean Kau46e29bc2017-08-28 16:31:161983def _MatchesFile(input_api, patterns, path):
1984 for pattern in patterns:
1985 if input_api.re.search(pattern, path):
1986 return True
1987 return False
1988
1989
Daniel Cheng7052cdf2017-11-21 19:23:291990def _GetOwnersFilesToCheckForIpcOwners(input_api):
1991 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:171992
Daniel Cheng7052cdf2017-11-21 19:23:291993 Returns:
1994 A dictionary mapping an OWNER file to the list of OWNERS rules it must
1995 contain to cover IPC-related files with noparent reviewer rules.
1996 """
1997 # Whether or not a file affects IPC is (mostly) determined by a simple list
1998 # of filename patterns.
dchenge07de812016-06-20 19:27:171999 file_patterns = [
palmerb19a0932017-01-24 04:00:312000 # Legacy IPC:
dchenge07de812016-06-20 19:27:172001 '*_messages.cc',
2002 '*_messages*.h',
2003 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312004 # Mojo IPC:
dchenge07de812016-06-20 19:27:172005 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472006 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172007 '*_struct_traits*.*',
2008 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312009 '*.typemap',
2010 # Android native IPC:
2011 '*.aidl',
2012 # Blink uses a different file naming convention:
2013 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472014 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172015 '*StructTraits*.*',
2016 '*TypeConverter*.*',
2017 ]
2018
scottmg7a6ed5ba2016-11-04 18:22:042019 # These third_party directories do not contain IPCs, but contain files
2020 # matching the above patterns, which trigger false positives.
2021 exclude_paths = [
2022 'third_party/crashpad/*',
Andres Medinae684cf42018-08-27 18:48:232023 'third_party/protobuf/benchmarks/python/*',
Daniel Chengebe635e2018-07-13 12:36:062024 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:292025 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:042026 ]
2027
dchenge07de812016-06-20 19:27:172028 # Dictionary mapping an OWNERS file path to Patterns.
2029 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2030 # rules ) to a PatternEntry.
2031 # PatternEntry is a dictionary with two keys:
2032 # - 'files': the files that are matched by this pattern
2033 # - 'rules': the per-file rules needed for this pattern
2034 # For example, if we expect OWNERS file to contain rules for *.mojom and
2035 # *_struct_traits*.*, Patterns might look like this:
2036 # {
2037 # '*.mojom': {
2038 # 'files': ...,
2039 # 'rules': [
2040 # 'per-file *.mojom=set noparent',
2041 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2042 # ],
2043 # },
2044 # '*_struct_traits*.*': {
2045 # 'files': ...,
2046 # 'rules': [
2047 # 'per-file *_struct_traits*.*=set noparent',
2048 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2049 # ],
2050 # },
2051 # }
2052 to_check = {}
2053
Daniel Cheng13ca61a882017-08-25 15:11:252054 def AddPatternToCheck(input_file, pattern):
2055 owners_file = input_api.os_path.join(
2056 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2057 if owners_file not in to_check:
2058 to_check[owners_file] = {}
2059 if pattern not in to_check[owners_file]:
2060 to_check[owners_file][pattern] = {
2061 'files': [],
2062 'rules': [
2063 'per-file %s=set noparent' % pattern,
2064 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2065 ]
2066 }
Vaclav Brozekd5de76a2018-03-17 07:57:502067 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252068
dchenge07de812016-06-20 19:27:172069 # Iterate through the affected files to see what we actually need to check
2070 # for. We should only nag patch authors about per-file rules if a file in that
2071 # directory would match that pattern. If a directory only contains *.mojom
2072 # files and no *_messages*.h files, we should only nag about rules for
2073 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252074 for f in input_api.AffectedFiles(include_deletes=False):
2075 # Manifest files don't have a strong naming convention. Instead, scan
Ken Rockot9f668262018-12-21 18:56:362076 # affected files for .json, .cc, and .h files which look like they contain
2077 # a manifest definition.
Sean Kau46e29bc2017-08-28 16:31:162078 if (f.LocalPath().endswith('.json') and
2079 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
2080 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:252081 json_comment_eater = _ImportJSONCommentEater(input_api)
2082 mostly_json_lines = '\n'.join(f.NewContents())
2083 # Comments aren't allowed in strict JSON, so filter them out.
2084 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:432085 try:
2086 json_content = input_api.json.loads(json_lines)
2087 except:
2088 # There's another PRESUBMIT check that already verifies that JSON files
2089 # are not invalid, so no need to emit another warning here.
2090 continue
Daniel Cheng13ca61a882017-08-25 15:11:252091 if 'interface_provider_specs' in json_content:
2092 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
Ken Rockot9f668262018-12-21 18:56:362093 else:
2094 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2095 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2096 if (manifest_pattern.search(f.LocalPath()) and not
2097 test_manifest_pattern.search(f.LocalPath())):
2098 # We expect all actual service manifest files to contain at least one
2099 # qualified reference to service_manager::Manifest.
2100 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2101 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172102 for pattern in file_patterns:
2103 if input_api.fnmatch.fnmatch(
2104 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042105 skip = False
2106 for exclude in exclude_paths:
2107 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2108 skip = True
2109 break
2110 if skip:
2111 continue
Daniel Cheng13ca61a882017-08-25 15:11:252112 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172113 break
2114
Daniel Cheng7052cdf2017-11-21 19:23:292115 return to_check
2116
2117
2118def _CheckIpcOwners(input_api, output_api):
2119 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2120 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2121
2122 if to_check:
2123 # If there are any OWNERS files to check, there are IPC-related changes in
2124 # this CL. Auto-CC the review list.
2125 output_api.AppendCC('[email protected]')
2126
2127 # Go through the OWNERS files to check, filtering out rules that are already
2128 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172129 for owners_file, patterns in to_check.iteritems():
2130 try:
2131 with file(owners_file) as f:
2132 lines = set(f.read().splitlines())
2133 for entry in patterns.itervalues():
2134 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2135 ]
2136 except IOError:
2137 # No OWNERS file, so all the rules are definitely missing.
2138 continue
2139
2140 # All the remaining lines weren't found in OWNERS files, so emit an error.
2141 errors = []
2142 for owners_file, patterns in to_check.iteritems():
2143 missing_lines = []
2144 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502145 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172146 missing_lines.extend(entry['rules'])
2147 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2148 if missing_lines:
2149 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052150 'Because of the presence of files:\n%s\n\n'
2151 '%s needs the following %d lines added:\n\n%s' %
2152 ('\n'.join(files), owners_file, len(missing_lines),
2153 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172154
2155 results = []
2156 if errors:
vabrf5ce3bf92016-07-11 14:52:412157 if input_api.is_committing:
2158 output = output_api.PresubmitError
2159 else:
2160 output = output_api.PresubmitPromptWarning
2161 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592162 'Found OWNERS files that need to be updated for IPC security ' +
2163 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172164 long_text='\n\n'.join(errors)))
2165
2166 return results
2167
2168
jbriance9e12f162016-11-25 07:57:502169def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312170 """Checks that added or removed lines in non third party affected
2171 header files do not lead to new useless class or struct forward
2172 declaration.
jbriance9e12f162016-11-25 07:57:502173 """
2174 results = []
2175 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2176 input_api.re.MULTILINE)
2177 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2178 input_api.re.MULTILINE)
2179 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312180 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192181 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:492182 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:312183 continue
2184
jbriance9e12f162016-11-25 07:57:502185 if not f.LocalPath().endswith('.h'):
2186 continue
2187
2188 contents = input_api.ReadFile(f)
2189 fwd_decls = input_api.re.findall(class_pattern, contents)
2190 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2191
2192 useless_fwd_decls = []
2193 for decl in fwd_decls:
2194 count = sum(1 for _ in input_api.re.finditer(
2195 r'\b%s\b' % input_api.re.escape(decl), contents))
2196 if count == 1:
2197 useless_fwd_decls.append(decl)
2198
2199 if not useless_fwd_decls:
2200 continue
2201
2202 for line in f.GenerateScmDiff().splitlines():
2203 if (line.startswith('-') and not line.startswith('--') or
2204 line.startswith('+') and not line.startswith('++')):
2205 for decl in useless_fwd_decls:
2206 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2207 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242208 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502209 (f.LocalPath(), decl)))
2210 useless_fwd_decls.remove(decl)
2211
2212 return results
2213
2214
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492215# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:292216def _CheckAndroidToastUsage(input_api, output_api):
2217 """Checks that code uses org.chromium.ui.widget.Toast instead of
2218 android.widget.Toast (Chromium Toast doesn't force hardware
2219 acceleration on low-end devices, saving memory).
2220 """
2221 toast_import_pattern = input_api.re.compile(
2222 r'^import android\.widget\.Toast;$')
2223
2224 errors = []
2225
2226 sources = lambda affected_file: input_api.FilterSourceFile(
2227 affected_file,
2228 black_list=(_EXCLUDED_PATHS +
2229 _TEST_CODE_EXCLUDED_PATHS +
2230 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042231 (r'^chromecast[\\/].*',
2232 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492233 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:292234
2235 for f in input_api.AffectedSourceFiles(sources):
2236 for line_num, line in f.ChangedContents():
2237 if toast_import_pattern.search(line):
2238 errors.append("%s:%d" % (f.LocalPath(), line_num))
2239
2240 results = []
2241
2242 if errors:
2243 results.append(output_api.PresubmitError(
2244 'android.widget.Toast usage is detected. Android toasts use hardware'
2245 ' acceleration, and can be\ncostly on low-end devices. Please use'
2246 ' org.chromium.ui.widget.Toast instead.\n'
2247 'Contact [email protected] if you have any questions.',
2248 errors))
2249
2250 return results
2251
2252
dgnaa68d5e2015-06-10 10:08:222253def _CheckAndroidCrLogUsage(input_api, output_api):
2254 """Checks that new logs using org.chromium.base.Log:
2255 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512256 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222257 """
pkotwicza1dd0b002016-05-16 14:41:042258
torne89540622017-03-24 19:41:302259 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042260 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302261 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:042262 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:302263 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:042264 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
2265 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:092266 # The customtabs_benchmark is a small app that does not depend on Chromium
2267 # java pieces.
Egor Paskoce145c42018-09-28 19:31:042268 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:042269 ]
2270
dgnaa68d5e2015-06-10 10:08:222271 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122272 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2273 class_in_base_pattern = input_api.re.compile(
2274 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2275 has_some_log_import_pattern = input_api.re.compile(
2276 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222277 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122278 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222279 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512280 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222281 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222282
Vincent Scheib16d7b272015-09-15 18:09:072283 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222284 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492285 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:042286 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122287
dgnaa68d5e2015-06-10 10:08:222288 tag_decl_errors = []
2289 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122290 tag_errors = []
dgn38736db2015-09-18 19:20:512291 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122292 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222293
2294 for f in input_api.AffectedSourceFiles(sources):
2295 file_content = input_api.ReadFile(f)
2296 has_modified_logs = False
2297
2298 # Per line checks
dgn87d9fb62015-06-12 09:15:122299 if (cr_log_import_pattern.search(file_content) or
2300 (class_in_base_pattern.search(file_content) and
2301 not has_some_log_import_pattern.search(file_content))):
2302 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222303 for line_num, line in f.ChangedContents():
2304
2305 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122306 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222307 if match:
2308 has_modified_logs = True
2309
2310 # Make sure it uses "TAG"
2311 if not match.group('tag') == 'TAG':
2312 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122313 else:
2314 # Report non cr Log function calls in changed lines
2315 for line_num, line in f.ChangedContents():
2316 if log_call_pattern.search(line):
2317 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222318
2319 # Per file checks
2320 if has_modified_logs:
2321 # Make sure the tag is using the "cr" prefix and is not too long
2322 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512323 tag_name = match.group('name') if match else None
2324 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222325 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512326 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222327 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512328 elif '.' in tag_name:
2329 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222330
2331 results = []
2332 if tag_decl_errors:
2333 results.append(output_api.PresubmitPromptWarning(
2334 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512335 '"private static final String TAG = "<package tag>".\n'
2336 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222337 tag_decl_errors))
2338
2339 if tag_length_errors:
2340 results.append(output_api.PresubmitError(
2341 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512342 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222343 tag_length_errors))
2344
2345 if tag_errors:
2346 results.append(output_api.PresubmitPromptWarning(
2347 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2348 tag_errors))
2349
dgn87d9fb62015-06-12 09:15:122350 if util_log_errors:
dgn4401aa52015-04-29 16:26:172351 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122352 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2353 util_log_errors))
2354
dgn38736db2015-09-18 19:20:512355 if tag_with_dot_errors:
2356 results.append(output_api.PresubmitPromptWarning(
2357 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2358 tag_with_dot_errors))
2359
dgn4401aa52015-04-29 16:26:172360 return results
2361
2362
Yoland Yanb92fa522017-08-28 17:37:062363def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2364 """Checks that junit.framework.* is no longer used."""
2365 deprecated_junit_framework_pattern = input_api.re.compile(
2366 r'^import junit\.framework\..*;',
2367 input_api.re.MULTILINE)
2368 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492369 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062370 errors = []
2371 for f in input_api.AffectedFiles(sources):
2372 for line_num, line in f.ChangedContents():
2373 if deprecated_junit_framework_pattern.search(line):
2374 errors.append("%s:%d" % (f.LocalPath(), line_num))
2375
2376 results = []
2377 if errors:
2378 results.append(output_api.PresubmitError(
2379 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2380 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2381 ' if you have any question.', errors))
2382 return results
2383
2384
2385def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2386 """Checks that if new Java test classes have inheritance.
2387 Either the new test class is JUnit3 test or it is a JUnit4 test class
2388 with a base class, either case is undesirable.
2389 """
2390 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2391
2392 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492393 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062394 errors = []
2395 for f in input_api.AffectedFiles(sources):
2396 if not f.OldContents():
2397 class_declaration_start_flag = False
2398 for line_num, line in f.ChangedContents():
2399 if class_declaration_pattern.search(line):
2400 class_declaration_start_flag = True
2401 if class_declaration_start_flag and ' extends ' in line:
2402 errors.append('%s:%d' % (f.LocalPath(), line_num))
2403 if '{' in line:
2404 class_declaration_start_flag = False
2405
2406 results = []
2407 if errors:
2408 results.append(output_api.PresubmitPromptWarning(
2409 'The newly created files include Test classes that inherits from base'
2410 ' class. Please do not use inheritance in JUnit4 tests or add new'
2411 ' JUnit3 tests. Contact [email protected] if you have any'
2412 ' questions.', errors))
2413 return results
2414
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202415
yolandyan45001472016-12-21 21:12:422416def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2417 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2418 deprecated_annotation_import_pattern = input_api.re.compile(
2419 r'^import android\.test\.suitebuilder\.annotation\..*;',
2420 input_api.re.MULTILINE)
2421 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492422 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:422423 errors = []
2424 for f in input_api.AffectedFiles(sources):
2425 for line_num, line in f.ChangedContents():
2426 if deprecated_annotation_import_pattern.search(line):
2427 errors.append("%s:%d" % (f.LocalPath(), line_num))
2428
2429 results = []
2430 if errors:
2431 results.append(output_api.PresubmitError(
2432 'Annotations in android.test.suitebuilder.annotation have been'
2433 ' deprecated since API level 24. Please use android.support.test.filters'
2434 ' from //third_party/android_support_test_runner:runner_java instead.'
2435 ' Contact [email protected] if you have any questions.', errors))
2436 return results
2437
2438
agrieve7b6479d82015-10-07 14:24:222439def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2440 """Checks if MDPI assets are placed in a correct directory."""
2441 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2442 ('/res/drawable/' in f.LocalPath() or
2443 '/res/drawable-ldrtl/' in f.LocalPath()))
2444 errors = []
2445 for f in input_api.AffectedFiles(include_deletes=False,
2446 file_filter=file_filter):
2447 errors.append(' %s' % f.LocalPath())
2448
2449 results = []
2450 if errors:
2451 results.append(output_api.PresubmitError(
2452 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2453 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2454 '/res/drawable-ldrtl/.\n'
2455 'Contact [email protected] if you have questions.', errors))
2456 return results
2457
2458
Nate Fischer535972b2017-09-16 01:06:182459def _CheckAndroidWebkitImports(input_api, output_api):
2460 """Checks that code uses org.chromium.base.Callback instead of
2461 android.widget.ValueCallback except in the WebView glue layer.
2462 """
2463 valuecallback_import_pattern = input_api.re.compile(
2464 r'^import android\.webkit\.ValueCallback;$')
2465
2466 errors = []
2467
2468 sources = lambda affected_file: input_api.FilterSourceFile(
2469 affected_file,
2470 black_list=(_EXCLUDED_PATHS +
2471 _TEST_CODE_EXCLUDED_PATHS +
2472 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042473 (r'^android_webview[\\/]glue[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492474 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:182475
2476 for f in input_api.AffectedSourceFiles(sources):
2477 for line_num, line in f.ChangedContents():
2478 if valuecallback_import_pattern.search(line):
2479 errors.append("%s:%d" % (f.LocalPath(), line_num))
2480
2481 results = []
2482
2483 if errors:
2484 results.append(output_api.PresubmitError(
2485 'android.webkit.ValueCallback usage is detected outside of the glue'
2486 ' layer. To stay compatible with the support library, android.webkit.*'
2487 ' classes should only be used inside the glue layer and'
2488 ' org.chromium.base.Callback should be used instead.',
2489 errors))
2490
2491 return results
2492
2493
Becky Zhou7c69b50992018-12-10 19:37:572494def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
2495 """Checks Android XML styles """
2496 import sys
2497 original_sys_path = sys.path
2498 try:
2499 sys.path = sys.path + [input_api.os_path.join(
2500 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
2501 import checkxmlstyle
2502 finally:
2503 # Restore sys.path to what it was before.
2504 sys.path = original_sys_path
2505
2506 if is_check_on_upload:
2507 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
2508 else:
2509 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
2510
2511
agrievef32bcc72016-04-04 14:57:402512class PydepsChecker(object):
2513 def __init__(self, input_api, pydeps_files):
2514 self._file_cache = {}
2515 self._input_api = input_api
2516 self._pydeps_files = pydeps_files
2517
2518 def _LoadFile(self, path):
2519 """Returns the list of paths within a .pydeps file relative to //."""
2520 if path not in self._file_cache:
2521 with open(path) as f:
2522 self._file_cache[path] = f.read()
2523 return self._file_cache[path]
2524
2525 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2526 """Returns an interable of paths within the .pydep, relativized to //."""
2527 os_path = self._input_api.os_path
2528 pydeps_dir = os_path.dirname(pydeps_path)
2529 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2530 if not l.startswith('*'))
2531 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2532
2533 def _CreateFilesToPydepsMap(self):
2534 """Returns a map of local_path -> list_of_pydeps."""
2535 ret = {}
2536 for pydep_local_path in self._pydeps_files:
2537 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2538 ret.setdefault(path, []).append(pydep_local_path)
2539 return ret
2540
2541 def ComputeAffectedPydeps(self):
2542 """Returns an iterable of .pydeps files that might need regenerating."""
2543 affected_pydeps = set()
2544 file_to_pydeps_map = None
2545 for f in self._input_api.AffectedFiles(include_deletes=True):
2546 local_path = f.LocalPath()
2547 if local_path == 'DEPS':
2548 return self._pydeps_files
2549 elif local_path.endswith('.pydeps'):
2550 if local_path in self._pydeps_files:
2551 affected_pydeps.add(local_path)
2552 elif local_path.endswith('.py'):
2553 if file_to_pydeps_map is None:
2554 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2555 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2556 return affected_pydeps
2557
2558 def DetermineIfStale(self, pydeps_path):
2559 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412560 import difflib
John Budorick47ca3fe2018-02-10 00:53:102561 import os
2562
agrievef32bcc72016-04-04 14:57:402563 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2564 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102565 env = dict(os.environ)
2566 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402567 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102568 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412569 old_contents = old_pydeps_data[2:]
2570 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402571 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412572 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402573
2574
2575def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2576 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402577 # This check is for Python dependency lists (.pydeps files), and involves
2578 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2579 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282580 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002581 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022582 # TODO(agrieve): Update when there's a better way to detect
2583 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402584 is_android = input_api.os_path.exists('third_party/android_tools')
2585 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2586 results = []
2587 # First, check for new / deleted .pydeps.
2588 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032589 # Check whether we are running the presubmit check for a file in src.
2590 # f.LocalPath is relative to repo (src, or internal repo).
2591 # os_path.exists is relative to src repo.
2592 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2593 # to src and we can conclude that the pydeps is in src.
2594 if input_api.os_path.exists(f.LocalPath()):
2595 if f.LocalPath().endswith('.pydeps'):
2596 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2597 results.append(output_api.PresubmitError(
2598 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2599 'remove %s' % f.LocalPath()))
2600 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2601 results.append(output_api.PresubmitError(
2602 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2603 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402604
2605 if results:
2606 return results
2607
2608 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2609
2610 for pydep_path in checker.ComputeAffectedPydeps():
2611 try:
phajdan.jr0d9878552016-11-04 10:49:412612 result = checker.DetermineIfStale(pydep_path)
2613 if result:
2614 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402615 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412616 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2617 'To regenerate, run:\n\n %s' %
2618 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402619 except input_api.subprocess.CalledProcessError as error:
2620 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2621 long_text=error.output)]
2622
2623 return results
2624
2625
glidere61efad2015-02-18 17:39:432626def _CheckSingletonInHeaders(input_api, output_api):
2627 """Checks to make sure no header files have |Singleton<|."""
2628 def FileFilter(affected_file):
2629 # It's ok for base/memory/singleton.h to have |Singleton<|.
2630 black_list = (_EXCLUDED_PATHS +
2631 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042632 (r"^base[\\/]memory[\\/]singleton\.h$",
2633 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:472634 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432635 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2636
sergeyu34d21222015-09-16 00:11:442637 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432638 files = []
2639 for f in input_api.AffectedSourceFiles(FileFilter):
2640 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2641 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2642 contents = input_api.ReadFile(f)
2643 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242644 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432645 pattern.search(line)):
2646 files.append(f)
2647 break
2648
2649 if files:
yolandyandaabc6d2016-04-18 18:29:392650 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442651 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432652 'Please move them to an appropriate source file so that the ' +
2653 'template gets instantiated in a single compilation unit.',
2654 files) ]
2655 return []
2656
2657
[email protected]fd20b902014-05-09 02:14:532658_DEPRECATED_CSS = [
2659 # Values
2660 ( "-webkit-box", "flex" ),
2661 ( "-webkit-inline-box", "inline-flex" ),
2662 ( "-webkit-flex", "flex" ),
2663 ( "-webkit-inline-flex", "inline-flex" ),
2664 ( "-webkit-min-content", "min-content" ),
2665 ( "-webkit-max-content", "max-content" ),
2666
2667 # Properties
2668 ( "-webkit-background-clip", "background-clip" ),
2669 ( "-webkit-background-origin", "background-origin" ),
2670 ( "-webkit-background-size", "background-size" ),
2671 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442672 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532673
2674 # Functions
2675 ( "-webkit-gradient", "gradient" ),
2676 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2677 ( "-webkit-linear-gradient", "linear-gradient" ),
2678 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2679 ( "-webkit-radial-gradient", "radial-gradient" ),
2680 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2681]
2682
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202683
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492684# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242685def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532686 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252687 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342688 documentation and iOS CSS for dom distiller
2689 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252690 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532691 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492692 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:252693 black_list = (_EXCLUDED_PATHS +
2694 _TEST_CODE_EXCLUDED_PATHS +
2695 input_api.DEFAULT_BLACK_LIST +
2696 (r"^chrome/common/extensions/docs",
2697 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342698 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442699 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252700 r"^native_client_sdk"))
2701 file_filter = lambda f: input_api.FilterSourceFile(
2702 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532703 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2704 for line_num, line in fpath.ChangedContents():
2705 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022706 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532707 results.append(output_api.PresubmitError(
2708 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2709 (fpath.LocalPath(), line_num, deprecated_value, value)))
2710 return results
2711
mohan.reddyf21db962014-10-16 12:26:472712
dbeam070cfe62014-10-22 06:44:022713_DEPRECATED_JS = [
2714 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2715 ( "__defineGetter__", "Object.defineProperty" ),
2716 ( "__defineSetter__", "Object.defineProperty" ),
2717]
2718
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202719
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492720# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242721def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022722 """Make sure that we don't use deprecated JS in Chrome code."""
2723 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492724 file_inclusion_pattern = [r".+\.js$"] # TODO(dbeam): .html?
dbeam070cfe62014-10-22 06:44:022725 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2726 input_api.DEFAULT_BLACK_LIST)
2727 file_filter = lambda f: input_api.FilterSourceFile(
2728 f, white_list=file_inclusion_pattern, black_list=black_list)
2729 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2730 for lnum, line in fpath.ChangedContents():
2731 for (deprecated, replacement) in _DEPRECATED_JS:
2732 if deprecated in line:
2733 results.append(output_api.PresubmitError(
2734 "%s:%d: Use of deprecated JS %s, use %s instead" %
2735 (fpath.LocalPath(), lnum, deprecated, replacement)))
2736 return results
2737
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202738
rlanday6802cf632017-05-30 17:48:362739def _CheckForRelativeIncludes(input_api, output_api):
2740 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2741 import sys
2742 original_sys_path = sys.path
2743 try:
2744 sys.path = sys.path + [input_api.os_path.join(
2745 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2746 from cpp_checker import CppChecker
2747 finally:
2748 # Restore sys.path to what it was before.
2749 sys.path = original_sys_path
2750
2751 bad_files = {}
2752 for f in input_api.AffectedFiles(include_deletes=False):
2753 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:492754 not f.LocalPath().startswith('third_party/blink') and
2755 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:362756 continue
2757
2758 if not CppChecker.IsCppFile(f.LocalPath()):
2759 continue
2760
Vaclav Brozekd5de76a2018-03-17 07:57:502761 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362762 if "#include" in line and "../" in line]
2763 if not relative_includes:
2764 continue
2765 bad_files[f.LocalPath()] = relative_includes
2766
2767 if not bad_files:
2768 return []
2769
2770 error_descriptions = []
2771 for file_path, bad_lines in bad_files.iteritems():
2772 error_description = file_path
2773 for line in bad_lines:
2774 error_description += '\n ' + line
2775 error_descriptions.append(error_description)
2776
2777 results = []
2778 results.append(output_api.PresubmitError(
2779 'You added one or more relative #include paths (including "../").\n'
2780 'These shouldn\'t be used because they can be used to include headers\n'
2781 'from code that\'s not correctly specified as a dependency in the\n'
2782 'relevant BUILD.gn file(s).',
2783 error_descriptions))
2784
2785 return results
2786
Takeshi Yoshinoe387aa32017-08-02 13:16:132787
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202788def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2789 if not isinstance(key, ast.Str):
2790 return 'Key at line %d must be a string literal' % key.lineno
2791 if not isinstance(value, ast.Dict):
2792 return 'Value at line %d must be a dict' % value.lineno
2793 if len(value.keys) != 1:
2794 return 'Dict at line %d must have single entry' % value.lineno
2795 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2796 return (
2797 'Entry at line %d must have a string literal \'filepath\' as key' %
2798 value.lineno)
2799 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132800
Takeshi Yoshinoe387aa32017-08-02 13:16:132801
Sergey Ulanov4af16052018-11-08 02:41:462802def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202803 if not isinstance(key, ast.Str):
2804 return 'Key at line %d must be a string literal' % key.lineno
2805 if not isinstance(value, ast.List):
2806 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:462807 for element in value.elts:
2808 if not isinstance(element, ast.Str):
2809 return 'Watchlist elements on line %d is not a string' % key.lineno
2810 if not email_regex.match(element.s):
2811 return ('Watchlist element on line %d doesn\'t look like a valid ' +
2812 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202813 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132814
Takeshi Yoshinoe387aa32017-08-02 13:16:132815
Sergey Ulanov4af16052018-11-08 02:41:462816def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202817 mismatch_template = (
2818 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2819 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132820
Sergey Ulanov4af16052018-11-08 02:41:462821 email_regex = input_api.re.compile(
2822 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
2823
2824 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202825 i = 0
2826 last_key = ''
2827 while True:
2828 if i >= len(wd_dict.keys):
2829 if i >= len(w_dict.keys):
2830 return None
2831 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2832 elif i >= len(w_dict.keys):
2833 return (
2834 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132835
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202836 wd_key = wd_dict.keys[i]
2837 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132838
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202839 result = _CheckWatchlistDefinitionsEntrySyntax(
2840 wd_key, wd_dict.values[i], ast)
2841 if result is not None:
2842 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132843
Sergey Ulanov4af16052018-11-08 02:41:462844 result = _CheckWatchlistsEntrySyntax(
2845 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202846 if result is not None:
2847 return 'Bad entry in WATCHLISTS dict: %s' % result
2848
2849 if wd_key.s != w_key.s:
2850 return mismatch_template % (
2851 '%s at line %d' % (wd_key.s, wd_key.lineno),
2852 '%s at line %d' % (w_key.s, w_key.lineno))
2853
2854 if wd_key.s < last_key:
2855 return (
2856 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2857 (wd_key.lineno, w_key.lineno))
2858 last_key = wd_key.s
2859
2860 i = i + 1
2861
2862
Sergey Ulanov4af16052018-11-08 02:41:462863def _CheckWATCHLISTSSyntax(expression, input_api):
2864 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202865 if not isinstance(expression, ast.Expression):
2866 return 'WATCHLISTS file must contain a valid expression'
2867 dictionary = expression.body
2868 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2869 return 'WATCHLISTS file must have single dict with exactly two entries'
2870
2871 first_key = dictionary.keys[0]
2872 first_value = dictionary.values[0]
2873 second_key = dictionary.keys[1]
2874 second_value = dictionary.values[1]
2875
2876 if (not isinstance(first_key, ast.Str) or
2877 first_key.s != 'WATCHLIST_DEFINITIONS' or
2878 not isinstance(first_value, ast.Dict)):
2879 return (
2880 'The first entry of the dict in WATCHLISTS file must be '
2881 'WATCHLIST_DEFINITIONS dict')
2882
2883 if (not isinstance(second_key, ast.Str) or
2884 second_key.s != 'WATCHLISTS' or
2885 not isinstance(second_value, ast.Dict)):
2886 return (
2887 'The second entry of the dict in WATCHLISTS file must be '
2888 'WATCHLISTS dict')
2889
Sergey Ulanov4af16052018-11-08 02:41:462890 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:132891
2892
2893def _CheckWATCHLISTS(input_api, output_api):
2894 for f in input_api.AffectedFiles(include_deletes=False):
2895 if f.LocalPath() == 'WATCHLISTS':
2896 contents = input_api.ReadFile(f, 'r')
2897
2898 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202899 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132900 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202901 # Get an AST tree for it and scan the tree for detailed style checking.
2902 expression = input_api.ast.parse(
2903 contents, filename='WATCHLISTS', mode='eval')
2904 except ValueError as e:
2905 return [output_api.PresubmitError(
2906 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2907 except SyntaxError as e:
2908 return [output_api.PresubmitError(
2909 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2910 except TypeError as e:
2911 return [output_api.PresubmitError(
2912 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132913
Sergey Ulanov4af16052018-11-08 02:41:462914 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202915 if result is not None:
2916 return [output_api.PresubmitError(result)]
2917 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132918
2919 return []
2920
2921
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192922def _CheckNewHeaderWithoutGnChange(input_api, output_api):
2923 """Checks that newly added header files have corresponding GN changes.
2924 Note that this is only a heuristic. To be precise, run script:
2925 build/check_gn_headers.py.
2926 """
2927
2928 def headers(f):
2929 return input_api.FilterSourceFile(
2930 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
2931
2932 new_headers = []
2933 for f in input_api.AffectedSourceFiles(headers):
2934 if f.Action() != 'A':
2935 continue
2936 new_headers.append(f.LocalPath())
2937
2938 def gn_files(f):
2939 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
2940
2941 all_gn_changed_contents = ''
2942 for f in input_api.AffectedSourceFiles(gn_files):
2943 for _, line in f.ChangedContents():
2944 all_gn_changed_contents += line
2945
2946 problems = []
2947 for header in new_headers:
2948 basename = input_api.os_path.basename(header)
2949 if basename not in all_gn_changed_contents:
2950 problems.append(header)
2951
2952 if problems:
2953 return [output_api.PresubmitPromptWarning(
2954 'Missing GN changes for new header files', items=sorted(problems),
2955 long_text='Please double check whether newly added header files need '
2956 'corresponding changes in gn or gni files.\nThis checking is only a '
2957 'heuristic. Run build/check_gn_headers.py to be precise.\n'
2958 'Read https://crbug.com/661774 for more info.')]
2959 return []
2960
2961
Michael Giuffridad3bc8672018-10-25 22:48:022962def _CheckCorrectProductNameInMessages(input_api, output_api):
2963 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
2964
2965 This assumes we won't intentionally reference one product from the other
2966 product.
2967 """
2968 all_problems = []
2969 test_cases = [{
2970 "filename_postfix": "google_chrome_strings.grd",
2971 "correct_name": "Chrome",
2972 "incorrect_name": "Chromium",
2973 }, {
2974 "filename_postfix": "chromium_strings.grd",
2975 "correct_name": "Chromium",
2976 "incorrect_name": "Chrome",
2977 }]
2978
2979 for test_case in test_cases:
2980 problems = []
2981 filename_filter = lambda x: x.LocalPath().endswith(
2982 test_case["filename_postfix"])
2983
2984 # Check each new line. Can yield false positives in multiline comments, but
2985 # easier than trying to parse the XML because messages can have nested
2986 # children, and associating message elements with affected lines is hard.
2987 for f in input_api.AffectedSourceFiles(filename_filter):
2988 for line_num, line in f.ChangedContents():
2989 if "<message" in line or "<!--" in line or "-->" in line:
2990 continue
2991 if test_case["incorrect_name"] in line:
2992 problems.append(
2993 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
2994
2995 if problems:
2996 message = (
2997 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
2998 % (test_case["correct_name"], test_case["correct_name"],
2999 test_case["incorrect_name"]))
3000 all_problems.append(
3001 output_api.PresubmitPromptWarning(message, items=problems))
3002
3003 return all_problems
3004
3005
dgnaa68d5e2015-06-10 10:08:223006def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:573007 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:223008 results = []
dgnaa68d5e2015-06-10 10:08:223009 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:223010 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:293011 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:063012 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
3013 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:423014 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:183015 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573016 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
3017 return results
3018
3019def _AndroidSpecificOnCommitChecks(input_api, output_api):
3020 """Groups commit checks that target android code."""
3021 results = []
3022 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:223023 return results
3024
3025
[email protected]22c9bd72011-03-27 16:47:393026def _CommonChecks(input_api, output_api):
3027 """Checks common to both upload and commit."""
3028 results = []
3029 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:383030 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:543031 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:083032
3033 author = input_api.change.author_email
3034 if author and author not in _KNOWN_ROBOTS:
3035 results.extend(
3036 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
3037
[email protected]55459852011-08-10 15:17:193038 results.extend(
[email protected]760deea2013-12-10 19:33:493039 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:233040 results.extend(
3041 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:543042 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:183043 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:343044 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:523045 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:223046 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:443047 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:593048 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:063049 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:123050 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:183051 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:223052 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:303053 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:493054 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:033055 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:493056 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:443057 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:273058 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:073059 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:543060 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:443061 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:393062 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:553063 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:043064 results.extend(
3065 input_api.canned_checks.CheckChangeHasNoTabs(
3066 input_api,
3067 output_api,
3068 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:403069 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:163070 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:083071 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:243072 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
3073 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:473074 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:043075 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:053076 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:143077 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:233078 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:433079 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:403080 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:153081 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:173082 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:503083 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:363084 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:133085 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:433086 results.extend(input_api.RunTests(
3087 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143088 results.extend(_CheckTranslationScreenshots(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:023089 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:243090
Vaclav Brozekcdc7defb2018-03-20 09:54:353091 for f in input_api.AffectedFiles():
3092 path, name = input_api.os_path.split(f.LocalPath())
3093 if name == 'PRESUBMIT.py':
3094 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:003095 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
3096 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:073097 # The PRESUBMIT.py file (and the directory containing it) might
3098 # have been affected by being moved or removed, so only try to
3099 # run the tests if they still exist.
3100 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
3101 input_api, output_api, full_path,
3102 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:393103 return results
[email protected]1f7b4172010-01-28 01:17:343104
[email protected]b337cb5b2011-01-23 21:24:053105
[email protected]b8079ae4a2012-12-05 19:56:493106def _CheckPatchFiles(input_api, output_api):
3107 problems = [f.LocalPath() for f in input_api.AffectedFiles()
3108 if f.LocalPath().endswith(('.orig', '.rej'))]
3109 if problems:
3110 return [output_api.PresubmitError(
3111 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:033112 else:
3113 return []
[email protected]b8079ae4a2012-12-05 19:56:493114
3115
Kent Tamura5a8755d2017-06-29 23:37:073116def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:213117 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
3118 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
3119 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:073120 include_re = input_api.re.compile(
3121 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
3122 extension_re = input_api.re.compile(r'\.[a-z]+$')
3123 errors = []
3124 for f in input_api.AffectedFiles():
3125 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
3126 continue
3127 found_line_number = None
3128 found_macro = None
3129 for line_num, line in f.ChangedContents():
3130 match = macro_re.search(line)
3131 if match:
3132 found_line_number = line_num
3133 found_macro = match.group(2)
3134 break
3135 if not found_line_number:
3136 continue
3137
3138 found_include = False
3139 for line in f.NewContents():
3140 if include_re.search(line):
3141 found_include = True
3142 break
3143 if found_include:
3144 continue
3145
3146 if not f.LocalPath().endswith('.h'):
3147 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
3148 try:
3149 content = input_api.ReadFile(primary_header_path, 'r')
3150 if include_re.search(content):
3151 continue
3152 except IOError:
3153 pass
3154 errors.append('%s:%d %s macro is used without including build/'
3155 'build_config.h.'
3156 % (f.LocalPath(), found_line_number, found_macro))
3157 if errors:
3158 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
3159 return []
3160
3161
[email protected]b00342e7f2013-03-26 16:21:543162def _DidYouMeanOSMacro(bad_macro):
3163 try:
3164 return {'A': 'OS_ANDROID',
3165 'B': 'OS_BSD',
3166 'C': 'OS_CHROMEOS',
3167 'F': 'OS_FREEBSD',
3168 'L': 'OS_LINUX',
3169 'M': 'OS_MACOSX',
3170 'N': 'OS_NACL',
3171 'O': 'OS_OPENBSD',
3172 'P': 'OS_POSIX',
3173 'S': 'OS_SOLARIS',
3174 'W': 'OS_WIN'}[bad_macro[3].upper()]
3175 except KeyError:
3176 return ''
3177
3178
3179def _CheckForInvalidOSMacrosInFile(input_api, f):
3180 """Check for sensible looking, totally invalid OS macros."""
3181 preprocessor_statement = input_api.re.compile(r'^\s*#')
3182 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
3183 results = []
3184 for lnum, line in f.ChangedContents():
3185 if preprocessor_statement.search(line):
3186 for match in os_macro.finditer(line):
3187 if not match.group(1) in _VALID_OS_MACROS:
3188 good = _DidYouMeanOSMacro(match.group(1))
3189 did_you_mean = ' (did you mean %s?)' % good if good else ''
3190 results.append(' %s:%d %s%s' % (f.LocalPath(),
3191 lnum,
3192 match.group(1),
3193 did_you_mean))
3194 return results
3195
3196
3197def _CheckForInvalidOSMacros(input_api, output_api):
3198 """Check all affected files for invalid OS macros."""
3199 bad_macros = []
tzik3f295992018-12-04 20:32:233200 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:473201 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:543202 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
3203
3204 if not bad_macros:
3205 return []
3206
3207 return [output_api.PresubmitError(
3208 'Possibly invalid OS macro[s] found. Please fix your code\n'
3209 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
3210
lliabraa35bab3932014-10-01 12:16:443211
3212def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
3213 """Check all affected files for invalid "if defined" macros."""
3214 ALWAYS_DEFINED_MACROS = (
3215 "TARGET_CPU_PPC",
3216 "TARGET_CPU_PPC64",
3217 "TARGET_CPU_68K",
3218 "TARGET_CPU_X86",
3219 "TARGET_CPU_ARM",
3220 "TARGET_CPU_MIPS",
3221 "TARGET_CPU_SPARC",
3222 "TARGET_CPU_ALPHA",
3223 "TARGET_IPHONE_SIMULATOR",
3224 "TARGET_OS_EMBEDDED",
3225 "TARGET_OS_IPHONE",
3226 "TARGET_OS_MAC",
3227 "TARGET_OS_UNIX",
3228 "TARGET_OS_WIN32",
3229 )
3230 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
3231 results = []
3232 for lnum, line in f.ChangedContents():
3233 for match in ifdef_macro.finditer(line):
3234 if match.group(1) in ALWAYS_DEFINED_MACROS:
3235 always_defined = ' %s is always defined. ' % match.group(1)
3236 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
3237 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
3238 lnum,
3239 always_defined,
3240 did_you_mean))
3241 return results
3242
3243
3244def _CheckForInvalidIfDefinedMacros(input_api, output_api):
3245 """Check all affected files for invalid "if defined" macros."""
3246 bad_macros = []
3247 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:213248 if f.LocalPath().startswith('third_party/sqlite/'):
3249 continue
lliabraa35bab3932014-10-01 12:16:443250 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3251 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3252
3253 if not bad_macros:
3254 return []
3255
3256 return [output_api.PresubmitError(
3257 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3258 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3259 bad_macros)]
3260
3261
mlamouria82272622014-09-16 18:45:043262def _CheckForIPCRules(input_api, output_api):
3263 """Check for same IPC rules described in
3264 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3265 """
3266 base_pattern = r'IPC_ENUM_TRAITS\('
3267 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3268 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3269
3270 problems = []
3271 for f in input_api.AffectedSourceFiles(None):
3272 local_path = f.LocalPath()
3273 if not local_path.endswith('.h'):
3274 continue
3275 for line_number, line in f.ChangedContents():
3276 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3277 problems.append(
3278 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3279
3280 if problems:
3281 return [output_api.PresubmitPromptWarning(
3282 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
3283 else:
3284 return []
3285
[email protected]b00342e7f2013-03-26 16:21:543286
Stephen Martinis97a394142018-06-07 23:06:053287def _CheckForLongPathnames(input_api, output_api):
3288 """Check to make sure no files being submitted have long paths.
3289 This causes issues on Windows.
3290 """
3291 problems = []
3292 for f in input_api.AffectedSourceFiles(None):
3293 local_path = f.LocalPath()
3294 # Windows has a path limit of 260 characters. Limit path length to 200 so
3295 # that we have some extra for the prefix on dev machines and the bots.
3296 if len(local_path) > 200:
3297 problems.append(local_path)
3298
3299 if problems:
3300 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
3301 else:
3302 return []
3303
3304
Daniel Bratell8ba52722018-03-02 16:06:143305def _CheckForIncludeGuards(input_api, output_api):
3306 """Check that header files have proper guards against multiple inclusion.
3307 If a file should not have such guards (and it probably should) then it
3308 should include the string "no-include-guard-because-multiply-included".
3309 """
Daniel Bratell6a75baef62018-06-04 10:04:453310 def is_chromium_header_file(f):
3311 # We only check header files under the control of the Chromium
3312 # project. That is, those outside third_party apart from
3313 # third_party/blink.
3314 file_with_path = input_api.os_path.normpath(f.LocalPath())
3315 return (file_with_path.endswith('.h') and
3316 (not file_with_path.startswith('third_party') or
3317 file_with_path.startswith(
3318 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:143319
3320 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:343321 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:143322
3323 errors = []
3324
Daniel Bratell6a75baef62018-06-04 10:04:453325 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:143326 guard_name = None
3327 guard_line_number = None
3328 seen_guard_end = False
3329
3330 file_with_path = input_api.os_path.normpath(f.LocalPath())
3331 base_file_name = input_api.os_path.splitext(
3332 input_api.os_path.basename(file_with_path))[0]
3333 upper_base_file_name = base_file_name.upper()
3334
3335 expected_guard = replace_special_with_underscore(
3336 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:143337
3338 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:573339 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
3340 # are too many (1000+) files with slight deviations from the
3341 # coding style. The most important part is that the include guard
3342 # is there, and that it's unique, not the name so this check is
3343 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:143344 #
3345 # As code becomes more uniform, this could be made stricter.
3346
3347 guard_name_pattern_list = [
3348 # Anything with the right suffix (maybe with an extra _).
3349 r'\w+_H__?',
3350
Daniel Bratell39b5b062018-05-16 18:09:573351 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:143352 r'\w+_h',
3353
3354 # Anything including the uppercase name of the file.
3355 r'\w*' + input_api.re.escape(replace_special_with_underscore(
3356 upper_base_file_name)) + r'\w*',
3357 ]
3358 guard_name_pattern = '|'.join(guard_name_pattern_list)
3359 guard_pattern = input_api.re.compile(
3360 r'#ifndef\s+(' + guard_name_pattern + ')')
3361
3362 for line_number, line in enumerate(f.NewContents()):
3363 if 'no-include-guard-because-multiply-included' in line:
3364 guard_name = 'DUMMY' # To not trigger check outside the loop.
3365 break
3366
3367 if guard_name is None:
3368 match = guard_pattern.match(line)
3369 if match:
3370 guard_name = match.group(1)
3371 guard_line_number = line_number
3372
Daniel Bratell39b5b062018-05-16 18:09:573373 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:453374 # don't match the chromium style guide, but new files should
3375 # get it right.
3376 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:573377 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:143378 errors.append(output_api.PresubmitPromptWarning(
3379 'Header using the wrong include guard name %s' % guard_name,
3380 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:573381 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:143382 else:
3383 # The line after #ifndef should have a #define of the same name.
3384 if line_number == guard_line_number + 1:
3385 expected_line = '#define %s' % guard_name
3386 if line != expected_line:
3387 errors.append(output_api.PresubmitPromptWarning(
3388 'Missing "%s" for include guard' % expected_line,
3389 ['%s:%d' % (f.LocalPath(), line_number + 1)],
3390 'Expected: %r\nGot: %r' % (expected_line, line)))
3391
3392 if not seen_guard_end and line == '#endif // %s' % guard_name:
3393 seen_guard_end = True
3394 elif seen_guard_end:
3395 if line.strip() != '':
3396 errors.append(output_api.PresubmitPromptWarning(
3397 'Include guard %s not covering the whole file' % (
3398 guard_name), [f.LocalPath()]))
3399 break # Nothing else to check and enough to warn once.
3400
3401 if guard_name is None:
3402 errors.append(output_api.PresubmitPromptWarning(
3403 'Missing include guard %s' % expected_guard,
3404 [f.LocalPath()],
3405 'Missing include guard in %s\n'
3406 'Recommended name: %s\n'
3407 'This check can be disabled by having the string\n'
3408 'no-include-guard-because-multiply-included in the header.' %
3409 (f.LocalPath(), expected_guard)))
3410
3411 return errors
3412
3413
mostynbb639aca52015-01-07 20:31:233414def _CheckForWindowsLineEndings(input_api, output_api):
3415 """Check source code and known ascii text files for Windows style line
3416 endings.
3417 """
earthdok1b5e0ee2015-03-10 15:19:103418 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233419
3420 file_inclusion_pattern = (
3421 known_text_files,
3422 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3423 )
3424
mostynbb639aca52015-01-07 20:31:233425 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533426 source_file_filter = lambda f: input_api.FilterSourceFile(
3427 f, white_list=file_inclusion_pattern, black_list=None)
3428 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503429 include_file = False
3430 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233431 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503432 include_file = True
3433 if include_file:
3434 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233435
3436 if problems:
3437 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3438 'these files to contain Windows style line endings?\n' +
3439 '\n'.join(problems))]
3440
3441 return []
3442
3443
Vaclav Brozekd5de76a2018-03-17 07:57:503444def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133445 """Checks that all source files use SYSLOG properly."""
3446 syslog_files = []
3447 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563448 for line_number, line in f.ChangedContents():
3449 if 'SYSLOG' in line:
3450 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3451
pastarmovj89f7ee12016-09-20 14:58:133452 if syslog_files:
3453 return [output_api.PresubmitPromptWarning(
3454 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3455 ' calls.\nFiles to check:\n', items=syslog_files)]
3456 return []
3457
3458
[email protected]1f7b4172010-01-28 01:17:343459def CheckChangeOnUpload(input_api, output_api):
3460 results = []
3461 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473462 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283463 results.extend(
jam93a6ee792017-02-08 23:59:223464 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193465 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223466 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133467 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163468 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:533469 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193470 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543471 return results
[email protected]ca8d1982009-02-19 16:33:123472
3473
[email protected]1bfb8322014-04-23 01:02:413474def GetTryServerMasterForBot(bot):
3475 """Returns the Try Server master for the given bot.
3476
[email protected]0bb112362014-07-26 04:38:323477 It tries to guess the master from the bot name, but may still fail
3478 and return None. There is no longer a default master.
3479 """
3480 # Potentially ambiguous bot names are listed explicitly.
3481 master_map = {
tandriie5587792016-07-14 00:34:503482 'chromium_presubmit': 'master.tryserver.chromium.linux',
3483 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413484 }
[email protected]0bb112362014-07-26 04:38:323485 master = master_map.get(bot)
3486 if not master:
wnwen4fbaab82016-05-25 12:54:363487 if 'android' in bot:
tandriie5587792016-07-14 00:34:503488 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363489 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503490 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323491 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503492 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323493 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503494 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323495 return master
[email protected]1bfb8322014-04-23 01:02:413496
3497
[email protected]ca8d1982009-02-19 16:33:123498def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543499 results = []
[email protected]1f7b4172010-01-28 01:17:343500 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573501 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543502 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273503 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343504 input_api,
3505 output_api,
[email protected]2fdd1f362013-01-16 03:56:033506 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273507
jam93a6ee792017-02-08 23:59:223508 results.extend(
3509 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543510 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3511 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413512 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3513 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543514 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143515
3516
3517def _CheckTranslationScreenshots(input_api, output_api):
3518 PART_FILE_TAG = "part"
3519 import os
3520 import sys
3521 from io import StringIO
3522
3523 try:
3524 old_sys_path = sys.path
3525 sys.path = sys.path + [input_api.os_path.join(
3526 input_api.PresubmitLocalPath(), 'tools', 'grit')]
3527 import grit.grd_reader
3528 import grit.node.message
3529 import grit.util
3530 finally:
3531 sys.path = old_sys_path
3532
3533 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
3534 """Load the grd file and return a dict of message ids to messages.
3535
3536 Ignores any nested grdp files pointed by <part> tag.
3537 """
3538 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
3539 stop_after=None, first_ids_file=None,
3540 debug=False, defines=None,
3541 tags_to_ignore=set([PART_FILE_TAG]))
3542 return {
3543 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
3544 grit.node.message.MessageNode)
3545 }
3546
3547 def _GetGrdpMessagesFromString(grdp_string):
3548 """Parses the contents of a grdp file given in grdp_string.
3549
3550 grd_reader can't parse grdp files directly. Instead, this creates a
3551 temporary directory with a grd file pointing to the grdp file, and loads the
3552 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
3553 """
3554 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
3555 <grit latest_public_release="1" current_release="1">
3556 <release seq="1">
3557 <messages>
3558 <part file="sub.grdp" />
3559 </messages>
3560 </release>
3561 </grit>
3562 """
3563 with grit.util.TempDir({'main.grd': WRAPPER,
3564 'sub.grdp': grdp_string}) as temp_dir:
3565 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
3566
3567 new_or_added_paths = set(f.LocalPath()
3568 for f in input_api.AffectedFiles()
3569 if (f.Action() == 'A' or f.Action() == 'M'))
3570 removed_paths = set(f.LocalPath()
3571 for f in input_api.AffectedFiles(include_deletes=True)
3572 if f.Action() == 'D')
3573
3574 affected_grds = [f for f in input_api.AffectedFiles()
3575 if (f.LocalPath().endswith('.grd') or
3576 f.LocalPath().endswith('.grdp'))]
3577 affected_png_paths = [f.AbsoluteLocalPath()
3578 for f in input_api.AffectedFiles()
3579 if (f.LocalPath().endswith('.png'))]
3580
3581 # Check for screenshots. Developers can upload screenshots using
3582 # tools/translation/upload_screenshots.py which finds and uploads
3583 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
3584 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
3585 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
3586 #
3587 # The logic here is as follows:
3588 #
3589 # - If the CL has a .png file under the screenshots directory for a grd
3590 # file, warn the developer. Actual images should never be checked into the
3591 # Chrome repo.
3592 #
3593 # - If the CL contains modified or new messages in grd files and doesn't
3594 # contain the corresponding .sha1 files, warn the developer to add images
3595 # and upload them via tools/translation/upload_screenshots.py.
3596 #
3597 # - If the CL contains modified or new messages in grd files and the
3598 # corresponding .sha1 files, everything looks good.
3599 #
3600 # - If the CL contains removed messages in grd files but the corresponding
3601 # .sha1 files aren't removed, warn the developer to remove them.
3602 unnecessary_screenshots = []
3603 missing_sha1 = []
3604 unnecessary_sha1_files = []
3605
3606
3607 def _CheckScreenshotAdded(screenshots_dir, message_id):
3608 sha1_path = input_api.os_path.join(
3609 screenshots_dir, message_id + '.png.sha1')
3610 if sha1_path not in new_or_added_paths:
3611 missing_sha1.append(sha1_path)
3612
3613
3614 def _CheckScreenshotRemoved(screenshots_dir, message_id):
3615 sha1_path = input_api.os_path.join(
3616 screenshots_dir, message_id + '.png.sha1')
3617 if sha1_path not in removed_paths:
3618 unnecessary_sha1_files.append(sha1_path)
3619
3620
3621 for f in affected_grds:
3622 file_path = f.LocalPath()
3623 old_id_to_msg_map = {}
3624 new_id_to_msg_map = {}
3625 if file_path.endswith('.grdp'):
3626 if f.OldContents():
3627 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393628 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143629 if f.NewContents():
3630 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393631 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143632 else:
3633 if f.OldContents():
3634 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393635 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143636 if f.NewContents():
3637 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393638 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143639
3640 # Compute added, removed and modified message IDs.
3641 old_ids = set(old_id_to_msg_map)
3642 new_ids = set(new_id_to_msg_map)
3643 added_ids = new_ids - old_ids
3644 removed_ids = old_ids - new_ids
3645 modified_ids = set([])
3646 for key in old_ids.intersection(new_ids):
3647 if (old_id_to_msg_map[key].FormatXml()
3648 != new_id_to_msg_map[key].FormatXml()):
3649 modified_ids.add(key)
3650
3651 grd_name, ext = input_api.os_path.splitext(
3652 input_api.os_path.basename(file_path))
3653 screenshots_dir = input_api.os_path.join(
3654 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
3655
3656 # Check the screenshot directory for .png files. Warn if there is any.
3657 for png_path in affected_png_paths:
3658 if png_path.startswith(screenshots_dir):
3659 unnecessary_screenshots.append(png_path)
3660
3661 for added_id in added_ids:
3662 _CheckScreenshotAdded(screenshots_dir, added_id)
3663
3664 for modified_id in modified_ids:
3665 _CheckScreenshotAdded(screenshots_dir, modified_id)
3666
3667 for removed_id in removed_ids:
3668 _CheckScreenshotRemoved(screenshots_dir, removed_id)
3669
3670 results = []
3671 if unnecessary_screenshots:
3672 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393673 'Do not include actual screenshots in the changelist. Run '
3674 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143675 sorted(unnecessary_screenshots)))
3676
3677 if missing_sha1:
3678 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393679 'You are adding or modifying UI strings.\n'
3680 'To ensure the best translations, take screenshots of the relevant UI '
3681 '(https://g.co/chrome/translation) and add these files to your '
3682 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143683
3684 if unnecessary_sha1_files:
3685 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393686 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143687 sorted(unnecessary_sha1_files)))
3688
3689 return results