blob: 78bb258f48c2b32e0753b7bcedc5d6e50620cb82 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d19842009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d19842009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
[email protected]40d1dbb2012-10-26 07:18:0013 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
14 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2815 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0816 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5417 r"^skia[\\\/].*",
Kent Tamurae9b3a9ec2017-08-31 02:20:1918 r"^third_party[\\\/](WebKit|blink)[\\\/].*",
Mark Mentovaiebb9ddd62017-09-25 17:24:4119 r"^third_party[\\\/]breakpad[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
vapierb2053f542017-03-09 19:46:1026 r"tools[\\\/]md_browser[\\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1427 # Test pages for Maps telemetry tests.
28 r"tools[\\\/]perf[\\\/]page_sets[\\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5429 # Test pages for WebRTC telemetry tests.
30 r"tools[\\\/]perf[\\\/]page_sets[\\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4031)
[email protected]ca8d19842009-02-19 16:33:1232
wnwenbdc444e2016-05-25 13:44:1533
[email protected]06e6d0ff2012-12-11 01:36:4434# Fragment of a regular expression that matches C++ and Objective-C++
35# implementation files.
36_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
37
wnwenbdc444e2016-05-25 13:44:1538
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]ca8d19842009-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',
Andrew Grievea7f1ee902018-05-18 16:17:22691 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:40692]
693
wnwenbdc444e2016-05-25 13:44:15694
agrievef32bcc72016-04-04 14:57:40695_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
696
697
Eric Boren6fd2b932018-01-25 15:05:08698# Bypass the AUTHORS check for these accounts.
699_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:29700 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
701 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:08702 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
703 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:59704 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:45705 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:59706 ) | set('%[email protected]' % s
Sergiy Byelozyorovf78077a92018-06-14 08:07:11707 for s in ('v8-ci-autoroll-builder',))
Eric Boren6fd2b932018-01-25 15:05:08708
709
[email protected]55459852011-08-10 15:17:19710def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
711 """Attempts to prevent use of functions intended only for testing in
712 non-testing code. For now this is just a best-effort implementation
713 that ignores header files and may have some false positives. A
714 better implementation would probably need a proper C++ parser.
715 """
716 # We only scan .cc files and the like, as the declaration of
717 # for-testing functions in header files are hard to distinguish from
718 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49719 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:19720
jochenc0d4808c2015-07-27 09:25:42721 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19722 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09723 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19724 exclusion_pattern = input_api.re.compile(
725 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
726 base_function_pattern, base_function_pattern))
727
728 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44729 black_list = (_EXCLUDED_PATHS +
730 _TEST_CODE_EXCLUDED_PATHS +
731 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19732 return input_api.FilterSourceFile(
733 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49734 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:19735 black_list=black_list)
736
737 problems = []
738 for f in input_api.AffectedSourceFiles(FilterFile):
739 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24740 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03741 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46742 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03743 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19744 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03745 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19746
747 if problems:
[email protected]f7051d52013-04-02 18:31:42748 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03749 else:
750 return []
[email protected]55459852011-08-10 15:17:19751
752
Vaclav Brozek7dbc28c2018-03-27 08:35:23753def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
754 """This is a simplified version of
755 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
756 """
757 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
758 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
759 name_pattern = r'ForTest(s|ing)?'
760 # Describes an occurrence of "ForTest*" inside a // comment.
761 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
762 # Catch calls.
763 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
764 # Ignore definitions. (Comments are ignored separately.)
765 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
766
767 problems = []
768 sources = lambda x: input_api.FilterSourceFile(
769 x,
770 black_list=(('(?i).*test', r'.*\/junit\/')
771 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49772 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:23773 )
774 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
775 local_path = f.LocalPath()
776 is_inside_javadoc = False
777 for line_number, line in f.ChangedContents():
778 if is_inside_javadoc and javadoc_end_re.search(line):
779 is_inside_javadoc = False
780 if not is_inside_javadoc and javadoc_start_re.search(line):
781 is_inside_javadoc = True
782 if is_inside_javadoc:
783 continue
784 if (inclusion_re.search(line) and
785 not comment_re.search(line) and
786 not exclusion_re.search(line)):
787 problems.append(
788 '%s:%d\n %s' % (local_path, line_number, line.strip()))
789
790 if problems:
791 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
792 else:
793 return []
794
795
[email protected]10689ca2011-09-02 02:31:54796def _CheckNoIOStreamInHeaders(input_api, output_api):
797 """Checks to make sure no .h files include <iostream>."""
798 files = []
799 pattern = input_api.re.compile(r'^#include\s*<iostream>',
800 input_api.re.MULTILINE)
801 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
802 if not f.LocalPath().endswith('.h'):
803 continue
804 contents = input_api.ReadFile(f)
805 if pattern.search(contents):
806 files.append(f)
807
808 if len(files):
yolandyandaabc6d2016-04-18 18:29:39809 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06810 'Do not #include <iostream> in header files, since it inserts static '
811 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54812 '#include <ostream>. See http://crbug.com/94794',
813 files) ]
814 return []
815
816
[email protected]72df4e782012-06-21 16:28:18817def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52818 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18819 problems = []
820 for f in input_api.AffectedFiles():
821 if (not f.LocalPath().endswith(('.cc', '.mm'))):
822 continue
823
824 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04825 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18826 problems.append(' %s:%d' % (f.LocalPath(), line_num))
827
828 if not problems:
829 return []
830 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
831 '\n'.join(problems))]
832
833
danakj61c1aa22015-10-26 19:55:52834def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57835 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52836 errors = []
837 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
838 input_api.re.MULTILINE)
839 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
840 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
841 continue
842 for lnum, line in f.ChangedContents():
843 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17844 errors.append(output_api.PresubmitError(
845 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57846 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17847 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52848 return errors
849
850
mcasasb7440c282015-02-04 14:52:19851def _FindHistogramNameInLine(histogram_name, line):
852 """Tries to find a histogram name or prefix in a line."""
853 if not "affected-histogram" in line:
854 return histogram_name in line
855 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
856 # the histogram_name.
857 if not '"' in line:
858 return False
859 histogram_prefix = line.split('\"')[1]
860 return histogram_prefix in histogram_name
861
862
863def _CheckUmaHistogramChanges(input_api, output_api):
864 """Check that UMA histogram names in touched lines can still be found in other
865 lines of the patch or in histograms.xml. Note that this check would not catch
866 the reverse: changes in histograms.xml not matched in the code itself."""
867 touched_histograms = []
868 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:47869 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
870 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
871 name_pattern = r'"(.*?)"'
872 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
873 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
874 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
875 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
876 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:17877 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:19878 for f in input_api.AffectedFiles():
879 # If histograms.xml itself is modified, keep the modified lines for later.
880 if f.LocalPath().endswith(('histograms.xml')):
881 histograms_xml_modifications = f.ChangedContents()
882 continue
Vaclav Brozekbdac817c2018-03-24 06:30:47883 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
884 single_line_re = single_line_c_re
885 split_line_prefix_re = split_line_c_prefix_re
886 elif f.LocalPath().endswith(('java')):
887 single_line_re = single_line_java_re
888 split_line_prefix_re = split_line_java_prefix_re
889 else:
mcasasb7440c282015-02-04 14:52:19890 continue
891 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:17892 if last_line_matched_prefix:
893 suffix_found = split_line_suffix_re.search(line)
894 if suffix_found :
895 touched_histograms.append([suffix_found.group(1), f, line_num])
896 last_line_matched_prefix = False
897 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:06898 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:19899 if found:
900 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:17901 continue
902 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:19903
904 # Search for the touched histogram names in the local modifications to
905 # histograms.xml, and, if not found, on the base histograms.xml file.
906 unmatched_histograms = []
907 for histogram_info in touched_histograms:
908 histogram_name_found = False
909 for line_num, line in histograms_xml_modifications:
910 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
911 if histogram_name_found:
912 break
913 if not histogram_name_found:
914 unmatched_histograms.append(histogram_info)
915
eromanb90c82e7e32015-04-01 15:13:49916 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19917 problems = []
918 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49919 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19920 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45921 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19922 histogram_name_found = False
923 for line in histograms_xml:
924 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
925 if histogram_name_found:
926 break
927 if not histogram_name_found:
928 problems.append(' [%s:%d] %s' %
929 (f.LocalPath(), line_num, histogram_name))
930
931 if not problems:
932 return []
933 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
934 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49935 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19936
wnwenbdc444e2016-05-25 13:44:15937
yolandyandaabc6d2016-04-18 18:29:39938def _CheckFlakyTestUsage(input_api, output_api):
939 """Check that FlakyTest annotation is our own instead of the android one"""
940 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
941 files = []
942 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
943 if f.LocalPath().endswith('Test.java'):
944 if pattern.search(input_api.ReadFile(f)):
945 files.append(f)
946 if len(files):
947 return [output_api.PresubmitError(
948 'Use org.chromium.base.test.util.FlakyTest instead of '
949 'android.test.FlakyTest',
950 files)]
951 return []
mcasasb7440c282015-02-04 14:52:19952
wnwenbdc444e2016-05-25 13:44:15953
[email protected]8ea5d4b2011-09-13 21:49:22954def _CheckNoNewWStrings(input_api, output_api):
955 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27956 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22957 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20958 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57959 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34960 '/win/' in f.LocalPath() or
961 'chrome_elf' in f.LocalPath() or
962 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20963 continue
[email protected]8ea5d4b2011-09-13 21:49:22964
[email protected]a11dbe9b2012-08-07 01:32:58965 allowWString = False
[email protected]b5c24292011-11-28 14:38:20966 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58967 if 'presubmit: allow wstring' in line:
968 allowWString = True
969 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27970 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58971 allowWString = False
972 else:
973 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22974
[email protected]55463aa62011-10-12 00:48:27975 if not problems:
976 return []
977 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58978 ' If you are calling a cross-platform API that accepts a wstring, '
979 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27980 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22981
982
[email protected]2a8ac9c2011-10-19 17:20:44983def _CheckNoDEPSGIT(input_api, output_api):
984 """Make sure .DEPS.git is never modified manually."""
985 if any(f.LocalPath().endswith('.DEPS.git') for f in
986 input_api.AffectedFiles()):
987 return [output_api.PresubmitError(
988 'Never commit changes to .DEPS.git. This file is maintained by an\n'
989 'automated system based on what\'s in DEPS and your changes will be\n'
990 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50991 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
992 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:44993 'for more information')]
994 return []
995
996
tandriief664692014-09-23 14:51:47997def _CheckValidHostsInDEPS(input_api, output_api):
998 """Checks that DEPS file deps are from allowed_hosts."""
999 # Run only if DEPS file has been modified to annoy fewer bystanders.
1000 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1001 return []
1002 # Outsource work to gclient verify
1003 try:
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201004 input_api.subprocess.check_output(['gclient', 'verify'],
1005 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471006 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201007 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471008 return [output_api.PresubmitError(
1009 'DEPS file must have only git dependencies.',
1010 long_text=error.output)]
1011
1012
[email protected]127f18ec2012-06-16 05:05:591013def _CheckNoBannedFunctions(input_api, output_api):
1014 """Make sure that banned functions are not used."""
1015 warnings = []
1016 errors = []
1017
wnwenbdc444e2016-05-25 13:44:151018 def IsBlacklisted(affected_file, blacklist):
1019 local_path = affected_file.LocalPath()
1020 for item in blacklist:
1021 if input_api.re.match(item, local_path):
1022 return True
1023 return False
1024
Sylvain Defresnea8b73d252018-02-28 15:45:541025 def IsIosObcjFile(affected_file):
1026 local_path = affected_file.LocalPath()
1027 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1028 return False
1029 basename = input_api.os_path.basename(local_path)
1030 if 'ios' in basename.split('_'):
1031 return True
1032 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1033 if sep and 'ios' in local_path.split(sep):
1034 return True
1035 return False
1036
wnwenbdc444e2016-05-25 13:44:151037 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
1038 matched = False
1039 if func_name[0:1] == '/':
1040 regex = func_name[1:]
1041 if input_api.re.search(regex, line):
1042 matched = True
1043 elif func_name in line:
dchenge07de812016-06-20 19:27:171044 matched = True
wnwenbdc444e2016-05-25 13:44:151045 if matched:
dchenge07de812016-06-20 19:27:171046 problems = warnings
wnwenbdc444e2016-05-25 13:44:151047 if error:
dchenge07de812016-06-20 19:27:171048 problems = errors
wnwenbdc444e2016-05-25 13:44:151049 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1050 for message_line in message:
1051 problems.append(' %s' % message_line)
1052
Eric Stevensona9a980972017-09-23 00:04:411053 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1054 for f in input_api.AffectedFiles(file_filter=file_filter):
1055 for line_num, line in f.ChangedContents():
1056 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1057 CheckForMatch(f, line_num, line, func_name, message, error)
1058
[email protected]127f18ec2012-06-16 05:05:591059 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1060 for f in input_api.AffectedFiles(file_filter=file_filter):
1061 for line_num, line in f.ChangedContents():
1062 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151063 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591064
Sylvain Defresnea8b73d252018-02-28 15:45:541065 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1066 for line_num, line in f.ChangedContents():
1067 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1068 CheckForMatch(f, line_num, line, func_name, message, error)
1069
[email protected]127f18ec2012-06-16 05:05:591070 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1071 for f in input_api.AffectedFiles(file_filter=file_filter):
1072 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491073 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491074 if IsBlacklisted(f, excluded_paths):
1075 continue
wnwenbdc444e2016-05-25 13:44:151076 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591077
1078 result = []
1079 if (warnings):
1080 result.append(output_api.PresubmitPromptWarning(
1081 'Banned functions were used.\n' + '\n'.join(warnings)))
1082 if (errors):
1083 result.append(output_api.PresubmitError(
1084 'Banned functions were used.\n' + '\n'.join(errors)))
1085 return result
1086
1087
[email protected]6c063c62012-07-11 19:11:061088def _CheckNoPragmaOnce(input_api, output_api):
1089 """Make sure that banned functions are not used."""
1090 files = []
1091 pattern = input_api.re.compile(r'^#pragma\s+once',
1092 input_api.re.MULTILINE)
1093 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1094 if not f.LocalPath().endswith('.h'):
1095 continue
1096 contents = input_api.ReadFile(f)
1097 if pattern.search(contents):
1098 files.append(f)
1099
1100 if files:
1101 return [output_api.PresubmitError(
1102 'Do not use #pragma once in header files.\n'
1103 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1104 files)]
1105 return []
1106
[email protected]127f18ec2012-06-16 05:05:591107
[email protected]e7479052012-09-19 00:26:121108def _CheckNoTrinaryTrueFalse(input_api, output_api):
1109 """Checks to make sure we don't introduce use of foo ? true : false."""
1110 problems = []
1111 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1112 for f in input_api.AffectedFiles():
1113 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1114 continue
1115
1116 for line_num, line in f.ChangedContents():
1117 if pattern.match(line):
1118 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1119
1120 if not problems:
1121 return []
1122 return [output_api.PresubmitPromptWarning(
1123 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1124 '\n'.join(problems))]
1125
1126
[email protected]55f9f382012-07-31 11:02:181127def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281128 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181129 change. Breaking - rules is an error, breaking ! rules is a
1130 warning.
1131 """
mohan.reddyf21db962014-10-16 12:26:471132 import sys
[email protected]55f9f382012-07-31 11:02:181133 # We need to wait until we have an input_api object and use this
1134 # roundabout construct to import checkdeps because this file is
1135 # eval-ed and thus doesn't have __file__.
1136 original_sys_path = sys.path
1137 try:
1138 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471139 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181140 import checkdeps
1141 from cpp_checker import CppChecker
Jinsuk Kim5a092672017-10-24 22:42:241142 from java_checker import JavaChecker
rhalavati08acd232017-04-03 07:23:281143 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:181144 from rules import Rule
1145 finally:
1146 # Restore sys.path to what it was before.
1147 sys.path = original_sys_path
1148
1149 added_includes = []
rhalavati08acd232017-04-03 07:23:281150 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241151 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181152 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:281153 if CppChecker.IsCppFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501154 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081155 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
rhalavati08acd232017-04-03 07:23:281156 elif ProtoChecker.IsProtoFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501157 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081158 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241159 elif JavaChecker.IsJavaFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501160 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081161 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181162
[email protected]26385172013-05-09 23:11:351163 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181164
1165 error_descriptions = []
1166 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281167 error_subjects = set()
1168 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181169 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1170 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081171 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181172 description_with_path = '%s\n %s' % (path, rule_description)
1173 if rule_type == Rule.DISALLOW:
1174 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281175 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181176 else:
1177 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281178 warning_subjects.add("#includes")
1179
1180 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1181 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081182 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281183 description_with_path = '%s\n %s' % (path, rule_description)
1184 if rule_type == Rule.DISALLOW:
1185 error_descriptions.append(description_with_path)
1186 error_subjects.add("imports")
1187 else:
1188 warning_descriptions.append(description_with_path)
1189 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181190
Jinsuk Kim5a092672017-10-24 22:42:241191 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021192 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081193 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241194 description_with_path = '%s\n %s' % (path, rule_description)
1195 if rule_type == Rule.DISALLOW:
1196 error_descriptions.append(description_with_path)
1197 error_subjects.add("imports")
1198 else:
1199 warning_descriptions.append(description_with_path)
1200 warning_subjects.add("imports")
1201
[email protected]55f9f382012-07-31 11:02:181202 results = []
1203 if error_descriptions:
1204 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281205 'You added one or more %s that violate checkdeps rules.'
1206 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181207 error_descriptions))
1208 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421209 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281210 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181211 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281212 '%s? See relevant DEPS file(s) for details and contacts.' %
1213 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181214 warning_descriptions))
1215 return results
1216
1217
[email protected]fbcafe5a2012-08-08 15:31:221218def _CheckFilePermissions(input_api, output_api):
1219 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151220 if input_api.platform == 'win32':
1221 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291222 checkperms_tool = input_api.os_path.join(
1223 input_api.PresubmitLocalPath(),
1224 'tools', 'checkperms', 'checkperms.py')
1225 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471226 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391227 with input_api.CreateTemporaryFile() as file_list:
1228 for f in input_api.AffectedFiles():
1229 # checkperms.py file/directory arguments must be relative to the
1230 # repository.
1231 file_list.write(f.LocalPath() + '\n')
1232 file_list.close()
1233 args += ['--file-list', file_list.name]
1234 try:
1235 input_api.subprocess.check_output(args)
1236 return []
1237 except input_api.subprocess.CalledProcessError as error:
1238 return [output_api.PresubmitError(
1239 'checkperms.py failed:',
1240 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221241
1242
robertocn832f5992017-01-04 19:01:301243def _CheckTeamTags(input_api, output_api):
1244 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1245 checkteamtags_tool = input_api.os_path.join(
1246 input_api.PresubmitLocalPath(),
1247 'tools', 'checkteamtags', 'checkteamtags.py')
1248 args = [input_api.python_executable, checkteamtags_tool,
1249 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221250 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301251 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1252 'OWNERS']
1253 try:
1254 if files:
1255 input_api.subprocess.check_output(args + files)
1256 return []
1257 except input_api.subprocess.CalledProcessError as error:
1258 return [output_api.PresubmitError(
1259 'checkteamtags.py failed:',
1260 long_text=error.output)]
1261
1262
[email protected]c8278b32012-10-30 20:35:491263def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1264 """Makes sure we don't include ui/aura/window_property.h
1265 in header files.
1266 """
1267 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1268 errors = []
1269 for f in input_api.AffectedFiles():
1270 if not f.LocalPath().endswith('.h'):
1271 continue
1272 for line_num, line in f.ChangedContents():
1273 if pattern.match(line):
1274 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1275
1276 results = []
1277 if errors:
1278 results.append(output_api.PresubmitError(
1279 'Header files should not include ui/aura/window_property.h', errors))
1280 return results
1281
1282
[email protected]70ca77752012-11-20 03:45:031283def _CheckForVersionControlConflictsInFile(input_api, f):
1284 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1285 errors = []
1286 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:231287 if f.LocalPath().endswith('.md'):
1288 # First-level headers in markdown look a lot like version control
1289 # conflict markers. http://daringfireball.net/projects/markdown/basics
1290 continue
[email protected]70ca77752012-11-20 03:45:031291 if pattern.match(line):
1292 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1293 return errors
1294
1295
1296def _CheckForVersionControlConflicts(input_api, output_api):
1297 """Usually this is not intentional and will cause a compile failure."""
1298 errors = []
1299 for f in input_api.AffectedFiles():
1300 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1301
1302 results = []
1303 if errors:
1304 results.append(output_api.PresubmitError(
1305 'Version control conflict markers found, please resolve.', errors))
1306 return results
1307
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201308
estadee17314a02017-01-12 16:22:161309def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1310 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1311 errors = []
1312 for f in input_api.AffectedFiles():
1313 for line_num, line in f.ChangedContents():
1314 if pattern.search(line):
1315 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1316
1317 results = []
1318 if errors:
1319 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501320 'Found Google support URL addressed by answer number. Please replace '
1321 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161322 return results
1323
[email protected]70ca77752012-11-20 03:45:031324
[email protected]06e6d0ff2012-12-11 01:36:441325def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1326 def FilterFile(affected_file):
1327 """Filter function for use with input_api.AffectedSourceFiles,
1328 below. This filters out everything except non-test files from
1329 top-level directories that generally speaking should not hard-code
1330 service URLs (e.g. src/android_webview/, src/content/ and others).
1331 """
1332 return input_api.FilterSourceFile(
1333 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491334 white_list=[r'^(android_webview|base|content|net)[\\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:441335 black_list=(_EXCLUDED_PATHS +
1336 _TEST_CODE_EXCLUDED_PATHS +
1337 input_api.DEFAULT_BLACK_LIST))
1338
reillyi38965732015-11-16 18:27:331339 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1340 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461341 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1342 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441343 problems = [] # items are (filename, line_number, line)
1344 for f in input_api.AffectedSourceFiles(FilterFile):
1345 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461346 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441347 problems.append((f.LocalPath(), line_num, line))
1348
1349 if problems:
[email protected]f7051d52013-04-02 18:31:421350 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441351 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581352 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441353 [' %s:%d: %s' % (
1354 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031355 else:
1356 return []
[email protected]06e6d0ff2012-12-11 01:36:441357
1358
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491359# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:271360def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1361 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311362 The native_client_sdk directory is excluded because it has auto-generated PNG
1363 files for documentation.
[email protected]d2530012013-01-25 16:39:271364 """
[email protected]d2530012013-01-25 16:39:271365 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491366 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
1367 black_list = [r'^native_client_sdk[\\\/]']
binji0dcdf342014-12-12 18:32:311368 file_filter = lambda f: input_api.FilterSourceFile(
1369 f, white_list=white_list, black_list=black_list)
1370 for f in input_api.AffectedFiles(include_deletes=False,
1371 file_filter=file_filter):
1372 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271373
1374 results = []
1375 if errors:
1376 results.append(output_api.PresubmitError(
1377 'The name of PNG files should not have abbreviations. \n'
1378 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1379 'Contact [email protected] if you have questions.', errors))
1380 return results
1381
1382
Daniel Cheng4dcdb6b2017-04-13 08:30:171383def _ExtractAddRulesFromParsedDeps(parsed_deps):
1384 """Extract the rules that add dependencies from a parsed DEPS file.
1385
1386 Args:
1387 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1388 add_rules = set()
1389 add_rules.update([
1390 rule[1:] for rule in parsed_deps.get('include_rules', [])
1391 if rule.startswith('+') or rule.startswith('!')
1392 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501393 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171394 {}).iteritems():
1395 add_rules.update([
1396 rule[1:] for rule in rules
1397 if rule.startswith('+') or rule.startswith('!')
1398 ])
1399 return add_rules
1400
1401
1402def _ParseDeps(contents):
1403 """Simple helper for parsing DEPS files."""
1404 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171405 class _VarImpl:
1406
1407 def __init__(self, local_scope):
1408 self._local_scope = local_scope
1409
1410 def Lookup(self, var_name):
1411 """Implements the Var syntax."""
1412 try:
1413 return self._local_scope['vars'][var_name]
1414 except KeyError:
1415 raise Exception('Var is not defined: %s' % var_name)
1416
1417 local_scope = {}
1418 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171419 'Var': _VarImpl(local_scope).Lookup,
1420 }
1421 exec contents in global_scope, local_scope
1422 return local_scope
1423
1424
1425def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081426 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411427 a set of DEPS entries that we should look up.
1428
1429 For a directory (rather than a specific filename) we fake a path to
1430 a specific filename by adding /DEPS. This is chosen as a file that
1431 will seldom or never be subject to per-file include_rules.
1432 """
[email protected]2b438d62013-11-14 17:54:141433 # We ignore deps entries on auto-generated directories.
1434 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081435
Daniel Cheng4dcdb6b2017-04-13 08:30:171436 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1437 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1438
1439 added_deps = new_deps.difference(old_deps)
1440
[email protected]2b438d62013-11-14 17:54:141441 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171442 for added_dep in added_deps:
1443 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1444 continue
1445 # Assume that a rule that ends in .h is a rule for a specific file.
1446 if added_dep.endswith('.h'):
1447 results.add(added_dep)
1448 else:
1449 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081450 return results
1451
1452
[email protected]e871964c2013-05-13 14:14:551453def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1454 """When a dependency prefixed with + is added to a DEPS file, we
1455 want to make sure that the change is reviewed by an OWNER of the
1456 target file or directory, to avoid layering violations from being
1457 introduced. This check verifies that this happens.
1458 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171459 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241460
1461 file_filter = lambda f: not input_api.re.match(
Kent Tamurae9b3a9ec2017-08-31 02:20:191462 r"^third_party[\\\/](WebKit|blink)[\\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241463 for f in input_api.AffectedFiles(include_deletes=False,
1464 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551465 filename = input_api.os_path.basename(f.LocalPath())
1466 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171467 virtual_depended_on_files.update(_CalculateAddedDeps(
1468 input_api.os_path,
1469 '\n'.join(f.OldContents()),
1470 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551471
[email protected]e871964c2013-05-13 14:14:551472 if not virtual_depended_on_files:
1473 return []
1474
1475 if input_api.is_committing:
1476 if input_api.tbr:
1477 return [output_api.PresubmitNotifyResult(
1478 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271479 if input_api.dry_run:
1480 return [output_api.PresubmitNotifyResult(
1481 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551482 if not input_api.change.issue:
1483 return [output_api.PresubmitError(
1484 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401485 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551486 output = output_api.PresubmitError
1487 else:
1488 output = output_api.PresubmitNotifyResult
1489
1490 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501491 owner_email, reviewers = (
1492 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1493 input_api,
1494 owners_db.email_regexp,
1495 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551496
1497 owner_email = owner_email or input_api.change.author_email
1498
[email protected]de4f7d22013-05-23 14:27:461499 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511500 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461501 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551502 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1503 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411504
1505 # We strip the /DEPS part that was added by
1506 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1507 # directory.
1508 def StripDeps(path):
1509 start_deps = path.rfind('/DEPS')
1510 if start_deps != -1:
1511 return path[:start_deps]
1512 else:
1513 return path
1514 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551515 for path in missing_files]
1516
1517 if unapproved_dependencies:
1518 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151519 output('You need LGTM from owners of depends-on paths in DEPS that were '
1520 'modified in this CL:\n %s' %
1521 '\n '.join(sorted(unapproved_dependencies)))]
1522 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1523 output_list.append(output(
1524 'Suggested missing target path OWNERS:\n %s' %
1525 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551526 return output_list
1527
1528 return []
1529
1530
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491531# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:401532def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491533 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:401534 black_list = (_EXCLUDED_PATHS +
1535 _TEST_CODE_EXCLUDED_PATHS +
1536 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501537 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191538 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481539 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461540 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121541 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1542 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581543 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
Olivier Liec4400b22018-07-31 19:50:441544 r"^chrome[\\\/]chrome_cleaner[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161545 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031546 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151547 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1548 r"^chromecast[\\\/]",
1549 r"^cloud_print[\\\/]",
manzagop85e629e2017-05-09 22:11:481550 r"^components[\\\/]browser_watcher[\\\/]"
1551 r"dump_stability_report_main_win.cc$",
jochen34415e52015-07-10 08:34:311552 r"^components[\\\/]html_viewer[\\\/]"
1553 r"web_test_delegate_impl\.cc$",
Samuel Huang577ef6c2018-03-13 18:19:341554 r"^components[\\\/]zucchini[\\\/].*",
peter80739bb2015-10-20 11:17:461555 # TODO(peter): Remove this exception. https://crbug.com/534537
1556 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1557 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251558 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1559 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241560 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111561 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151562 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111563 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521564 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501565 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361566 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311567 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131568 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001569 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441570 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451571 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021572 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351573 r"dump_file_system.cc$",
1574 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401575 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491576 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:401577
thomasanderson625d3932017-03-29 07:16:581578 log_info = set([])
1579 printf = set([])
[email protected]85218562013-11-22 07:41:401580
1581 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581582 for _, line in f.ChangedContents():
1583 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1584 log_info.add(f.LocalPath())
1585 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1586 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371587
thomasanderson625d3932017-03-29 07:16:581588 if input_api.re.search(r"\bprintf\(", line):
1589 printf.add(f.LocalPath())
1590 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1591 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401592
1593 if log_info:
1594 return [output_api.PresubmitError(
1595 'These files spam the console log with LOG(INFO):',
1596 items=log_info)]
1597 if printf:
1598 return [output_api.PresubmitError(
1599 'These files spam the console log with printf/fprintf:',
1600 items=printf)]
1601 return []
1602
1603
[email protected]49aa76a2013-12-04 06:59:161604def _CheckForAnonymousVariables(input_api, output_api):
1605 """These types are all expected to hold locks while in scope and
1606 so should never be anonymous (which causes them to be immediately
1607 destroyed)."""
1608 they_who_must_be_named = [
1609 'base::AutoLock',
1610 'base::AutoReset',
1611 'base::AutoUnlock',
1612 'SkAutoAlphaRestore',
1613 'SkAutoBitmapShaderInstall',
1614 'SkAutoBlitterChoose',
1615 'SkAutoBounderCommit',
1616 'SkAutoCallProc',
1617 'SkAutoCanvasRestore',
1618 'SkAutoCommentBlock',
1619 'SkAutoDescriptor',
1620 'SkAutoDisableDirectionCheck',
1621 'SkAutoDisableOvalCheck',
1622 'SkAutoFree',
1623 'SkAutoGlyphCache',
1624 'SkAutoHDC',
1625 'SkAutoLockColors',
1626 'SkAutoLockPixels',
1627 'SkAutoMalloc',
1628 'SkAutoMaskFreeImage',
1629 'SkAutoMutexAcquire',
1630 'SkAutoPathBoundsUpdate',
1631 'SkAutoPDFRelease',
1632 'SkAutoRasterClipValidate',
1633 'SkAutoRef',
1634 'SkAutoTime',
1635 'SkAutoTrace',
1636 'SkAutoUnref',
1637 ]
1638 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1639 # bad: base::AutoLock(lock.get());
1640 # not bad: base::AutoLock lock(lock.get());
1641 bad_pattern = input_api.re.compile(anonymous)
1642 # good: new base::AutoLock(lock.get())
1643 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1644 errors = []
1645
1646 for f in input_api.AffectedFiles():
1647 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1648 continue
1649 for linenum, line in f.ChangedContents():
1650 if bad_pattern.search(line) and not good_pattern.search(line):
1651 errors.append('%s:%d' % (f.LocalPath(), linenum))
1652
1653 if errors:
1654 return [output_api.PresubmitError(
1655 'These lines create anonymous variables that need to be named:',
1656 items=errors)]
1657 return []
1658
1659
Peter Kasting4844e46e2018-02-23 07:27:101660def _CheckUniquePtr(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491661 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:101662 sources = lambda affected_file: input_api.FilterSourceFile(
1663 affected_file,
1664 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1665 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491666 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:551667
1668 # Pattern to capture a single "<...>" block of template arguments. It can
1669 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
1670 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
1671 # latter would likely require counting that < and > match, which is not
1672 # expressible in regular languages. Should the need arise, one can introduce
1673 # limited counting (matching up to a total number of nesting depth), which
1674 # should cover all practical cases for already a low nesting limit.
1675 template_arg_pattern = (
1676 r'<[^>]*' # Opening block of <.
1677 r'>([^<]*>)?') # Closing block of >.
1678 # Prefix expressing that whatever follows is not already inside a <...>
1679 # block.
1680 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:101681 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:551682 not_inside_template_arg_pattern
1683 + r'\bstd::unique_ptr'
1684 + template_arg_pattern
1685 + r'\(\)')
1686
1687 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
1688 template_arg_no_array_pattern = (
1689 r'<[^>]*[^]]' # Opening block of <.
1690 r'>([^(<]*[^]]>)?') # Closing block of >.
1691 # Prefix saying that what follows is the start of an expression.
1692 start_of_expr_pattern = r'(=|\breturn|^)\s*'
1693 # Suffix saying that what follows are call parentheses with a non-empty list
1694 # of arguments.
1695 nonempty_arg_list_pattern = r'\(([^)]|$)'
1696 return_construct_pattern = input_api.re.compile(
1697 start_of_expr_pattern
1698 + r'std::unique_ptr'
1699 + template_arg_no_array_pattern
1700 + nonempty_arg_list_pattern)
1701
Vaclav Brozek851d9602018-04-04 16:13:051702 problems_constructor = []
1703 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:101704 for f in input_api.AffectedSourceFiles(sources):
1705 for line_number, line in f.ChangedContents():
1706 # Disallow:
1707 # return std::unique_ptr<T>(foo);
1708 # bar = std::unique_ptr<T>(foo);
1709 # But allow:
1710 # return std::unique_ptr<T[]>(foo);
1711 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozek851d9602018-04-04 16:13:051712 local_path = f.LocalPath()
Peter Kasting4844e46e2018-02-23 07:27:101713 if return_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051714 problems_constructor.append(
1715 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:101716 # Disallow:
1717 # std::unique_ptr<T>()
1718 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051719 problems_nullptr.append(
1720 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1721
1722 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:161723 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:051724 errors.append(output_api.PresubmitError(
1725 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161726 problems_nullptr))
1727 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:051728 errors.append(output_api.PresubmitError(
1729 'The following files use explicit std::unique_ptr constructor.'
1730 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161731 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:101732 return errors
1733
1734
[email protected]999261d2014-03-03 20:08:081735def _CheckUserActionUpdate(input_api, output_api):
1736 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521737 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081738 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521739 # If actions.xml is already included in the changelist, the PRESUBMIT
1740 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081741 return []
1742
[email protected]999261d2014-03-03 20:08:081743 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1744 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521745 current_actions = None
[email protected]999261d2014-03-03 20:08:081746 for f in input_api.AffectedFiles(file_filter=file_filter):
1747 for line_num, line in f.ChangedContents():
1748 match = input_api.re.search(action_re, line)
1749 if match:
[email protected]2f92dec2014-03-07 19:21:521750 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1751 # loaded only once.
1752 if not current_actions:
1753 with open('tools/metrics/actions/actions.xml') as actions_f:
1754 current_actions = actions_f.read()
1755 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081756 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521757 action = 'name="{0}"'.format(action_name)
1758 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081759 return [output_api.PresubmitPromptWarning(
1760 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521761 'tools/metrics/actions/actions.xml. Please run '
1762 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081763 % (f.LocalPath(), line_num, action_name))]
1764 return []
1765
1766
Daniel Cheng13ca61a882017-08-25 15:11:251767def _ImportJSONCommentEater(input_api):
1768 import sys
1769 sys.path = sys.path + [input_api.os_path.join(
1770 input_api.PresubmitLocalPath(),
1771 'tools', 'json_comment_eater')]
1772 import json_comment_eater
1773 return json_comment_eater
1774
1775
[email protected]99171a92014-06-03 08:44:471776def _GetJSONParseError(input_api, filename, eat_comments=True):
1777 try:
1778 contents = input_api.ReadFile(filename)
1779 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:251780 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:131781 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471782
1783 input_api.json.loads(contents)
1784 except ValueError as e:
1785 return e
1786 return None
1787
1788
1789def _GetIDLParseError(input_api, filename):
1790 try:
1791 contents = input_api.ReadFile(filename)
1792 idl_schema = input_api.os_path.join(
1793 input_api.PresubmitLocalPath(),
1794 'tools', 'json_schema_compiler', 'idl_schema.py')
1795 process = input_api.subprocess.Popen(
1796 [input_api.python_executable, idl_schema],
1797 stdin=input_api.subprocess.PIPE,
1798 stdout=input_api.subprocess.PIPE,
1799 stderr=input_api.subprocess.PIPE,
1800 universal_newlines=True)
1801 (_, error) = process.communicate(input=contents)
1802 return error or None
1803 except ValueError as e:
1804 return e
1805
1806
1807def _CheckParseErrors(input_api, output_api):
1808 """Check that IDL and JSON files do not contain syntax errors."""
1809 actions = {
1810 '.idl': _GetIDLParseError,
1811 '.json': _GetJSONParseError,
1812 }
[email protected]99171a92014-06-03 08:44:471813 # Most JSON files are preprocessed and support comments, but these do not.
1814 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491815 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471816 ]
1817 # Only run IDL checker on files in these directories.
1818 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491819 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1820 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471821 ]
1822
1823 def get_action(affected_file):
1824 filename = affected_file.LocalPath()
1825 return actions.get(input_api.os_path.splitext(filename)[1])
1826
[email protected]99171a92014-06-03 08:44:471827 def FilterFile(affected_file):
1828 action = get_action(affected_file)
1829 if not action:
1830 return False
1831 path = affected_file.LocalPath()
1832
Sean Kau46e29bc2017-08-28 16:31:161833 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:471834 return False
1835
1836 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:161837 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:471838 return False
1839 return True
1840
1841 results = []
1842 for affected_file in input_api.AffectedFiles(
1843 file_filter=FilterFile, include_deletes=False):
1844 action = get_action(affected_file)
1845 kwargs = {}
1846 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:161847 _MatchesFile(input_api, json_no_comments_patterns,
1848 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:471849 kwargs['eat_comments'] = False
1850 parse_error = action(input_api,
1851 affected_file.AbsoluteLocalPath(),
1852 **kwargs)
1853 if parse_error:
1854 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1855 (affected_file.LocalPath(), parse_error)))
1856 return results
1857
1858
[email protected]760deea2013-12-10 19:33:491859def _CheckJavaStyle(input_api, output_api):
1860 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471861 import sys
[email protected]760deea2013-12-10 19:33:491862 original_sys_path = sys.path
1863 try:
1864 sys.path = sys.path + [input_api.os_path.join(
1865 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1866 import checkstyle
1867 finally:
1868 # Restore sys.path to what it was before.
1869 sys.path = original_sys_path
1870
1871 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091872 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511873 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491874
1875
Sean Kau46e29bc2017-08-28 16:31:161876def _MatchesFile(input_api, patterns, path):
1877 for pattern in patterns:
1878 if input_api.re.search(pattern, path):
1879 return True
1880 return False
1881
1882
Daniel Cheng7052cdf2017-11-21 19:23:291883def _GetOwnersFilesToCheckForIpcOwners(input_api):
1884 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:171885
Daniel Cheng7052cdf2017-11-21 19:23:291886 Returns:
1887 A dictionary mapping an OWNER file to the list of OWNERS rules it must
1888 contain to cover IPC-related files with noparent reviewer rules.
1889 """
1890 # Whether or not a file affects IPC is (mostly) determined by a simple list
1891 # of filename patterns.
dchenge07de812016-06-20 19:27:171892 file_patterns = [
palmerb19a0932017-01-24 04:00:311893 # Legacy IPC:
dchenge07de812016-06-20 19:27:171894 '*_messages.cc',
1895 '*_messages*.h',
1896 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311897 # Mojo IPC:
dchenge07de812016-06-20 19:27:171898 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:471899 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:171900 '*_struct_traits*.*',
1901 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311902 '*.typemap',
1903 # Android native IPC:
1904 '*.aidl',
1905 # Blink uses a different file naming convention:
1906 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:471907 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:171908 '*StructTraits*.*',
1909 '*TypeConverter*.*',
1910 ]
1911
scottmg7a6ed5ba2016-11-04 18:22:041912 # These third_party directories do not contain IPCs, but contain files
1913 # matching the above patterns, which trigger false positives.
1914 exclude_paths = [
1915 'third_party/crashpad/*',
Daniel Chengebe635e2018-07-13 12:36:061916 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:291917 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:041918 ]
1919
dchenge07de812016-06-20 19:27:171920 # Dictionary mapping an OWNERS file path to Patterns.
1921 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1922 # rules ) to a PatternEntry.
1923 # PatternEntry is a dictionary with two keys:
1924 # - 'files': the files that are matched by this pattern
1925 # - 'rules': the per-file rules needed for this pattern
1926 # For example, if we expect OWNERS file to contain rules for *.mojom and
1927 # *_struct_traits*.*, Patterns might look like this:
1928 # {
1929 # '*.mojom': {
1930 # 'files': ...,
1931 # 'rules': [
1932 # 'per-file *.mojom=set noparent',
1933 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1934 # ],
1935 # },
1936 # '*_struct_traits*.*': {
1937 # 'files': ...,
1938 # 'rules': [
1939 # 'per-file *_struct_traits*.*=set noparent',
1940 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1941 # ],
1942 # },
1943 # }
1944 to_check = {}
1945
Daniel Cheng13ca61a882017-08-25 15:11:251946 def AddPatternToCheck(input_file, pattern):
1947 owners_file = input_api.os_path.join(
1948 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
1949 if owners_file not in to_check:
1950 to_check[owners_file] = {}
1951 if pattern not in to_check[owners_file]:
1952 to_check[owners_file][pattern] = {
1953 'files': [],
1954 'rules': [
1955 'per-file %s=set noparent' % pattern,
1956 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1957 ]
1958 }
Vaclav Brozekd5de76a2018-03-17 07:57:501959 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:251960
dchenge07de812016-06-20 19:27:171961 # Iterate through the affected files to see what we actually need to check
1962 # for. We should only nag patch authors about per-file rules if a file in that
1963 # directory would match that pattern. If a directory only contains *.mojom
1964 # files and no *_messages*.h files, we should only nag about rules for
1965 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:251966 for f in input_api.AffectedFiles(include_deletes=False):
1967 # Manifest files don't have a strong naming convention. Instead, scan
1968 # affected files for .json files and see if they look like a manifest.
Sean Kau46e29bc2017-08-28 16:31:161969 if (f.LocalPath().endswith('.json') and
1970 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
1971 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:251972 json_comment_eater = _ImportJSONCommentEater(input_api)
1973 mostly_json_lines = '\n'.join(f.NewContents())
1974 # Comments aren't allowed in strict JSON, so filter them out.
1975 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:431976 try:
1977 json_content = input_api.json.loads(json_lines)
1978 except:
1979 # There's another PRESUBMIT check that already verifies that JSON files
1980 # are not invalid, so no need to emit another warning here.
1981 continue
Daniel Cheng13ca61a882017-08-25 15:11:251982 if 'interface_provider_specs' in json_content:
1983 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:171984 for pattern in file_patterns:
1985 if input_api.fnmatch.fnmatch(
1986 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041987 skip = False
1988 for exclude in exclude_paths:
1989 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1990 skip = True
1991 break
1992 if skip:
1993 continue
Daniel Cheng13ca61a882017-08-25 15:11:251994 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:171995 break
1996
Daniel Cheng7052cdf2017-11-21 19:23:291997 return to_check
1998
1999
2000def _CheckIpcOwners(input_api, output_api):
2001 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2002 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2003
2004 if to_check:
2005 # If there are any OWNERS files to check, there are IPC-related changes in
2006 # this CL. Auto-CC the review list.
2007 output_api.AppendCC('[email protected]')
2008
2009 # Go through the OWNERS files to check, filtering out rules that are already
2010 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172011 for owners_file, patterns in to_check.iteritems():
2012 try:
2013 with file(owners_file) as f:
2014 lines = set(f.read().splitlines())
2015 for entry in patterns.itervalues():
2016 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2017 ]
2018 except IOError:
2019 # No OWNERS file, so all the rules are definitely missing.
2020 continue
2021
2022 # All the remaining lines weren't found in OWNERS files, so emit an error.
2023 errors = []
2024 for owners_file, patterns in to_check.iteritems():
2025 missing_lines = []
2026 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502027 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172028 missing_lines.extend(entry['rules'])
2029 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2030 if missing_lines:
2031 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052032 'Because of the presence of files:\n%s\n\n'
2033 '%s needs the following %d lines added:\n\n%s' %
2034 ('\n'.join(files), owners_file, len(missing_lines),
2035 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172036
2037 results = []
2038 if errors:
vabrf5ce3bf92016-07-11 14:52:412039 if input_api.is_committing:
2040 output = output_api.PresubmitError
2041 else:
2042 output = output_api.PresubmitPromptWarning
2043 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592044 'Found OWNERS files that need to be updated for IPC security ' +
2045 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172046 long_text='\n\n'.join(errors)))
2047
2048 return results
2049
2050
jbriance9e12f162016-11-25 07:57:502051def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312052 """Checks that added or removed lines in non third party affected
2053 header files do not lead to new useless class or struct forward
2054 declaration.
jbriance9e12f162016-11-25 07:57:502055 """
2056 results = []
2057 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2058 input_api.re.MULTILINE)
2059 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2060 input_api.re.MULTILINE)
2061 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312062 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192063 not f.LocalPath().startswith('third_party/blink') and
2064 not f.LocalPath().startswith('third_party\\blink') and
jbriance2c51e821a2016-12-12 08:24:312065 not f.LocalPath().startswith('third_party/WebKit') and
2066 not f.LocalPath().startswith('third_party\\WebKit')):
2067 continue
2068
jbriance9e12f162016-11-25 07:57:502069 if not f.LocalPath().endswith('.h'):
2070 continue
2071
2072 contents = input_api.ReadFile(f)
2073 fwd_decls = input_api.re.findall(class_pattern, contents)
2074 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2075
2076 useless_fwd_decls = []
2077 for decl in fwd_decls:
2078 count = sum(1 for _ in input_api.re.finditer(
2079 r'\b%s\b' % input_api.re.escape(decl), contents))
2080 if count == 1:
2081 useless_fwd_decls.append(decl)
2082
2083 if not useless_fwd_decls:
2084 continue
2085
2086 for line in f.GenerateScmDiff().splitlines():
2087 if (line.startswith('-') and not line.startswith('--') or
2088 line.startswith('+') and not line.startswith('++')):
2089 for decl in useless_fwd_decls:
2090 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2091 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242092 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502093 (f.LocalPath(), decl)))
2094 useless_fwd_decls.remove(decl)
2095
2096 return results
2097
2098
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492099# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:292100def _CheckAndroidToastUsage(input_api, output_api):
2101 """Checks that code uses org.chromium.ui.widget.Toast instead of
2102 android.widget.Toast (Chromium Toast doesn't force hardware
2103 acceleration on low-end devices, saving memory).
2104 """
2105 toast_import_pattern = input_api.re.compile(
2106 r'^import android\.widget\.Toast;$')
2107
2108 errors = []
2109
2110 sources = lambda affected_file: input_api.FilterSourceFile(
2111 affected_file,
2112 black_list=(_EXCLUDED_PATHS +
2113 _TEST_CODE_EXCLUDED_PATHS +
2114 input_api.DEFAULT_BLACK_LIST +
2115 (r'^chromecast[\\\/].*',
2116 r'^remoting[\\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492117 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:292118
2119 for f in input_api.AffectedSourceFiles(sources):
2120 for line_num, line in f.ChangedContents():
2121 if toast_import_pattern.search(line):
2122 errors.append("%s:%d" % (f.LocalPath(), line_num))
2123
2124 results = []
2125
2126 if errors:
2127 results.append(output_api.PresubmitError(
2128 'android.widget.Toast usage is detected. Android toasts use hardware'
2129 ' acceleration, and can be\ncostly on low-end devices. Please use'
2130 ' org.chromium.ui.widget.Toast instead.\n'
2131 'Contact [email protected] if you have any questions.',
2132 errors))
2133
2134 return results
2135
2136
dgnaa68d5e2015-06-10 10:08:222137def _CheckAndroidCrLogUsage(input_api, output_api):
2138 """Checks that new logs using org.chromium.base.Log:
2139 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512140 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222141 """
pkotwicza1dd0b002016-05-16 14:41:042142
torne89540622017-03-24 19:41:302143 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042144 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302145 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:042146 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:302147 # WebView license viewer code cannot depend on //base; used in stub APK.
2148 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
2149 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:042150 ]
2151
dgnaa68d5e2015-06-10 10:08:222152 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122153 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2154 class_in_base_pattern = input_api.re.compile(
2155 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2156 has_some_log_import_pattern = input_api.re.compile(
2157 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222158 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122159 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222160 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512161 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222162 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222163
Vincent Scheib16d7b272015-09-15 18:09:072164 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222165 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492166 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:042167 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122168
dgnaa68d5e2015-06-10 10:08:222169 tag_decl_errors = []
2170 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122171 tag_errors = []
dgn38736db2015-09-18 19:20:512172 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122173 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222174
2175 for f in input_api.AffectedSourceFiles(sources):
2176 file_content = input_api.ReadFile(f)
2177 has_modified_logs = False
2178
2179 # Per line checks
dgn87d9fb62015-06-12 09:15:122180 if (cr_log_import_pattern.search(file_content) or
2181 (class_in_base_pattern.search(file_content) and
2182 not has_some_log_import_pattern.search(file_content))):
2183 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222184 for line_num, line in f.ChangedContents():
2185
2186 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122187 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222188 if match:
2189 has_modified_logs = True
2190
2191 # Make sure it uses "TAG"
2192 if not match.group('tag') == 'TAG':
2193 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122194 else:
2195 # Report non cr Log function calls in changed lines
2196 for line_num, line in f.ChangedContents():
2197 if log_call_pattern.search(line):
2198 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222199
2200 # Per file checks
2201 if has_modified_logs:
2202 # Make sure the tag is using the "cr" prefix and is not too long
2203 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512204 tag_name = match.group('name') if match else None
2205 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222206 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512207 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222208 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512209 elif '.' in tag_name:
2210 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222211
2212 results = []
2213 if tag_decl_errors:
2214 results.append(output_api.PresubmitPromptWarning(
2215 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512216 '"private static final String TAG = "<package tag>".\n'
2217 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222218 tag_decl_errors))
2219
2220 if tag_length_errors:
2221 results.append(output_api.PresubmitError(
2222 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512223 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222224 tag_length_errors))
2225
2226 if tag_errors:
2227 results.append(output_api.PresubmitPromptWarning(
2228 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2229 tag_errors))
2230
dgn87d9fb62015-06-12 09:15:122231 if util_log_errors:
dgn4401aa52015-04-29 16:26:172232 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122233 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2234 util_log_errors))
2235
dgn38736db2015-09-18 19:20:512236 if tag_with_dot_errors:
2237 results.append(output_api.PresubmitPromptWarning(
2238 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2239 tag_with_dot_errors))
2240
dgn4401aa52015-04-29 16:26:172241 return results
2242
2243
Yoland Yanb92fa522017-08-28 17:37:062244def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2245 """Checks that junit.framework.* is no longer used."""
2246 deprecated_junit_framework_pattern = input_api.re.compile(
2247 r'^import junit\.framework\..*;',
2248 input_api.re.MULTILINE)
2249 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492250 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062251 errors = []
2252 for f in input_api.AffectedFiles(sources):
2253 for line_num, line in f.ChangedContents():
2254 if deprecated_junit_framework_pattern.search(line):
2255 errors.append("%s:%d" % (f.LocalPath(), line_num))
2256
2257 results = []
2258 if errors:
2259 results.append(output_api.PresubmitError(
2260 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2261 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2262 ' if you have any question.', errors))
2263 return results
2264
2265
2266def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2267 """Checks that if new Java test classes have inheritance.
2268 Either the new test class is JUnit3 test or it is a JUnit4 test class
2269 with a base class, either case is undesirable.
2270 """
2271 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2272
2273 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492274 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062275 errors = []
2276 for f in input_api.AffectedFiles(sources):
2277 if not f.OldContents():
2278 class_declaration_start_flag = False
2279 for line_num, line in f.ChangedContents():
2280 if class_declaration_pattern.search(line):
2281 class_declaration_start_flag = True
2282 if class_declaration_start_flag and ' extends ' in line:
2283 errors.append('%s:%d' % (f.LocalPath(), line_num))
2284 if '{' in line:
2285 class_declaration_start_flag = False
2286
2287 results = []
2288 if errors:
2289 results.append(output_api.PresubmitPromptWarning(
2290 'The newly created files include Test classes that inherits from base'
2291 ' class. Please do not use inheritance in JUnit4 tests or add new'
2292 ' JUnit3 tests. Contact [email protected] if you have any'
2293 ' questions.', errors))
2294 return results
2295
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202296
yolandyan45001472016-12-21 21:12:422297def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2298 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2299 deprecated_annotation_import_pattern = input_api.re.compile(
2300 r'^import android\.test\.suitebuilder\.annotation\..*;',
2301 input_api.re.MULTILINE)
2302 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492303 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:422304 errors = []
2305 for f in input_api.AffectedFiles(sources):
2306 for line_num, line in f.ChangedContents():
2307 if deprecated_annotation_import_pattern.search(line):
2308 errors.append("%s:%d" % (f.LocalPath(), line_num))
2309
2310 results = []
2311 if errors:
2312 results.append(output_api.PresubmitError(
2313 'Annotations in android.test.suitebuilder.annotation have been'
2314 ' deprecated since API level 24. Please use android.support.test.filters'
2315 ' from //third_party/android_support_test_runner:runner_java instead.'
2316 ' Contact [email protected] if you have any questions.', errors))
2317 return results
2318
2319
agrieve7b6479d82015-10-07 14:24:222320def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2321 """Checks if MDPI assets are placed in a correct directory."""
2322 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2323 ('/res/drawable/' in f.LocalPath() or
2324 '/res/drawable-ldrtl/' in f.LocalPath()))
2325 errors = []
2326 for f in input_api.AffectedFiles(include_deletes=False,
2327 file_filter=file_filter):
2328 errors.append(' %s' % f.LocalPath())
2329
2330 results = []
2331 if errors:
2332 results.append(output_api.PresubmitError(
2333 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2334 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2335 '/res/drawable-ldrtl/.\n'
2336 'Contact [email protected] if you have questions.', errors))
2337 return results
2338
2339
Nate Fischer535972b2017-09-16 01:06:182340def _CheckAndroidWebkitImports(input_api, output_api):
2341 """Checks that code uses org.chromium.base.Callback instead of
2342 android.widget.ValueCallback except in the WebView glue layer.
2343 """
2344 valuecallback_import_pattern = input_api.re.compile(
2345 r'^import android\.webkit\.ValueCallback;$')
2346
2347 errors = []
2348
2349 sources = lambda affected_file: input_api.FilterSourceFile(
2350 affected_file,
2351 black_list=(_EXCLUDED_PATHS +
2352 _TEST_CODE_EXCLUDED_PATHS +
2353 input_api.DEFAULT_BLACK_LIST +
2354 (r'^android_webview[\\\/]glue[\\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492355 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:182356
2357 for f in input_api.AffectedSourceFiles(sources):
2358 for line_num, line in f.ChangedContents():
2359 if valuecallback_import_pattern.search(line):
2360 errors.append("%s:%d" % (f.LocalPath(), line_num))
2361
2362 results = []
2363
2364 if errors:
2365 results.append(output_api.PresubmitError(
2366 'android.webkit.ValueCallback usage is detected outside of the glue'
2367 ' layer. To stay compatible with the support library, android.webkit.*'
2368 ' classes should only be used inside the glue layer and'
2369 ' org.chromium.base.Callback should be used instead.',
2370 errors))
2371
2372 return results
2373
2374
agrievef32bcc72016-04-04 14:57:402375class PydepsChecker(object):
2376 def __init__(self, input_api, pydeps_files):
2377 self._file_cache = {}
2378 self._input_api = input_api
2379 self._pydeps_files = pydeps_files
2380
2381 def _LoadFile(self, path):
2382 """Returns the list of paths within a .pydeps file relative to //."""
2383 if path not in self._file_cache:
2384 with open(path) as f:
2385 self._file_cache[path] = f.read()
2386 return self._file_cache[path]
2387
2388 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2389 """Returns an interable of paths within the .pydep, relativized to //."""
2390 os_path = self._input_api.os_path
2391 pydeps_dir = os_path.dirname(pydeps_path)
2392 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2393 if not l.startswith('*'))
2394 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2395
2396 def _CreateFilesToPydepsMap(self):
2397 """Returns a map of local_path -> list_of_pydeps."""
2398 ret = {}
2399 for pydep_local_path in self._pydeps_files:
2400 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2401 ret.setdefault(path, []).append(pydep_local_path)
2402 return ret
2403
2404 def ComputeAffectedPydeps(self):
2405 """Returns an iterable of .pydeps files that might need regenerating."""
2406 affected_pydeps = set()
2407 file_to_pydeps_map = None
2408 for f in self._input_api.AffectedFiles(include_deletes=True):
2409 local_path = f.LocalPath()
2410 if local_path == 'DEPS':
2411 return self._pydeps_files
2412 elif local_path.endswith('.pydeps'):
2413 if local_path in self._pydeps_files:
2414 affected_pydeps.add(local_path)
2415 elif local_path.endswith('.py'):
2416 if file_to_pydeps_map is None:
2417 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2418 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2419 return affected_pydeps
2420
2421 def DetermineIfStale(self, pydeps_path):
2422 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412423 import difflib
John Budorick47ca3fe2018-02-10 00:53:102424 import os
2425
agrievef32bcc72016-04-04 14:57:402426 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2427 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102428 env = dict(os.environ)
2429 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402430 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102431 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412432 old_contents = old_pydeps_data[2:]
2433 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402434 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412435 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402436
2437
2438def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2439 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402440 # This check is for Python dependency lists (.pydeps files), and involves
2441 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2442 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282443 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002444 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022445 # TODO(agrieve): Update when there's a better way to detect
2446 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402447 is_android = input_api.os_path.exists('third_party/android_tools')
2448 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2449 results = []
2450 # First, check for new / deleted .pydeps.
2451 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032452 # Check whether we are running the presubmit check for a file in src.
2453 # f.LocalPath is relative to repo (src, or internal repo).
2454 # os_path.exists is relative to src repo.
2455 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2456 # to src and we can conclude that the pydeps is in src.
2457 if input_api.os_path.exists(f.LocalPath()):
2458 if f.LocalPath().endswith('.pydeps'):
2459 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2460 results.append(output_api.PresubmitError(
2461 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2462 'remove %s' % f.LocalPath()))
2463 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2464 results.append(output_api.PresubmitError(
2465 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2466 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402467
2468 if results:
2469 return results
2470
2471 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2472
2473 for pydep_path in checker.ComputeAffectedPydeps():
2474 try:
phajdan.jr0d9878552016-11-04 10:49:412475 result = checker.DetermineIfStale(pydep_path)
2476 if result:
2477 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402478 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412479 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2480 'To regenerate, run:\n\n %s' %
2481 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402482 except input_api.subprocess.CalledProcessError as error:
2483 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2484 long_text=error.output)]
2485
2486 return results
2487
2488
glidere61efad2015-02-18 17:39:432489def _CheckSingletonInHeaders(input_api, output_api):
2490 """Checks to make sure no header files have |Singleton<|."""
2491 def FileFilter(affected_file):
2492 # It's ok for base/memory/singleton.h to have |Singleton<|.
2493 black_list = (_EXCLUDED_PATHS +
2494 input_api.DEFAULT_BLACK_LIST +
Michael Warrese4451492018-03-07 04:42:472495 (r"^base[\\\/]memory[\\\/]singleton\.h$",
2496 r"^net[\\\/]quic[\\\/]platform[\\\/]impl[\\\/]"
2497 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432498 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2499
sergeyu34d21222015-09-16 00:11:442500 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432501 files = []
2502 for f in input_api.AffectedSourceFiles(FileFilter):
2503 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2504 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2505 contents = input_api.ReadFile(f)
2506 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242507 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432508 pattern.search(line)):
2509 files.append(f)
2510 break
2511
2512 if files:
yolandyandaabc6d2016-04-18 18:29:392513 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442514 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432515 'Please move them to an appropriate source file so that the ' +
2516 'template gets instantiated in a single compilation unit.',
2517 files) ]
2518 return []
2519
2520
[email protected]fd20b902014-05-09 02:14:532521_DEPRECATED_CSS = [
2522 # Values
2523 ( "-webkit-box", "flex" ),
2524 ( "-webkit-inline-box", "inline-flex" ),
2525 ( "-webkit-flex", "flex" ),
2526 ( "-webkit-inline-flex", "inline-flex" ),
2527 ( "-webkit-min-content", "min-content" ),
2528 ( "-webkit-max-content", "max-content" ),
2529
2530 # Properties
2531 ( "-webkit-background-clip", "background-clip" ),
2532 ( "-webkit-background-origin", "background-origin" ),
2533 ( "-webkit-background-size", "background-size" ),
2534 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442535 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532536
2537 # Functions
2538 ( "-webkit-gradient", "gradient" ),
2539 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2540 ( "-webkit-linear-gradient", "linear-gradient" ),
2541 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2542 ( "-webkit-radial-gradient", "radial-gradient" ),
2543 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2544]
2545
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202546
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492547# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242548def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532549 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252550 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342551 documentation and iOS CSS for dom distiller
2552 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252553 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532554 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492555 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:252556 black_list = (_EXCLUDED_PATHS +
2557 _TEST_CODE_EXCLUDED_PATHS +
2558 input_api.DEFAULT_BLACK_LIST +
2559 (r"^chrome/common/extensions/docs",
2560 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342561 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442562 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252563 r"^native_client_sdk"))
2564 file_filter = lambda f: input_api.FilterSourceFile(
2565 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532566 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2567 for line_num, line in fpath.ChangedContents():
2568 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022569 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532570 results.append(output_api.PresubmitError(
2571 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2572 (fpath.LocalPath(), line_num, deprecated_value, value)))
2573 return results
2574
mohan.reddyf21db962014-10-16 12:26:472575
dbeam070cfe62014-10-22 06:44:022576_DEPRECATED_JS = [
2577 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2578 ( "__defineGetter__", "Object.defineProperty" ),
2579 ( "__defineSetter__", "Object.defineProperty" ),
2580]
2581
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202582
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492583# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242584def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022585 """Make sure that we don't use deprecated JS in Chrome code."""
2586 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492587 file_inclusion_pattern = [r".+\.js$"] # TODO(dbeam): .html?
dbeam070cfe62014-10-22 06:44:022588 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2589 input_api.DEFAULT_BLACK_LIST)
2590 file_filter = lambda f: input_api.FilterSourceFile(
2591 f, white_list=file_inclusion_pattern, black_list=black_list)
2592 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2593 for lnum, line in fpath.ChangedContents():
2594 for (deprecated, replacement) in _DEPRECATED_JS:
2595 if deprecated in line:
2596 results.append(output_api.PresubmitError(
2597 "%s:%d: Use of deprecated JS %s, use %s instead" %
2598 (fpath.LocalPath(), lnum, deprecated, replacement)))
2599 return results
2600
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202601
dpapadd651231d82017-07-21 02:44:472602def _CheckForRiskyJsArrowFunction(line_number, line):
2603 if ' => ' in line:
2604 return "line %d, is using an => (arrow) function\n %s\n" % (
2605 line_number, line)
2606 return ''
2607
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202608
dpapadd651231d82017-07-21 02:44:472609def _CheckForRiskyJsConstLet(input_api, line_number, line):
2610 if input_api.re.match('^\s*(const|let)\s', line):
2611 return "line %d, is using const/let keyword\n %s\n" % (
2612 line_number, line)
2613 return ''
dbeam070cfe62014-10-22 06:44:022614
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202615
dbeam1ec68ac2016-12-15 05:22:242616def _CheckForRiskyJsFeatures(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492617 maybe_ios_js = [r"^(ios|components|ui\/webui\/resources)\/.+\.js$"]
Steven Bennetts90545f3cb2017-08-14 18:11:002618 # 'ui/webui/resources/cr_components are not allowed on ios'
2619 not_ios_filter = (r".*ui\/webui\/resources\/cr_components.*", )
Steven Bennetts9c7e3c22017-08-02 19:10:572620 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js,
Steven Bennetts90545f3cb2017-08-14 18:11:002621 black_list=not_ios_filter)
dpapadd651231d82017-07-21 02:44:472622 results = []
dbeam1ec68ac2016-12-15 05:22:242623 for f in input_api.AffectedFiles(file_filter=file_filter):
dpapadd651231d82017-07-21 02:44:472624 arrow_error_lines = []
2625 const_let_error_lines = []
dbeam1ec68ac2016-12-15 05:22:242626 for lnum, line in f.ChangedContents():
dpapadd651231d82017-07-21 02:44:472627 arrow_error_lines += filter(None, [
2628 _CheckForRiskyJsArrowFunction(lnum, line),
2629 ])
dbeam1ec68ac2016-12-15 05:22:242630
dpapadd651231d82017-07-21 02:44:472631 const_let_error_lines += filter(None, [
2632 _CheckForRiskyJsConstLet(input_api, lnum, line),
2633 ])
dbeam1ec68ac2016-12-15 05:22:242634
dpapadd651231d82017-07-21 02:44:472635 if arrow_error_lines:
2636 arrow_error_lines = map(
2637 lambda e: "%s:%s" % (f.LocalPath(), e), arrow_error_lines)
2638 results.append(
2639 output_api.PresubmitPromptWarning('\n'.join(arrow_error_lines + [
2640"""
2641Use of => (arrow) operator detected in:
dbeam1ec68ac2016-12-15 05:22:242642%s
2643Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2644https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
dpapadd651231d82017-07-21 02:44:472645""" % f.LocalPath()
2646 ])))
dbeam1ec68ac2016-12-15 05:22:242647
dpapadd651231d82017-07-21 02:44:472648 if const_let_error_lines:
2649 const_let_error_lines = map(
2650 lambda e: "%s:%s" % (f.LocalPath(), e), const_let_error_lines)
2651 results.append(
2652 output_api.PresubmitPromptWarning('\n'.join(const_let_error_lines + [
2653"""
2654Use of const/let keywords detected in:
2655%s
2656Please ensure your code does not run on iOS9 because const/let is not fully
2657supported.
2658https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#let-Block_Scoped-Variables
2659https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#const-Block_Scoped-Constants
2660""" % f.LocalPath()
2661 ])))
2662
2663 return results
dbeam1ec68ac2016-12-15 05:22:242664
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202665
rlanday6802cf632017-05-30 17:48:362666def _CheckForRelativeIncludes(input_api, output_api):
2667 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2668 import sys
2669 original_sys_path = sys.path
2670 try:
2671 sys.path = sys.path + [input_api.os_path.join(
2672 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2673 from cpp_checker import CppChecker
2674 finally:
2675 # Restore sys.path to what it was before.
2676 sys.path = original_sys_path
2677
2678 bad_files = {}
2679 for f in input_api.AffectedFiles(include_deletes=False):
2680 if (f.LocalPath().startswith('third_party') and
2681 not f.LocalPath().startswith('third_party/WebKit') and
2682 not f.LocalPath().startswith('third_party\\WebKit')):
2683 continue
2684
2685 if not CppChecker.IsCppFile(f.LocalPath()):
2686 continue
2687
Vaclav Brozekd5de76a2018-03-17 07:57:502688 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362689 if "#include" in line and "../" in line]
2690 if not relative_includes:
2691 continue
2692 bad_files[f.LocalPath()] = relative_includes
2693
2694 if not bad_files:
2695 return []
2696
2697 error_descriptions = []
2698 for file_path, bad_lines in bad_files.iteritems():
2699 error_description = file_path
2700 for line in bad_lines:
2701 error_description += '\n ' + line
2702 error_descriptions.append(error_description)
2703
2704 results = []
2705 results.append(output_api.PresubmitError(
2706 'You added one or more relative #include paths (including "../").\n'
2707 'These shouldn\'t be used because they can be used to include headers\n'
2708 'from code that\'s not correctly specified as a dependency in the\n'
2709 'relevant BUILD.gn file(s).',
2710 error_descriptions))
2711
2712 return results
2713
Takeshi Yoshinoe387aa32017-08-02 13:16:132714
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202715def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2716 if not isinstance(key, ast.Str):
2717 return 'Key at line %d must be a string literal' % key.lineno
2718 if not isinstance(value, ast.Dict):
2719 return 'Value at line %d must be a dict' % value.lineno
2720 if len(value.keys) != 1:
2721 return 'Dict at line %d must have single entry' % value.lineno
2722 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2723 return (
2724 'Entry at line %d must have a string literal \'filepath\' as key' %
2725 value.lineno)
2726 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132727
Takeshi Yoshinoe387aa32017-08-02 13:16:132728
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202729def _CheckWatchlistsEntrySyntax(key, value, ast):
2730 if not isinstance(key, ast.Str):
2731 return 'Key at line %d must be a string literal' % key.lineno
2732 if not isinstance(value, ast.List):
2733 return 'Value at line %d must be a list' % value.lineno
2734 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132735
Takeshi Yoshinoe387aa32017-08-02 13:16:132736
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202737def _CheckWATCHLISTSEntries(wd_dict, w_dict, ast):
2738 mismatch_template = (
2739 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2740 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132741
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202742 i = 0
2743 last_key = ''
2744 while True:
2745 if i >= len(wd_dict.keys):
2746 if i >= len(w_dict.keys):
2747 return None
2748 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2749 elif i >= len(w_dict.keys):
2750 return (
2751 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132752
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202753 wd_key = wd_dict.keys[i]
2754 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132755
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202756 result = _CheckWatchlistDefinitionsEntrySyntax(
2757 wd_key, wd_dict.values[i], ast)
2758 if result is not None:
2759 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132760
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202761 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast)
2762 if result is not None:
2763 return 'Bad entry in WATCHLISTS dict: %s' % result
2764
2765 if wd_key.s != w_key.s:
2766 return mismatch_template % (
2767 '%s at line %d' % (wd_key.s, wd_key.lineno),
2768 '%s at line %d' % (w_key.s, w_key.lineno))
2769
2770 if wd_key.s < last_key:
2771 return (
2772 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2773 (wd_key.lineno, w_key.lineno))
2774 last_key = wd_key.s
2775
2776 i = i + 1
2777
2778
2779def _CheckWATCHLISTSSyntax(expression, ast):
2780 if not isinstance(expression, ast.Expression):
2781 return 'WATCHLISTS file must contain a valid expression'
2782 dictionary = expression.body
2783 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2784 return 'WATCHLISTS file must have single dict with exactly two entries'
2785
2786 first_key = dictionary.keys[0]
2787 first_value = dictionary.values[0]
2788 second_key = dictionary.keys[1]
2789 second_value = dictionary.values[1]
2790
2791 if (not isinstance(first_key, ast.Str) or
2792 first_key.s != 'WATCHLIST_DEFINITIONS' or
2793 not isinstance(first_value, ast.Dict)):
2794 return (
2795 'The first entry of the dict in WATCHLISTS file must be '
2796 'WATCHLIST_DEFINITIONS dict')
2797
2798 if (not isinstance(second_key, ast.Str) or
2799 second_key.s != 'WATCHLISTS' or
2800 not isinstance(second_value, ast.Dict)):
2801 return (
2802 'The second entry of the dict in WATCHLISTS file must be '
2803 'WATCHLISTS dict')
2804
2805 return _CheckWATCHLISTSEntries(first_value, second_value, ast)
Takeshi Yoshinoe387aa32017-08-02 13:16:132806
2807
2808def _CheckWATCHLISTS(input_api, output_api):
2809 for f in input_api.AffectedFiles(include_deletes=False):
2810 if f.LocalPath() == 'WATCHLISTS':
2811 contents = input_api.ReadFile(f, 'r')
2812
2813 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202814 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132815 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202816 # Get an AST tree for it and scan the tree for detailed style checking.
2817 expression = input_api.ast.parse(
2818 contents, filename='WATCHLISTS', mode='eval')
2819 except ValueError as e:
2820 return [output_api.PresubmitError(
2821 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2822 except SyntaxError as e:
2823 return [output_api.PresubmitError(
2824 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2825 except TypeError as e:
2826 return [output_api.PresubmitError(
2827 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132828
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202829 result = _CheckWATCHLISTSSyntax(expression, input_api.ast)
2830 if result is not None:
2831 return [output_api.PresubmitError(result)]
2832 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132833
2834 return []
2835
2836
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192837def _CheckNewHeaderWithoutGnChange(input_api, output_api):
2838 """Checks that newly added header files have corresponding GN changes.
2839 Note that this is only a heuristic. To be precise, run script:
2840 build/check_gn_headers.py.
2841 """
2842
2843 def headers(f):
2844 return input_api.FilterSourceFile(
2845 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
2846
2847 new_headers = []
2848 for f in input_api.AffectedSourceFiles(headers):
2849 if f.Action() != 'A':
2850 continue
2851 new_headers.append(f.LocalPath())
2852
2853 def gn_files(f):
2854 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
2855
2856 all_gn_changed_contents = ''
2857 for f in input_api.AffectedSourceFiles(gn_files):
2858 for _, line in f.ChangedContents():
2859 all_gn_changed_contents += line
2860
2861 problems = []
2862 for header in new_headers:
2863 basename = input_api.os_path.basename(header)
2864 if basename not in all_gn_changed_contents:
2865 problems.append(header)
2866
2867 if problems:
2868 return [output_api.PresubmitPromptWarning(
2869 'Missing GN changes for new header files', items=sorted(problems),
2870 long_text='Please double check whether newly added header files need '
2871 'corresponding changes in gn or gni files.\nThis checking is only a '
2872 'heuristic. Run build/check_gn_headers.py to be precise.\n'
2873 'Read https://crbug.com/661774 for more info.')]
2874 return []
2875
2876
dgnaa68d5e2015-06-10 10:08:222877def _AndroidSpecificOnUploadChecks(input_api, output_api):
2878 """Groups checks that target android code."""
2879 results = []
dgnaa68d5e2015-06-10 10:08:222880 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222881 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292882 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:062883 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
2884 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:422885 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:182886 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222887 return results
2888
2889
[email protected]22c9bd72011-03-27 16:47:392890def _CommonChecks(input_api, output_api):
2891 """Checks common to both upload and commit."""
2892 results = []
2893 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382894 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542895 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:082896
2897 author = input_api.change.author_email
2898 if author and author not in _KNOWN_ROBOTS:
2899 results.extend(
2900 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
2901
[email protected]55459852011-08-10 15:17:192902 results.extend(
[email protected]760deea2013-12-10 19:33:492903 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:232904 results.extend(
2905 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542906 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182907 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522908 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222909 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442910 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592911 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062912 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122913 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182914 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222915 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302916 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492917 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032918 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492919 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442920 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272921 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:072922 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542923 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442924 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392925 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552926 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042927 results.extend(
2928 input_api.canned_checks.CheckChangeHasNoTabs(
2929 input_api,
2930 output_api,
2931 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402932 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162933 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082934 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242935 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2936 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472937 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042938 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:052939 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:142940 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232941 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432942 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402943 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152944 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172945 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502946 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242947 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:362948 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:132949 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:432950 results.extend(input_api.RunTests(
2951 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:142952 results.extend(_CheckTranslationScreenshots(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242953
Vaclav Brozekcdc7defb2018-03-20 09:54:352954 for f in input_api.AffectedFiles():
2955 path, name = input_api.os_path.split(f.LocalPath())
2956 if name == 'PRESUBMIT.py':
2957 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:002958 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
2959 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:072960 # The PRESUBMIT.py file (and the directory containing it) might
2961 # have been affected by being moved or removed, so only try to
2962 # run the tests if they still exist.
2963 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2964 input_api, output_api, full_path,
2965 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392966 return results
[email protected]1f7b4172010-01-28 01:17:342967
[email protected]b337cb5b2011-01-23 21:24:052968
[email protected]b8079ae4a2012-12-05 19:56:492969def _CheckPatchFiles(input_api, output_api):
2970 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2971 if f.LocalPath().endswith(('.orig', '.rej'))]
2972 if problems:
2973 return [output_api.PresubmitError(
2974 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032975 else:
2976 return []
[email protected]b8079ae4a2012-12-05 19:56:492977
2978
Kent Tamura5a8755d2017-06-29 23:37:072979def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:212980 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
2981 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
2982 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:072983 include_re = input_api.re.compile(
2984 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
2985 extension_re = input_api.re.compile(r'\.[a-z]+$')
2986 errors = []
2987 for f in input_api.AffectedFiles():
2988 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
2989 continue
2990 found_line_number = None
2991 found_macro = None
2992 for line_num, line in f.ChangedContents():
2993 match = macro_re.search(line)
2994 if match:
2995 found_line_number = line_num
2996 found_macro = match.group(2)
2997 break
2998 if not found_line_number:
2999 continue
3000
3001 found_include = False
3002 for line in f.NewContents():
3003 if include_re.search(line):
3004 found_include = True
3005 break
3006 if found_include:
3007 continue
3008
3009 if not f.LocalPath().endswith('.h'):
3010 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
3011 try:
3012 content = input_api.ReadFile(primary_header_path, 'r')
3013 if include_re.search(content):
3014 continue
3015 except IOError:
3016 pass
3017 errors.append('%s:%d %s macro is used without including build/'
3018 'build_config.h.'
3019 % (f.LocalPath(), found_line_number, found_macro))
3020 if errors:
3021 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
3022 return []
3023
3024
[email protected]b00342e7f2013-03-26 16:21:543025def _DidYouMeanOSMacro(bad_macro):
3026 try:
3027 return {'A': 'OS_ANDROID',
3028 'B': 'OS_BSD',
3029 'C': 'OS_CHROMEOS',
3030 'F': 'OS_FREEBSD',
3031 'L': 'OS_LINUX',
3032 'M': 'OS_MACOSX',
3033 'N': 'OS_NACL',
3034 'O': 'OS_OPENBSD',
3035 'P': 'OS_POSIX',
3036 'S': 'OS_SOLARIS',
3037 'W': 'OS_WIN'}[bad_macro[3].upper()]
3038 except KeyError:
3039 return ''
3040
3041
3042def _CheckForInvalidOSMacrosInFile(input_api, f):
3043 """Check for sensible looking, totally invalid OS macros."""
3044 preprocessor_statement = input_api.re.compile(r'^\s*#')
3045 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
3046 results = []
3047 for lnum, line in f.ChangedContents():
3048 if preprocessor_statement.search(line):
3049 for match in os_macro.finditer(line):
3050 if not match.group(1) in _VALID_OS_MACROS:
3051 good = _DidYouMeanOSMacro(match.group(1))
3052 did_you_mean = ' (did you mean %s?)' % good if good else ''
3053 results.append(' %s:%d %s%s' % (f.LocalPath(),
3054 lnum,
3055 match.group(1),
3056 did_you_mean))
3057 return results
3058
3059
3060def _CheckForInvalidOSMacros(input_api, output_api):
3061 """Check all affected files for invalid OS macros."""
3062 bad_macros = []
3063 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:473064 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:543065 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
3066
3067 if not bad_macros:
3068 return []
3069
3070 return [output_api.PresubmitError(
3071 'Possibly invalid OS macro[s] found. Please fix your code\n'
3072 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
3073
lliabraa35bab3932014-10-01 12:16:443074
3075def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
3076 """Check all affected files for invalid "if defined" macros."""
3077 ALWAYS_DEFINED_MACROS = (
3078 "TARGET_CPU_PPC",
3079 "TARGET_CPU_PPC64",
3080 "TARGET_CPU_68K",
3081 "TARGET_CPU_X86",
3082 "TARGET_CPU_ARM",
3083 "TARGET_CPU_MIPS",
3084 "TARGET_CPU_SPARC",
3085 "TARGET_CPU_ALPHA",
3086 "TARGET_IPHONE_SIMULATOR",
3087 "TARGET_OS_EMBEDDED",
3088 "TARGET_OS_IPHONE",
3089 "TARGET_OS_MAC",
3090 "TARGET_OS_UNIX",
3091 "TARGET_OS_WIN32",
3092 )
3093 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
3094 results = []
3095 for lnum, line in f.ChangedContents():
3096 for match in ifdef_macro.finditer(line):
3097 if match.group(1) in ALWAYS_DEFINED_MACROS:
3098 always_defined = ' %s is always defined. ' % match.group(1)
3099 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
3100 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
3101 lnum,
3102 always_defined,
3103 did_you_mean))
3104 return results
3105
3106
3107def _CheckForInvalidIfDefinedMacros(input_api, output_api):
3108 """Check all affected files for invalid "if defined" macros."""
3109 bad_macros = []
3110 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:213111 if f.LocalPath().startswith('third_party/sqlite/'):
3112 continue
lliabraa35bab3932014-10-01 12:16:443113 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3114 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3115
3116 if not bad_macros:
3117 return []
3118
3119 return [output_api.PresubmitError(
3120 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3121 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3122 bad_macros)]
3123
3124
mlamouria82272622014-09-16 18:45:043125def _CheckForIPCRules(input_api, output_api):
3126 """Check for same IPC rules described in
3127 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3128 """
3129 base_pattern = r'IPC_ENUM_TRAITS\('
3130 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3131 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3132
3133 problems = []
3134 for f in input_api.AffectedSourceFiles(None):
3135 local_path = f.LocalPath()
3136 if not local_path.endswith('.h'):
3137 continue
3138 for line_number, line in f.ChangedContents():
3139 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3140 problems.append(
3141 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3142
3143 if problems:
3144 return [output_api.PresubmitPromptWarning(
3145 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
3146 else:
3147 return []
3148
[email protected]b00342e7f2013-03-26 16:21:543149
Stephen Martinis97a394142018-06-07 23:06:053150def _CheckForLongPathnames(input_api, output_api):
3151 """Check to make sure no files being submitted have long paths.
3152 This causes issues on Windows.
3153 """
3154 problems = []
3155 for f in input_api.AffectedSourceFiles(None):
3156 local_path = f.LocalPath()
3157 # Windows has a path limit of 260 characters. Limit path length to 200 so
3158 # that we have some extra for the prefix on dev machines and the bots.
3159 if len(local_path) > 200:
3160 problems.append(local_path)
3161
3162 if problems:
3163 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
3164 else:
3165 return []
3166
3167
Daniel Bratell8ba52722018-03-02 16:06:143168def _CheckForIncludeGuards(input_api, output_api):
3169 """Check that header files have proper guards against multiple inclusion.
3170 If a file should not have such guards (and it probably should) then it
3171 should include the string "no-include-guard-because-multiply-included".
3172 """
Daniel Bratell6a75baef62018-06-04 10:04:453173 def is_chromium_header_file(f):
3174 # We only check header files under the control of the Chromium
3175 # project. That is, those outside third_party apart from
3176 # third_party/blink.
3177 file_with_path = input_api.os_path.normpath(f.LocalPath())
3178 return (file_with_path.endswith('.h') and
3179 (not file_with_path.startswith('third_party') or
3180 file_with_path.startswith(
3181 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:143182
3183 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:343184 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:143185
3186 errors = []
3187
Daniel Bratell6a75baef62018-06-04 10:04:453188 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:143189 guard_name = None
3190 guard_line_number = None
3191 seen_guard_end = False
3192
3193 file_with_path = input_api.os_path.normpath(f.LocalPath())
3194 base_file_name = input_api.os_path.splitext(
3195 input_api.os_path.basename(file_with_path))[0]
3196 upper_base_file_name = base_file_name.upper()
3197
3198 expected_guard = replace_special_with_underscore(
3199 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:143200
3201 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:573202 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
3203 # are too many (1000+) files with slight deviations from the
3204 # coding style. The most important part is that the include guard
3205 # is there, and that it's unique, not the name so this check is
3206 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:143207 #
3208 # As code becomes more uniform, this could be made stricter.
3209
3210 guard_name_pattern_list = [
3211 # Anything with the right suffix (maybe with an extra _).
3212 r'\w+_H__?',
3213
Daniel Bratell39b5b062018-05-16 18:09:573214 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:143215 r'\w+_h',
3216
3217 # Anything including the uppercase name of the file.
3218 r'\w*' + input_api.re.escape(replace_special_with_underscore(
3219 upper_base_file_name)) + r'\w*',
3220 ]
3221 guard_name_pattern = '|'.join(guard_name_pattern_list)
3222 guard_pattern = input_api.re.compile(
3223 r'#ifndef\s+(' + guard_name_pattern + ')')
3224
3225 for line_number, line in enumerate(f.NewContents()):
3226 if 'no-include-guard-because-multiply-included' in line:
3227 guard_name = 'DUMMY' # To not trigger check outside the loop.
3228 break
3229
3230 if guard_name is None:
3231 match = guard_pattern.match(line)
3232 if match:
3233 guard_name = match.group(1)
3234 guard_line_number = line_number
3235
Daniel Bratell39b5b062018-05-16 18:09:573236 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:453237 # don't match the chromium style guide, but new files should
3238 # get it right.
3239 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:573240 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:143241 errors.append(output_api.PresubmitPromptWarning(
3242 'Header using the wrong include guard name %s' % guard_name,
3243 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:573244 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:143245 else:
3246 # The line after #ifndef should have a #define of the same name.
3247 if line_number == guard_line_number + 1:
3248 expected_line = '#define %s' % guard_name
3249 if line != expected_line:
3250 errors.append(output_api.PresubmitPromptWarning(
3251 'Missing "%s" for include guard' % expected_line,
3252 ['%s:%d' % (f.LocalPath(), line_number + 1)],
3253 'Expected: %r\nGot: %r' % (expected_line, line)))
3254
3255 if not seen_guard_end and line == '#endif // %s' % guard_name:
3256 seen_guard_end = True
3257 elif seen_guard_end:
3258 if line.strip() != '':
3259 errors.append(output_api.PresubmitPromptWarning(
3260 'Include guard %s not covering the whole file' % (
3261 guard_name), [f.LocalPath()]))
3262 break # Nothing else to check and enough to warn once.
3263
3264 if guard_name is None:
3265 errors.append(output_api.PresubmitPromptWarning(
3266 'Missing include guard %s' % expected_guard,
3267 [f.LocalPath()],
3268 'Missing include guard in %s\n'
3269 'Recommended name: %s\n'
3270 'This check can be disabled by having the string\n'
3271 'no-include-guard-because-multiply-included in the header.' %
3272 (f.LocalPath(), expected_guard)))
3273
3274 return errors
3275
3276
mostynbb639aca52015-01-07 20:31:233277def _CheckForWindowsLineEndings(input_api, output_api):
3278 """Check source code and known ascii text files for Windows style line
3279 endings.
3280 """
earthdok1b5e0ee2015-03-10 15:19:103281 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233282
3283 file_inclusion_pattern = (
3284 known_text_files,
3285 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3286 )
3287
mostynbb639aca52015-01-07 20:31:233288 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533289 source_file_filter = lambda f: input_api.FilterSourceFile(
3290 f, white_list=file_inclusion_pattern, black_list=None)
3291 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503292 include_file = False
3293 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233294 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503295 include_file = True
3296 if include_file:
3297 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233298
3299 if problems:
3300 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3301 'these files to contain Windows style line endings?\n' +
3302 '\n'.join(problems))]
3303
3304 return []
3305
3306
Vaclav Brozekd5de76a2018-03-17 07:57:503307def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133308 """Checks that all source files use SYSLOG properly."""
3309 syslog_files = []
3310 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563311 for line_number, line in f.ChangedContents():
3312 if 'SYSLOG' in line:
3313 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3314
pastarmovj89f7ee12016-09-20 14:58:133315 if syslog_files:
3316 return [output_api.PresubmitPromptWarning(
3317 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3318 ' calls.\nFiles to check:\n', items=syslog_files)]
3319 return []
3320
3321
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193322def _CheckCrbugLinksHaveHttps(input_api, output_api):
Miguel Casas68bdb652017-12-19 16:29:093323 """Checks that crbug(.com) links are correctly prefixed by https://,
3324 unless they come in the accepted form TODO(crbug.com/...)
3325 """
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493326 white_list = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193327 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS)
3328 sources = lambda f: input_api.FilterSourceFile(
3329 f, white_list=white_list, black_list=black_list)
3330
3331 pattern = input_api.re.compile(r'//.*(?<!:\/\/)crbug[.com]*')
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203332 accepted_pattern = input_api.re.compile(r'//.*TODO\(crbug[.com]*')
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193333 problems = []
3334 for f in input_api.AffectedSourceFiles(sources):
3335 for line_num, line in f.ChangedContents():
Miguel Casas68bdb652017-12-19 16:29:093336 if pattern.search(line) and not accepted_pattern.search(line):
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193337 problems.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3338
3339 if problems:
3340 return [output_api.PresubmitPromptWarning(
3341 'Found unprefixed crbug.com URL(s), consider prepending https://\n'+
3342 '\n'.join(problems))]
3343 return []
3344
3345
[email protected]1f7b4172010-01-28 01:17:343346def CheckChangeOnUpload(input_api, output_api):
3347 results = []
3348 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473349 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283350 results.extend(
jam93a6ee792017-02-08 23:59:223351 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193352 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223353 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133354 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163355 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193356 results.extend(_CheckCrbugLinksHaveHttps(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:533357 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193358 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543359 return results
[email protected]ca8d19842009-02-19 16:33:123360
3361
[email protected]1bfb8322014-04-23 01:02:413362def GetTryServerMasterForBot(bot):
3363 """Returns the Try Server master for the given bot.
3364
[email protected]0bb112362014-07-26 04:38:323365 It tries to guess the master from the bot name, but may still fail
3366 and return None. There is no longer a default master.
3367 """
3368 # Potentially ambiguous bot names are listed explicitly.
3369 master_map = {
tandriie5587792016-07-14 00:34:503370 'chromium_presubmit': 'master.tryserver.chromium.linux',
3371 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413372 }
[email protected]0bb112362014-07-26 04:38:323373 master = master_map.get(bot)
3374 if not master:
wnwen4fbaab82016-05-25 12:54:363375 if 'android' in bot:
tandriie5587792016-07-14 00:34:503376 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363377 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503378 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323379 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503380 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323381 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503382 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323383 return master
[email protected]1bfb8322014-04-23 01:02:413384
3385
[email protected]ca8d19842009-02-19 16:33:123386def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543387 results = []
[email protected]1f7b4172010-01-28 01:17:343388 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543389 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273390 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343391 input_api,
3392 output_api,
[email protected]2fdd1f362013-01-16 03:56:033393 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273394
jam93a6ee792017-02-08 23:59:223395 results.extend(
3396 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543397 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3398 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413399 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3400 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543401 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143402
3403
3404def _CheckTranslationScreenshots(input_api, output_api):
3405 PART_FILE_TAG = "part"
3406 import os
3407 import sys
3408 from io import StringIO
3409
3410 try:
3411 old_sys_path = sys.path
3412 sys.path = sys.path + [input_api.os_path.join(
3413 input_api.PresubmitLocalPath(), 'tools', 'grit')]
3414 import grit.grd_reader
3415 import grit.node.message
3416 import grit.util
3417 finally:
3418 sys.path = old_sys_path
3419
3420 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
3421 """Load the grd file and return a dict of message ids to messages.
3422
3423 Ignores any nested grdp files pointed by <part> tag.
3424 """
3425 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
3426 stop_after=None, first_ids_file=None,
3427 debug=False, defines=None,
3428 tags_to_ignore=set([PART_FILE_TAG]))
3429 return {
3430 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
3431 grit.node.message.MessageNode)
3432 }
3433
3434 def _GetGrdpMessagesFromString(grdp_string):
3435 """Parses the contents of a grdp file given in grdp_string.
3436
3437 grd_reader can't parse grdp files directly. Instead, this creates a
3438 temporary directory with a grd file pointing to the grdp file, and loads the
3439 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
3440 """
3441 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
3442 <grit latest_public_release="1" current_release="1">
3443 <release seq="1">
3444 <messages>
3445 <part file="sub.grdp" />
3446 </messages>
3447 </release>
3448 </grit>
3449 """
3450 with grit.util.TempDir({'main.grd': WRAPPER,
3451 'sub.grdp': grdp_string}) as temp_dir:
3452 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
3453
3454 new_or_added_paths = set(f.LocalPath()
3455 for f in input_api.AffectedFiles()
3456 if (f.Action() == 'A' or f.Action() == 'M'))
3457 removed_paths = set(f.LocalPath()
3458 for f in input_api.AffectedFiles(include_deletes=True)
3459 if f.Action() == 'D')
3460
3461 affected_grds = [f for f in input_api.AffectedFiles()
3462 if (f.LocalPath().endswith('.grd') or
3463 f.LocalPath().endswith('.grdp'))]
3464 affected_png_paths = [f.AbsoluteLocalPath()
3465 for f in input_api.AffectedFiles()
3466 if (f.LocalPath().endswith('.png'))]
3467
3468 # Check for screenshots. Developers can upload screenshots using
3469 # tools/translation/upload_screenshots.py which finds and uploads
3470 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
3471 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
3472 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
3473 #
3474 # The logic here is as follows:
3475 #
3476 # - If the CL has a .png file under the screenshots directory for a grd
3477 # file, warn the developer. Actual images should never be checked into the
3478 # Chrome repo.
3479 #
3480 # - If the CL contains modified or new messages in grd files and doesn't
3481 # contain the corresponding .sha1 files, warn the developer to add images
3482 # and upload them via tools/translation/upload_screenshots.py.
3483 #
3484 # - If the CL contains modified or new messages in grd files and the
3485 # corresponding .sha1 files, everything looks good.
3486 #
3487 # - If the CL contains removed messages in grd files but the corresponding
3488 # .sha1 files aren't removed, warn the developer to remove them.
3489 unnecessary_screenshots = []
3490 missing_sha1 = []
3491 unnecessary_sha1_files = []
3492
3493
3494 def _CheckScreenshotAdded(screenshots_dir, message_id):
3495 sha1_path = input_api.os_path.join(
3496 screenshots_dir, message_id + '.png.sha1')
3497 if sha1_path not in new_or_added_paths:
3498 missing_sha1.append(sha1_path)
3499
3500
3501 def _CheckScreenshotRemoved(screenshots_dir, message_id):
3502 sha1_path = input_api.os_path.join(
3503 screenshots_dir, message_id + '.png.sha1')
3504 if sha1_path not in removed_paths:
3505 unnecessary_sha1_files.append(sha1_path)
3506
3507
3508 for f in affected_grds:
3509 file_path = f.LocalPath()
3510 old_id_to_msg_map = {}
3511 new_id_to_msg_map = {}
3512 if file_path.endswith('.grdp'):
3513 if f.OldContents():
3514 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393515 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143516 if f.NewContents():
3517 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393518 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143519 else:
3520 if f.OldContents():
3521 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393522 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143523 if f.NewContents():
3524 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393525 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143526
3527 # Compute added, removed and modified message IDs.
3528 old_ids = set(old_id_to_msg_map)
3529 new_ids = set(new_id_to_msg_map)
3530 added_ids = new_ids - old_ids
3531 removed_ids = old_ids - new_ids
3532 modified_ids = set([])
3533 for key in old_ids.intersection(new_ids):
3534 if (old_id_to_msg_map[key].FormatXml()
3535 != new_id_to_msg_map[key].FormatXml()):
3536 modified_ids.add(key)
3537
3538 grd_name, ext = input_api.os_path.splitext(
3539 input_api.os_path.basename(file_path))
3540 screenshots_dir = input_api.os_path.join(
3541 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
3542
3543 # Check the screenshot directory for .png files. Warn if there is any.
3544 for png_path in affected_png_paths:
3545 if png_path.startswith(screenshots_dir):
3546 unnecessary_screenshots.append(png_path)
3547
3548 for added_id in added_ids:
3549 _CheckScreenshotAdded(screenshots_dir, added_id)
3550
3551 for modified_id in modified_ids:
3552 _CheckScreenshotAdded(screenshots_dir, modified_id)
3553
3554 for removed_id in removed_ids:
3555 _CheckScreenshotRemoved(screenshots_dir, removed_id)
3556
3557 results = []
3558 if unnecessary_screenshots:
3559 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393560 'Do not include actual screenshots in the changelist. Run '
3561 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143562 sorted(unnecessary_screenshots)))
3563
3564 if missing_sha1:
3565 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393566 'You are adding or modifying UI strings.\n'
3567 'To ensure the best translations, take screenshots of the relevant UI '
3568 '(https://g.co/chrome/translation) and add these files to your '
3569 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143570
3571 if unnecessary_sha1_files:
3572 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393573 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143574 sorted(unnecessary_sha1_files)))
3575
3576 return results