blob: 336841c63d9e5ccf52960d21e0fb2ea55a272a7d [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]40d1dbb2012-10-26 07:18:0013 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
14 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2815 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0816 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5417 r"^skia[\\\/].*",
Kent Tamurae9b3a9ec2017-08-31 02:20:1918 r"^third_party[\\\/](WebKit|blink)[\\\/].*",
Mark Mentovaiebb9ddd62017-09-25 17:24:4119 r"^third_party[\\\/]breakpad[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
vapierb2053f542017-03-09 19:46:1026 r"tools[\\\/]md_browser[\\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1427 # Test pages for Maps telemetry tests.
28 r"tools[\\\/]perf[\\\/]page_sets[\\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5429 # Test pages for WebRTC telemetry tests.
30 r"tools[\\\/]perf[\\\/]page_sets[\\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4031)
[email protected]ca8d1982009-02-19 16:33:1232
wnwenbdc444e2016-05-25 13:44:1533
[email protected]06e6d0ff2012-12-11 01:36:4434# Fragment of a regular expression that matches C++ and Objective-C++
35# implementation files.
36_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
37
wnwenbdc444e2016-05-25 13:44:1538
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1939# Fragment of a regular expression that matches C++ and Objective-C++
40# header files.
41_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
42
43
[email protected]06e6d0ff2012-12-11 01:36:4444# Regular expression that matches code only used for test binaries
45# (best effort).
46_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4947 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4448 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4449 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1250 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4451 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4952 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0553 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4954 r'content[\\\/]shell[\\\/].*',
[email protected]7b054982013-11-27 00:44:4755 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4956 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0857 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4958 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4459)
[email protected]ca8d1982009-02-19 16:33:1260
wnwenbdc444e2016-05-25 13:44:1561
[email protected]eea609a2011-11-18 13:10:1262_TEST_ONLY_WARNING = (
63 'You might be calling functions intended only for testing from\n'
64 'production code. It is OK to ignore this warning if you know what\n'
65 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5866 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1267
68
[email protected]cf9b78f2012-11-14 11:40:2869_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4070 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2171 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
72 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2873
wnwenbdc444e2016-05-25 13:44:1574
Eric Stevensona9a980972017-09-23 00:04:4175_BANNED_JAVA_FUNCTIONS = (
76 (
77 'StrictMode.allowThreadDiskReads()',
78 (
79 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
80 'directly.',
81 ),
82 False,
83 ),
84 (
85 'StrictMode.allowThreadDiskWrites()',
86 (
87 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
88 'directly.',
89 ),
90 False,
91 ),
92)
93
[email protected]127f18ec2012-06-16 05:05:5994_BANNED_OBJC_FUNCTIONS = (
95 (
96 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2097 (
98 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5999 'prohibited. Please use CrTrackingArea instead.',
100 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
101 ),
102 False,
103 ),
104 (
[email protected]eaae1972014-04-16 04:17:26105 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20106 (
107 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59108 'instead.',
109 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
110 ),
111 False,
112 ),
113 (
114 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20115 (
116 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59117 'Please use |convertPoint:(point) fromView:nil| instead.',
118 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
119 ),
120 True,
121 ),
122 (
123 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20124 (
125 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59126 'Please use |convertPoint:(point) toView:nil| instead.',
127 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
128 ),
129 True,
130 ),
131 (
132 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20133 (
134 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59135 'Please use |convertRect:(point) fromView:nil| instead.',
136 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
137 ),
138 True,
139 ),
140 (
141 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20142 (
143 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59144 'Please use |convertRect:(point) toView:nil| instead.',
145 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
146 ),
147 True,
148 ),
149 (
150 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20151 (
152 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59153 'Please use |convertSize:(point) fromView:nil| instead.',
154 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
155 ),
156 True,
157 ),
158 (
159 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20160 (
161 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59162 'Please use |convertSize:(point) toView:nil| instead.',
163 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
164 ),
165 True,
166 ),
jif65398702016-10-27 10:19:48167 (
168 r"/\s+UTF8String\s*]",
169 (
170 'The use of -[NSString UTF8String] is dangerous as it can return null',
171 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
172 'Please use |SysNSStringToUTF8| instead.',
173 ),
174 True,
175 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34176 (
177 r'__unsafe_unretained',
178 (
179 'The use of __unsafe_unretained is almost certainly wrong, unless',
180 'when interacting with NSFastEnumeration or NSInvocation.',
181 'Please use __weak in files build with ARC, nothing otherwise.',
182 ),
183 False,
184 ),
[email protected]127f18ec2012-06-16 05:05:59185)
186
Sylvain Defresnea8b73d252018-02-28 15:45:54187_BANNED_IOS_OBJC_FUNCTIONS = (
188 (
189 r'/\bTEST[(]',
190 (
191 'TEST() macro should not be used in Objective-C++ code as it does not ',
192 'drain the autorelease pool at the end of the test. Use TEST_F() ',
193 'macro instead with a fixture inheriting from PlatformTest (or a ',
194 'typedef).'
195 ),
196 True,
197 ),
198 (
199 r'/\btesting::Test\b',
200 (
201 'testing::Test should not be used in Objective-C++ code as it does ',
202 'not drain the autorelease pool at the end of the test. Use ',
203 'PlatformTest instead.'
204 ),
205 True,
206 ),
207)
208
[email protected]127f18ec2012-06-16 05:05:59209
210_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20211 # Make sure that gtest's FRIEND_TEST() macro is not used; the
212 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30213 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20214 (
thomasandersone7caaa9b2017-03-29 19:22:53215 r'\bNULL\b',
216 (
217 'New code should not use NULL. Use nullptr instead.',
218 ),
219 True,
220 (),
221 ),
222 (
[email protected]23e6cbc2012-06-16 18:51:20223 'FRIEND_TEST(',
224 (
[email protected]e3c945502012-06-26 20:01:49225 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20226 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
227 ),
228 False,
[email protected]7345da02012-11-27 14:31:49229 (),
[email protected]23e6cbc2012-06-16 18:51:20230 ),
231 (
thomasanderson4b569052016-09-14 20:15:53232 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
233 (
234 'Chrome clients wishing to select events on X windows should use',
235 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
236 'you are selecting events from the GPU process, or if you are using',
237 'an XDisplay other than gfx::GetXDisplay().',
238 ),
239 True,
240 (
241 r"^ui[\\\/]gl[\\\/].*\.cc$",
242 r"^media[\\\/]gpu[\\\/].*\.cc$",
243 r"^gpu[\\\/].*\.cc$",
244 ),
245 ),
246 (
thomasandersone043e3ce2017-06-08 00:43:20247 r'XInternAtom|xcb_intern_atom',
248 (
thomasanderson11aa41d2017-06-08 22:22:38249 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20250 ),
251 True,
252 (
thomasanderson11aa41d2017-06-08 22:22:38253 r"^gpu[\\\/]ipc[\\\/]service[\\\/]gpu_watchdog_thread\.cc$",
254 r"^remoting[\\\/]host[\\\/]linux[\\\/]x_server_clipboard\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20255 r"^ui[\\\/]gfx[\\\/]x[\\\/]x11_atom_cache\.cc$",
256 ),
257 ),
258 (
tomhudsone2c14d552016-05-26 17:07:46259 'setMatrixClip',
260 (
261 'Overriding setMatrixClip() is prohibited; ',
262 'the base function is deprecated. ',
263 ),
264 True,
265 (),
266 ),
267 (
[email protected]52657f62013-05-20 05:30:31268 'SkRefPtr',
269 (
270 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22271 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31272 ),
273 True,
274 (),
275 ),
276 (
277 'SkAutoRef',
278 (
279 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22280 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31281 ),
282 True,
283 (),
284 ),
285 (
286 'SkAutoTUnref',
287 (
288 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22289 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31290 ),
291 True,
292 (),
293 ),
294 (
295 'SkAutoUnref',
296 (
297 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
298 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22299 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31300 ),
301 True,
302 (),
303 ),
[email protected]d89eec82013-12-03 14:10:59304 (
305 r'/HANDLE_EINTR\(.*close',
306 (
307 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
308 'descriptor will be closed, and it is incorrect to retry the close.',
309 'Either call close directly and ignore its return value, or wrap close',
310 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
311 ),
312 True,
313 (),
314 ),
315 (
316 r'/IGNORE_EINTR\((?!.*close)',
317 (
318 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
319 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
320 ),
321 True,
322 (
323 # Files that #define IGNORE_EINTR.
324 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
325 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
326 ),
327 ),
[email protected]ec5b3f02014-04-04 18:43:43328 (
329 r'/v8::Extension\(',
330 (
331 'Do not introduce new v8::Extensions into the code base, use',
332 'gin::Wrappable instead. See http://crbug.com/334679',
333 ),
334 True,
[email protected]f55c90ee62014-04-12 00:50:03335 (
joaodasilva718f87672014-08-30 09:25:49336 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03337 ),
[email protected]ec5b3f02014-04-04 18:43:43338 ),
skyostilf9469f72015-04-20 10:38:52339 (
jame2d1a952016-04-02 00:27:10340 '#pragma comment(lib,',
341 (
342 'Specify libraries to link with in build files and not in the source.',
343 ),
344 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41345 (
346 r'^third_party[\\\/]abseil-cpp[\\\/].*',
347 ),
jame2d1a952016-04-02 00:27:10348 ),
fdorayc4ac18d2017-05-01 21:39:59349 (
Gabriel Charette7cc6c432018-04-25 20:52:02350 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59351 (
352 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
353 ),
354 False,
355 (),
356 ),
357 (
Gabriel Charette7cc6c432018-04-25 20:52:02358 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59359 (
360 'Consider using THREAD_CHECKER macros instead of the class directly.',
361 ),
362 False,
363 (),
364 ),
dbeamb6f4fde2017-06-15 04:03:06365 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06366 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
367 (
368 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
369 'deprecated (http://crbug.com/634507). Please avoid converting away',
370 'from the Time types in Chromium code, especially if any math is',
371 'being done on time values. For interfacing with platform/library',
372 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
373 'type converter methods instead. For faking TimeXXX values (for unit',
374 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
375 'other use cases, please contact base/time/OWNERS.',
376 ),
377 False,
378 (),
379 ),
380 (
dbeamb6f4fde2017-06-15 04:03:06381 'CallJavascriptFunctionUnsafe',
382 (
383 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
384 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
385 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
386 ),
387 False,
388 (
389 r'^content[\\\/]browser[\\\/]webui[\\\/]web_ui_impl\.(cc|h)$',
390 r'^content[\\\/]public[\\\/]browser[\\\/]web_ui\.h$',
391 r'^content[\\\/]public[\\\/]test[\\\/]test_web_ui\.(cc|h)$',
392 ),
393 ),
dskiba1474c2bfd62017-07-20 02:19:24394 (
395 'leveldb::DB::Open',
396 (
397 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
398 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
399 "Chrome's tracing, making their memory usage visible.",
400 ),
401 True,
402 (
403 r'^third_party/leveldatabase/.*\.(cc|h)$',
404 ),
Gabriel Charette0592c3a2017-07-26 12:02:04405 ),
406 (
Chris Mumfordc38afb62017-10-09 17:55:08407 'leveldb::NewMemEnv',
408 (
409 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58410 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
411 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08412 ),
413 True,
414 (
415 r'^third_party/leveldatabase/.*\.(cc|h)$',
416 ),
417 ),
418 (
Gabriel Charetted9839bc2017-07-29 14:17:47419 'RunLoop::QuitCurrent',
420 (
Robert Liao64b7ab22017-08-04 23:03:43421 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
422 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47423 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41424 False,
Gabriel Charetted9839bc2017-07-29 14:17:47425 (),
Gabriel Charettea44975052017-08-21 23:14:04426 ),
427 (
428 'base::ScopedMockTimeMessageLoopTaskRunner',
429 (
Gabriel Charette87cc1af2018-04-25 20:52:51430 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
431 'ScopedTaskEnvironment::MainThreadType::MOCK_TIME. There are still a',
432 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
433 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
434 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04435 ),
Gabriel Charette87cc1af2018-04-25 20:52:51436 False,
Gabriel Charettea44975052017-08-21 23:14:04437 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57438 ),
439 (
440 r'std::regex',
441 (
442 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02443 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57444 ),
445 True,
446 (),
Francois Doray43670e32017-09-27 12:40:38447 ),
448 (
449 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
450 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
451 (
452 'Use the new API in base/threading/thread_restrictions.h.',
453 ),
Gabriel Charette04b138f2018-08-06 00:03:22454 False,
Francois Doray43670e32017-09-27 12:40:38455 (),
456 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38457 (
458 r'/\bbase::Bind\(',
459 (
Gabriel Charette147335ea2018-03-22 15:59:19460 'Please consider using base::Bind{Once,Repeating} instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02461 'of base::Bind. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38462 ),
463 False,
464 (),
465 ),
466 (
467 r'/\bbase::Callback<',
468 (
Gabriel Charette147335ea2018-03-22 15:59:19469 'Please consider using base::{Once,Repeating}Callback instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02470 'of base::Callback. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38471 ),
472 False,
473 (),
474 ),
475 (
476 r'/\bbase::Closure\b',
477 (
Gabriel Charette147335ea2018-03-22 15:59:19478 'Please consider using base::{Once,Repeating}Closure instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02479 'of base::Closure. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38480 ),
481 False,
482 (),
483 ),
Victor Costan3653df62018-02-08 21:38:16484 (
Gabriel Charette147335ea2018-03-22 15:59:19485 r'RunMessageLoop',
486 (
487 'RunMessageLoop is deprecated, use RunLoop instead.',
488 ),
489 False,
490 (),
491 ),
492 (
493 r'RunThisRunLoop',
494 (
495 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
496 ),
497 False,
498 (),
499 ),
500 (
501 r'RunAllPendingInMessageLoop()',
502 (
503 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
504 "if you're convinced you need this.",
505 ),
506 False,
507 (),
508 ),
509 (
510 r'RunAllPendingInMessageLoop(BrowserThread',
511 (
512 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
513 'BrowserThread::UI, TestBrowserThreadBundle::RunIOThreadUntilIdle',
514 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
515 'async events instead of flushing threads.',
516 ),
517 False,
518 (),
519 ),
520 (
521 r'MessageLoopRunner',
522 (
523 'MessageLoopRunner is deprecated, use RunLoop instead.',
524 ),
525 False,
526 (),
527 ),
528 (
529 r'GetDeferredQuitTaskForRunLoop',
530 (
531 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
532 "gab@ if you found a use case where this is the only solution.",
533 ),
534 False,
535 (),
536 ),
537 (
Victor Costan3653df62018-02-08 21:38:16538 'sqlite3_initialize',
539 (
540 'Instead of sqlite3_initialize, depend on //sql, ',
541 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
542 ),
543 True,
544 (
545 r'^sql/initialization\.(cc|h)$',
546 r'^third_party/sqlite/.*\.(c|cc|h)$',
547 ),
548 ),
Matt Menke7f520a82018-03-28 21:38:37549 (
550 'net::URLFetcher',
551 (
552 'net::URLFetcher should no longer be used in content embedders. ',
553 'Instead, use network::SimpleURLLoader instead, which supports ',
554 'an out-of-process network stack. ',
555 'net::URLFetcher may still be used in binaries that do not embed',
556 'content.',
557 ),
Matt Menke59716d02018-04-05 12:45:53558 False,
Matt Menke7f520a82018-03-28 21:38:37559 (
560 r'^ios[\\\/].*\.(cc|h)$',
561 r'.*[\\\/]ios[\\\/].*\.(cc|h)$',
562 r'.*_ios\.(cc|h)$',
563 r'^net[\\\/].*\.(cc|h)$',
564 r'.*[\\\/]tools[\\\/].*\.(cc|h)$',
565 ),
566 ),
jdoerried7d10ab2018-04-27 10:46:13567 (
568 r'/\barraysize\b',
569 (
570 "arraysize is deprecated, please use base::size(array) instead ",
571 "(https://crbug.com/837308). ",
572 ),
573 False,
574 (),
575 ),
tzik5de2157f2018-05-08 03:42:47576 (
577 r'std::random_shuffle',
578 (
579 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
580 'base::RandomShuffle instead.'
581 ),
582 True,
583 (),
584 ),
[email protected]127f18ec2012-06-16 05:05:59585)
586
wnwenbdc444e2016-05-25 13:44:15587
mlamouria82272622014-09-16 18:45:04588_IPC_ENUM_TRAITS_DEPRECATED = (
589 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50590 'See http://www.chromium.org/Home/chromium-security/education/'
591 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:04592
Stephen Martinis97a394142018-06-07 23:06:05593_LONG_PATH_ERROR = (
594 'Some files included in this CL have file names that are too long (> 200'
595 ' characters). If committed, these files will cause issues on Windows. See'
596 ' https://crbug.com/612667 for more details.'
597)
598
Shenghua Zhangbfaa38b82017-11-16 21:58:02599_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
600 r".*[\\\/]BuildHooksAndroidImpl\.java",
601 r".*[\\\/]LicenseContentProvider\.java",
James Wallace-Leef31ae6c2018-05-01 23:30:20602 r".*[\\\/]PlatformServiceBridgeImpl.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:02603]
[email protected]127f18ec2012-06-16 05:05:59604
Sean Kau46e29bc2017-08-28 16:31:16605# These paths contain test data and other known invalid JSON files.
606_KNOWN_INVALID_JSON_FILE_PATTERNS = [
607 r'test[\\\/]data[\\\/]',
608 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
609 r'^third_party[\\\/]protobuf[\\\/]',
Raphael Kubo da Costa211f3b472017-11-16 00:27:16610 r'^third_party[\\\/]WebKit[\\\/]LayoutTests[\\\/]external[\\\/]wpt[\\\/]',
Alexey Kozyatinskiya42a629f2018-04-17 17:49:38611 r'^third_party[\\\/]blink[\\\/]renderer[\\\/]devtools[\\\/]protocol\.json$',
Sean Kau46e29bc2017-08-28 16:31:16612]
613
614
[email protected]b00342e7f2013-03-26 16:21:54615_VALID_OS_MACROS = (
616 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08617 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54618 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:12619 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:54620 'OS_BSD',
621 'OS_CAT', # For testing.
622 'OS_CHROMEOS',
623 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37624 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54625 'OS_IOS',
626 'OS_LINUX',
627 'OS_MACOSX',
628 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21629 'OS_NACL_NONSFI',
630 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12631 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54632 'OS_OPENBSD',
633 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37634 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54635 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54636 'OS_WIN',
637)
638
639
agrievef32bcc72016-04-04 14:57:40640_ANDROID_SPECIFIC_PYDEPS_FILES = [
David 'Digit' Turner0006f4732018-08-07 07:12:36641 'base/android/jni_generator/jni_generator.pydeps',
642 'base/android/jni_generator/jni_registration_generator.pydeps',
643 'build/android/gyp/aar.pydeps',
644 'build/android/gyp/aidl.pydeps',
645 'build/android/gyp/apkbuilder.pydeps',
646 'build/android/gyp/app_bundle_to_apks.pydeps',
647 'build/android/gyp/bytecode_processor.pydeps',
648 'build/android/gyp/compile_resources.pydeps',
649 'build/android/gyp/create_bundle_wrapper_script.pydeps',
650 'build/android/gyp/copy_ex.pydeps',
651 'build/android/gyp/create_app_bundle.pydeps',
652 'build/android/gyp/create_apk_operations_script.pydeps',
653 'build/android/gyp/create_dist_jar.pydeps',
654 'build/android/gyp/create_java_binary_script.pydeps',
655 'build/android/gyp/create_stack_script.pydeps',
656 'build/android/gyp/create_test_runner_script.pydeps',
657 'build/android/gyp/create_tool_wrapper.pydeps',
658 'build/android/gyp/desugar.pydeps',
659 'build/android/gyp/dex.pydeps',
660 'build/android/gyp/dist_aar.pydeps',
661 'build/android/gyp/emma_instr.pydeps',
662 'build/android/gyp/filter_zip.pydeps',
663 'build/android/gyp/gcc_preprocess.pydeps',
664 'build/android/gyp/generate_proguarded_module_jar.pydeps',
665 'build/android/gyp/ijar.pydeps',
666 'build/android/gyp/java_cpp_enum.pydeps',
667 'build/android/gyp/javac.pydeps',
668 'build/android/gyp/jinja_template.pydeps',
669 'build/android/gyp/lint.pydeps',
670 'build/android/gyp/main_dex_list.pydeps',
671 'build/android/gyp/merge_jar_info_files.pydeps',
672 'build/android/gyp/merge_manifest.pydeps',
673 'build/android/gyp/prepare_resources.pydeps',
674 'build/android/gyp/proguard.pydeps',
675 'build/android/gyp/write_build_config.pydeps',
676 'build/android/gyp/write_ordered_libraries.pydeps',
677 'build/android/incremental_install/generate_android_manifest.pydeps',
678 'build/android/incremental_install/write_installer_json.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22679 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:40680 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04681 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36682 'build/protoc_java.pydeps',
jbudorick276cc562017-04-29 01:34:58683 'build/secondary/third_party/android_platform/'
684 'development/scripts/stack.pydeps',
agrieve732db3a2016-04-26 19:18:19685 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40686]
687
wnwenbdc444e2016-05-25 13:44:15688
agrievef32bcc72016-04-04 14:57:40689_GENERIC_PYDEPS_FILES = [
John Chencde89192018-01-27 21:18:40690 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Cole Winstanley7045a1b2018-08-27 23:37:29691 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22692 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:40693]
694
wnwenbdc444e2016-05-25 13:44:15695
agrievef32bcc72016-04-04 14:57:40696_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
697
698
Eric Boren6fd2b932018-01-25 15:05:08699# Bypass the AUTHORS check for these accounts.
700_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:29701 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
702 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:08703 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
Eric Boren57cc805b2018-08-20 17:28:32704 'spirv', 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:59705 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:45706 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:59707 ) | set('%[email protected]' % s
Sergiy Byelozyorovf78077a92018-06-14 08:07:11708 for s in ('v8-ci-autoroll-builder',))
Eric Boren6fd2b932018-01-25 15:05:08709
710
[email protected]55459852011-08-10 15:17:19711def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
712 """Attempts to prevent use of functions intended only for testing in
713 non-testing code. For now this is just a best-effort implementation
714 that ignores header files and may have some false positives. A
715 better implementation would probably need a proper C++ parser.
716 """
717 # We only scan .cc files and the like, as the declaration of
718 # for-testing functions in header files are hard to distinguish from
719 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49720 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:19721
jochenc0d4808c2015-07-27 09:25:42722 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19723 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09724 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19725 exclusion_pattern = input_api.re.compile(
726 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
727 base_function_pattern, base_function_pattern))
728
729 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44730 black_list = (_EXCLUDED_PATHS +
731 _TEST_CODE_EXCLUDED_PATHS +
732 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19733 return input_api.FilterSourceFile(
734 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49735 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:19736 black_list=black_list)
737
738 problems = []
739 for f in input_api.AffectedSourceFiles(FilterFile):
740 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24741 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03742 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46743 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03744 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19745 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03746 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19747
748 if problems:
[email protected]f7051d52013-04-02 18:31:42749 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03750 else:
751 return []
[email protected]55459852011-08-10 15:17:19752
753
Vaclav Brozek7dbc28c2018-03-27 08:35:23754def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
755 """This is a simplified version of
756 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
757 """
758 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
759 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
760 name_pattern = r'ForTest(s|ing)?'
761 # Describes an occurrence of "ForTest*" inside a // comment.
762 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
763 # Catch calls.
764 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
765 # Ignore definitions. (Comments are ignored separately.)
766 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
767
768 problems = []
769 sources = lambda x: input_api.FilterSourceFile(
770 x,
771 black_list=(('(?i).*test', r'.*\/junit\/')
772 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49773 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:23774 )
775 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
776 local_path = f.LocalPath()
777 is_inside_javadoc = False
778 for line_number, line in f.ChangedContents():
779 if is_inside_javadoc and javadoc_end_re.search(line):
780 is_inside_javadoc = False
781 if not is_inside_javadoc and javadoc_start_re.search(line):
782 is_inside_javadoc = True
783 if is_inside_javadoc:
784 continue
785 if (inclusion_re.search(line) and
786 not comment_re.search(line) and
787 not exclusion_re.search(line)):
788 problems.append(
789 '%s:%d\n %s' % (local_path, line_number, line.strip()))
790
791 if problems:
792 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
793 else:
794 return []
795
796
[email protected]10689ca2011-09-02 02:31:54797def _CheckNoIOStreamInHeaders(input_api, output_api):
798 """Checks to make sure no .h files include <iostream>."""
799 files = []
800 pattern = input_api.re.compile(r'^#include\s*<iostream>',
801 input_api.re.MULTILINE)
802 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
803 if not f.LocalPath().endswith('.h'):
804 continue
805 contents = input_api.ReadFile(f)
806 if pattern.search(contents):
807 files.append(f)
808
809 if len(files):
yolandyandaabc6d2016-04-18 18:29:39810 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06811 'Do not #include <iostream> in header files, since it inserts static '
812 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54813 '#include <ostream>. See http://crbug.com/94794',
814 files) ]
815 return []
816
Danil Chapovalov3518f362018-08-11 16:13:43817def _CheckNoStrCatRedefines(input_api, output_api):
818 """Checks no windows headers with StrCat redefined are included directly."""
819 files = []
820 pattern_deny = input_api.re.compile(
821 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
822 input_api.re.MULTILINE)
823 pattern_allow = input_api.re.compile(
824 r'^#include\s"base/win/windows_defines.inc"',
825 input_api.re.MULTILINE)
826 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
827 contents = input_api.ReadFile(f)
828 if pattern_deny.search(contents) and not pattern_allow.search(contents):
829 files.append(f.LocalPath())
830
831 if len(files):
832 return [output_api.PresubmitError(
833 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
834 'directly since they pollute code with StrCat macro. Instead, '
835 'include matching header from base/win. See http://crbug.com/856536',
836 files) ]
837 return []
838
[email protected]10689ca2011-09-02 02:31:54839
[email protected]72df4e782012-06-21 16:28:18840def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52841 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18842 problems = []
843 for f in input_api.AffectedFiles():
844 if (not f.LocalPath().endswith(('.cc', '.mm'))):
845 continue
846
847 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04848 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18849 problems.append(' %s:%d' % (f.LocalPath(), line_num))
850
851 if not problems:
852 return []
853 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
854 '\n'.join(problems))]
855
856
danakj61c1aa22015-10-26 19:55:52857def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57858 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52859 errors = []
860 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
861 input_api.re.MULTILINE)
862 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
863 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
864 continue
865 for lnum, line in f.ChangedContents():
866 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17867 errors.append(output_api.PresubmitError(
868 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57869 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17870 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52871 return errors
872
873
mcasasb7440c282015-02-04 14:52:19874def _FindHistogramNameInLine(histogram_name, line):
875 """Tries to find a histogram name or prefix in a line."""
876 if not "affected-histogram" in line:
877 return histogram_name in line
878 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
879 # the histogram_name.
880 if not '"' in line:
881 return False
882 histogram_prefix = line.split('\"')[1]
883 return histogram_prefix in histogram_name
884
885
886def _CheckUmaHistogramChanges(input_api, output_api):
887 """Check that UMA histogram names in touched lines can still be found in other
888 lines of the patch or in histograms.xml. Note that this check would not catch
889 the reverse: changes in histograms.xml not matched in the code itself."""
890 touched_histograms = []
891 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:47892 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
893 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
894 name_pattern = r'"(.*?)"'
895 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
896 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
897 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
898 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
899 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:17900 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:19901 for f in input_api.AffectedFiles():
902 # If histograms.xml itself is modified, keep the modified lines for later.
903 if f.LocalPath().endswith(('histograms.xml')):
904 histograms_xml_modifications = f.ChangedContents()
905 continue
Vaclav Brozekbdac817c2018-03-24 06:30:47906 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
907 single_line_re = single_line_c_re
908 split_line_prefix_re = split_line_c_prefix_re
909 elif f.LocalPath().endswith(('java')):
910 single_line_re = single_line_java_re
911 split_line_prefix_re = split_line_java_prefix_re
912 else:
mcasasb7440c282015-02-04 14:52:19913 continue
914 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:17915 if last_line_matched_prefix:
916 suffix_found = split_line_suffix_re.search(line)
917 if suffix_found :
918 touched_histograms.append([suffix_found.group(1), f, line_num])
919 last_line_matched_prefix = False
920 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:06921 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:19922 if found:
923 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:17924 continue
925 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:19926
927 # Search for the touched histogram names in the local modifications to
928 # histograms.xml, and, if not found, on the base histograms.xml file.
929 unmatched_histograms = []
930 for histogram_info in touched_histograms:
931 histogram_name_found = False
932 for line_num, line in histograms_xml_modifications:
933 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
934 if histogram_name_found:
935 break
936 if not histogram_name_found:
937 unmatched_histograms.append(histogram_info)
938
eromanb90c82e7e32015-04-01 15:13:49939 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19940 problems = []
941 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49942 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19943 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45944 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19945 histogram_name_found = False
946 for line in histograms_xml:
947 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
948 if histogram_name_found:
949 break
950 if not histogram_name_found:
951 problems.append(' [%s:%d] %s' %
952 (f.LocalPath(), line_num, histogram_name))
953
954 if not problems:
955 return []
956 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
957 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49958 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19959
wnwenbdc444e2016-05-25 13:44:15960
yolandyandaabc6d2016-04-18 18:29:39961def _CheckFlakyTestUsage(input_api, output_api):
962 """Check that FlakyTest annotation is our own instead of the android one"""
963 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
964 files = []
965 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
966 if f.LocalPath().endswith('Test.java'):
967 if pattern.search(input_api.ReadFile(f)):
968 files.append(f)
969 if len(files):
970 return [output_api.PresubmitError(
971 'Use org.chromium.base.test.util.FlakyTest instead of '
972 'android.test.FlakyTest',
973 files)]
974 return []
mcasasb7440c282015-02-04 14:52:19975
wnwenbdc444e2016-05-25 13:44:15976
[email protected]8ea5d4b2011-09-13 21:49:22977def _CheckNoNewWStrings(input_api, output_api):
978 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27979 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22980 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20981 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57982 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34983 '/win/' in f.LocalPath() or
984 'chrome_elf' in f.LocalPath() or
985 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20986 continue
[email protected]8ea5d4b2011-09-13 21:49:22987
[email protected]a11dbe9b2012-08-07 01:32:58988 allowWString = False
[email protected]b5c24292011-11-28 14:38:20989 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58990 if 'presubmit: allow wstring' in line:
991 allowWString = True
992 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27993 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58994 allowWString = False
995 else:
996 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22997
[email protected]55463aa62011-10-12 00:48:27998 if not problems:
999 return []
1000 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581001 ' If you are calling a cross-platform API that accepts a wstring, '
1002 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271003 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221004
1005
[email protected]2a8ac9c2011-10-19 17:20:441006def _CheckNoDEPSGIT(input_api, output_api):
1007 """Make sure .DEPS.git is never modified manually."""
1008 if any(f.LocalPath().endswith('.DEPS.git') for f in
1009 input_api.AffectedFiles()):
1010 return [output_api.PresubmitError(
1011 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1012 'automated system based on what\'s in DEPS and your changes will be\n'
1013 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501014 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1015 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441016 'for more information')]
1017 return []
1018
1019
tandriief664692014-09-23 14:51:471020def _CheckValidHostsInDEPS(input_api, output_api):
1021 """Checks that DEPS file deps are from allowed_hosts."""
1022 # Run only if DEPS file has been modified to annoy fewer bystanders.
1023 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1024 return []
1025 # Outsource work to gclient verify
1026 try:
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201027 input_api.subprocess.check_output(['gclient', 'verify'],
1028 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471029 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201030 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471031 return [output_api.PresubmitError(
1032 'DEPS file must have only git dependencies.',
1033 long_text=error.output)]
1034
1035
[email protected]127f18ec2012-06-16 05:05:591036def _CheckNoBannedFunctions(input_api, output_api):
1037 """Make sure that banned functions are not used."""
1038 warnings = []
1039 errors = []
1040
wnwenbdc444e2016-05-25 13:44:151041 def IsBlacklisted(affected_file, blacklist):
1042 local_path = affected_file.LocalPath()
1043 for item in blacklist:
1044 if input_api.re.match(item, local_path):
1045 return True
1046 return False
1047
Sylvain Defresnea8b73d252018-02-28 15:45:541048 def IsIosObcjFile(affected_file):
1049 local_path = affected_file.LocalPath()
1050 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1051 return False
1052 basename = input_api.os_path.basename(local_path)
1053 if 'ios' in basename.split('_'):
1054 return True
1055 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1056 if sep and 'ios' in local_path.split(sep):
1057 return True
1058 return False
1059
wnwenbdc444e2016-05-25 13:44:151060 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
1061 matched = False
1062 if func_name[0:1] == '/':
1063 regex = func_name[1:]
1064 if input_api.re.search(regex, line):
1065 matched = True
1066 elif func_name in line:
dchenge07de812016-06-20 19:27:171067 matched = True
wnwenbdc444e2016-05-25 13:44:151068 if matched:
dchenge07de812016-06-20 19:27:171069 problems = warnings
wnwenbdc444e2016-05-25 13:44:151070 if error:
dchenge07de812016-06-20 19:27:171071 problems = errors
wnwenbdc444e2016-05-25 13:44:151072 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1073 for message_line in message:
1074 problems.append(' %s' % message_line)
1075
Eric Stevensona9a980972017-09-23 00:04:411076 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1077 for f in input_api.AffectedFiles(file_filter=file_filter):
1078 for line_num, line in f.ChangedContents():
1079 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1080 CheckForMatch(f, line_num, line, func_name, message, error)
1081
[email protected]127f18ec2012-06-16 05:05:591082 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1083 for f in input_api.AffectedFiles(file_filter=file_filter):
1084 for line_num, line in f.ChangedContents():
1085 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151086 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591087
Sylvain Defresnea8b73d252018-02-28 15:45:541088 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1089 for line_num, line in f.ChangedContents():
1090 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1091 CheckForMatch(f, line_num, line, func_name, message, error)
1092
[email protected]127f18ec2012-06-16 05:05:591093 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1094 for f in input_api.AffectedFiles(file_filter=file_filter):
1095 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491096 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491097 if IsBlacklisted(f, excluded_paths):
1098 continue
wnwenbdc444e2016-05-25 13:44:151099 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591100
1101 result = []
1102 if (warnings):
1103 result.append(output_api.PresubmitPromptWarning(
1104 'Banned functions were used.\n' + '\n'.join(warnings)))
1105 if (errors):
1106 result.append(output_api.PresubmitError(
1107 'Banned functions were used.\n' + '\n'.join(errors)))
1108 return result
1109
1110
[email protected]6c063c62012-07-11 19:11:061111def _CheckNoPragmaOnce(input_api, output_api):
1112 """Make sure that banned functions are not used."""
1113 files = []
1114 pattern = input_api.re.compile(r'^#pragma\s+once',
1115 input_api.re.MULTILINE)
1116 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1117 if not f.LocalPath().endswith('.h'):
1118 continue
1119 contents = input_api.ReadFile(f)
1120 if pattern.search(contents):
1121 files.append(f)
1122
1123 if files:
1124 return [output_api.PresubmitError(
1125 'Do not use #pragma once in header files.\n'
1126 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1127 files)]
1128 return []
1129
[email protected]127f18ec2012-06-16 05:05:591130
[email protected]e7479052012-09-19 00:26:121131def _CheckNoTrinaryTrueFalse(input_api, output_api):
1132 """Checks to make sure we don't introduce use of foo ? true : false."""
1133 problems = []
1134 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1135 for f in input_api.AffectedFiles():
1136 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1137 continue
1138
1139 for line_num, line in f.ChangedContents():
1140 if pattern.match(line):
1141 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1142
1143 if not problems:
1144 return []
1145 return [output_api.PresubmitPromptWarning(
1146 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1147 '\n'.join(problems))]
1148
1149
[email protected]55f9f382012-07-31 11:02:181150def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281151 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181152 change. Breaking - rules is an error, breaking ! rules is a
1153 warning.
1154 """
mohan.reddyf21db962014-10-16 12:26:471155 import sys
[email protected]55f9f382012-07-31 11:02:181156 # We need to wait until we have an input_api object and use this
1157 # roundabout construct to import checkdeps because this file is
1158 # eval-ed and thus doesn't have __file__.
1159 original_sys_path = sys.path
1160 try:
1161 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471162 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181163 import checkdeps
1164 from cpp_checker import CppChecker
Jinsuk Kim5a092672017-10-24 22:42:241165 from java_checker import JavaChecker
rhalavati08acd232017-04-03 07:23:281166 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:181167 from rules import Rule
1168 finally:
1169 # Restore sys.path to what it was before.
1170 sys.path = original_sys_path
1171
1172 added_includes = []
rhalavati08acd232017-04-03 07:23:281173 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241174 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181175 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:281176 if CppChecker.IsCppFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501177 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081178 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
rhalavati08acd232017-04-03 07:23:281179 elif ProtoChecker.IsProtoFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501180 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081181 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241182 elif JavaChecker.IsJavaFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501183 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081184 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181185
[email protected]26385172013-05-09 23:11:351186 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181187
1188 error_descriptions = []
1189 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281190 error_subjects = set()
1191 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181192 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1193 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081194 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181195 description_with_path = '%s\n %s' % (path, rule_description)
1196 if rule_type == Rule.DISALLOW:
1197 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281198 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181199 else:
1200 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281201 warning_subjects.add("#includes")
1202
1203 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1204 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081205 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281206 description_with_path = '%s\n %s' % (path, rule_description)
1207 if rule_type == Rule.DISALLOW:
1208 error_descriptions.append(description_with_path)
1209 error_subjects.add("imports")
1210 else:
1211 warning_descriptions.append(description_with_path)
1212 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181213
Jinsuk Kim5a092672017-10-24 22:42:241214 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021215 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081216 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241217 description_with_path = '%s\n %s' % (path, rule_description)
1218 if rule_type == Rule.DISALLOW:
1219 error_descriptions.append(description_with_path)
1220 error_subjects.add("imports")
1221 else:
1222 warning_descriptions.append(description_with_path)
1223 warning_subjects.add("imports")
1224
[email protected]55f9f382012-07-31 11:02:181225 results = []
1226 if error_descriptions:
1227 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281228 'You added one or more %s that violate checkdeps rules.'
1229 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181230 error_descriptions))
1231 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421232 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281233 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181234 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281235 '%s? See relevant DEPS file(s) for details and contacts.' %
1236 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181237 warning_descriptions))
1238 return results
1239
1240
[email protected]fbcafe5a2012-08-08 15:31:221241def _CheckFilePermissions(input_api, output_api):
1242 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151243 if input_api.platform == 'win32':
1244 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291245 checkperms_tool = input_api.os_path.join(
1246 input_api.PresubmitLocalPath(),
1247 'tools', 'checkperms', 'checkperms.py')
1248 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471249 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391250 with input_api.CreateTemporaryFile() as file_list:
1251 for f in input_api.AffectedFiles():
1252 # checkperms.py file/directory arguments must be relative to the
1253 # repository.
1254 file_list.write(f.LocalPath() + '\n')
1255 file_list.close()
1256 args += ['--file-list', file_list.name]
1257 try:
1258 input_api.subprocess.check_output(args)
1259 return []
1260 except input_api.subprocess.CalledProcessError as error:
1261 return [output_api.PresubmitError(
1262 'checkperms.py failed:',
1263 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221264
1265
robertocn832f5992017-01-04 19:01:301266def _CheckTeamTags(input_api, output_api):
1267 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1268 checkteamtags_tool = input_api.os_path.join(
1269 input_api.PresubmitLocalPath(),
1270 'tools', 'checkteamtags', 'checkteamtags.py')
1271 args = [input_api.python_executable, checkteamtags_tool,
1272 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221273 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301274 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1275 'OWNERS']
1276 try:
1277 if files:
1278 input_api.subprocess.check_output(args + files)
1279 return []
1280 except input_api.subprocess.CalledProcessError as error:
1281 return [output_api.PresubmitError(
1282 'checkteamtags.py failed:',
1283 long_text=error.output)]
1284
1285
[email protected]c8278b32012-10-30 20:35:491286def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1287 """Makes sure we don't include ui/aura/window_property.h
1288 in header files.
1289 """
1290 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1291 errors = []
1292 for f in input_api.AffectedFiles():
1293 if not f.LocalPath().endswith('.h'):
1294 continue
1295 for line_num, line in f.ChangedContents():
1296 if pattern.match(line):
1297 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1298
1299 results = []
1300 if errors:
1301 results.append(output_api.PresubmitError(
1302 'Header files should not include ui/aura/window_property.h', errors))
1303 return results
1304
1305
[email protected]70ca77752012-11-20 03:45:031306def _CheckForVersionControlConflictsInFile(input_api, f):
1307 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1308 errors = []
1309 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:231310 if f.LocalPath().endswith('.md'):
1311 # First-level headers in markdown look a lot like version control
1312 # conflict markers. http://daringfireball.net/projects/markdown/basics
1313 continue
[email protected]70ca77752012-11-20 03:45:031314 if pattern.match(line):
1315 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1316 return errors
1317
1318
1319def _CheckForVersionControlConflicts(input_api, output_api):
1320 """Usually this is not intentional and will cause a compile failure."""
1321 errors = []
1322 for f in input_api.AffectedFiles():
1323 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1324
1325 results = []
1326 if errors:
1327 results.append(output_api.PresubmitError(
1328 'Version control conflict markers found, please resolve.', errors))
1329 return results
1330
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201331
estadee17314a02017-01-12 16:22:161332def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1333 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1334 errors = []
1335 for f in input_api.AffectedFiles():
1336 for line_num, line in f.ChangedContents():
1337 if pattern.search(line):
1338 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1339
1340 results = []
1341 if errors:
1342 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501343 'Found Google support URL addressed by answer number. Please replace '
1344 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161345 return results
1346
[email protected]70ca77752012-11-20 03:45:031347
[email protected]06e6d0ff2012-12-11 01:36:441348def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1349 def FilterFile(affected_file):
1350 """Filter function for use with input_api.AffectedSourceFiles,
1351 below. This filters out everything except non-test files from
1352 top-level directories that generally speaking should not hard-code
1353 service URLs (e.g. src/android_webview/, src/content/ and others).
1354 """
1355 return input_api.FilterSourceFile(
1356 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491357 white_list=[r'^(android_webview|base|content|net)[\\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:441358 black_list=(_EXCLUDED_PATHS +
1359 _TEST_CODE_EXCLUDED_PATHS +
1360 input_api.DEFAULT_BLACK_LIST))
1361
reillyi38965732015-11-16 18:27:331362 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1363 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461364 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1365 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441366 problems = [] # items are (filename, line_number, line)
1367 for f in input_api.AffectedSourceFiles(FilterFile):
1368 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461369 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441370 problems.append((f.LocalPath(), line_num, line))
1371
1372 if problems:
[email protected]f7051d52013-04-02 18:31:421373 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441374 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581375 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441376 [' %s:%d: %s' % (
1377 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031378 else:
1379 return []
[email protected]06e6d0ff2012-12-11 01:36:441380
1381
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491382# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:271383def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1384 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311385 The native_client_sdk directory is excluded because it has auto-generated PNG
1386 files for documentation.
[email protected]d2530012013-01-25 16:39:271387 """
[email protected]d2530012013-01-25 16:39:271388 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491389 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
1390 black_list = [r'^native_client_sdk[\\\/]']
binji0dcdf342014-12-12 18:32:311391 file_filter = lambda f: input_api.FilterSourceFile(
1392 f, white_list=white_list, black_list=black_list)
1393 for f in input_api.AffectedFiles(include_deletes=False,
1394 file_filter=file_filter):
1395 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271396
1397 results = []
1398 if errors:
1399 results.append(output_api.PresubmitError(
1400 'The name of PNG files should not have abbreviations. \n'
1401 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1402 'Contact [email protected] if you have questions.', errors))
1403 return results
1404
1405
Daniel Cheng4dcdb6b2017-04-13 08:30:171406def _ExtractAddRulesFromParsedDeps(parsed_deps):
1407 """Extract the rules that add dependencies from a parsed DEPS file.
1408
1409 Args:
1410 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1411 add_rules = set()
1412 add_rules.update([
1413 rule[1:] for rule in parsed_deps.get('include_rules', [])
1414 if rule.startswith('+') or rule.startswith('!')
1415 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501416 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171417 {}).iteritems():
1418 add_rules.update([
1419 rule[1:] for rule in rules
1420 if rule.startswith('+') or rule.startswith('!')
1421 ])
1422 return add_rules
1423
1424
1425def _ParseDeps(contents):
1426 """Simple helper for parsing DEPS files."""
1427 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171428 class _VarImpl:
1429
1430 def __init__(self, local_scope):
1431 self._local_scope = local_scope
1432
1433 def Lookup(self, var_name):
1434 """Implements the Var syntax."""
1435 try:
1436 return self._local_scope['vars'][var_name]
1437 except KeyError:
1438 raise Exception('Var is not defined: %s' % var_name)
1439
1440 local_scope = {}
1441 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171442 'Var': _VarImpl(local_scope).Lookup,
1443 }
1444 exec contents in global_scope, local_scope
1445 return local_scope
1446
1447
1448def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081449 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411450 a set of DEPS entries that we should look up.
1451
1452 For a directory (rather than a specific filename) we fake a path to
1453 a specific filename by adding /DEPS. This is chosen as a file that
1454 will seldom or never be subject to per-file include_rules.
1455 """
[email protected]2b438d62013-11-14 17:54:141456 # We ignore deps entries on auto-generated directories.
1457 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081458
Daniel Cheng4dcdb6b2017-04-13 08:30:171459 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1460 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1461
1462 added_deps = new_deps.difference(old_deps)
1463
[email protected]2b438d62013-11-14 17:54:141464 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171465 for added_dep in added_deps:
1466 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1467 continue
1468 # Assume that a rule that ends in .h is a rule for a specific file.
1469 if added_dep.endswith('.h'):
1470 results.add(added_dep)
1471 else:
1472 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081473 return results
1474
1475
[email protected]e871964c2013-05-13 14:14:551476def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1477 """When a dependency prefixed with + is added to a DEPS file, we
1478 want to make sure that the change is reviewed by an OWNER of the
1479 target file or directory, to avoid layering violations from being
1480 introduced. This check verifies that this happens.
1481 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171482 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241483
1484 file_filter = lambda f: not input_api.re.match(
Kent Tamurae9b3a9ec2017-08-31 02:20:191485 r"^third_party[\\\/](WebKit|blink)[\\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241486 for f in input_api.AffectedFiles(include_deletes=False,
1487 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551488 filename = input_api.os_path.basename(f.LocalPath())
1489 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171490 virtual_depended_on_files.update(_CalculateAddedDeps(
1491 input_api.os_path,
1492 '\n'.join(f.OldContents()),
1493 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551494
[email protected]e871964c2013-05-13 14:14:551495 if not virtual_depended_on_files:
1496 return []
1497
1498 if input_api.is_committing:
1499 if input_api.tbr:
1500 return [output_api.PresubmitNotifyResult(
1501 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271502 if input_api.dry_run:
1503 return [output_api.PresubmitNotifyResult(
1504 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551505 if not input_api.change.issue:
1506 return [output_api.PresubmitError(
1507 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401508 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551509 output = output_api.PresubmitError
1510 else:
1511 output = output_api.PresubmitNotifyResult
1512
1513 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501514 owner_email, reviewers = (
1515 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1516 input_api,
1517 owners_db.email_regexp,
1518 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551519
1520 owner_email = owner_email or input_api.change.author_email
1521
[email protected]de4f7d22013-05-23 14:27:461522 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511523 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461524 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551525 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1526 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411527
1528 # We strip the /DEPS part that was added by
1529 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1530 # directory.
1531 def StripDeps(path):
1532 start_deps = path.rfind('/DEPS')
1533 if start_deps != -1:
1534 return path[:start_deps]
1535 else:
1536 return path
1537 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551538 for path in missing_files]
1539
1540 if unapproved_dependencies:
1541 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151542 output('You need LGTM from owners of depends-on paths in DEPS that were '
1543 'modified in this CL:\n %s' %
1544 '\n '.join(sorted(unapproved_dependencies)))]
1545 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1546 output_list.append(output(
1547 'Suggested missing target path OWNERS:\n %s' %
1548 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551549 return output_list
1550
1551 return []
1552
1553
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491554# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:401555def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491556 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:401557 black_list = (_EXCLUDED_PATHS +
1558 _TEST_CODE_EXCLUDED_PATHS +
1559 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501560 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191561 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481562 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461563 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121564 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1565 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581566 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
Olivier Liec4400b22018-07-31 19:50:441567 r"^chrome[\\\/]chrome_cleaner[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161568 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031569 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151570 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1571 r"^chromecast[\\\/]",
1572 r"^cloud_print[\\\/]",
manzagop85e629e2017-05-09 22:11:481573 r"^components[\\\/]browser_watcher[\\\/]"
1574 r"dump_stability_report_main_win.cc$",
jochen34415e52015-07-10 08:34:311575 r"^components[\\\/]html_viewer[\\\/]"
1576 r"web_test_delegate_impl\.cc$",
Samuel Huang577ef6c2018-03-13 18:19:341577 r"^components[\\\/]zucchini[\\\/].*",
peter80739bb2015-10-20 11:17:461578 # TODO(peter): Remove this exception. https://crbug.com/534537
1579 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1580 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251581 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1582 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241583 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111584 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151585 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111586 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521587 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501588 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361589 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311590 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131591 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001592 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441593 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451594 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021595 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351596 r"dump_file_system.cc$",
1597 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401598 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491599 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:401600
thomasanderson625d3932017-03-29 07:16:581601 log_info = set([])
1602 printf = set([])
[email protected]85218562013-11-22 07:41:401603
1604 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581605 for _, line in f.ChangedContents():
1606 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1607 log_info.add(f.LocalPath())
1608 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1609 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371610
thomasanderson625d3932017-03-29 07:16:581611 if input_api.re.search(r"\bprintf\(", line):
1612 printf.add(f.LocalPath())
1613 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1614 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401615
1616 if log_info:
1617 return [output_api.PresubmitError(
1618 'These files spam the console log with LOG(INFO):',
1619 items=log_info)]
1620 if printf:
1621 return [output_api.PresubmitError(
1622 'These files spam the console log with printf/fprintf:',
1623 items=printf)]
1624 return []
1625
1626
[email protected]49aa76a2013-12-04 06:59:161627def _CheckForAnonymousVariables(input_api, output_api):
1628 """These types are all expected to hold locks while in scope and
1629 so should never be anonymous (which causes them to be immediately
1630 destroyed)."""
1631 they_who_must_be_named = [
1632 'base::AutoLock',
1633 'base::AutoReset',
1634 'base::AutoUnlock',
1635 'SkAutoAlphaRestore',
1636 'SkAutoBitmapShaderInstall',
1637 'SkAutoBlitterChoose',
1638 'SkAutoBounderCommit',
1639 'SkAutoCallProc',
1640 'SkAutoCanvasRestore',
1641 'SkAutoCommentBlock',
1642 'SkAutoDescriptor',
1643 'SkAutoDisableDirectionCheck',
1644 'SkAutoDisableOvalCheck',
1645 'SkAutoFree',
1646 'SkAutoGlyphCache',
1647 'SkAutoHDC',
1648 'SkAutoLockColors',
1649 'SkAutoLockPixels',
1650 'SkAutoMalloc',
1651 'SkAutoMaskFreeImage',
1652 'SkAutoMutexAcquire',
1653 'SkAutoPathBoundsUpdate',
1654 'SkAutoPDFRelease',
1655 'SkAutoRasterClipValidate',
1656 'SkAutoRef',
1657 'SkAutoTime',
1658 'SkAutoTrace',
1659 'SkAutoUnref',
1660 ]
1661 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1662 # bad: base::AutoLock(lock.get());
1663 # not bad: base::AutoLock lock(lock.get());
1664 bad_pattern = input_api.re.compile(anonymous)
1665 # good: new base::AutoLock(lock.get())
1666 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1667 errors = []
1668
1669 for f in input_api.AffectedFiles():
1670 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1671 continue
1672 for linenum, line in f.ChangedContents():
1673 if bad_pattern.search(line) and not good_pattern.search(line):
1674 errors.append('%s:%d' % (f.LocalPath(), linenum))
1675
1676 if errors:
1677 return [output_api.PresubmitError(
1678 'These lines create anonymous variables that need to be named:',
1679 items=errors)]
1680 return []
1681
1682
Peter Kasting4844e46e2018-02-23 07:27:101683def _CheckUniquePtr(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491684 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:101685 sources = lambda affected_file: input_api.FilterSourceFile(
1686 affected_file,
1687 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1688 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491689 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:551690
1691 # Pattern to capture a single "<...>" block of template arguments. It can
1692 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
1693 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
1694 # latter would likely require counting that < and > match, which is not
1695 # expressible in regular languages. Should the need arise, one can introduce
1696 # limited counting (matching up to a total number of nesting depth), which
1697 # should cover all practical cases for already a low nesting limit.
1698 template_arg_pattern = (
1699 r'<[^>]*' # Opening block of <.
1700 r'>([^<]*>)?') # Closing block of >.
1701 # Prefix expressing that whatever follows is not already inside a <...>
1702 # block.
1703 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:101704 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:551705 not_inside_template_arg_pattern
1706 + r'\bstd::unique_ptr'
1707 + template_arg_pattern
1708 + r'\(\)')
1709
1710 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
1711 template_arg_no_array_pattern = (
1712 r'<[^>]*[^]]' # Opening block of <.
1713 r'>([^(<]*[^]]>)?') # Closing block of >.
1714 # Prefix saying that what follows is the start of an expression.
1715 start_of_expr_pattern = r'(=|\breturn|^)\s*'
1716 # Suffix saying that what follows are call parentheses with a non-empty list
1717 # of arguments.
1718 nonempty_arg_list_pattern = r'\(([^)]|$)'
1719 return_construct_pattern = input_api.re.compile(
1720 start_of_expr_pattern
1721 + r'std::unique_ptr'
1722 + template_arg_no_array_pattern
1723 + nonempty_arg_list_pattern)
1724
Vaclav Brozek851d9602018-04-04 16:13:051725 problems_constructor = []
1726 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:101727 for f in input_api.AffectedSourceFiles(sources):
1728 for line_number, line in f.ChangedContents():
1729 # Disallow:
1730 # return std::unique_ptr<T>(foo);
1731 # bar = std::unique_ptr<T>(foo);
1732 # But allow:
1733 # return std::unique_ptr<T[]>(foo);
1734 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozek851d9602018-04-04 16:13:051735 local_path = f.LocalPath()
Peter Kasting4844e46e2018-02-23 07:27:101736 if return_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051737 problems_constructor.append(
1738 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:101739 # Disallow:
1740 # std::unique_ptr<T>()
1741 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051742 problems_nullptr.append(
1743 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1744
1745 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:161746 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:051747 errors.append(output_api.PresubmitError(
1748 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161749 problems_nullptr))
1750 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:051751 errors.append(output_api.PresubmitError(
1752 'The following files use explicit std::unique_ptr constructor.'
1753 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161754 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:101755 return errors
1756
1757
[email protected]999261d2014-03-03 20:08:081758def _CheckUserActionUpdate(input_api, output_api):
1759 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521760 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081761 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521762 # If actions.xml is already included in the changelist, the PRESUBMIT
1763 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081764 return []
1765
[email protected]999261d2014-03-03 20:08:081766 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1767 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521768 current_actions = None
[email protected]999261d2014-03-03 20:08:081769 for f in input_api.AffectedFiles(file_filter=file_filter):
1770 for line_num, line in f.ChangedContents():
1771 match = input_api.re.search(action_re, line)
1772 if match:
[email protected]2f92dec2014-03-07 19:21:521773 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1774 # loaded only once.
1775 if not current_actions:
1776 with open('tools/metrics/actions/actions.xml') as actions_f:
1777 current_actions = actions_f.read()
1778 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081779 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521780 action = 'name="{0}"'.format(action_name)
1781 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081782 return [output_api.PresubmitPromptWarning(
1783 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521784 'tools/metrics/actions/actions.xml. Please run '
1785 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081786 % (f.LocalPath(), line_num, action_name))]
1787 return []
1788
1789
Daniel Cheng13ca61a882017-08-25 15:11:251790def _ImportJSONCommentEater(input_api):
1791 import sys
1792 sys.path = sys.path + [input_api.os_path.join(
1793 input_api.PresubmitLocalPath(),
1794 'tools', 'json_comment_eater')]
1795 import json_comment_eater
1796 return json_comment_eater
1797
1798
[email protected]99171a92014-06-03 08:44:471799def _GetJSONParseError(input_api, filename, eat_comments=True):
1800 try:
1801 contents = input_api.ReadFile(filename)
1802 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:251803 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:131804 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471805
1806 input_api.json.loads(contents)
1807 except ValueError as e:
1808 return e
1809 return None
1810
1811
1812def _GetIDLParseError(input_api, filename):
1813 try:
1814 contents = input_api.ReadFile(filename)
1815 idl_schema = input_api.os_path.join(
1816 input_api.PresubmitLocalPath(),
1817 'tools', 'json_schema_compiler', 'idl_schema.py')
1818 process = input_api.subprocess.Popen(
1819 [input_api.python_executable, idl_schema],
1820 stdin=input_api.subprocess.PIPE,
1821 stdout=input_api.subprocess.PIPE,
1822 stderr=input_api.subprocess.PIPE,
1823 universal_newlines=True)
1824 (_, error) = process.communicate(input=contents)
1825 return error or None
1826 except ValueError as e:
1827 return e
1828
1829
1830def _CheckParseErrors(input_api, output_api):
1831 """Check that IDL and JSON files do not contain syntax errors."""
1832 actions = {
1833 '.idl': _GetIDLParseError,
1834 '.json': _GetJSONParseError,
1835 }
[email protected]99171a92014-06-03 08:44:471836 # Most JSON files are preprocessed and support comments, but these do not.
1837 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491838 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471839 ]
1840 # Only run IDL checker on files in these directories.
1841 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491842 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1843 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471844 ]
1845
1846 def get_action(affected_file):
1847 filename = affected_file.LocalPath()
1848 return actions.get(input_api.os_path.splitext(filename)[1])
1849
[email protected]99171a92014-06-03 08:44:471850 def FilterFile(affected_file):
1851 action = get_action(affected_file)
1852 if not action:
1853 return False
1854 path = affected_file.LocalPath()
1855
Sean Kau46e29bc2017-08-28 16:31:161856 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:471857 return False
1858
1859 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:161860 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:471861 return False
1862 return True
1863
1864 results = []
1865 for affected_file in input_api.AffectedFiles(
1866 file_filter=FilterFile, include_deletes=False):
1867 action = get_action(affected_file)
1868 kwargs = {}
1869 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:161870 _MatchesFile(input_api, json_no_comments_patterns,
1871 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:471872 kwargs['eat_comments'] = False
1873 parse_error = action(input_api,
1874 affected_file.AbsoluteLocalPath(),
1875 **kwargs)
1876 if parse_error:
1877 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1878 (affected_file.LocalPath(), parse_error)))
1879 return results
1880
1881
[email protected]760deea2013-12-10 19:33:491882def _CheckJavaStyle(input_api, output_api):
1883 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471884 import sys
[email protected]760deea2013-12-10 19:33:491885 original_sys_path = sys.path
1886 try:
1887 sys.path = sys.path + [input_api.os_path.join(
1888 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1889 import checkstyle
1890 finally:
1891 # Restore sys.path to what it was before.
1892 sys.path = original_sys_path
1893
1894 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091895 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511896 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491897
1898
Sean Kau46e29bc2017-08-28 16:31:161899def _MatchesFile(input_api, patterns, path):
1900 for pattern in patterns:
1901 if input_api.re.search(pattern, path):
1902 return True
1903 return False
1904
1905
Daniel Cheng7052cdf2017-11-21 19:23:291906def _GetOwnersFilesToCheckForIpcOwners(input_api):
1907 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:171908
Daniel Cheng7052cdf2017-11-21 19:23:291909 Returns:
1910 A dictionary mapping an OWNER file to the list of OWNERS rules it must
1911 contain to cover IPC-related files with noparent reviewer rules.
1912 """
1913 # Whether or not a file affects IPC is (mostly) determined by a simple list
1914 # of filename patterns.
dchenge07de812016-06-20 19:27:171915 file_patterns = [
palmerb19a0932017-01-24 04:00:311916 # Legacy IPC:
dchenge07de812016-06-20 19:27:171917 '*_messages.cc',
1918 '*_messages*.h',
1919 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311920 # Mojo IPC:
dchenge07de812016-06-20 19:27:171921 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:471922 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:171923 '*_struct_traits*.*',
1924 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311925 '*.typemap',
1926 # Android native IPC:
1927 '*.aidl',
1928 # Blink uses a different file naming convention:
1929 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:471930 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:171931 '*StructTraits*.*',
1932 '*TypeConverter*.*',
1933 ]
1934
scottmg7a6ed5ba2016-11-04 18:22:041935 # These third_party directories do not contain IPCs, but contain files
1936 # matching the above patterns, which trigger false positives.
1937 exclude_paths = [
1938 'third_party/crashpad/*',
Andres Medinae684cf42018-08-27 18:48:231939 'third_party/protobuf/benchmarks/python/*',
Daniel Chengebe635e2018-07-13 12:36:061940 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:291941 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:041942 ]
1943
dchenge07de812016-06-20 19:27:171944 # Dictionary mapping an OWNERS file path to Patterns.
1945 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1946 # rules ) to a PatternEntry.
1947 # PatternEntry is a dictionary with two keys:
1948 # - 'files': the files that are matched by this pattern
1949 # - 'rules': the per-file rules needed for this pattern
1950 # For example, if we expect OWNERS file to contain rules for *.mojom and
1951 # *_struct_traits*.*, Patterns might look like this:
1952 # {
1953 # '*.mojom': {
1954 # 'files': ...,
1955 # 'rules': [
1956 # 'per-file *.mojom=set noparent',
1957 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1958 # ],
1959 # },
1960 # '*_struct_traits*.*': {
1961 # 'files': ...,
1962 # 'rules': [
1963 # 'per-file *_struct_traits*.*=set noparent',
1964 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1965 # ],
1966 # },
1967 # }
1968 to_check = {}
1969
Daniel Cheng13ca61a882017-08-25 15:11:251970 def AddPatternToCheck(input_file, pattern):
1971 owners_file = input_api.os_path.join(
1972 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
1973 if owners_file not in to_check:
1974 to_check[owners_file] = {}
1975 if pattern not in to_check[owners_file]:
1976 to_check[owners_file][pattern] = {
1977 'files': [],
1978 'rules': [
1979 'per-file %s=set noparent' % pattern,
1980 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1981 ]
1982 }
Vaclav Brozekd5de76a2018-03-17 07:57:501983 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:251984
dchenge07de812016-06-20 19:27:171985 # Iterate through the affected files to see what we actually need to check
1986 # for. We should only nag patch authors about per-file rules if a file in that
1987 # directory would match that pattern. If a directory only contains *.mojom
1988 # files and no *_messages*.h files, we should only nag about rules for
1989 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:251990 for f in input_api.AffectedFiles(include_deletes=False):
1991 # Manifest files don't have a strong naming convention. Instead, scan
1992 # affected files for .json files and see if they look like a manifest.
Sean Kau46e29bc2017-08-28 16:31:161993 if (f.LocalPath().endswith('.json') and
1994 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
1995 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:251996 json_comment_eater = _ImportJSONCommentEater(input_api)
1997 mostly_json_lines = '\n'.join(f.NewContents())
1998 # Comments aren't allowed in strict JSON, so filter them out.
1999 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:432000 try:
2001 json_content = input_api.json.loads(json_lines)
2002 except:
2003 # There's another PRESUBMIT check that already verifies that JSON files
2004 # are not invalid, so no need to emit another warning here.
2005 continue
Daniel Cheng13ca61a882017-08-25 15:11:252006 if 'interface_provider_specs' in json_content:
2007 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172008 for pattern in file_patterns:
2009 if input_api.fnmatch.fnmatch(
2010 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042011 skip = False
2012 for exclude in exclude_paths:
2013 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2014 skip = True
2015 break
2016 if skip:
2017 continue
Daniel Cheng13ca61a882017-08-25 15:11:252018 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172019 break
2020
Daniel Cheng7052cdf2017-11-21 19:23:292021 return to_check
2022
2023
2024def _CheckIpcOwners(input_api, output_api):
2025 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2026 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2027
2028 if to_check:
2029 # If there are any OWNERS files to check, there are IPC-related changes in
2030 # this CL. Auto-CC the review list.
2031 output_api.AppendCC('[email protected]')
2032
2033 # Go through the OWNERS files to check, filtering out rules that are already
2034 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172035 for owners_file, patterns in to_check.iteritems():
2036 try:
2037 with file(owners_file) as f:
2038 lines = set(f.read().splitlines())
2039 for entry in patterns.itervalues():
2040 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2041 ]
2042 except IOError:
2043 # No OWNERS file, so all the rules are definitely missing.
2044 continue
2045
2046 # All the remaining lines weren't found in OWNERS files, so emit an error.
2047 errors = []
2048 for owners_file, patterns in to_check.iteritems():
2049 missing_lines = []
2050 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502051 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172052 missing_lines.extend(entry['rules'])
2053 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2054 if missing_lines:
2055 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052056 'Because of the presence of files:\n%s\n\n'
2057 '%s needs the following %d lines added:\n\n%s' %
2058 ('\n'.join(files), owners_file, len(missing_lines),
2059 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172060
2061 results = []
2062 if errors:
vabrf5ce3bf92016-07-11 14:52:412063 if input_api.is_committing:
2064 output = output_api.PresubmitError
2065 else:
2066 output = output_api.PresubmitPromptWarning
2067 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592068 'Found OWNERS files that need to be updated for IPC security ' +
2069 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172070 long_text='\n\n'.join(errors)))
2071
2072 return results
2073
2074
jbriance9e12f162016-11-25 07:57:502075def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312076 """Checks that added or removed lines in non third party affected
2077 header files do not lead to new useless class or struct forward
2078 declaration.
jbriance9e12f162016-11-25 07:57:502079 """
2080 results = []
2081 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2082 input_api.re.MULTILINE)
2083 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2084 input_api.re.MULTILINE)
2085 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312086 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192087 not f.LocalPath().startswith('third_party/blink') and
2088 not f.LocalPath().startswith('third_party\\blink') and
jbriance2c51e821a2016-12-12 08:24:312089 not f.LocalPath().startswith('third_party/WebKit') and
2090 not f.LocalPath().startswith('third_party\\WebKit')):
2091 continue
2092
jbriance9e12f162016-11-25 07:57:502093 if not f.LocalPath().endswith('.h'):
2094 continue
2095
2096 contents = input_api.ReadFile(f)
2097 fwd_decls = input_api.re.findall(class_pattern, contents)
2098 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2099
2100 useless_fwd_decls = []
2101 for decl in fwd_decls:
2102 count = sum(1 for _ in input_api.re.finditer(
2103 r'\b%s\b' % input_api.re.escape(decl), contents))
2104 if count == 1:
2105 useless_fwd_decls.append(decl)
2106
2107 if not useless_fwd_decls:
2108 continue
2109
2110 for line in f.GenerateScmDiff().splitlines():
2111 if (line.startswith('-') and not line.startswith('--') or
2112 line.startswith('+') and not line.startswith('++')):
2113 for decl in useless_fwd_decls:
2114 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2115 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242116 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502117 (f.LocalPath(), decl)))
2118 useless_fwd_decls.remove(decl)
2119
2120 return results
2121
2122
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492123# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:292124def _CheckAndroidToastUsage(input_api, output_api):
2125 """Checks that code uses org.chromium.ui.widget.Toast instead of
2126 android.widget.Toast (Chromium Toast doesn't force hardware
2127 acceleration on low-end devices, saving memory).
2128 """
2129 toast_import_pattern = input_api.re.compile(
2130 r'^import android\.widget\.Toast;$')
2131
2132 errors = []
2133
2134 sources = lambda affected_file: input_api.FilterSourceFile(
2135 affected_file,
2136 black_list=(_EXCLUDED_PATHS +
2137 _TEST_CODE_EXCLUDED_PATHS +
2138 input_api.DEFAULT_BLACK_LIST +
2139 (r'^chromecast[\\\/].*',
2140 r'^remoting[\\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492141 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:292142
2143 for f in input_api.AffectedSourceFiles(sources):
2144 for line_num, line in f.ChangedContents():
2145 if toast_import_pattern.search(line):
2146 errors.append("%s:%d" % (f.LocalPath(), line_num))
2147
2148 results = []
2149
2150 if errors:
2151 results.append(output_api.PresubmitError(
2152 'android.widget.Toast usage is detected. Android toasts use hardware'
2153 ' acceleration, and can be\ncostly on low-end devices. Please use'
2154 ' org.chromium.ui.widget.Toast instead.\n'
2155 'Contact [email protected] if you have any questions.',
2156 errors))
2157
2158 return results
2159
2160
dgnaa68d5e2015-06-10 10:08:222161def _CheckAndroidCrLogUsage(input_api, output_api):
2162 """Checks that new logs using org.chromium.base.Log:
2163 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512164 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222165 """
pkotwicza1dd0b002016-05-16 14:41:042166
torne89540622017-03-24 19:41:302167 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042168 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302169 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:042170 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:302171 # WebView license viewer code cannot depend on //base; used in stub APK.
2172 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
2173 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:042174 ]
2175
dgnaa68d5e2015-06-10 10:08:222176 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122177 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2178 class_in_base_pattern = input_api.re.compile(
2179 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2180 has_some_log_import_pattern = input_api.re.compile(
2181 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222182 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122183 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222184 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512185 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222186 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222187
Vincent Scheib16d7b272015-09-15 18:09:072188 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222189 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492190 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:042191 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122192
dgnaa68d5e2015-06-10 10:08:222193 tag_decl_errors = []
2194 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122195 tag_errors = []
dgn38736db2015-09-18 19:20:512196 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122197 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222198
2199 for f in input_api.AffectedSourceFiles(sources):
2200 file_content = input_api.ReadFile(f)
2201 has_modified_logs = False
2202
2203 # Per line checks
dgn87d9fb62015-06-12 09:15:122204 if (cr_log_import_pattern.search(file_content) or
2205 (class_in_base_pattern.search(file_content) and
2206 not has_some_log_import_pattern.search(file_content))):
2207 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222208 for line_num, line in f.ChangedContents():
2209
2210 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122211 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222212 if match:
2213 has_modified_logs = True
2214
2215 # Make sure it uses "TAG"
2216 if not match.group('tag') == 'TAG':
2217 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122218 else:
2219 # Report non cr Log function calls in changed lines
2220 for line_num, line in f.ChangedContents():
2221 if log_call_pattern.search(line):
2222 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222223
2224 # Per file checks
2225 if has_modified_logs:
2226 # Make sure the tag is using the "cr" prefix and is not too long
2227 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512228 tag_name = match.group('name') if match else None
2229 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222230 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512231 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222232 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512233 elif '.' in tag_name:
2234 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222235
2236 results = []
2237 if tag_decl_errors:
2238 results.append(output_api.PresubmitPromptWarning(
2239 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512240 '"private static final String TAG = "<package tag>".\n'
2241 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222242 tag_decl_errors))
2243
2244 if tag_length_errors:
2245 results.append(output_api.PresubmitError(
2246 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512247 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222248 tag_length_errors))
2249
2250 if tag_errors:
2251 results.append(output_api.PresubmitPromptWarning(
2252 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2253 tag_errors))
2254
dgn87d9fb62015-06-12 09:15:122255 if util_log_errors:
dgn4401aa52015-04-29 16:26:172256 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122257 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2258 util_log_errors))
2259
dgn38736db2015-09-18 19:20:512260 if tag_with_dot_errors:
2261 results.append(output_api.PresubmitPromptWarning(
2262 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2263 tag_with_dot_errors))
2264
dgn4401aa52015-04-29 16:26:172265 return results
2266
2267
Yoland Yanb92fa522017-08-28 17:37:062268def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2269 """Checks that junit.framework.* is no longer used."""
2270 deprecated_junit_framework_pattern = input_api.re.compile(
2271 r'^import junit\.framework\..*;',
2272 input_api.re.MULTILINE)
2273 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492274 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062275 errors = []
2276 for f in input_api.AffectedFiles(sources):
2277 for line_num, line in f.ChangedContents():
2278 if deprecated_junit_framework_pattern.search(line):
2279 errors.append("%s:%d" % (f.LocalPath(), line_num))
2280
2281 results = []
2282 if errors:
2283 results.append(output_api.PresubmitError(
2284 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2285 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2286 ' if you have any question.', errors))
2287 return results
2288
2289
2290def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2291 """Checks that if new Java test classes have inheritance.
2292 Either the new test class is JUnit3 test or it is a JUnit4 test class
2293 with a base class, either case is undesirable.
2294 """
2295 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2296
2297 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492298 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062299 errors = []
2300 for f in input_api.AffectedFiles(sources):
2301 if not f.OldContents():
2302 class_declaration_start_flag = False
2303 for line_num, line in f.ChangedContents():
2304 if class_declaration_pattern.search(line):
2305 class_declaration_start_flag = True
2306 if class_declaration_start_flag and ' extends ' in line:
2307 errors.append('%s:%d' % (f.LocalPath(), line_num))
2308 if '{' in line:
2309 class_declaration_start_flag = False
2310
2311 results = []
2312 if errors:
2313 results.append(output_api.PresubmitPromptWarning(
2314 'The newly created files include Test classes that inherits from base'
2315 ' class. Please do not use inheritance in JUnit4 tests or add new'
2316 ' JUnit3 tests. Contact [email protected] if you have any'
2317 ' questions.', errors))
2318 return results
2319
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202320
yolandyan45001472016-12-21 21:12:422321def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2322 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2323 deprecated_annotation_import_pattern = input_api.re.compile(
2324 r'^import android\.test\.suitebuilder\.annotation\..*;',
2325 input_api.re.MULTILINE)
2326 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492327 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:422328 errors = []
2329 for f in input_api.AffectedFiles(sources):
2330 for line_num, line in f.ChangedContents():
2331 if deprecated_annotation_import_pattern.search(line):
2332 errors.append("%s:%d" % (f.LocalPath(), line_num))
2333
2334 results = []
2335 if errors:
2336 results.append(output_api.PresubmitError(
2337 'Annotations in android.test.suitebuilder.annotation have been'
2338 ' deprecated since API level 24. Please use android.support.test.filters'
2339 ' from //third_party/android_support_test_runner:runner_java instead.'
2340 ' Contact [email protected] if you have any questions.', errors))
2341 return results
2342
2343
agrieve7b6479d82015-10-07 14:24:222344def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2345 """Checks if MDPI assets are placed in a correct directory."""
2346 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2347 ('/res/drawable/' in f.LocalPath() or
2348 '/res/drawable-ldrtl/' in f.LocalPath()))
2349 errors = []
2350 for f in input_api.AffectedFiles(include_deletes=False,
2351 file_filter=file_filter):
2352 errors.append(' %s' % f.LocalPath())
2353
2354 results = []
2355 if errors:
2356 results.append(output_api.PresubmitError(
2357 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2358 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2359 '/res/drawable-ldrtl/.\n'
2360 'Contact [email protected] if you have questions.', errors))
2361 return results
2362
2363
Nate Fischer535972b2017-09-16 01:06:182364def _CheckAndroidWebkitImports(input_api, output_api):
2365 """Checks that code uses org.chromium.base.Callback instead of
2366 android.widget.ValueCallback except in the WebView glue layer.
2367 """
2368 valuecallback_import_pattern = input_api.re.compile(
2369 r'^import android\.webkit\.ValueCallback;$')
2370
2371 errors = []
2372
2373 sources = lambda affected_file: input_api.FilterSourceFile(
2374 affected_file,
2375 black_list=(_EXCLUDED_PATHS +
2376 _TEST_CODE_EXCLUDED_PATHS +
2377 input_api.DEFAULT_BLACK_LIST +
2378 (r'^android_webview[\\\/]glue[\\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492379 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:182380
2381 for f in input_api.AffectedSourceFiles(sources):
2382 for line_num, line in f.ChangedContents():
2383 if valuecallback_import_pattern.search(line):
2384 errors.append("%s:%d" % (f.LocalPath(), line_num))
2385
2386 results = []
2387
2388 if errors:
2389 results.append(output_api.PresubmitError(
2390 'android.webkit.ValueCallback usage is detected outside of the glue'
2391 ' layer. To stay compatible with the support library, android.webkit.*'
2392 ' classes should only be used inside the glue layer and'
2393 ' org.chromium.base.Callback should be used instead.',
2394 errors))
2395
2396 return results
2397
2398
agrievef32bcc72016-04-04 14:57:402399class PydepsChecker(object):
2400 def __init__(self, input_api, pydeps_files):
2401 self._file_cache = {}
2402 self._input_api = input_api
2403 self._pydeps_files = pydeps_files
2404
2405 def _LoadFile(self, path):
2406 """Returns the list of paths within a .pydeps file relative to //."""
2407 if path not in self._file_cache:
2408 with open(path) as f:
2409 self._file_cache[path] = f.read()
2410 return self._file_cache[path]
2411
2412 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2413 """Returns an interable of paths within the .pydep, relativized to //."""
2414 os_path = self._input_api.os_path
2415 pydeps_dir = os_path.dirname(pydeps_path)
2416 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2417 if not l.startswith('*'))
2418 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2419
2420 def _CreateFilesToPydepsMap(self):
2421 """Returns a map of local_path -> list_of_pydeps."""
2422 ret = {}
2423 for pydep_local_path in self._pydeps_files:
2424 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2425 ret.setdefault(path, []).append(pydep_local_path)
2426 return ret
2427
2428 def ComputeAffectedPydeps(self):
2429 """Returns an iterable of .pydeps files that might need regenerating."""
2430 affected_pydeps = set()
2431 file_to_pydeps_map = None
2432 for f in self._input_api.AffectedFiles(include_deletes=True):
2433 local_path = f.LocalPath()
2434 if local_path == 'DEPS':
2435 return self._pydeps_files
2436 elif local_path.endswith('.pydeps'):
2437 if local_path in self._pydeps_files:
2438 affected_pydeps.add(local_path)
2439 elif local_path.endswith('.py'):
2440 if file_to_pydeps_map is None:
2441 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2442 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2443 return affected_pydeps
2444
2445 def DetermineIfStale(self, pydeps_path):
2446 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412447 import difflib
John Budorick47ca3fe2018-02-10 00:53:102448 import os
2449
agrievef32bcc72016-04-04 14:57:402450 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2451 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102452 env = dict(os.environ)
2453 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402454 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102455 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412456 old_contents = old_pydeps_data[2:]
2457 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402458 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412459 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402460
2461
2462def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2463 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402464 # This check is for Python dependency lists (.pydeps files), and involves
2465 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2466 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282467 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002468 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022469 # TODO(agrieve): Update when there's a better way to detect
2470 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402471 is_android = input_api.os_path.exists('third_party/android_tools')
2472 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2473 results = []
2474 # First, check for new / deleted .pydeps.
2475 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032476 # Check whether we are running the presubmit check for a file in src.
2477 # f.LocalPath is relative to repo (src, or internal repo).
2478 # os_path.exists is relative to src repo.
2479 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2480 # to src and we can conclude that the pydeps is in src.
2481 if input_api.os_path.exists(f.LocalPath()):
2482 if f.LocalPath().endswith('.pydeps'):
2483 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2484 results.append(output_api.PresubmitError(
2485 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2486 'remove %s' % f.LocalPath()))
2487 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2488 results.append(output_api.PresubmitError(
2489 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2490 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402491
2492 if results:
2493 return results
2494
2495 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2496
2497 for pydep_path in checker.ComputeAffectedPydeps():
2498 try:
phajdan.jr0d9878552016-11-04 10:49:412499 result = checker.DetermineIfStale(pydep_path)
2500 if result:
2501 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402502 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412503 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2504 'To regenerate, run:\n\n %s' %
2505 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402506 except input_api.subprocess.CalledProcessError as error:
2507 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2508 long_text=error.output)]
2509
2510 return results
2511
2512
glidere61efad2015-02-18 17:39:432513def _CheckSingletonInHeaders(input_api, output_api):
2514 """Checks to make sure no header files have |Singleton<|."""
2515 def FileFilter(affected_file):
2516 # It's ok for base/memory/singleton.h to have |Singleton<|.
2517 black_list = (_EXCLUDED_PATHS +
2518 input_api.DEFAULT_BLACK_LIST +
Michael Warrese4451492018-03-07 04:42:472519 (r"^base[\\\/]memory[\\\/]singleton\.h$",
2520 r"^net[\\\/]quic[\\\/]platform[\\\/]impl[\\\/]"
2521 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432522 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2523
sergeyu34d21222015-09-16 00:11:442524 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432525 files = []
2526 for f in input_api.AffectedSourceFiles(FileFilter):
2527 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2528 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2529 contents = input_api.ReadFile(f)
2530 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242531 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432532 pattern.search(line)):
2533 files.append(f)
2534 break
2535
2536 if files:
yolandyandaabc6d2016-04-18 18:29:392537 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442538 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432539 'Please move them to an appropriate source file so that the ' +
2540 'template gets instantiated in a single compilation unit.',
2541 files) ]
2542 return []
2543
2544
[email protected]fd20b902014-05-09 02:14:532545_DEPRECATED_CSS = [
2546 # Values
2547 ( "-webkit-box", "flex" ),
2548 ( "-webkit-inline-box", "inline-flex" ),
2549 ( "-webkit-flex", "flex" ),
2550 ( "-webkit-inline-flex", "inline-flex" ),
2551 ( "-webkit-min-content", "min-content" ),
2552 ( "-webkit-max-content", "max-content" ),
2553
2554 # Properties
2555 ( "-webkit-background-clip", "background-clip" ),
2556 ( "-webkit-background-origin", "background-origin" ),
2557 ( "-webkit-background-size", "background-size" ),
2558 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442559 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532560
2561 # Functions
2562 ( "-webkit-gradient", "gradient" ),
2563 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2564 ( "-webkit-linear-gradient", "linear-gradient" ),
2565 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2566 ( "-webkit-radial-gradient", "radial-gradient" ),
2567 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2568]
2569
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202570
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492571# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242572def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532573 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252574 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342575 documentation and iOS CSS for dom distiller
2576 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252577 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532578 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492579 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:252580 black_list = (_EXCLUDED_PATHS +
2581 _TEST_CODE_EXCLUDED_PATHS +
2582 input_api.DEFAULT_BLACK_LIST +
2583 (r"^chrome/common/extensions/docs",
2584 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342585 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442586 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252587 r"^native_client_sdk"))
2588 file_filter = lambda f: input_api.FilterSourceFile(
2589 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532590 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2591 for line_num, line in fpath.ChangedContents():
2592 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022593 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532594 results.append(output_api.PresubmitError(
2595 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2596 (fpath.LocalPath(), line_num, deprecated_value, value)))
2597 return results
2598
mohan.reddyf21db962014-10-16 12:26:472599
dbeam070cfe62014-10-22 06:44:022600_DEPRECATED_JS = [
2601 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2602 ( "__defineGetter__", "Object.defineProperty" ),
2603 ( "__defineSetter__", "Object.defineProperty" ),
2604]
2605
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202606
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492607# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242608def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022609 """Make sure that we don't use deprecated JS in Chrome code."""
2610 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492611 file_inclusion_pattern = [r".+\.js$"] # TODO(dbeam): .html?
dbeam070cfe62014-10-22 06:44:022612 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2613 input_api.DEFAULT_BLACK_LIST)
2614 file_filter = lambda f: input_api.FilterSourceFile(
2615 f, white_list=file_inclusion_pattern, black_list=black_list)
2616 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2617 for lnum, line in fpath.ChangedContents():
2618 for (deprecated, replacement) in _DEPRECATED_JS:
2619 if deprecated in line:
2620 results.append(output_api.PresubmitError(
2621 "%s:%d: Use of deprecated JS %s, use %s instead" %
2622 (fpath.LocalPath(), lnum, deprecated, replacement)))
2623 return results
2624
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202625
dpapadd651231d82017-07-21 02:44:472626def _CheckForRiskyJsArrowFunction(line_number, line):
2627 if ' => ' in line:
2628 return "line %d, is using an => (arrow) function\n %s\n" % (
2629 line_number, line)
2630 return ''
2631
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202632
dpapadd651231d82017-07-21 02:44:472633def _CheckForRiskyJsConstLet(input_api, line_number, line):
2634 if input_api.re.match('^\s*(const|let)\s', line):
2635 return "line %d, is using const/let keyword\n %s\n" % (
2636 line_number, line)
2637 return ''
dbeam070cfe62014-10-22 06:44:022638
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202639
dbeam1ec68ac2016-12-15 05:22:242640def _CheckForRiskyJsFeatures(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492641 maybe_ios_js = [r"^(ios|components|ui\/webui\/resources)\/.+\.js$"]
Steven Bennetts90545f3cb2017-08-14 18:11:002642 # 'ui/webui/resources/cr_components are not allowed on ios'
2643 not_ios_filter = (r".*ui\/webui\/resources\/cr_components.*", )
Steven Bennetts9c7e3c22017-08-02 19:10:572644 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js,
Steven Bennetts90545f3cb2017-08-14 18:11:002645 black_list=not_ios_filter)
dpapadd651231d82017-07-21 02:44:472646 results = []
dbeam1ec68ac2016-12-15 05:22:242647 for f in input_api.AffectedFiles(file_filter=file_filter):
dpapadd651231d82017-07-21 02:44:472648 arrow_error_lines = []
2649 const_let_error_lines = []
dbeam1ec68ac2016-12-15 05:22:242650 for lnum, line in f.ChangedContents():
dpapadd651231d82017-07-21 02:44:472651 arrow_error_lines += filter(None, [
2652 _CheckForRiskyJsArrowFunction(lnum, line),
2653 ])
dbeam1ec68ac2016-12-15 05:22:242654
dpapadd651231d82017-07-21 02:44:472655 const_let_error_lines += filter(None, [
2656 _CheckForRiskyJsConstLet(input_api, lnum, line),
2657 ])
dbeam1ec68ac2016-12-15 05:22:242658
dpapadd651231d82017-07-21 02:44:472659 if arrow_error_lines:
2660 arrow_error_lines = map(
2661 lambda e: "%s:%s" % (f.LocalPath(), e), arrow_error_lines)
2662 results.append(
2663 output_api.PresubmitPromptWarning('\n'.join(arrow_error_lines + [
2664"""
2665Use of => (arrow) operator detected in:
dbeam1ec68ac2016-12-15 05:22:242666%s
2667Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2668https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
dpapadd651231d82017-07-21 02:44:472669""" % f.LocalPath()
2670 ])))
dbeam1ec68ac2016-12-15 05:22:242671
dpapadd651231d82017-07-21 02:44:472672 if const_let_error_lines:
2673 const_let_error_lines = map(
2674 lambda e: "%s:%s" % (f.LocalPath(), e), const_let_error_lines)
2675 results.append(
2676 output_api.PresubmitPromptWarning('\n'.join(const_let_error_lines + [
2677"""
2678Use of const/let keywords detected in:
2679%s
2680Please ensure your code does not run on iOS9 because const/let is not fully
2681supported.
2682https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#let-Block_Scoped-Variables
2683https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#const-Block_Scoped-Constants
2684""" % f.LocalPath()
2685 ])))
2686
2687 return results
dbeam1ec68ac2016-12-15 05:22:242688
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202689
rlanday6802cf632017-05-30 17:48:362690def _CheckForRelativeIncludes(input_api, output_api):
2691 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2692 import sys
2693 original_sys_path = sys.path
2694 try:
2695 sys.path = sys.path + [input_api.os_path.join(
2696 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2697 from cpp_checker import CppChecker
2698 finally:
2699 # Restore sys.path to what it was before.
2700 sys.path = original_sys_path
2701
2702 bad_files = {}
2703 for f in input_api.AffectedFiles(include_deletes=False):
2704 if (f.LocalPath().startswith('third_party') and
2705 not f.LocalPath().startswith('third_party/WebKit') and
2706 not f.LocalPath().startswith('third_party\\WebKit')):
2707 continue
2708
2709 if not CppChecker.IsCppFile(f.LocalPath()):
2710 continue
2711
Vaclav Brozekd5de76a2018-03-17 07:57:502712 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362713 if "#include" in line and "../" in line]
2714 if not relative_includes:
2715 continue
2716 bad_files[f.LocalPath()] = relative_includes
2717
2718 if not bad_files:
2719 return []
2720
2721 error_descriptions = []
2722 for file_path, bad_lines in bad_files.iteritems():
2723 error_description = file_path
2724 for line in bad_lines:
2725 error_description += '\n ' + line
2726 error_descriptions.append(error_description)
2727
2728 results = []
2729 results.append(output_api.PresubmitError(
2730 'You added one or more relative #include paths (including "../").\n'
2731 'These shouldn\'t be used because they can be used to include headers\n'
2732 'from code that\'s not correctly specified as a dependency in the\n'
2733 'relevant BUILD.gn file(s).',
2734 error_descriptions))
2735
2736 return results
2737
Takeshi Yoshinoe387aa32017-08-02 13:16:132738
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202739def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2740 if not isinstance(key, ast.Str):
2741 return 'Key at line %d must be a string literal' % key.lineno
2742 if not isinstance(value, ast.Dict):
2743 return 'Value at line %d must be a dict' % value.lineno
2744 if len(value.keys) != 1:
2745 return 'Dict at line %d must have single entry' % value.lineno
2746 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2747 return (
2748 'Entry at line %d must have a string literal \'filepath\' as key' %
2749 value.lineno)
2750 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132751
Takeshi Yoshinoe387aa32017-08-02 13:16:132752
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202753def _CheckWatchlistsEntrySyntax(key, value, ast):
2754 if not isinstance(key, ast.Str):
2755 return 'Key at line %d must be a string literal' % key.lineno
2756 if not isinstance(value, ast.List):
2757 return 'Value at line %d must be a list' % value.lineno
2758 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132759
Takeshi Yoshinoe387aa32017-08-02 13:16:132760
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202761def _CheckWATCHLISTSEntries(wd_dict, w_dict, ast):
2762 mismatch_template = (
2763 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2764 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132765
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202766 i = 0
2767 last_key = ''
2768 while True:
2769 if i >= len(wd_dict.keys):
2770 if i >= len(w_dict.keys):
2771 return None
2772 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2773 elif i >= len(w_dict.keys):
2774 return (
2775 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132776
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202777 wd_key = wd_dict.keys[i]
2778 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132779
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202780 result = _CheckWatchlistDefinitionsEntrySyntax(
2781 wd_key, wd_dict.values[i], ast)
2782 if result is not None:
2783 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132784
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202785 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast)
2786 if result is not None:
2787 return 'Bad entry in WATCHLISTS dict: %s' % result
2788
2789 if wd_key.s != w_key.s:
2790 return mismatch_template % (
2791 '%s at line %d' % (wd_key.s, wd_key.lineno),
2792 '%s at line %d' % (w_key.s, w_key.lineno))
2793
2794 if wd_key.s < last_key:
2795 return (
2796 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2797 (wd_key.lineno, w_key.lineno))
2798 last_key = wd_key.s
2799
2800 i = i + 1
2801
2802
2803def _CheckWATCHLISTSSyntax(expression, ast):
2804 if not isinstance(expression, ast.Expression):
2805 return 'WATCHLISTS file must contain a valid expression'
2806 dictionary = expression.body
2807 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2808 return 'WATCHLISTS file must have single dict with exactly two entries'
2809
2810 first_key = dictionary.keys[0]
2811 first_value = dictionary.values[0]
2812 second_key = dictionary.keys[1]
2813 second_value = dictionary.values[1]
2814
2815 if (not isinstance(first_key, ast.Str) or
2816 first_key.s != 'WATCHLIST_DEFINITIONS' or
2817 not isinstance(first_value, ast.Dict)):
2818 return (
2819 'The first entry of the dict in WATCHLISTS file must be '
2820 'WATCHLIST_DEFINITIONS dict')
2821
2822 if (not isinstance(second_key, ast.Str) or
2823 second_key.s != 'WATCHLISTS' or
2824 not isinstance(second_value, ast.Dict)):
2825 return (
2826 'The second entry of the dict in WATCHLISTS file must be '
2827 'WATCHLISTS dict')
2828
2829 return _CheckWATCHLISTSEntries(first_value, second_value, ast)
Takeshi Yoshinoe387aa32017-08-02 13:16:132830
2831
2832def _CheckWATCHLISTS(input_api, output_api):
2833 for f in input_api.AffectedFiles(include_deletes=False):
2834 if f.LocalPath() == 'WATCHLISTS':
2835 contents = input_api.ReadFile(f, 'r')
2836
2837 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202838 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132839 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202840 # Get an AST tree for it and scan the tree for detailed style checking.
2841 expression = input_api.ast.parse(
2842 contents, filename='WATCHLISTS', mode='eval')
2843 except ValueError as e:
2844 return [output_api.PresubmitError(
2845 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2846 except SyntaxError as e:
2847 return [output_api.PresubmitError(
2848 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2849 except TypeError as e:
2850 return [output_api.PresubmitError(
2851 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132852
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202853 result = _CheckWATCHLISTSSyntax(expression, input_api.ast)
2854 if result is not None:
2855 return [output_api.PresubmitError(result)]
2856 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132857
2858 return []
2859
2860
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192861def _CheckNewHeaderWithoutGnChange(input_api, output_api):
2862 """Checks that newly added header files have corresponding GN changes.
2863 Note that this is only a heuristic. To be precise, run script:
2864 build/check_gn_headers.py.
2865 """
2866
2867 def headers(f):
2868 return input_api.FilterSourceFile(
2869 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
2870
2871 new_headers = []
2872 for f in input_api.AffectedSourceFiles(headers):
2873 if f.Action() != 'A':
2874 continue
2875 new_headers.append(f.LocalPath())
2876
2877 def gn_files(f):
2878 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
2879
2880 all_gn_changed_contents = ''
2881 for f in input_api.AffectedSourceFiles(gn_files):
2882 for _, line in f.ChangedContents():
2883 all_gn_changed_contents += line
2884
2885 problems = []
2886 for header in new_headers:
2887 basename = input_api.os_path.basename(header)
2888 if basename not in all_gn_changed_contents:
2889 problems.append(header)
2890
2891 if problems:
2892 return [output_api.PresubmitPromptWarning(
2893 'Missing GN changes for new header files', items=sorted(problems),
2894 long_text='Please double check whether newly added header files need '
2895 'corresponding changes in gn or gni files.\nThis checking is only a '
2896 'heuristic. Run build/check_gn_headers.py to be precise.\n'
2897 'Read https://crbug.com/661774 for more info.')]
2898 return []
2899
2900
dgnaa68d5e2015-06-10 10:08:222901def _AndroidSpecificOnUploadChecks(input_api, output_api):
2902 """Groups checks that target android code."""
2903 results = []
dgnaa68d5e2015-06-10 10:08:222904 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222905 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292906 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:062907 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
2908 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:422909 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:182910 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222911 return results
2912
2913
[email protected]22c9bd72011-03-27 16:47:392914def _CommonChecks(input_api, output_api):
2915 """Checks common to both upload and commit."""
2916 results = []
2917 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382918 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542919 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:082920
2921 author = input_api.change.author_email
2922 if author and author not in _KNOWN_ROBOTS:
2923 results.extend(
2924 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
2925
[email protected]55459852011-08-10 15:17:192926 results.extend(
[email protected]760deea2013-12-10 19:33:492927 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:232928 results.extend(
2929 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542930 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182931 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522932 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222933 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442934 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592935 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062936 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122937 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182938 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222939 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302940 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492941 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032942 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492943 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442944 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272945 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:072946 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542947 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442948 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392949 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552950 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042951 results.extend(
2952 input_api.canned_checks.CheckChangeHasNoTabs(
2953 input_api,
2954 output_api,
2955 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402956 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162957 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082958 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242959 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2960 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472961 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042962 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:052963 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:142964 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232965 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432966 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402967 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152968 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172969 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502970 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242971 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:362972 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:132973 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:432974 results.extend(input_api.RunTests(
2975 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:142976 results.extend(_CheckTranslationScreenshots(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242977
Vaclav Brozekcdc7defb2018-03-20 09:54:352978 for f in input_api.AffectedFiles():
2979 path, name = input_api.os_path.split(f.LocalPath())
2980 if name == 'PRESUBMIT.py':
2981 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:002982 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
2983 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:072984 # The PRESUBMIT.py file (and the directory containing it) might
2985 # have been affected by being moved or removed, so only try to
2986 # run the tests if they still exist.
2987 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2988 input_api, output_api, full_path,
2989 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392990 return results
[email protected]1f7b4172010-01-28 01:17:342991
[email protected]b337cb5b2011-01-23 21:24:052992
[email protected]b8079ae4a2012-12-05 19:56:492993def _CheckPatchFiles(input_api, output_api):
2994 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2995 if f.LocalPath().endswith(('.orig', '.rej'))]
2996 if problems:
2997 return [output_api.PresubmitError(
2998 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032999 else:
3000 return []
[email protected]b8079ae4a2012-12-05 19:56:493001
3002
Kent Tamura5a8755d2017-06-29 23:37:073003def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:213004 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
3005 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
3006 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:073007 include_re = input_api.re.compile(
3008 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
3009 extension_re = input_api.re.compile(r'\.[a-z]+$')
3010 errors = []
3011 for f in input_api.AffectedFiles():
3012 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
3013 continue
3014 found_line_number = None
3015 found_macro = None
3016 for line_num, line in f.ChangedContents():
3017 match = macro_re.search(line)
3018 if match:
3019 found_line_number = line_num
3020 found_macro = match.group(2)
3021 break
3022 if not found_line_number:
3023 continue
3024
3025 found_include = False
3026 for line in f.NewContents():
3027 if include_re.search(line):
3028 found_include = True
3029 break
3030 if found_include:
3031 continue
3032
3033 if not f.LocalPath().endswith('.h'):
3034 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
3035 try:
3036 content = input_api.ReadFile(primary_header_path, 'r')
3037 if include_re.search(content):
3038 continue
3039 except IOError:
3040 pass
3041 errors.append('%s:%d %s macro is used without including build/'
3042 'build_config.h.'
3043 % (f.LocalPath(), found_line_number, found_macro))
3044 if errors:
3045 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
3046 return []
3047
3048
[email protected]b00342e7f2013-03-26 16:21:543049def _DidYouMeanOSMacro(bad_macro):
3050 try:
3051 return {'A': 'OS_ANDROID',
3052 'B': 'OS_BSD',
3053 'C': 'OS_CHROMEOS',
3054 'F': 'OS_FREEBSD',
3055 'L': 'OS_LINUX',
3056 'M': 'OS_MACOSX',
3057 'N': 'OS_NACL',
3058 'O': 'OS_OPENBSD',
3059 'P': 'OS_POSIX',
3060 'S': 'OS_SOLARIS',
3061 'W': 'OS_WIN'}[bad_macro[3].upper()]
3062 except KeyError:
3063 return ''
3064
3065
3066def _CheckForInvalidOSMacrosInFile(input_api, f):
3067 """Check for sensible looking, totally invalid OS macros."""
3068 preprocessor_statement = input_api.re.compile(r'^\s*#')
3069 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
3070 results = []
3071 for lnum, line in f.ChangedContents():
3072 if preprocessor_statement.search(line):
3073 for match in os_macro.finditer(line):
3074 if not match.group(1) in _VALID_OS_MACROS:
3075 good = _DidYouMeanOSMacro(match.group(1))
3076 did_you_mean = ' (did you mean %s?)' % good if good else ''
3077 results.append(' %s:%d %s%s' % (f.LocalPath(),
3078 lnum,
3079 match.group(1),
3080 did_you_mean))
3081 return results
3082
3083
3084def _CheckForInvalidOSMacros(input_api, output_api):
3085 """Check all affected files for invalid OS macros."""
3086 bad_macros = []
3087 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:473088 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:543089 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
3090
3091 if not bad_macros:
3092 return []
3093
3094 return [output_api.PresubmitError(
3095 'Possibly invalid OS macro[s] found. Please fix your code\n'
3096 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
3097
lliabraa35bab3932014-10-01 12:16:443098
3099def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
3100 """Check all affected files for invalid "if defined" macros."""
3101 ALWAYS_DEFINED_MACROS = (
3102 "TARGET_CPU_PPC",
3103 "TARGET_CPU_PPC64",
3104 "TARGET_CPU_68K",
3105 "TARGET_CPU_X86",
3106 "TARGET_CPU_ARM",
3107 "TARGET_CPU_MIPS",
3108 "TARGET_CPU_SPARC",
3109 "TARGET_CPU_ALPHA",
3110 "TARGET_IPHONE_SIMULATOR",
3111 "TARGET_OS_EMBEDDED",
3112 "TARGET_OS_IPHONE",
3113 "TARGET_OS_MAC",
3114 "TARGET_OS_UNIX",
3115 "TARGET_OS_WIN32",
3116 )
3117 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
3118 results = []
3119 for lnum, line in f.ChangedContents():
3120 for match in ifdef_macro.finditer(line):
3121 if match.group(1) in ALWAYS_DEFINED_MACROS:
3122 always_defined = ' %s is always defined. ' % match.group(1)
3123 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
3124 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
3125 lnum,
3126 always_defined,
3127 did_you_mean))
3128 return results
3129
3130
3131def _CheckForInvalidIfDefinedMacros(input_api, output_api):
3132 """Check all affected files for invalid "if defined" macros."""
3133 bad_macros = []
3134 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:213135 if f.LocalPath().startswith('third_party/sqlite/'):
3136 continue
lliabraa35bab3932014-10-01 12:16:443137 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3138 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3139
3140 if not bad_macros:
3141 return []
3142
3143 return [output_api.PresubmitError(
3144 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3145 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3146 bad_macros)]
3147
3148
mlamouria82272622014-09-16 18:45:043149def _CheckForIPCRules(input_api, output_api):
3150 """Check for same IPC rules described in
3151 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3152 """
3153 base_pattern = r'IPC_ENUM_TRAITS\('
3154 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3155 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3156
3157 problems = []
3158 for f in input_api.AffectedSourceFiles(None):
3159 local_path = f.LocalPath()
3160 if not local_path.endswith('.h'):
3161 continue
3162 for line_number, line in f.ChangedContents():
3163 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3164 problems.append(
3165 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3166
3167 if problems:
3168 return [output_api.PresubmitPromptWarning(
3169 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
3170 else:
3171 return []
3172
[email protected]b00342e7f2013-03-26 16:21:543173
Stephen Martinis97a394142018-06-07 23:06:053174def _CheckForLongPathnames(input_api, output_api):
3175 """Check to make sure no files being submitted have long paths.
3176 This causes issues on Windows.
3177 """
3178 problems = []
3179 for f in input_api.AffectedSourceFiles(None):
3180 local_path = f.LocalPath()
3181 # Windows has a path limit of 260 characters. Limit path length to 200 so
3182 # that we have some extra for the prefix on dev machines and the bots.
3183 if len(local_path) > 200:
3184 problems.append(local_path)
3185
3186 if problems:
3187 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
3188 else:
3189 return []
3190
3191
Daniel Bratell8ba52722018-03-02 16:06:143192def _CheckForIncludeGuards(input_api, output_api):
3193 """Check that header files have proper guards against multiple inclusion.
3194 If a file should not have such guards (and it probably should) then it
3195 should include the string "no-include-guard-because-multiply-included".
3196 """
Daniel Bratell6a75baef62018-06-04 10:04:453197 def is_chromium_header_file(f):
3198 # We only check header files under the control of the Chromium
3199 # project. That is, those outside third_party apart from
3200 # third_party/blink.
3201 file_with_path = input_api.os_path.normpath(f.LocalPath())
3202 return (file_with_path.endswith('.h') and
3203 (not file_with_path.startswith('third_party') or
3204 file_with_path.startswith(
3205 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:143206
3207 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:343208 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:143209
3210 errors = []
3211
Daniel Bratell6a75baef62018-06-04 10:04:453212 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:143213 guard_name = None
3214 guard_line_number = None
3215 seen_guard_end = False
3216
3217 file_with_path = input_api.os_path.normpath(f.LocalPath())
3218 base_file_name = input_api.os_path.splitext(
3219 input_api.os_path.basename(file_with_path))[0]
3220 upper_base_file_name = base_file_name.upper()
3221
3222 expected_guard = replace_special_with_underscore(
3223 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:143224
3225 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:573226 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
3227 # are too many (1000+) files with slight deviations from the
3228 # coding style. The most important part is that the include guard
3229 # is there, and that it's unique, not the name so this check is
3230 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:143231 #
3232 # As code becomes more uniform, this could be made stricter.
3233
3234 guard_name_pattern_list = [
3235 # Anything with the right suffix (maybe with an extra _).
3236 r'\w+_H__?',
3237
Daniel Bratell39b5b062018-05-16 18:09:573238 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:143239 r'\w+_h',
3240
3241 # Anything including the uppercase name of the file.
3242 r'\w*' + input_api.re.escape(replace_special_with_underscore(
3243 upper_base_file_name)) + r'\w*',
3244 ]
3245 guard_name_pattern = '|'.join(guard_name_pattern_list)
3246 guard_pattern = input_api.re.compile(
3247 r'#ifndef\s+(' + guard_name_pattern + ')')
3248
3249 for line_number, line in enumerate(f.NewContents()):
3250 if 'no-include-guard-because-multiply-included' in line:
3251 guard_name = 'DUMMY' # To not trigger check outside the loop.
3252 break
3253
3254 if guard_name is None:
3255 match = guard_pattern.match(line)
3256 if match:
3257 guard_name = match.group(1)
3258 guard_line_number = line_number
3259
Daniel Bratell39b5b062018-05-16 18:09:573260 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:453261 # don't match the chromium style guide, but new files should
3262 # get it right.
3263 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:573264 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:143265 errors.append(output_api.PresubmitPromptWarning(
3266 'Header using the wrong include guard name %s' % guard_name,
3267 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:573268 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:143269 else:
3270 # The line after #ifndef should have a #define of the same name.
3271 if line_number == guard_line_number + 1:
3272 expected_line = '#define %s' % guard_name
3273 if line != expected_line:
3274 errors.append(output_api.PresubmitPromptWarning(
3275 'Missing "%s" for include guard' % expected_line,
3276 ['%s:%d' % (f.LocalPath(), line_number + 1)],
3277 'Expected: %r\nGot: %r' % (expected_line, line)))
3278
3279 if not seen_guard_end and line == '#endif // %s' % guard_name:
3280 seen_guard_end = True
3281 elif seen_guard_end:
3282 if line.strip() != '':
3283 errors.append(output_api.PresubmitPromptWarning(
3284 'Include guard %s not covering the whole file' % (
3285 guard_name), [f.LocalPath()]))
3286 break # Nothing else to check and enough to warn once.
3287
3288 if guard_name is None:
3289 errors.append(output_api.PresubmitPromptWarning(
3290 'Missing include guard %s' % expected_guard,
3291 [f.LocalPath()],
3292 'Missing include guard in %s\n'
3293 'Recommended name: %s\n'
3294 'This check can be disabled by having the string\n'
3295 'no-include-guard-because-multiply-included in the header.' %
3296 (f.LocalPath(), expected_guard)))
3297
3298 return errors
3299
3300
mostynbb639aca52015-01-07 20:31:233301def _CheckForWindowsLineEndings(input_api, output_api):
3302 """Check source code and known ascii text files for Windows style line
3303 endings.
3304 """
earthdok1b5e0ee2015-03-10 15:19:103305 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233306
3307 file_inclusion_pattern = (
3308 known_text_files,
3309 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3310 )
3311
mostynbb639aca52015-01-07 20:31:233312 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533313 source_file_filter = lambda f: input_api.FilterSourceFile(
3314 f, white_list=file_inclusion_pattern, black_list=None)
3315 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503316 include_file = False
3317 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233318 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503319 include_file = True
3320 if include_file:
3321 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233322
3323 if problems:
3324 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3325 'these files to contain Windows style line endings?\n' +
3326 '\n'.join(problems))]
3327
3328 return []
3329
3330
Vaclav Brozekd5de76a2018-03-17 07:57:503331def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133332 """Checks that all source files use SYSLOG properly."""
3333 syslog_files = []
3334 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563335 for line_number, line in f.ChangedContents():
3336 if 'SYSLOG' in line:
3337 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3338
pastarmovj89f7ee12016-09-20 14:58:133339 if syslog_files:
3340 return [output_api.PresubmitPromptWarning(
3341 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3342 ' calls.\nFiles to check:\n', items=syslog_files)]
3343 return []
3344
3345
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193346def _CheckCrbugLinksHaveHttps(input_api, output_api):
Miguel Casas68bdb652017-12-19 16:29:093347 """Checks that crbug(.com) links are correctly prefixed by https://,
3348 unless they come in the accepted form TODO(crbug.com/...)
3349 """
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193350
Wei-Yin Chen (陳威尹)ce74dfc2018-08-08 01:15:183351 # The cr bug strings are split to avoid matching in real presubmit
3352 # checkings.
3353 pattern = input_api.re.compile(r'//.*(?<!:\/\/)cr''bug[.com]*')
3354 accepted_pattern = input_api.re.compile(r'//.*TODO\(cr''bug[.com]*')
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193355 problems = []
Wei-Yin Chen (陳威尹)ce74dfc2018-08-08 01:15:183356 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193357 for line_num, line in f.ChangedContents():
Miguel Casas68bdb652017-12-19 16:29:093358 if pattern.search(line) and not accepted_pattern.search(line):
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193359 problems.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3360
3361 if problems:
3362 return [output_api.PresubmitPromptWarning(
Wei-Yin Chen (陳威尹)ce74dfc2018-08-08 01:15:183363 'Found unprefixed crbug.com URL(s), consider prepending https://\n' +
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193364 '\n'.join(problems))]
3365 return []
3366
3367
[email protected]1f7b4172010-01-28 01:17:343368def CheckChangeOnUpload(input_api, output_api):
3369 results = []
3370 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473371 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283372 results.extend(
jam93a6ee792017-02-08 23:59:223373 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193374 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223375 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133376 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163377 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193378 results.extend(_CheckCrbugLinksHaveHttps(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:533379 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193380 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543381 return results
[email protected]ca8d1982009-02-19 16:33:123382
3383
[email protected]1bfb8322014-04-23 01:02:413384def GetTryServerMasterForBot(bot):
3385 """Returns the Try Server master for the given bot.
3386
[email protected]0bb112362014-07-26 04:38:323387 It tries to guess the master from the bot name, but may still fail
3388 and return None. There is no longer a default master.
3389 """
3390 # Potentially ambiguous bot names are listed explicitly.
3391 master_map = {
tandriie5587792016-07-14 00:34:503392 'chromium_presubmit': 'master.tryserver.chromium.linux',
3393 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413394 }
[email protected]0bb112362014-07-26 04:38:323395 master = master_map.get(bot)
3396 if not master:
wnwen4fbaab82016-05-25 12:54:363397 if 'android' in bot:
tandriie5587792016-07-14 00:34:503398 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363399 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503400 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323401 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503402 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323403 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503404 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323405 return master
[email protected]1bfb8322014-04-23 01:02:413406
3407
[email protected]ca8d1982009-02-19 16:33:123408def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543409 results = []
[email protected]1f7b4172010-01-28 01:17:343410 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543411 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273412 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343413 input_api,
3414 output_api,
[email protected]2fdd1f362013-01-16 03:56:033415 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273416
jam93a6ee792017-02-08 23:59:223417 results.extend(
3418 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543419 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3420 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413421 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3422 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543423 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143424
3425
3426def _CheckTranslationScreenshots(input_api, output_api):
3427 PART_FILE_TAG = "part"
3428 import os
3429 import sys
3430 from io import StringIO
3431
3432 try:
3433 old_sys_path = sys.path
3434 sys.path = sys.path + [input_api.os_path.join(
3435 input_api.PresubmitLocalPath(), 'tools', 'grit')]
3436 import grit.grd_reader
3437 import grit.node.message
3438 import grit.util
3439 finally:
3440 sys.path = old_sys_path
3441
3442 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
3443 """Load the grd file and return a dict of message ids to messages.
3444
3445 Ignores any nested grdp files pointed by <part> tag.
3446 """
3447 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
3448 stop_after=None, first_ids_file=None,
3449 debug=False, defines=None,
3450 tags_to_ignore=set([PART_FILE_TAG]))
3451 return {
3452 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
3453 grit.node.message.MessageNode)
3454 }
3455
3456 def _GetGrdpMessagesFromString(grdp_string):
3457 """Parses the contents of a grdp file given in grdp_string.
3458
3459 grd_reader can't parse grdp files directly. Instead, this creates a
3460 temporary directory with a grd file pointing to the grdp file, and loads the
3461 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
3462 """
3463 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
3464 <grit latest_public_release="1" current_release="1">
3465 <release seq="1">
3466 <messages>
3467 <part file="sub.grdp" />
3468 </messages>
3469 </release>
3470 </grit>
3471 """
3472 with grit.util.TempDir({'main.grd': WRAPPER,
3473 'sub.grdp': grdp_string}) as temp_dir:
3474 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
3475
3476 new_or_added_paths = set(f.LocalPath()
3477 for f in input_api.AffectedFiles()
3478 if (f.Action() == 'A' or f.Action() == 'M'))
3479 removed_paths = set(f.LocalPath()
3480 for f in input_api.AffectedFiles(include_deletes=True)
3481 if f.Action() == 'D')
3482
3483 affected_grds = [f for f in input_api.AffectedFiles()
3484 if (f.LocalPath().endswith('.grd') or
3485 f.LocalPath().endswith('.grdp'))]
3486 affected_png_paths = [f.AbsoluteLocalPath()
3487 for f in input_api.AffectedFiles()
3488 if (f.LocalPath().endswith('.png'))]
3489
3490 # Check for screenshots. Developers can upload screenshots using
3491 # tools/translation/upload_screenshots.py which finds and uploads
3492 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
3493 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
3494 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
3495 #
3496 # The logic here is as follows:
3497 #
3498 # - If the CL has a .png file under the screenshots directory for a grd
3499 # file, warn the developer. Actual images should never be checked into the
3500 # Chrome repo.
3501 #
3502 # - If the CL contains modified or new messages in grd files and doesn't
3503 # contain the corresponding .sha1 files, warn the developer to add images
3504 # and upload them via tools/translation/upload_screenshots.py.
3505 #
3506 # - If the CL contains modified or new messages in grd files and the
3507 # corresponding .sha1 files, everything looks good.
3508 #
3509 # - If the CL contains removed messages in grd files but the corresponding
3510 # .sha1 files aren't removed, warn the developer to remove them.
3511 unnecessary_screenshots = []
3512 missing_sha1 = []
3513 unnecessary_sha1_files = []
3514
3515
3516 def _CheckScreenshotAdded(screenshots_dir, message_id):
3517 sha1_path = input_api.os_path.join(
3518 screenshots_dir, message_id + '.png.sha1')
3519 if sha1_path not in new_or_added_paths:
3520 missing_sha1.append(sha1_path)
3521
3522
3523 def _CheckScreenshotRemoved(screenshots_dir, message_id):
3524 sha1_path = input_api.os_path.join(
3525 screenshots_dir, message_id + '.png.sha1')
3526 if sha1_path not in removed_paths:
3527 unnecessary_sha1_files.append(sha1_path)
3528
3529
3530 for f in affected_grds:
3531 file_path = f.LocalPath()
3532 old_id_to_msg_map = {}
3533 new_id_to_msg_map = {}
3534 if file_path.endswith('.grdp'):
3535 if f.OldContents():
3536 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393537 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143538 if f.NewContents():
3539 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393540 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143541 else:
3542 if f.OldContents():
3543 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393544 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143545 if f.NewContents():
3546 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393547 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143548
3549 # Compute added, removed and modified message IDs.
3550 old_ids = set(old_id_to_msg_map)
3551 new_ids = set(new_id_to_msg_map)
3552 added_ids = new_ids - old_ids
3553 removed_ids = old_ids - new_ids
3554 modified_ids = set([])
3555 for key in old_ids.intersection(new_ids):
3556 if (old_id_to_msg_map[key].FormatXml()
3557 != new_id_to_msg_map[key].FormatXml()):
3558 modified_ids.add(key)
3559
3560 grd_name, ext = input_api.os_path.splitext(
3561 input_api.os_path.basename(file_path))
3562 screenshots_dir = input_api.os_path.join(
3563 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
3564
3565 # Check the screenshot directory for .png files. Warn if there is any.
3566 for png_path in affected_png_paths:
3567 if png_path.startswith(screenshots_dir):
3568 unnecessary_screenshots.append(png_path)
3569
3570 for added_id in added_ids:
3571 _CheckScreenshotAdded(screenshots_dir, added_id)
3572
3573 for modified_id in modified_ids:
3574 _CheckScreenshotAdded(screenshots_dir, modified_id)
3575
3576 for removed_id in removed_ids:
3577 _CheckScreenshotRemoved(screenshots_dir, removed_id)
3578
3579 results = []
3580 if unnecessary_screenshots:
3581 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393582 'Do not include actual screenshots in the changelist. Run '
3583 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143584 sorted(unnecessary_screenshots)))
3585
3586 if missing_sha1:
3587 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393588 'You are adding or modifying UI strings.\n'
3589 'To ensure the best translations, take screenshots of the relevant UI '
3590 '(https://g.co/chrome/translation) and add these files to your '
3591 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143592
3593 if unnecessary_sha1_files:
3594 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393595 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143596 sorted(unnecessary_sha1_files)))
3597
3598 return results