blob: 2c0898bb70fdd4efd939c58c5ab882d928c25f31 [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',
Eric Boren57cc805b2018-08-20 17:28:32703 'spirv', '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
Danil Chapovalov3518f362018-08-11 16:13:43816def _CheckNoStrCatRedefines(input_api, output_api):
817 """Checks no windows headers with StrCat redefined are included directly."""
818 files = []
819 pattern_deny = input_api.re.compile(
820 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
821 input_api.re.MULTILINE)
822 pattern_allow = input_api.re.compile(
823 r'^#include\s"base/win/windows_defines.inc"',
824 input_api.re.MULTILINE)
825 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
826 contents = input_api.ReadFile(f)
827 if pattern_deny.search(contents) and not pattern_allow.search(contents):
828 files.append(f.LocalPath())
829
830 if len(files):
831 return [output_api.PresubmitError(
832 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
833 'directly since they pollute code with StrCat macro. Instead, '
834 'include matching header from base/win. See http://crbug.com/856536',
835 files) ]
836 return []
837
[email protected]10689ca2011-09-02 02:31:54838
[email protected]72df4e782012-06-21 16:28:18839def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52840 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18841 problems = []
842 for f in input_api.AffectedFiles():
843 if (not f.LocalPath().endswith(('.cc', '.mm'))):
844 continue
845
846 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04847 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18848 problems.append(' %s:%d' % (f.LocalPath(), line_num))
849
850 if not problems:
851 return []
852 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
853 '\n'.join(problems))]
854
855
danakj61c1aa22015-10-26 19:55:52856def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57857 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52858 errors = []
859 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
860 input_api.re.MULTILINE)
861 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
862 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
863 continue
864 for lnum, line in f.ChangedContents():
865 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17866 errors.append(output_api.PresubmitError(
867 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57868 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17869 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52870 return errors
871
872
mcasasb7440c282015-02-04 14:52:19873def _FindHistogramNameInLine(histogram_name, line):
874 """Tries to find a histogram name or prefix in a line."""
875 if not "affected-histogram" in line:
876 return histogram_name in line
877 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
878 # the histogram_name.
879 if not '"' in line:
880 return False
881 histogram_prefix = line.split('\"')[1]
882 return histogram_prefix in histogram_name
883
884
885def _CheckUmaHistogramChanges(input_api, output_api):
886 """Check that UMA histogram names in touched lines can still be found in other
887 lines of the patch or in histograms.xml. Note that this check would not catch
888 the reverse: changes in histograms.xml not matched in the code itself."""
889 touched_histograms = []
890 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:47891 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
892 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
893 name_pattern = r'"(.*?)"'
894 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
895 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
896 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
897 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
898 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:17899 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:19900 for f in input_api.AffectedFiles():
901 # If histograms.xml itself is modified, keep the modified lines for later.
902 if f.LocalPath().endswith(('histograms.xml')):
903 histograms_xml_modifications = f.ChangedContents()
904 continue
Vaclav Brozekbdac817c2018-03-24 06:30:47905 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
906 single_line_re = single_line_c_re
907 split_line_prefix_re = split_line_c_prefix_re
908 elif f.LocalPath().endswith(('java')):
909 single_line_re = single_line_java_re
910 split_line_prefix_re = split_line_java_prefix_re
911 else:
mcasasb7440c282015-02-04 14:52:19912 continue
913 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:17914 if last_line_matched_prefix:
915 suffix_found = split_line_suffix_re.search(line)
916 if suffix_found :
917 touched_histograms.append([suffix_found.group(1), f, line_num])
918 last_line_matched_prefix = False
919 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:06920 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:19921 if found:
922 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:17923 continue
924 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:19925
926 # Search for the touched histogram names in the local modifications to
927 # histograms.xml, and, if not found, on the base histograms.xml file.
928 unmatched_histograms = []
929 for histogram_info in touched_histograms:
930 histogram_name_found = False
931 for line_num, line in histograms_xml_modifications:
932 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
933 if histogram_name_found:
934 break
935 if not histogram_name_found:
936 unmatched_histograms.append(histogram_info)
937
eromanb90c82e7e32015-04-01 15:13:49938 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19939 problems = []
940 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49941 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19942 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45943 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19944 histogram_name_found = False
945 for line in histograms_xml:
946 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
947 if histogram_name_found:
948 break
949 if not histogram_name_found:
950 problems.append(' [%s:%d] %s' %
951 (f.LocalPath(), line_num, histogram_name))
952
953 if not problems:
954 return []
955 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
956 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49957 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19958
wnwenbdc444e2016-05-25 13:44:15959
yolandyandaabc6d2016-04-18 18:29:39960def _CheckFlakyTestUsage(input_api, output_api):
961 """Check that FlakyTest annotation is our own instead of the android one"""
962 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
963 files = []
964 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
965 if f.LocalPath().endswith('Test.java'):
966 if pattern.search(input_api.ReadFile(f)):
967 files.append(f)
968 if len(files):
969 return [output_api.PresubmitError(
970 'Use org.chromium.base.test.util.FlakyTest instead of '
971 'android.test.FlakyTest',
972 files)]
973 return []
mcasasb7440c282015-02-04 14:52:19974
wnwenbdc444e2016-05-25 13:44:15975
[email protected]8ea5d4b2011-09-13 21:49:22976def _CheckNoNewWStrings(input_api, output_api):
977 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27978 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22979 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20980 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57981 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34982 '/win/' in f.LocalPath() or
983 'chrome_elf' in f.LocalPath() or
984 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20985 continue
[email protected]8ea5d4b2011-09-13 21:49:22986
[email protected]a11dbe9b2012-08-07 01:32:58987 allowWString = False
[email protected]b5c24292011-11-28 14:38:20988 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58989 if 'presubmit: allow wstring' in line:
990 allowWString = True
991 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27992 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58993 allowWString = False
994 else:
995 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22996
[email protected]55463aa62011-10-12 00:48:27997 if not problems:
998 return []
999 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581000 ' If you are calling a cross-platform API that accepts a wstring, '
1001 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271002 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221003
1004
[email protected]2a8ac9c2011-10-19 17:20:441005def _CheckNoDEPSGIT(input_api, output_api):
1006 """Make sure .DEPS.git is never modified manually."""
1007 if any(f.LocalPath().endswith('.DEPS.git') for f in
1008 input_api.AffectedFiles()):
1009 return [output_api.PresubmitError(
1010 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1011 'automated system based on what\'s in DEPS and your changes will be\n'
1012 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501013 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1014 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441015 'for more information')]
1016 return []
1017
1018
tandriief664692014-09-23 14:51:471019def _CheckValidHostsInDEPS(input_api, output_api):
1020 """Checks that DEPS file deps are from allowed_hosts."""
1021 # Run only if DEPS file has been modified to annoy fewer bystanders.
1022 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1023 return []
1024 # Outsource work to gclient verify
1025 try:
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201026 input_api.subprocess.check_output(['gclient', 'verify'],
1027 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471028 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201029 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471030 return [output_api.PresubmitError(
1031 'DEPS file must have only git dependencies.',
1032 long_text=error.output)]
1033
1034
[email protected]127f18ec2012-06-16 05:05:591035def _CheckNoBannedFunctions(input_api, output_api):
1036 """Make sure that banned functions are not used."""
1037 warnings = []
1038 errors = []
1039
wnwenbdc444e2016-05-25 13:44:151040 def IsBlacklisted(affected_file, blacklist):
1041 local_path = affected_file.LocalPath()
1042 for item in blacklist:
1043 if input_api.re.match(item, local_path):
1044 return True
1045 return False
1046
Sylvain Defresnea8b73d252018-02-28 15:45:541047 def IsIosObcjFile(affected_file):
1048 local_path = affected_file.LocalPath()
1049 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1050 return False
1051 basename = input_api.os_path.basename(local_path)
1052 if 'ios' in basename.split('_'):
1053 return True
1054 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1055 if sep and 'ios' in local_path.split(sep):
1056 return True
1057 return False
1058
wnwenbdc444e2016-05-25 13:44:151059 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
1060 matched = False
1061 if func_name[0:1] == '/':
1062 regex = func_name[1:]
1063 if input_api.re.search(regex, line):
1064 matched = True
1065 elif func_name in line:
dchenge07de812016-06-20 19:27:171066 matched = True
wnwenbdc444e2016-05-25 13:44:151067 if matched:
dchenge07de812016-06-20 19:27:171068 problems = warnings
wnwenbdc444e2016-05-25 13:44:151069 if error:
dchenge07de812016-06-20 19:27:171070 problems = errors
wnwenbdc444e2016-05-25 13:44:151071 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1072 for message_line in message:
1073 problems.append(' %s' % message_line)
1074
Eric Stevensona9a980972017-09-23 00:04:411075 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1076 for f in input_api.AffectedFiles(file_filter=file_filter):
1077 for line_num, line in f.ChangedContents():
1078 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1079 CheckForMatch(f, line_num, line, func_name, message, error)
1080
[email protected]127f18ec2012-06-16 05:05:591081 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1082 for f in input_api.AffectedFiles(file_filter=file_filter):
1083 for line_num, line in f.ChangedContents():
1084 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151085 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591086
Sylvain Defresnea8b73d252018-02-28 15:45:541087 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1088 for line_num, line in f.ChangedContents():
1089 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1090 CheckForMatch(f, line_num, line, func_name, message, error)
1091
[email protected]127f18ec2012-06-16 05:05:591092 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1093 for f in input_api.AffectedFiles(file_filter=file_filter):
1094 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491095 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491096 if IsBlacklisted(f, excluded_paths):
1097 continue
wnwenbdc444e2016-05-25 13:44:151098 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591099
1100 result = []
1101 if (warnings):
1102 result.append(output_api.PresubmitPromptWarning(
1103 'Banned functions were used.\n' + '\n'.join(warnings)))
1104 if (errors):
1105 result.append(output_api.PresubmitError(
1106 'Banned functions were used.\n' + '\n'.join(errors)))
1107 return result
1108
1109
[email protected]6c063c62012-07-11 19:11:061110def _CheckNoPragmaOnce(input_api, output_api):
1111 """Make sure that banned functions are not used."""
1112 files = []
1113 pattern = input_api.re.compile(r'^#pragma\s+once',
1114 input_api.re.MULTILINE)
1115 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1116 if not f.LocalPath().endswith('.h'):
1117 continue
1118 contents = input_api.ReadFile(f)
1119 if pattern.search(contents):
1120 files.append(f)
1121
1122 if files:
1123 return [output_api.PresubmitError(
1124 'Do not use #pragma once in header files.\n'
1125 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1126 files)]
1127 return []
1128
[email protected]127f18ec2012-06-16 05:05:591129
[email protected]e7479052012-09-19 00:26:121130def _CheckNoTrinaryTrueFalse(input_api, output_api):
1131 """Checks to make sure we don't introduce use of foo ? true : false."""
1132 problems = []
1133 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1134 for f in input_api.AffectedFiles():
1135 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1136 continue
1137
1138 for line_num, line in f.ChangedContents():
1139 if pattern.match(line):
1140 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1141
1142 if not problems:
1143 return []
1144 return [output_api.PresubmitPromptWarning(
1145 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1146 '\n'.join(problems))]
1147
1148
[email protected]55f9f382012-07-31 11:02:181149def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281150 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181151 change. Breaking - rules is an error, breaking ! rules is a
1152 warning.
1153 """
mohan.reddyf21db962014-10-16 12:26:471154 import sys
[email protected]55f9f382012-07-31 11:02:181155 # We need to wait until we have an input_api object and use this
1156 # roundabout construct to import checkdeps because this file is
1157 # eval-ed and thus doesn't have __file__.
1158 original_sys_path = sys.path
1159 try:
1160 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471161 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181162 import checkdeps
1163 from cpp_checker import CppChecker
Jinsuk Kim5a092672017-10-24 22:42:241164 from java_checker import JavaChecker
rhalavati08acd232017-04-03 07:23:281165 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:181166 from rules import Rule
1167 finally:
1168 # Restore sys.path to what it was before.
1169 sys.path = original_sys_path
1170
1171 added_includes = []
rhalavati08acd232017-04-03 07:23:281172 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241173 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181174 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:281175 if CppChecker.IsCppFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501176 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081177 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
rhalavati08acd232017-04-03 07:23:281178 elif ProtoChecker.IsProtoFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501179 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081180 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241181 elif JavaChecker.IsJavaFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501182 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081183 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181184
[email protected]26385172013-05-09 23:11:351185 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181186
1187 error_descriptions = []
1188 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281189 error_subjects = set()
1190 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181191 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1192 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081193 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181194 description_with_path = '%s\n %s' % (path, rule_description)
1195 if rule_type == Rule.DISALLOW:
1196 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281197 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181198 else:
1199 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281200 warning_subjects.add("#includes")
1201
1202 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1203 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081204 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281205 description_with_path = '%s\n %s' % (path, rule_description)
1206 if rule_type == Rule.DISALLOW:
1207 error_descriptions.append(description_with_path)
1208 error_subjects.add("imports")
1209 else:
1210 warning_descriptions.append(description_with_path)
1211 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181212
Jinsuk Kim5a092672017-10-24 22:42:241213 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021214 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081215 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241216 description_with_path = '%s\n %s' % (path, rule_description)
1217 if rule_type == Rule.DISALLOW:
1218 error_descriptions.append(description_with_path)
1219 error_subjects.add("imports")
1220 else:
1221 warning_descriptions.append(description_with_path)
1222 warning_subjects.add("imports")
1223
[email protected]55f9f382012-07-31 11:02:181224 results = []
1225 if error_descriptions:
1226 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281227 'You added one or more %s that violate checkdeps rules.'
1228 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181229 error_descriptions))
1230 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421231 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281232 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181233 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281234 '%s? See relevant DEPS file(s) for details and contacts.' %
1235 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181236 warning_descriptions))
1237 return results
1238
1239
[email protected]fbcafe5a2012-08-08 15:31:221240def _CheckFilePermissions(input_api, output_api):
1241 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151242 if input_api.platform == 'win32':
1243 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291244 checkperms_tool = input_api.os_path.join(
1245 input_api.PresubmitLocalPath(),
1246 'tools', 'checkperms', 'checkperms.py')
1247 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471248 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391249 with input_api.CreateTemporaryFile() as file_list:
1250 for f in input_api.AffectedFiles():
1251 # checkperms.py file/directory arguments must be relative to the
1252 # repository.
1253 file_list.write(f.LocalPath() + '\n')
1254 file_list.close()
1255 args += ['--file-list', file_list.name]
1256 try:
1257 input_api.subprocess.check_output(args)
1258 return []
1259 except input_api.subprocess.CalledProcessError as error:
1260 return [output_api.PresubmitError(
1261 'checkperms.py failed:',
1262 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221263
1264
robertocn832f5992017-01-04 19:01:301265def _CheckTeamTags(input_api, output_api):
1266 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1267 checkteamtags_tool = input_api.os_path.join(
1268 input_api.PresubmitLocalPath(),
1269 'tools', 'checkteamtags', 'checkteamtags.py')
1270 args = [input_api.python_executable, checkteamtags_tool,
1271 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221272 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301273 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1274 'OWNERS']
1275 try:
1276 if files:
1277 input_api.subprocess.check_output(args + files)
1278 return []
1279 except input_api.subprocess.CalledProcessError as error:
1280 return [output_api.PresubmitError(
1281 'checkteamtags.py failed:',
1282 long_text=error.output)]
1283
1284
[email protected]c8278b32012-10-30 20:35:491285def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1286 """Makes sure we don't include ui/aura/window_property.h
1287 in header files.
1288 """
1289 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1290 errors = []
1291 for f in input_api.AffectedFiles():
1292 if not f.LocalPath().endswith('.h'):
1293 continue
1294 for line_num, line in f.ChangedContents():
1295 if pattern.match(line):
1296 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1297
1298 results = []
1299 if errors:
1300 results.append(output_api.PresubmitError(
1301 'Header files should not include ui/aura/window_property.h', errors))
1302 return results
1303
1304
[email protected]70ca77752012-11-20 03:45:031305def _CheckForVersionControlConflictsInFile(input_api, f):
1306 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1307 errors = []
1308 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:231309 if f.LocalPath().endswith('.md'):
1310 # First-level headers in markdown look a lot like version control
1311 # conflict markers. http://daringfireball.net/projects/markdown/basics
1312 continue
[email protected]70ca77752012-11-20 03:45:031313 if pattern.match(line):
1314 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1315 return errors
1316
1317
1318def _CheckForVersionControlConflicts(input_api, output_api):
1319 """Usually this is not intentional and will cause a compile failure."""
1320 errors = []
1321 for f in input_api.AffectedFiles():
1322 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1323
1324 results = []
1325 if errors:
1326 results.append(output_api.PresubmitError(
1327 'Version control conflict markers found, please resolve.', errors))
1328 return results
1329
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201330
estadee17314a02017-01-12 16:22:161331def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1332 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1333 errors = []
1334 for f in input_api.AffectedFiles():
1335 for line_num, line in f.ChangedContents():
1336 if pattern.search(line):
1337 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1338
1339 results = []
1340 if errors:
1341 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501342 'Found Google support URL addressed by answer number. Please replace '
1343 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161344 return results
1345
[email protected]70ca77752012-11-20 03:45:031346
[email protected]06e6d0ff2012-12-11 01:36:441347def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1348 def FilterFile(affected_file):
1349 """Filter function for use with input_api.AffectedSourceFiles,
1350 below. This filters out everything except non-test files from
1351 top-level directories that generally speaking should not hard-code
1352 service URLs (e.g. src/android_webview/, src/content/ and others).
1353 """
1354 return input_api.FilterSourceFile(
1355 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491356 white_list=[r'^(android_webview|base|content|net)[\\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:441357 black_list=(_EXCLUDED_PATHS +
1358 _TEST_CODE_EXCLUDED_PATHS +
1359 input_api.DEFAULT_BLACK_LIST))
1360
reillyi38965732015-11-16 18:27:331361 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1362 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461363 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1364 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441365 problems = [] # items are (filename, line_number, line)
1366 for f in input_api.AffectedSourceFiles(FilterFile):
1367 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461368 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441369 problems.append((f.LocalPath(), line_num, line))
1370
1371 if problems:
[email protected]f7051d52013-04-02 18:31:421372 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441373 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581374 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441375 [' %s:%d: %s' % (
1376 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031377 else:
1378 return []
[email protected]06e6d0ff2012-12-11 01:36:441379
1380
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491381# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:271382def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1383 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311384 The native_client_sdk directory is excluded because it has auto-generated PNG
1385 files for documentation.
[email protected]d2530012013-01-25 16:39:271386 """
[email protected]d2530012013-01-25 16:39:271387 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491388 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
1389 black_list = [r'^native_client_sdk[\\\/]']
binji0dcdf342014-12-12 18:32:311390 file_filter = lambda f: input_api.FilterSourceFile(
1391 f, white_list=white_list, black_list=black_list)
1392 for f in input_api.AffectedFiles(include_deletes=False,
1393 file_filter=file_filter):
1394 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271395
1396 results = []
1397 if errors:
1398 results.append(output_api.PresubmitError(
1399 'The name of PNG files should not have abbreviations. \n'
1400 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1401 'Contact [email protected] if you have questions.', errors))
1402 return results
1403
1404
Daniel Cheng4dcdb6b2017-04-13 08:30:171405def _ExtractAddRulesFromParsedDeps(parsed_deps):
1406 """Extract the rules that add dependencies from a parsed DEPS file.
1407
1408 Args:
1409 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1410 add_rules = set()
1411 add_rules.update([
1412 rule[1:] for rule in parsed_deps.get('include_rules', [])
1413 if rule.startswith('+') or rule.startswith('!')
1414 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501415 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171416 {}).iteritems():
1417 add_rules.update([
1418 rule[1:] for rule in rules
1419 if rule.startswith('+') or rule.startswith('!')
1420 ])
1421 return add_rules
1422
1423
1424def _ParseDeps(contents):
1425 """Simple helper for parsing DEPS files."""
1426 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171427 class _VarImpl:
1428
1429 def __init__(self, local_scope):
1430 self._local_scope = local_scope
1431
1432 def Lookup(self, var_name):
1433 """Implements the Var syntax."""
1434 try:
1435 return self._local_scope['vars'][var_name]
1436 except KeyError:
1437 raise Exception('Var is not defined: %s' % var_name)
1438
1439 local_scope = {}
1440 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171441 'Var': _VarImpl(local_scope).Lookup,
1442 }
1443 exec contents in global_scope, local_scope
1444 return local_scope
1445
1446
1447def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081448 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411449 a set of DEPS entries that we should look up.
1450
1451 For a directory (rather than a specific filename) we fake a path to
1452 a specific filename by adding /DEPS. This is chosen as a file that
1453 will seldom or never be subject to per-file include_rules.
1454 """
[email protected]2b438d62013-11-14 17:54:141455 # We ignore deps entries on auto-generated directories.
1456 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081457
Daniel Cheng4dcdb6b2017-04-13 08:30:171458 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1459 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1460
1461 added_deps = new_deps.difference(old_deps)
1462
[email protected]2b438d62013-11-14 17:54:141463 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171464 for added_dep in added_deps:
1465 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1466 continue
1467 # Assume that a rule that ends in .h is a rule for a specific file.
1468 if added_dep.endswith('.h'):
1469 results.add(added_dep)
1470 else:
1471 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081472 return results
1473
1474
[email protected]e871964c2013-05-13 14:14:551475def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1476 """When a dependency prefixed with + is added to a DEPS file, we
1477 want to make sure that the change is reviewed by an OWNER of the
1478 target file or directory, to avoid layering violations from being
1479 introduced. This check verifies that this happens.
1480 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171481 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241482
1483 file_filter = lambda f: not input_api.re.match(
Kent Tamurae9b3a9ec2017-08-31 02:20:191484 r"^third_party[\\\/](WebKit|blink)[\\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241485 for f in input_api.AffectedFiles(include_deletes=False,
1486 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551487 filename = input_api.os_path.basename(f.LocalPath())
1488 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171489 virtual_depended_on_files.update(_CalculateAddedDeps(
1490 input_api.os_path,
1491 '\n'.join(f.OldContents()),
1492 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551493
[email protected]e871964c2013-05-13 14:14:551494 if not virtual_depended_on_files:
1495 return []
1496
1497 if input_api.is_committing:
1498 if input_api.tbr:
1499 return [output_api.PresubmitNotifyResult(
1500 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271501 if input_api.dry_run:
1502 return [output_api.PresubmitNotifyResult(
1503 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551504 if not input_api.change.issue:
1505 return [output_api.PresubmitError(
1506 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401507 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551508 output = output_api.PresubmitError
1509 else:
1510 output = output_api.PresubmitNotifyResult
1511
1512 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501513 owner_email, reviewers = (
1514 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1515 input_api,
1516 owners_db.email_regexp,
1517 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551518
1519 owner_email = owner_email or input_api.change.author_email
1520
[email protected]de4f7d22013-05-23 14:27:461521 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511522 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461523 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551524 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1525 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411526
1527 # We strip the /DEPS part that was added by
1528 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1529 # directory.
1530 def StripDeps(path):
1531 start_deps = path.rfind('/DEPS')
1532 if start_deps != -1:
1533 return path[:start_deps]
1534 else:
1535 return path
1536 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551537 for path in missing_files]
1538
1539 if unapproved_dependencies:
1540 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151541 output('You need LGTM from owners of depends-on paths in DEPS that were '
1542 'modified in this CL:\n %s' %
1543 '\n '.join(sorted(unapproved_dependencies)))]
1544 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1545 output_list.append(output(
1546 'Suggested missing target path OWNERS:\n %s' %
1547 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551548 return output_list
1549
1550 return []
1551
1552
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491553# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:401554def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491555 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:401556 black_list = (_EXCLUDED_PATHS +
1557 _TEST_CODE_EXCLUDED_PATHS +
1558 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501559 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191560 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481561 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461562 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121563 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1564 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581565 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
Olivier Liec4400b22018-07-31 19:50:441566 r"^chrome[\\\/]chrome_cleaner[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161567 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031568 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151569 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1570 r"^chromecast[\\\/]",
1571 r"^cloud_print[\\\/]",
manzagop85e629e2017-05-09 22:11:481572 r"^components[\\\/]browser_watcher[\\\/]"
1573 r"dump_stability_report_main_win.cc$",
jochen34415e52015-07-10 08:34:311574 r"^components[\\\/]html_viewer[\\\/]"
1575 r"web_test_delegate_impl\.cc$",
Samuel Huang577ef6c2018-03-13 18:19:341576 r"^components[\\\/]zucchini[\\\/].*",
peter80739bb2015-10-20 11:17:461577 # TODO(peter): Remove this exception. https://crbug.com/534537
1578 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1579 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251580 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1581 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241582 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111583 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151584 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111585 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521586 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501587 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361588 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311589 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131590 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001591 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441592 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451593 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021594 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351595 r"dump_file_system.cc$",
1596 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401597 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491598 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:401599
thomasanderson625d3932017-03-29 07:16:581600 log_info = set([])
1601 printf = set([])
[email protected]85218562013-11-22 07:41:401602
1603 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581604 for _, line in f.ChangedContents():
1605 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1606 log_info.add(f.LocalPath())
1607 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1608 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371609
thomasanderson625d3932017-03-29 07:16:581610 if input_api.re.search(r"\bprintf\(", line):
1611 printf.add(f.LocalPath())
1612 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1613 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401614
1615 if log_info:
1616 return [output_api.PresubmitError(
1617 'These files spam the console log with LOG(INFO):',
1618 items=log_info)]
1619 if printf:
1620 return [output_api.PresubmitError(
1621 'These files spam the console log with printf/fprintf:',
1622 items=printf)]
1623 return []
1624
1625
[email protected]49aa76a2013-12-04 06:59:161626def _CheckForAnonymousVariables(input_api, output_api):
1627 """These types are all expected to hold locks while in scope and
1628 so should never be anonymous (which causes them to be immediately
1629 destroyed)."""
1630 they_who_must_be_named = [
1631 'base::AutoLock',
1632 'base::AutoReset',
1633 'base::AutoUnlock',
1634 'SkAutoAlphaRestore',
1635 'SkAutoBitmapShaderInstall',
1636 'SkAutoBlitterChoose',
1637 'SkAutoBounderCommit',
1638 'SkAutoCallProc',
1639 'SkAutoCanvasRestore',
1640 'SkAutoCommentBlock',
1641 'SkAutoDescriptor',
1642 'SkAutoDisableDirectionCheck',
1643 'SkAutoDisableOvalCheck',
1644 'SkAutoFree',
1645 'SkAutoGlyphCache',
1646 'SkAutoHDC',
1647 'SkAutoLockColors',
1648 'SkAutoLockPixels',
1649 'SkAutoMalloc',
1650 'SkAutoMaskFreeImage',
1651 'SkAutoMutexAcquire',
1652 'SkAutoPathBoundsUpdate',
1653 'SkAutoPDFRelease',
1654 'SkAutoRasterClipValidate',
1655 'SkAutoRef',
1656 'SkAutoTime',
1657 'SkAutoTrace',
1658 'SkAutoUnref',
1659 ]
1660 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1661 # bad: base::AutoLock(lock.get());
1662 # not bad: base::AutoLock lock(lock.get());
1663 bad_pattern = input_api.re.compile(anonymous)
1664 # good: new base::AutoLock(lock.get())
1665 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1666 errors = []
1667
1668 for f in input_api.AffectedFiles():
1669 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1670 continue
1671 for linenum, line in f.ChangedContents():
1672 if bad_pattern.search(line) and not good_pattern.search(line):
1673 errors.append('%s:%d' % (f.LocalPath(), linenum))
1674
1675 if errors:
1676 return [output_api.PresubmitError(
1677 'These lines create anonymous variables that need to be named:',
1678 items=errors)]
1679 return []
1680
1681
Peter Kasting4844e46e2018-02-23 07:27:101682def _CheckUniquePtr(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491683 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:101684 sources = lambda affected_file: input_api.FilterSourceFile(
1685 affected_file,
1686 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1687 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491688 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:551689
1690 # Pattern to capture a single "<...>" block of template arguments. It can
1691 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
1692 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
1693 # latter would likely require counting that < and > match, which is not
1694 # expressible in regular languages. Should the need arise, one can introduce
1695 # limited counting (matching up to a total number of nesting depth), which
1696 # should cover all practical cases for already a low nesting limit.
1697 template_arg_pattern = (
1698 r'<[^>]*' # Opening block of <.
1699 r'>([^<]*>)?') # Closing block of >.
1700 # Prefix expressing that whatever follows is not already inside a <...>
1701 # block.
1702 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:101703 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:551704 not_inside_template_arg_pattern
1705 + r'\bstd::unique_ptr'
1706 + template_arg_pattern
1707 + r'\(\)')
1708
1709 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
1710 template_arg_no_array_pattern = (
1711 r'<[^>]*[^]]' # Opening block of <.
1712 r'>([^(<]*[^]]>)?') # Closing block of >.
1713 # Prefix saying that what follows is the start of an expression.
1714 start_of_expr_pattern = r'(=|\breturn|^)\s*'
1715 # Suffix saying that what follows are call parentheses with a non-empty list
1716 # of arguments.
1717 nonempty_arg_list_pattern = r'\(([^)]|$)'
1718 return_construct_pattern = input_api.re.compile(
1719 start_of_expr_pattern
1720 + r'std::unique_ptr'
1721 + template_arg_no_array_pattern
1722 + nonempty_arg_list_pattern)
1723
Vaclav Brozek851d9602018-04-04 16:13:051724 problems_constructor = []
1725 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:101726 for f in input_api.AffectedSourceFiles(sources):
1727 for line_number, line in f.ChangedContents():
1728 # Disallow:
1729 # return std::unique_ptr<T>(foo);
1730 # bar = std::unique_ptr<T>(foo);
1731 # But allow:
1732 # return std::unique_ptr<T[]>(foo);
1733 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozek851d9602018-04-04 16:13:051734 local_path = f.LocalPath()
Peter Kasting4844e46e2018-02-23 07:27:101735 if return_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051736 problems_constructor.append(
1737 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:101738 # Disallow:
1739 # std::unique_ptr<T>()
1740 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051741 problems_nullptr.append(
1742 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1743
1744 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:161745 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:051746 errors.append(output_api.PresubmitError(
1747 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161748 problems_nullptr))
1749 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:051750 errors.append(output_api.PresubmitError(
1751 'The following files use explicit std::unique_ptr constructor.'
1752 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161753 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:101754 return errors
1755
1756
[email protected]999261d2014-03-03 20:08:081757def _CheckUserActionUpdate(input_api, output_api):
1758 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521759 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081760 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521761 # If actions.xml is already included in the changelist, the PRESUBMIT
1762 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081763 return []
1764
[email protected]999261d2014-03-03 20:08:081765 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1766 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521767 current_actions = None
[email protected]999261d2014-03-03 20:08:081768 for f in input_api.AffectedFiles(file_filter=file_filter):
1769 for line_num, line in f.ChangedContents():
1770 match = input_api.re.search(action_re, line)
1771 if match:
[email protected]2f92dec2014-03-07 19:21:521772 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1773 # loaded only once.
1774 if not current_actions:
1775 with open('tools/metrics/actions/actions.xml') as actions_f:
1776 current_actions = actions_f.read()
1777 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081778 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521779 action = 'name="{0}"'.format(action_name)
1780 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081781 return [output_api.PresubmitPromptWarning(
1782 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521783 'tools/metrics/actions/actions.xml. Please run '
1784 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081785 % (f.LocalPath(), line_num, action_name))]
1786 return []
1787
1788
Daniel Cheng13ca61a882017-08-25 15:11:251789def _ImportJSONCommentEater(input_api):
1790 import sys
1791 sys.path = sys.path + [input_api.os_path.join(
1792 input_api.PresubmitLocalPath(),
1793 'tools', 'json_comment_eater')]
1794 import json_comment_eater
1795 return json_comment_eater
1796
1797
[email protected]99171a92014-06-03 08:44:471798def _GetJSONParseError(input_api, filename, eat_comments=True):
1799 try:
1800 contents = input_api.ReadFile(filename)
1801 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:251802 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:131803 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471804
1805 input_api.json.loads(contents)
1806 except ValueError as e:
1807 return e
1808 return None
1809
1810
1811def _GetIDLParseError(input_api, filename):
1812 try:
1813 contents = input_api.ReadFile(filename)
1814 idl_schema = input_api.os_path.join(
1815 input_api.PresubmitLocalPath(),
1816 'tools', 'json_schema_compiler', 'idl_schema.py')
1817 process = input_api.subprocess.Popen(
1818 [input_api.python_executable, idl_schema],
1819 stdin=input_api.subprocess.PIPE,
1820 stdout=input_api.subprocess.PIPE,
1821 stderr=input_api.subprocess.PIPE,
1822 universal_newlines=True)
1823 (_, error) = process.communicate(input=contents)
1824 return error or None
1825 except ValueError as e:
1826 return e
1827
1828
1829def _CheckParseErrors(input_api, output_api):
1830 """Check that IDL and JSON files do not contain syntax errors."""
1831 actions = {
1832 '.idl': _GetIDLParseError,
1833 '.json': _GetJSONParseError,
1834 }
[email protected]99171a92014-06-03 08:44:471835 # Most JSON files are preprocessed and support comments, but these do not.
1836 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491837 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471838 ]
1839 # Only run IDL checker on files in these directories.
1840 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491841 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1842 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471843 ]
1844
1845 def get_action(affected_file):
1846 filename = affected_file.LocalPath()
1847 return actions.get(input_api.os_path.splitext(filename)[1])
1848
[email protected]99171a92014-06-03 08:44:471849 def FilterFile(affected_file):
1850 action = get_action(affected_file)
1851 if not action:
1852 return False
1853 path = affected_file.LocalPath()
1854
Sean Kau46e29bc2017-08-28 16:31:161855 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:471856 return False
1857
1858 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:161859 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:471860 return False
1861 return True
1862
1863 results = []
1864 for affected_file in input_api.AffectedFiles(
1865 file_filter=FilterFile, include_deletes=False):
1866 action = get_action(affected_file)
1867 kwargs = {}
1868 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:161869 _MatchesFile(input_api, json_no_comments_patterns,
1870 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:471871 kwargs['eat_comments'] = False
1872 parse_error = action(input_api,
1873 affected_file.AbsoluteLocalPath(),
1874 **kwargs)
1875 if parse_error:
1876 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1877 (affected_file.LocalPath(), parse_error)))
1878 return results
1879
1880
[email protected]760deea2013-12-10 19:33:491881def _CheckJavaStyle(input_api, output_api):
1882 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471883 import sys
[email protected]760deea2013-12-10 19:33:491884 original_sys_path = sys.path
1885 try:
1886 sys.path = sys.path + [input_api.os_path.join(
1887 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1888 import checkstyle
1889 finally:
1890 # Restore sys.path to what it was before.
1891 sys.path = original_sys_path
1892
1893 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091894 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511895 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491896
1897
Sean Kau46e29bc2017-08-28 16:31:161898def _MatchesFile(input_api, patterns, path):
1899 for pattern in patterns:
1900 if input_api.re.search(pattern, path):
1901 return True
1902 return False
1903
1904
Daniel Cheng7052cdf2017-11-21 19:23:291905def _GetOwnersFilesToCheckForIpcOwners(input_api):
1906 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:171907
Daniel Cheng7052cdf2017-11-21 19:23:291908 Returns:
1909 A dictionary mapping an OWNER file to the list of OWNERS rules it must
1910 contain to cover IPC-related files with noparent reviewer rules.
1911 """
1912 # Whether or not a file affects IPC is (mostly) determined by a simple list
1913 # of filename patterns.
dchenge07de812016-06-20 19:27:171914 file_patterns = [
palmerb19a0932017-01-24 04:00:311915 # Legacy IPC:
dchenge07de812016-06-20 19:27:171916 '*_messages.cc',
1917 '*_messages*.h',
1918 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311919 # Mojo IPC:
dchenge07de812016-06-20 19:27:171920 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:471921 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:171922 '*_struct_traits*.*',
1923 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311924 '*.typemap',
1925 # Android native IPC:
1926 '*.aidl',
1927 # Blink uses a different file naming convention:
1928 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:471929 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:171930 '*StructTraits*.*',
1931 '*TypeConverter*.*',
1932 ]
1933
scottmg7a6ed5ba2016-11-04 18:22:041934 # These third_party directories do not contain IPCs, but contain files
1935 # matching the above patterns, which trigger false positives.
1936 exclude_paths = [
1937 'third_party/crashpad/*',
Andres Medinae684cf42018-08-27 18:48:231938 'third_party/protobuf/benchmarks/python/*',
Daniel Chengebe635e2018-07-13 12:36:061939 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:291940 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:041941 ]
1942
dchenge07de812016-06-20 19:27:171943 # Dictionary mapping an OWNERS file path to Patterns.
1944 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1945 # rules ) to a PatternEntry.
1946 # PatternEntry is a dictionary with two keys:
1947 # - 'files': the files that are matched by this pattern
1948 # - 'rules': the per-file rules needed for this pattern
1949 # For example, if we expect OWNERS file to contain rules for *.mojom and
1950 # *_struct_traits*.*, Patterns might look like this:
1951 # {
1952 # '*.mojom': {
1953 # 'files': ...,
1954 # 'rules': [
1955 # 'per-file *.mojom=set noparent',
1956 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1957 # ],
1958 # },
1959 # '*_struct_traits*.*': {
1960 # 'files': ...,
1961 # 'rules': [
1962 # 'per-file *_struct_traits*.*=set noparent',
1963 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1964 # ],
1965 # },
1966 # }
1967 to_check = {}
1968
Daniel Cheng13ca61a882017-08-25 15:11:251969 def AddPatternToCheck(input_file, pattern):
1970 owners_file = input_api.os_path.join(
1971 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
1972 if owners_file not in to_check:
1973 to_check[owners_file] = {}
1974 if pattern not in to_check[owners_file]:
1975 to_check[owners_file][pattern] = {
1976 'files': [],
1977 'rules': [
1978 'per-file %s=set noparent' % pattern,
1979 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1980 ]
1981 }
Vaclav Brozekd5de76a2018-03-17 07:57:501982 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:251983
dchenge07de812016-06-20 19:27:171984 # Iterate through the affected files to see what we actually need to check
1985 # for. We should only nag patch authors about per-file rules if a file in that
1986 # directory would match that pattern. If a directory only contains *.mojom
1987 # files and no *_messages*.h files, we should only nag about rules for
1988 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:251989 for f in input_api.AffectedFiles(include_deletes=False):
1990 # Manifest files don't have a strong naming convention. Instead, scan
1991 # affected files for .json files and see if they look like a manifest.
Sean Kau46e29bc2017-08-28 16:31:161992 if (f.LocalPath().endswith('.json') and
1993 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
1994 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:251995 json_comment_eater = _ImportJSONCommentEater(input_api)
1996 mostly_json_lines = '\n'.join(f.NewContents())
1997 # Comments aren't allowed in strict JSON, so filter them out.
1998 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:431999 try:
2000 json_content = input_api.json.loads(json_lines)
2001 except:
2002 # There's another PRESUBMIT check that already verifies that JSON files
2003 # are not invalid, so no need to emit another warning here.
2004 continue
Daniel Cheng13ca61a882017-08-25 15:11:252005 if 'interface_provider_specs' in json_content:
2006 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172007 for pattern in file_patterns:
2008 if input_api.fnmatch.fnmatch(
2009 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042010 skip = False
2011 for exclude in exclude_paths:
2012 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2013 skip = True
2014 break
2015 if skip:
2016 continue
Daniel Cheng13ca61a882017-08-25 15:11:252017 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172018 break
2019
Daniel Cheng7052cdf2017-11-21 19:23:292020 return to_check
2021
2022
2023def _CheckIpcOwners(input_api, output_api):
2024 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2025 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2026
2027 if to_check:
2028 # If there are any OWNERS files to check, there are IPC-related changes in
2029 # this CL. Auto-CC the review list.
2030 output_api.AppendCC('[email protected]')
2031
2032 # Go through the OWNERS files to check, filtering out rules that are already
2033 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172034 for owners_file, patterns in to_check.iteritems():
2035 try:
2036 with file(owners_file) as f:
2037 lines = set(f.read().splitlines())
2038 for entry in patterns.itervalues():
2039 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2040 ]
2041 except IOError:
2042 # No OWNERS file, so all the rules are definitely missing.
2043 continue
2044
2045 # All the remaining lines weren't found in OWNERS files, so emit an error.
2046 errors = []
2047 for owners_file, patterns in to_check.iteritems():
2048 missing_lines = []
2049 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502050 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172051 missing_lines.extend(entry['rules'])
2052 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2053 if missing_lines:
2054 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052055 'Because of the presence of files:\n%s\n\n'
2056 '%s needs the following %d lines added:\n\n%s' %
2057 ('\n'.join(files), owners_file, len(missing_lines),
2058 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172059
2060 results = []
2061 if errors:
vabrf5ce3bf92016-07-11 14:52:412062 if input_api.is_committing:
2063 output = output_api.PresubmitError
2064 else:
2065 output = output_api.PresubmitPromptWarning
2066 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592067 'Found OWNERS files that need to be updated for IPC security ' +
2068 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172069 long_text='\n\n'.join(errors)))
2070
2071 return results
2072
2073
jbriance9e12f162016-11-25 07:57:502074def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312075 """Checks that added or removed lines in non third party affected
2076 header files do not lead to new useless class or struct forward
2077 declaration.
jbriance9e12f162016-11-25 07:57:502078 """
2079 results = []
2080 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2081 input_api.re.MULTILINE)
2082 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2083 input_api.re.MULTILINE)
2084 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312085 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192086 not f.LocalPath().startswith('third_party/blink') and
2087 not f.LocalPath().startswith('third_party\\blink') and
jbriance2c51e821a2016-12-12 08:24:312088 not f.LocalPath().startswith('third_party/WebKit') and
2089 not f.LocalPath().startswith('third_party\\WebKit')):
2090 continue
2091
jbriance9e12f162016-11-25 07:57:502092 if not f.LocalPath().endswith('.h'):
2093 continue
2094
2095 contents = input_api.ReadFile(f)
2096 fwd_decls = input_api.re.findall(class_pattern, contents)
2097 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2098
2099 useless_fwd_decls = []
2100 for decl in fwd_decls:
2101 count = sum(1 for _ in input_api.re.finditer(
2102 r'\b%s\b' % input_api.re.escape(decl), contents))
2103 if count == 1:
2104 useless_fwd_decls.append(decl)
2105
2106 if not useless_fwd_decls:
2107 continue
2108
2109 for line in f.GenerateScmDiff().splitlines():
2110 if (line.startswith('-') and not line.startswith('--') or
2111 line.startswith('+') and not line.startswith('++')):
2112 for decl in useless_fwd_decls:
2113 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2114 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242115 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502116 (f.LocalPath(), decl)))
2117 useless_fwd_decls.remove(decl)
2118
2119 return results
2120
2121
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492122# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:292123def _CheckAndroidToastUsage(input_api, output_api):
2124 """Checks that code uses org.chromium.ui.widget.Toast instead of
2125 android.widget.Toast (Chromium Toast doesn't force hardware
2126 acceleration on low-end devices, saving memory).
2127 """
2128 toast_import_pattern = input_api.re.compile(
2129 r'^import android\.widget\.Toast;$')
2130
2131 errors = []
2132
2133 sources = lambda affected_file: input_api.FilterSourceFile(
2134 affected_file,
2135 black_list=(_EXCLUDED_PATHS +
2136 _TEST_CODE_EXCLUDED_PATHS +
2137 input_api.DEFAULT_BLACK_LIST +
2138 (r'^chromecast[\\\/].*',
2139 r'^remoting[\\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492140 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:292141
2142 for f in input_api.AffectedSourceFiles(sources):
2143 for line_num, line in f.ChangedContents():
2144 if toast_import_pattern.search(line):
2145 errors.append("%s:%d" % (f.LocalPath(), line_num))
2146
2147 results = []
2148
2149 if errors:
2150 results.append(output_api.PresubmitError(
2151 'android.widget.Toast usage is detected. Android toasts use hardware'
2152 ' acceleration, and can be\ncostly on low-end devices. Please use'
2153 ' org.chromium.ui.widget.Toast instead.\n'
2154 'Contact [email protected] if you have any questions.',
2155 errors))
2156
2157 return results
2158
2159
dgnaa68d5e2015-06-10 10:08:222160def _CheckAndroidCrLogUsage(input_api, output_api):
2161 """Checks that new logs using org.chromium.base.Log:
2162 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512163 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222164 """
pkotwicza1dd0b002016-05-16 14:41:042165
torne89540622017-03-24 19:41:302166 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042167 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302168 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:042169 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:302170 # WebView license viewer code cannot depend on //base; used in stub APK.
2171 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
2172 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:042173 ]
2174
dgnaa68d5e2015-06-10 10:08:222175 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122176 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2177 class_in_base_pattern = input_api.re.compile(
2178 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2179 has_some_log_import_pattern = input_api.re.compile(
2180 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222181 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122182 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222183 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512184 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222185 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222186
Vincent Scheib16d7b272015-09-15 18:09:072187 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222188 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492189 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:042190 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122191
dgnaa68d5e2015-06-10 10:08:222192 tag_decl_errors = []
2193 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122194 tag_errors = []
dgn38736db2015-09-18 19:20:512195 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122196 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222197
2198 for f in input_api.AffectedSourceFiles(sources):
2199 file_content = input_api.ReadFile(f)
2200 has_modified_logs = False
2201
2202 # Per line checks
dgn87d9fb62015-06-12 09:15:122203 if (cr_log_import_pattern.search(file_content) or
2204 (class_in_base_pattern.search(file_content) and
2205 not has_some_log_import_pattern.search(file_content))):
2206 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222207 for line_num, line in f.ChangedContents():
2208
2209 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122210 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222211 if match:
2212 has_modified_logs = True
2213
2214 # Make sure it uses "TAG"
2215 if not match.group('tag') == 'TAG':
2216 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122217 else:
2218 # Report non cr Log function calls in changed lines
2219 for line_num, line in f.ChangedContents():
2220 if log_call_pattern.search(line):
2221 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222222
2223 # Per file checks
2224 if has_modified_logs:
2225 # Make sure the tag is using the "cr" prefix and is not too long
2226 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512227 tag_name = match.group('name') if match else None
2228 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222229 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512230 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222231 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512232 elif '.' in tag_name:
2233 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222234
2235 results = []
2236 if tag_decl_errors:
2237 results.append(output_api.PresubmitPromptWarning(
2238 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512239 '"private static final String TAG = "<package tag>".\n'
2240 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222241 tag_decl_errors))
2242
2243 if tag_length_errors:
2244 results.append(output_api.PresubmitError(
2245 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512246 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222247 tag_length_errors))
2248
2249 if tag_errors:
2250 results.append(output_api.PresubmitPromptWarning(
2251 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2252 tag_errors))
2253
dgn87d9fb62015-06-12 09:15:122254 if util_log_errors:
dgn4401aa52015-04-29 16:26:172255 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122256 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2257 util_log_errors))
2258
dgn38736db2015-09-18 19:20:512259 if tag_with_dot_errors:
2260 results.append(output_api.PresubmitPromptWarning(
2261 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2262 tag_with_dot_errors))
2263
dgn4401aa52015-04-29 16:26:172264 return results
2265
2266
Yoland Yanb92fa522017-08-28 17:37:062267def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2268 """Checks that junit.framework.* is no longer used."""
2269 deprecated_junit_framework_pattern = input_api.re.compile(
2270 r'^import junit\.framework\..*;',
2271 input_api.re.MULTILINE)
2272 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492273 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062274 errors = []
2275 for f in input_api.AffectedFiles(sources):
2276 for line_num, line in f.ChangedContents():
2277 if deprecated_junit_framework_pattern.search(line):
2278 errors.append("%s:%d" % (f.LocalPath(), line_num))
2279
2280 results = []
2281 if errors:
2282 results.append(output_api.PresubmitError(
2283 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2284 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2285 ' if you have any question.', errors))
2286 return results
2287
2288
2289def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2290 """Checks that if new Java test classes have inheritance.
2291 Either the new test class is JUnit3 test or it is a JUnit4 test class
2292 with a base class, either case is undesirable.
2293 """
2294 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2295
2296 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492297 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062298 errors = []
2299 for f in input_api.AffectedFiles(sources):
2300 if not f.OldContents():
2301 class_declaration_start_flag = False
2302 for line_num, line in f.ChangedContents():
2303 if class_declaration_pattern.search(line):
2304 class_declaration_start_flag = True
2305 if class_declaration_start_flag and ' extends ' in line:
2306 errors.append('%s:%d' % (f.LocalPath(), line_num))
2307 if '{' in line:
2308 class_declaration_start_flag = False
2309
2310 results = []
2311 if errors:
2312 results.append(output_api.PresubmitPromptWarning(
2313 'The newly created files include Test classes that inherits from base'
2314 ' class. Please do not use inheritance in JUnit4 tests or add new'
2315 ' JUnit3 tests. Contact [email protected] if you have any'
2316 ' questions.', errors))
2317 return results
2318
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202319
yolandyan45001472016-12-21 21:12:422320def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2321 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2322 deprecated_annotation_import_pattern = input_api.re.compile(
2323 r'^import android\.test\.suitebuilder\.annotation\..*;',
2324 input_api.re.MULTILINE)
2325 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492326 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:422327 errors = []
2328 for f in input_api.AffectedFiles(sources):
2329 for line_num, line in f.ChangedContents():
2330 if deprecated_annotation_import_pattern.search(line):
2331 errors.append("%s:%d" % (f.LocalPath(), line_num))
2332
2333 results = []
2334 if errors:
2335 results.append(output_api.PresubmitError(
2336 'Annotations in android.test.suitebuilder.annotation have been'
2337 ' deprecated since API level 24. Please use android.support.test.filters'
2338 ' from //third_party/android_support_test_runner:runner_java instead.'
2339 ' Contact [email protected] if you have any questions.', errors))
2340 return results
2341
2342
agrieve7b6479d82015-10-07 14:24:222343def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2344 """Checks if MDPI assets are placed in a correct directory."""
2345 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2346 ('/res/drawable/' in f.LocalPath() or
2347 '/res/drawable-ldrtl/' in f.LocalPath()))
2348 errors = []
2349 for f in input_api.AffectedFiles(include_deletes=False,
2350 file_filter=file_filter):
2351 errors.append(' %s' % f.LocalPath())
2352
2353 results = []
2354 if errors:
2355 results.append(output_api.PresubmitError(
2356 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2357 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2358 '/res/drawable-ldrtl/.\n'
2359 'Contact [email protected] if you have questions.', errors))
2360 return results
2361
2362
Nate Fischer535972b2017-09-16 01:06:182363def _CheckAndroidWebkitImports(input_api, output_api):
2364 """Checks that code uses org.chromium.base.Callback instead of
2365 android.widget.ValueCallback except in the WebView glue layer.
2366 """
2367 valuecallback_import_pattern = input_api.re.compile(
2368 r'^import android\.webkit\.ValueCallback;$')
2369
2370 errors = []
2371
2372 sources = lambda affected_file: input_api.FilterSourceFile(
2373 affected_file,
2374 black_list=(_EXCLUDED_PATHS +
2375 _TEST_CODE_EXCLUDED_PATHS +
2376 input_api.DEFAULT_BLACK_LIST +
2377 (r'^android_webview[\\\/]glue[\\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492378 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:182379
2380 for f in input_api.AffectedSourceFiles(sources):
2381 for line_num, line in f.ChangedContents():
2382 if valuecallback_import_pattern.search(line):
2383 errors.append("%s:%d" % (f.LocalPath(), line_num))
2384
2385 results = []
2386
2387 if errors:
2388 results.append(output_api.PresubmitError(
2389 'android.webkit.ValueCallback usage is detected outside of the glue'
2390 ' layer. To stay compatible with the support library, android.webkit.*'
2391 ' classes should only be used inside the glue layer and'
2392 ' org.chromium.base.Callback should be used instead.',
2393 errors))
2394
2395 return results
2396
2397
agrievef32bcc72016-04-04 14:57:402398class PydepsChecker(object):
2399 def __init__(self, input_api, pydeps_files):
2400 self._file_cache = {}
2401 self._input_api = input_api
2402 self._pydeps_files = pydeps_files
2403
2404 def _LoadFile(self, path):
2405 """Returns the list of paths within a .pydeps file relative to //."""
2406 if path not in self._file_cache:
2407 with open(path) as f:
2408 self._file_cache[path] = f.read()
2409 return self._file_cache[path]
2410
2411 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2412 """Returns an interable of paths within the .pydep, relativized to //."""
2413 os_path = self._input_api.os_path
2414 pydeps_dir = os_path.dirname(pydeps_path)
2415 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2416 if not l.startswith('*'))
2417 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2418
2419 def _CreateFilesToPydepsMap(self):
2420 """Returns a map of local_path -> list_of_pydeps."""
2421 ret = {}
2422 for pydep_local_path in self._pydeps_files:
2423 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2424 ret.setdefault(path, []).append(pydep_local_path)
2425 return ret
2426
2427 def ComputeAffectedPydeps(self):
2428 """Returns an iterable of .pydeps files that might need regenerating."""
2429 affected_pydeps = set()
2430 file_to_pydeps_map = None
2431 for f in self._input_api.AffectedFiles(include_deletes=True):
2432 local_path = f.LocalPath()
2433 if local_path == 'DEPS':
2434 return self._pydeps_files
2435 elif local_path.endswith('.pydeps'):
2436 if local_path in self._pydeps_files:
2437 affected_pydeps.add(local_path)
2438 elif local_path.endswith('.py'):
2439 if file_to_pydeps_map is None:
2440 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2441 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2442 return affected_pydeps
2443
2444 def DetermineIfStale(self, pydeps_path):
2445 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412446 import difflib
John Budorick47ca3fe2018-02-10 00:53:102447 import os
2448
agrievef32bcc72016-04-04 14:57:402449 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2450 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102451 env = dict(os.environ)
2452 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402453 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102454 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412455 old_contents = old_pydeps_data[2:]
2456 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402457 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412458 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402459
2460
2461def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2462 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402463 # This check is for Python dependency lists (.pydeps files), and involves
2464 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2465 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282466 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002467 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022468 # TODO(agrieve): Update when there's a better way to detect
2469 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402470 is_android = input_api.os_path.exists('third_party/android_tools')
2471 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2472 results = []
2473 # First, check for new / deleted .pydeps.
2474 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032475 # Check whether we are running the presubmit check for a file in src.
2476 # f.LocalPath is relative to repo (src, or internal repo).
2477 # os_path.exists is relative to src repo.
2478 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2479 # to src and we can conclude that the pydeps is in src.
2480 if input_api.os_path.exists(f.LocalPath()):
2481 if f.LocalPath().endswith('.pydeps'):
2482 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2483 results.append(output_api.PresubmitError(
2484 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2485 'remove %s' % f.LocalPath()))
2486 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2487 results.append(output_api.PresubmitError(
2488 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2489 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402490
2491 if results:
2492 return results
2493
2494 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2495
2496 for pydep_path in checker.ComputeAffectedPydeps():
2497 try:
phajdan.jr0d9878552016-11-04 10:49:412498 result = checker.DetermineIfStale(pydep_path)
2499 if result:
2500 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402501 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412502 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2503 'To regenerate, run:\n\n %s' %
2504 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402505 except input_api.subprocess.CalledProcessError as error:
2506 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2507 long_text=error.output)]
2508
2509 return results
2510
2511
glidere61efad2015-02-18 17:39:432512def _CheckSingletonInHeaders(input_api, output_api):
2513 """Checks to make sure no header files have |Singleton<|."""
2514 def FileFilter(affected_file):
2515 # It's ok for base/memory/singleton.h to have |Singleton<|.
2516 black_list = (_EXCLUDED_PATHS +
2517 input_api.DEFAULT_BLACK_LIST +
Michael Warrese4451492018-03-07 04:42:472518 (r"^base[\\\/]memory[\\\/]singleton\.h$",
2519 r"^net[\\\/]quic[\\\/]platform[\\\/]impl[\\\/]"
2520 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432521 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2522
sergeyu34d21222015-09-16 00:11:442523 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432524 files = []
2525 for f in input_api.AffectedSourceFiles(FileFilter):
2526 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2527 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2528 contents = input_api.ReadFile(f)
2529 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242530 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432531 pattern.search(line)):
2532 files.append(f)
2533 break
2534
2535 if files:
yolandyandaabc6d2016-04-18 18:29:392536 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442537 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432538 'Please move them to an appropriate source file so that the ' +
2539 'template gets instantiated in a single compilation unit.',
2540 files) ]
2541 return []
2542
2543
[email protected]fd20b902014-05-09 02:14:532544_DEPRECATED_CSS = [
2545 # Values
2546 ( "-webkit-box", "flex" ),
2547 ( "-webkit-inline-box", "inline-flex" ),
2548 ( "-webkit-flex", "flex" ),
2549 ( "-webkit-inline-flex", "inline-flex" ),
2550 ( "-webkit-min-content", "min-content" ),
2551 ( "-webkit-max-content", "max-content" ),
2552
2553 # Properties
2554 ( "-webkit-background-clip", "background-clip" ),
2555 ( "-webkit-background-origin", "background-origin" ),
2556 ( "-webkit-background-size", "background-size" ),
2557 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442558 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532559
2560 # Functions
2561 ( "-webkit-gradient", "gradient" ),
2562 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2563 ( "-webkit-linear-gradient", "linear-gradient" ),
2564 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2565 ( "-webkit-radial-gradient", "radial-gradient" ),
2566 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2567]
2568
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202569
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492570# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242571def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532572 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252573 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342574 documentation and iOS CSS for dom distiller
2575 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252576 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532577 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492578 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:252579 black_list = (_EXCLUDED_PATHS +
2580 _TEST_CODE_EXCLUDED_PATHS +
2581 input_api.DEFAULT_BLACK_LIST +
2582 (r"^chrome/common/extensions/docs",
2583 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342584 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442585 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252586 r"^native_client_sdk"))
2587 file_filter = lambda f: input_api.FilterSourceFile(
2588 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532589 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2590 for line_num, line in fpath.ChangedContents():
2591 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022592 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532593 results.append(output_api.PresubmitError(
2594 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2595 (fpath.LocalPath(), line_num, deprecated_value, value)))
2596 return results
2597
mohan.reddyf21db962014-10-16 12:26:472598
dbeam070cfe62014-10-22 06:44:022599_DEPRECATED_JS = [
2600 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2601 ( "__defineGetter__", "Object.defineProperty" ),
2602 ( "__defineSetter__", "Object.defineProperty" ),
2603]
2604
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202605
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492606# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242607def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022608 """Make sure that we don't use deprecated JS in Chrome code."""
2609 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492610 file_inclusion_pattern = [r".+\.js$"] # TODO(dbeam): .html?
dbeam070cfe62014-10-22 06:44:022611 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2612 input_api.DEFAULT_BLACK_LIST)
2613 file_filter = lambda f: input_api.FilterSourceFile(
2614 f, white_list=file_inclusion_pattern, black_list=black_list)
2615 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2616 for lnum, line in fpath.ChangedContents():
2617 for (deprecated, replacement) in _DEPRECATED_JS:
2618 if deprecated in line:
2619 results.append(output_api.PresubmitError(
2620 "%s:%d: Use of deprecated JS %s, use %s instead" %
2621 (fpath.LocalPath(), lnum, deprecated, replacement)))
2622 return results
2623
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202624
dpapadd651231d82017-07-21 02:44:472625def _CheckForRiskyJsArrowFunction(line_number, line):
2626 if ' => ' in line:
2627 return "line %d, is using an => (arrow) function\n %s\n" % (
2628 line_number, line)
2629 return ''
2630
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202631
dpapadd651231d82017-07-21 02:44:472632def _CheckForRiskyJsConstLet(input_api, line_number, line):
2633 if input_api.re.match('^\s*(const|let)\s', line):
2634 return "line %d, is using const/let keyword\n %s\n" % (
2635 line_number, line)
2636 return ''
dbeam070cfe62014-10-22 06:44:022637
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202638
dbeam1ec68ac2016-12-15 05:22:242639def _CheckForRiskyJsFeatures(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492640 maybe_ios_js = [r"^(ios|components|ui\/webui\/resources)\/.+\.js$"]
Steven Bennetts90545f3cb2017-08-14 18:11:002641 # 'ui/webui/resources/cr_components are not allowed on ios'
2642 not_ios_filter = (r".*ui\/webui\/resources\/cr_components.*", )
Steven Bennetts9c7e3c22017-08-02 19:10:572643 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js,
Steven Bennetts90545f3cb2017-08-14 18:11:002644 black_list=not_ios_filter)
dpapadd651231d82017-07-21 02:44:472645 results = []
dbeam1ec68ac2016-12-15 05:22:242646 for f in input_api.AffectedFiles(file_filter=file_filter):
dpapadd651231d82017-07-21 02:44:472647 arrow_error_lines = []
2648 const_let_error_lines = []
dbeam1ec68ac2016-12-15 05:22:242649 for lnum, line in f.ChangedContents():
dpapadd651231d82017-07-21 02:44:472650 arrow_error_lines += filter(None, [
2651 _CheckForRiskyJsArrowFunction(lnum, line),
2652 ])
dbeam1ec68ac2016-12-15 05:22:242653
dpapadd651231d82017-07-21 02:44:472654 const_let_error_lines += filter(None, [
2655 _CheckForRiskyJsConstLet(input_api, lnum, line),
2656 ])
dbeam1ec68ac2016-12-15 05:22:242657
dpapadd651231d82017-07-21 02:44:472658 if arrow_error_lines:
2659 arrow_error_lines = map(
2660 lambda e: "%s:%s" % (f.LocalPath(), e), arrow_error_lines)
2661 results.append(
2662 output_api.PresubmitPromptWarning('\n'.join(arrow_error_lines + [
2663"""
2664Use of => (arrow) operator detected in:
dbeam1ec68ac2016-12-15 05:22:242665%s
2666Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2667https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
dpapadd651231d82017-07-21 02:44:472668""" % f.LocalPath()
2669 ])))
dbeam1ec68ac2016-12-15 05:22:242670
dpapadd651231d82017-07-21 02:44:472671 if const_let_error_lines:
2672 const_let_error_lines = map(
2673 lambda e: "%s:%s" % (f.LocalPath(), e), const_let_error_lines)
2674 results.append(
2675 output_api.PresubmitPromptWarning('\n'.join(const_let_error_lines + [
2676"""
2677Use of const/let keywords detected in:
2678%s
2679Please ensure your code does not run on iOS9 because const/let is not fully
2680supported.
2681https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#let-Block_Scoped-Variables
2682https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#const-Block_Scoped-Constants
2683""" % f.LocalPath()
2684 ])))
2685
2686 return results
dbeam1ec68ac2016-12-15 05:22:242687
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202688
rlanday6802cf632017-05-30 17:48:362689def _CheckForRelativeIncludes(input_api, output_api):
2690 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2691 import sys
2692 original_sys_path = sys.path
2693 try:
2694 sys.path = sys.path + [input_api.os_path.join(
2695 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2696 from cpp_checker import CppChecker
2697 finally:
2698 # Restore sys.path to what it was before.
2699 sys.path = original_sys_path
2700
2701 bad_files = {}
2702 for f in input_api.AffectedFiles(include_deletes=False):
2703 if (f.LocalPath().startswith('third_party') and
2704 not f.LocalPath().startswith('third_party/WebKit') and
2705 not f.LocalPath().startswith('third_party\\WebKit')):
2706 continue
2707
2708 if not CppChecker.IsCppFile(f.LocalPath()):
2709 continue
2710
Vaclav Brozekd5de76a2018-03-17 07:57:502711 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362712 if "#include" in line and "../" in line]
2713 if not relative_includes:
2714 continue
2715 bad_files[f.LocalPath()] = relative_includes
2716
2717 if not bad_files:
2718 return []
2719
2720 error_descriptions = []
2721 for file_path, bad_lines in bad_files.iteritems():
2722 error_description = file_path
2723 for line in bad_lines:
2724 error_description += '\n ' + line
2725 error_descriptions.append(error_description)
2726
2727 results = []
2728 results.append(output_api.PresubmitError(
2729 'You added one or more relative #include paths (including "../").\n'
2730 'These shouldn\'t be used because they can be used to include headers\n'
2731 'from code that\'s not correctly specified as a dependency in the\n'
2732 'relevant BUILD.gn file(s).',
2733 error_descriptions))
2734
2735 return results
2736
Takeshi Yoshinoe387aa32017-08-02 13:16:132737
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202738def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2739 if not isinstance(key, ast.Str):
2740 return 'Key at line %d must be a string literal' % key.lineno
2741 if not isinstance(value, ast.Dict):
2742 return 'Value at line %d must be a dict' % value.lineno
2743 if len(value.keys) != 1:
2744 return 'Dict at line %d must have single entry' % value.lineno
2745 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2746 return (
2747 'Entry at line %d must have a string literal \'filepath\' as key' %
2748 value.lineno)
2749 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132750
Takeshi Yoshinoe387aa32017-08-02 13:16:132751
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202752def _CheckWatchlistsEntrySyntax(key, value, ast):
2753 if not isinstance(key, ast.Str):
2754 return 'Key at line %d must be a string literal' % key.lineno
2755 if not isinstance(value, ast.List):
2756 return 'Value at line %d must be a list' % value.lineno
2757 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132758
Takeshi Yoshinoe387aa32017-08-02 13:16:132759
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202760def _CheckWATCHLISTSEntries(wd_dict, w_dict, ast):
2761 mismatch_template = (
2762 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2763 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132764
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202765 i = 0
2766 last_key = ''
2767 while True:
2768 if i >= len(wd_dict.keys):
2769 if i >= len(w_dict.keys):
2770 return None
2771 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2772 elif i >= len(w_dict.keys):
2773 return (
2774 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132775
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202776 wd_key = wd_dict.keys[i]
2777 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132778
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202779 result = _CheckWatchlistDefinitionsEntrySyntax(
2780 wd_key, wd_dict.values[i], ast)
2781 if result is not None:
2782 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132783
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202784 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast)
2785 if result is not None:
2786 return 'Bad entry in WATCHLISTS dict: %s' % result
2787
2788 if wd_key.s != w_key.s:
2789 return mismatch_template % (
2790 '%s at line %d' % (wd_key.s, wd_key.lineno),
2791 '%s at line %d' % (w_key.s, w_key.lineno))
2792
2793 if wd_key.s < last_key:
2794 return (
2795 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2796 (wd_key.lineno, w_key.lineno))
2797 last_key = wd_key.s
2798
2799 i = i + 1
2800
2801
2802def _CheckWATCHLISTSSyntax(expression, ast):
2803 if not isinstance(expression, ast.Expression):
2804 return 'WATCHLISTS file must contain a valid expression'
2805 dictionary = expression.body
2806 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2807 return 'WATCHLISTS file must have single dict with exactly two entries'
2808
2809 first_key = dictionary.keys[0]
2810 first_value = dictionary.values[0]
2811 second_key = dictionary.keys[1]
2812 second_value = dictionary.values[1]
2813
2814 if (not isinstance(first_key, ast.Str) or
2815 first_key.s != 'WATCHLIST_DEFINITIONS' or
2816 not isinstance(first_value, ast.Dict)):
2817 return (
2818 'The first entry of the dict in WATCHLISTS file must be '
2819 'WATCHLIST_DEFINITIONS dict')
2820
2821 if (not isinstance(second_key, ast.Str) or
2822 second_key.s != 'WATCHLISTS' or
2823 not isinstance(second_value, ast.Dict)):
2824 return (
2825 'The second entry of the dict in WATCHLISTS file must be '
2826 'WATCHLISTS dict')
2827
2828 return _CheckWATCHLISTSEntries(first_value, second_value, ast)
Takeshi Yoshinoe387aa32017-08-02 13:16:132829
2830
2831def _CheckWATCHLISTS(input_api, output_api):
2832 for f in input_api.AffectedFiles(include_deletes=False):
2833 if f.LocalPath() == 'WATCHLISTS':
2834 contents = input_api.ReadFile(f, 'r')
2835
2836 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202837 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132838 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202839 # Get an AST tree for it and scan the tree for detailed style checking.
2840 expression = input_api.ast.parse(
2841 contents, filename='WATCHLISTS', mode='eval')
2842 except ValueError as e:
2843 return [output_api.PresubmitError(
2844 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2845 except SyntaxError as e:
2846 return [output_api.PresubmitError(
2847 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2848 except TypeError as e:
2849 return [output_api.PresubmitError(
2850 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132851
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202852 result = _CheckWATCHLISTSSyntax(expression, input_api.ast)
2853 if result is not None:
2854 return [output_api.PresubmitError(result)]
2855 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132856
2857 return []
2858
2859
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192860def _CheckNewHeaderWithoutGnChange(input_api, output_api):
2861 """Checks that newly added header files have corresponding GN changes.
2862 Note that this is only a heuristic. To be precise, run script:
2863 build/check_gn_headers.py.
2864 """
2865
2866 def headers(f):
2867 return input_api.FilterSourceFile(
2868 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
2869
2870 new_headers = []
2871 for f in input_api.AffectedSourceFiles(headers):
2872 if f.Action() != 'A':
2873 continue
2874 new_headers.append(f.LocalPath())
2875
2876 def gn_files(f):
2877 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
2878
2879 all_gn_changed_contents = ''
2880 for f in input_api.AffectedSourceFiles(gn_files):
2881 for _, line in f.ChangedContents():
2882 all_gn_changed_contents += line
2883
2884 problems = []
2885 for header in new_headers:
2886 basename = input_api.os_path.basename(header)
2887 if basename not in all_gn_changed_contents:
2888 problems.append(header)
2889
2890 if problems:
2891 return [output_api.PresubmitPromptWarning(
2892 'Missing GN changes for new header files', items=sorted(problems),
2893 long_text='Please double check whether newly added header files need '
2894 'corresponding changes in gn or gni files.\nThis checking is only a '
2895 'heuristic. Run build/check_gn_headers.py to be precise.\n'
2896 'Read https://crbug.com/661774 for more info.')]
2897 return []
2898
2899
dgnaa68d5e2015-06-10 10:08:222900def _AndroidSpecificOnUploadChecks(input_api, output_api):
2901 """Groups checks that target android code."""
2902 results = []
dgnaa68d5e2015-06-10 10:08:222903 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222904 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292905 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:062906 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
2907 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:422908 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:182909 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222910 return results
2911
2912
[email protected]22c9bd72011-03-27 16:47:392913def _CommonChecks(input_api, output_api):
2914 """Checks common to both upload and commit."""
2915 results = []
2916 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382917 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542918 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:082919
2920 author = input_api.change.author_email
2921 if author and author not in _KNOWN_ROBOTS:
2922 results.extend(
2923 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
2924
[email protected]55459852011-08-10 15:17:192925 results.extend(
[email protected]760deea2013-12-10 19:33:492926 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:232927 results.extend(
2928 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542929 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182930 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522931 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222932 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442933 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592934 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062935 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122936 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182937 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222938 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302939 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492940 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032941 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492942 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442943 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272944 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:072945 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542946 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442947 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392948 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552949 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042950 results.extend(
2951 input_api.canned_checks.CheckChangeHasNoTabs(
2952 input_api,
2953 output_api,
2954 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402955 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162956 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082957 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242958 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2959 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472960 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042961 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:052962 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:142963 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232964 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432965 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402966 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152967 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172968 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502969 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242970 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:362971 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:132972 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:432973 results.extend(input_api.RunTests(
2974 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:142975 results.extend(_CheckTranslationScreenshots(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242976
Vaclav Brozekcdc7defb2018-03-20 09:54:352977 for f in input_api.AffectedFiles():
2978 path, name = input_api.os_path.split(f.LocalPath())
2979 if name == 'PRESUBMIT.py':
2980 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:002981 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
2982 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:072983 # The PRESUBMIT.py file (and the directory containing it) might
2984 # have been affected by being moved or removed, so only try to
2985 # run the tests if they still exist.
2986 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2987 input_api, output_api, full_path,
2988 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392989 return results
[email protected]1f7b4172010-01-28 01:17:342990
[email protected]b337cb5b2011-01-23 21:24:052991
[email protected]b8079ae4a2012-12-05 19:56:492992def _CheckPatchFiles(input_api, output_api):
2993 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2994 if f.LocalPath().endswith(('.orig', '.rej'))]
2995 if problems:
2996 return [output_api.PresubmitError(
2997 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032998 else:
2999 return []
[email protected]b8079ae4a2012-12-05 19:56:493000
3001
Kent Tamura5a8755d2017-06-29 23:37:073002def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:213003 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
3004 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
3005 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:073006 include_re = input_api.re.compile(
3007 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
3008 extension_re = input_api.re.compile(r'\.[a-z]+$')
3009 errors = []
3010 for f in input_api.AffectedFiles():
3011 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
3012 continue
3013 found_line_number = None
3014 found_macro = None
3015 for line_num, line in f.ChangedContents():
3016 match = macro_re.search(line)
3017 if match:
3018 found_line_number = line_num
3019 found_macro = match.group(2)
3020 break
3021 if not found_line_number:
3022 continue
3023
3024 found_include = False
3025 for line in f.NewContents():
3026 if include_re.search(line):
3027 found_include = True
3028 break
3029 if found_include:
3030 continue
3031
3032 if not f.LocalPath().endswith('.h'):
3033 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
3034 try:
3035 content = input_api.ReadFile(primary_header_path, 'r')
3036 if include_re.search(content):
3037 continue
3038 except IOError:
3039 pass
3040 errors.append('%s:%d %s macro is used without including build/'
3041 'build_config.h.'
3042 % (f.LocalPath(), found_line_number, found_macro))
3043 if errors:
3044 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
3045 return []
3046
3047
[email protected]b00342e7f2013-03-26 16:21:543048def _DidYouMeanOSMacro(bad_macro):
3049 try:
3050 return {'A': 'OS_ANDROID',
3051 'B': 'OS_BSD',
3052 'C': 'OS_CHROMEOS',
3053 'F': 'OS_FREEBSD',
3054 'L': 'OS_LINUX',
3055 'M': 'OS_MACOSX',
3056 'N': 'OS_NACL',
3057 'O': 'OS_OPENBSD',
3058 'P': 'OS_POSIX',
3059 'S': 'OS_SOLARIS',
3060 'W': 'OS_WIN'}[bad_macro[3].upper()]
3061 except KeyError:
3062 return ''
3063
3064
3065def _CheckForInvalidOSMacrosInFile(input_api, f):
3066 """Check for sensible looking, totally invalid OS macros."""
3067 preprocessor_statement = input_api.re.compile(r'^\s*#')
3068 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
3069 results = []
3070 for lnum, line in f.ChangedContents():
3071 if preprocessor_statement.search(line):
3072 for match in os_macro.finditer(line):
3073 if not match.group(1) in _VALID_OS_MACROS:
3074 good = _DidYouMeanOSMacro(match.group(1))
3075 did_you_mean = ' (did you mean %s?)' % good if good else ''
3076 results.append(' %s:%d %s%s' % (f.LocalPath(),
3077 lnum,
3078 match.group(1),
3079 did_you_mean))
3080 return results
3081
3082
3083def _CheckForInvalidOSMacros(input_api, output_api):
3084 """Check all affected files for invalid OS macros."""
3085 bad_macros = []
3086 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:473087 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:543088 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
3089
3090 if not bad_macros:
3091 return []
3092
3093 return [output_api.PresubmitError(
3094 'Possibly invalid OS macro[s] found. Please fix your code\n'
3095 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
3096
lliabraa35bab3932014-10-01 12:16:443097
3098def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
3099 """Check all affected files for invalid "if defined" macros."""
3100 ALWAYS_DEFINED_MACROS = (
3101 "TARGET_CPU_PPC",
3102 "TARGET_CPU_PPC64",
3103 "TARGET_CPU_68K",
3104 "TARGET_CPU_X86",
3105 "TARGET_CPU_ARM",
3106 "TARGET_CPU_MIPS",
3107 "TARGET_CPU_SPARC",
3108 "TARGET_CPU_ALPHA",
3109 "TARGET_IPHONE_SIMULATOR",
3110 "TARGET_OS_EMBEDDED",
3111 "TARGET_OS_IPHONE",
3112 "TARGET_OS_MAC",
3113 "TARGET_OS_UNIX",
3114 "TARGET_OS_WIN32",
3115 )
3116 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
3117 results = []
3118 for lnum, line in f.ChangedContents():
3119 for match in ifdef_macro.finditer(line):
3120 if match.group(1) in ALWAYS_DEFINED_MACROS:
3121 always_defined = ' %s is always defined. ' % match.group(1)
3122 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
3123 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
3124 lnum,
3125 always_defined,
3126 did_you_mean))
3127 return results
3128
3129
3130def _CheckForInvalidIfDefinedMacros(input_api, output_api):
3131 """Check all affected files for invalid "if defined" macros."""
3132 bad_macros = []
3133 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:213134 if f.LocalPath().startswith('third_party/sqlite/'):
3135 continue
lliabraa35bab3932014-10-01 12:16:443136 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3137 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3138
3139 if not bad_macros:
3140 return []
3141
3142 return [output_api.PresubmitError(
3143 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3144 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3145 bad_macros)]
3146
3147
mlamouria82272622014-09-16 18:45:043148def _CheckForIPCRules(input_api, output_api):
3149 """Check for same IPC rules described in
3150 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3151 """
3152 base_pattern = r'IPC_ENUM_TRAITS\('
3153 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3154 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3155
3156 problems = []
3157 for f in input_api.AffectedSourceFiles(None):
3158 local_path = f.LocalPath()
3159 if not local_path.endswith('.h'):
3160 continue
3161 for line_number, line in f.ChangedContents():
3162 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3163 problems.append(
3164 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3165
3166 if problems:
3167 return [output_api.PresubmitPromptWarning(
3168 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
3169 else:
3170 return []
3171
[email protected]b00342e7f2013-03-26 16:21:543172
Stephen Martinis97a394142018-06-07 23:06:053173def _CheckForLongPathnames(input_api, output_api):
3174 """Check to make sure no files being submitted have long paths.
3175 This causes issues on Windows.
3176 """
3177 problems = []
3178 for f in input_api.AffectedSourceFiles(None):
3179 local_path = f.LocalPath()
3180 # Windows has a path limit of 260 characters. Limit path length to 200 so
3181 # that we have some extra for the prefix on dev machines and the bots.
3182 if len(local_path) > 200:
3183 problems.append(local_path)
3184
3185 if problems:
3186 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
3187 else:
3188 return []
3189
3190
Daniel Bratell8ba52722018-03-02 16:06:143191def _CheckForIncludeGuards(input_api, output_api):
3192 """Check that header files have proper guards against multiple inclusion.
3193 If a file should not have such guards (and it probably should) then it
3194 should include the string "no-include-guard-because-multiply-included".
3195 """
Daniel Bratell6a75baef62018-06-04 10:04:453196 def is_chromium_header_file(f):
3197 # We only check header files under the control of the Chromium
3198 # project. That is, those outside third_party apart from
3199 # third_party/blink.
3200 file_with_path = input_api.os_path.normpath(f.LocalPath())
3201 return (file_with_path.endswith('.h') and
3202 (not file_with_path.startswith('third_party') or
3203 file_with_path.startswith(
3204 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:143205
3206 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:343207 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:143208
3209 errors = []
3210
Daniel Bratell6a75baef62018-06-04 10:04:453211 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:143212 guard_name = None
3213 guard_line_number = None
3214 seen_guard_end = False
3215
3216 file_with_path = input_api.os_path.normpath(f.LocalPath())
3217 base_file_name = input_api.os_path.splitext(
3218 input_api.os_path.basename(file_with_path))[0]
3219 upper_base_file_name = base_file_name.upper()
3220
3221 expected_guard = replace_special_with_underscore(
3222 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:143223
3224 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:573225 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
3226 # are too many (1000+) files with slight deviations from the
3227 # coding style. The most important part is that the include guard
3228 # is there, and that it's unique, not the name so this check is
3229 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:143230 #
3231 # As code becomes more uniform, this could be made stricter.
3232
3233 guard_name_pattern_list = [
3234 # Anything with the right suffix (maybe with an extra _).
3235 r'\w+_H__?',
3236
Daniel Bratell39b5b062018-05-16 18:09:573237 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:143238 r'\w+_h',
3239
3240 # Anything including the uppercase name of the file.
3241 r'\w*' + input_api.re.escape(replace_special_with_underscore(
3242 upper_base_file_name)) + r'\w*',
3243 ]
3244 guard_name_pattern = '|'.join(guard_name_pattern_list)
3245 guard_pattern = input_api.re.compile(
3246 r'#ifndef\s+(' + guard_name_pattern + ')')
3247
3248 for line_number, line in enumerate(f.NewContents()):
3249 if 'no-include-guard-because-multiply-included' in line:
3250 guard_name = 'DUMMY' # To not trigger check outside the loop.
3251 break
3252
3253 if guard_name is None:
3254 match = guard_pattern.match(line)
3255 if match:
3256 guard_name = match.group(1)
3257 guard_line_number = line_number
3258
Daniel Bratell39b5b062018-05-16 18:09:573259 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:453260 # don't match the chromium style guide, but new files should
3261 # get it right.
3262 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:573263 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:143264 errors.append(output_api.PresubmitPromptWarning(
3265 'Header using the wrong include guard name %s' % guard_name,
3266 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:573267 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:143268 else:
3269 # The line after #ifndef should have a #define of the same name.
3270 if line_number == guard_line_number + 1:
3271 expected_line = '#define %s' % guard_name
3272 if line != expected_line:
3273 errors.append(output_api.PresubmitPromptWarning(
3274 'Missing "%s" for include guard' % expected_line,
3275 ['%s:%d' % (f.LocalPath(), line_number + 1)],
3276 'Expected: %r\nGot: %r' % (expected_line, line)))
3277
3278 if not seen_guard_end and line == '#endif // %s' % guard_name:
3279 seen_guard_end = True
3280 elif seen_guard_end:
3281 if line.strip() != '':
3282 errors.append(output_api.PresubmitPromptWarning(
3283 'Include guard %s not covering the whole file' % (
3284 guard_name), [f.LocalPath()]))
3285 break # Nothing else to check and enough to warn once.
3286
3287 if guard_name is None:
3288 errors.append(output_api.PresubmitPromptWarning(
3289 'Missing include guard %s' % expected_guard,
3290 [f.LocalPath()],
3291 'Missing include guard in %s\n'
3292 'Recommended name: %s\n'
3293 'This check can be disabled by having the string\n'
3294 'no-include-guard-because-multiply-included in the header.' %
3295 (f.LocalPath(), expected_guard)))
3296
3297 return errors
3298
3299
mostynbb639aca52015-01-07 20:31:233300def _CheckForWindowsLineEndings(input_api, output_api):
3301 """Check source code and known ascii text files for Windows style line
3302 endings.
3303 """
earthdok1b5e0ee2015-03-10 15:19:103304 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233305
3306 file_inclusion_pattern = (
3307 known_text_files,
3308 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3309 )
3310
mostynbb639aca52015-01-07 20:31:233311 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533312 source_file_filter = lambda f: input_api.FilterSourceFile(
3313 f, white_list=file_inclusion_pattern, black_list=None)
3314 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503315 include_file = False
3316 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233317 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503318 include_file = True
3319 if include_file:
3320 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233321
3322 if problems:
3323 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3324 'these files to contain Windows style line endings?\n' +
3325 '\n'.join(problems))]
3326
3327 return []
3328
3329
Vaclav Brozekd5de76a2018-03-17 07:57:503330def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133331 """Checks that all source files use SYSLOG properly."""
3332 syslog_files = []
3333 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563334 for line_number, line in f.ChangedContents():
3335 if 'SYSLOG' in line:
3336 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3337
pastarmovj89f7ee12016-09-20 14:58:133338 if syslog_files:
3339 return [output_api.PresubmitPromptWarning(
3340 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3341 ' calls.\nFiles to check:\n', items=syslog_files)]
3342 return []
3343
3344
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193345def _CheckCrbugLinksHaveHttps(input_api, output_api):
Miguel Casas68bdb652017-12-19 16:29:093346 """Checks that crbug(.com) links are correctly prefixed by https://,
3347 unless they come in the accepted form TODO(crbug.com/...)
3348 """
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193349
Wei-Yin Chen (陳威尹)ce74dfc2018-08-08 01:15:183350 # The cr bug strings are split to avoid matching in real presubmit
3351 # checkings.
3352 pattern = input_api.re.compile(r'//.*(?<!:\/\/)cr''bug[.com]*')
3353 accepted_pattern = input_api.re.compile(r'//.*TODO\(cr''bug[.com]*')
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193354 problems = []
Wei-Yin Chen (陳威尹)ce74dfc2018-08-08 01:15:183355 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193356 for line_num, line in f.ChangedContents():
Miguel Casas68bdb652017-12-19 16:29:093357 if pattern.search(line) and not accepted_pattern.search(line):
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193358 problems.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3359
3360 if problems:
3361 return [output_api.PresubmitPromptWarning(
Wei-Yin Chen (陳威尹)ce74dfc2018-08-08 01:15:183362 'Found unprefixed crbug.com URL(s), consider prepending https://\n' +
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193363 '\n'.join(problems))]
3364 return []
3365
3366
[email protected]1f7b4172010-01-28 01:17:343367def CheckChangeOnUpload(input_api, output_api):
3368 results = []
3369 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473370 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283371 results.extend(
jam93a6ee792017-02-08 23:59:223372 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193373 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223374 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133375 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163376 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193377 results.extend(_CheckCrbugLinksHaveHttps(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:533378 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193379 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543380 return results
[email protected]ca8d19842009-02-19 16:33:123381
3382
[email protected]1bfb8322014-04-23 01:02:413383def GetTryServerMasterForBot(bot):
3384 """Returns the Try Server master for the given bot.
3385
[email protected]0bb112362014-07-26 04:38:323386 It tries to guess the master from the bot name, but may still fail
3387 and return None. There is no longer a default master.
3388 """
3389 # Potentially ambiguous bot names are listed explicitly.
3390 master_map = {
tandriie5587792016-07-14 00:34:503391 'chromium_presubmit': 'master.tryserver.chromium.linux',
3392 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413393 }
[email protected]0bb112362014-07-26 04:38:323394 master = master_map.get(bot)
3395 if not master:
wnwen4fbaab82016-05-25 12:54:363396 if 'android' in bot:
tandriie5587792016-07-14 00:34:503397 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363398 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503399 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323400 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503401 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323402 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503403 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323404 return master
[email protected]1bfb8322014-04-23 01:02:413405
3406
[email protected]ca8d19842009-02-19 16:33:123407def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543408 results = []
[email protected]1f7b4172010-01-28 01:17:343409 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543410 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273411 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343412 input_api,
3413 output_api,
[email protected]2fdd1f362013-01-16 03:56:033414 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273415
jam93a6ee792017-02-08 23:59:223416 results.extend(
3417 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543418 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3419 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413420 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3421 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543422 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143423
3424
3425def _CheckTranslationScreenshots(input_api, output_api):
3426 PART_FILE_TAG = "part"
3427 import os
3428 import sys
3429 from io import StringIO
3430
3431 try:
3432 old_sys_path = sys.path
3433 sys.path = sys.path + [input_api.os_path.join(
3434 input_api.PresubmitLocalPath(), 'tools', 'grit')]
3435 import grit.grd_reader
3436 import grit.node.message
3437 import grit.util
3438 finally:
3439 sys.path = old_sys_path
3440
3441 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
3442 """Load the grd file and return a dict of message ids to messages.
3443
3444 Ignores any nested grdp files pointed by <part> tag.
3445 """
3446 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
3447 stop_after=None, first_ids_file=None,
3448 debug=False, defines=None,
3449 tags_to_ignore=set([PART_FILE_TAG]))
3450 return {
3451 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
3452 grit.node.message.MessageNode)
3453 }
3454
3455 def _GetGrdpMessagesFromString(grdp_string):
3456 """Parses the contents of a grdp file given in grdp_string.
3457
3458 grd_reader can't parse grdp files directly. Instead, this creates a
3459 temporary directory with a grd file pointing to the grdp file, and loads the
3460 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
3461 """
3462 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
3463 <grit latest_public_release="1" current_release="1">
3464 <release seq="1">
3465 <messages>
3466 <part file="sub.grdp" />
3467 </messages>
3468 </release>
3469 </grit>
3470 """
3471 with grit.util.TempDir({'main.grd': WRAPPER,
3472 'sub.grdp': grdp_string}) as temp_dir:
3473 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
3474
3475 new_or_added_paths = set(f.LocalPath()
3476 for f in input_api.AffectedFiles()
3477 if (f.Action() == 'A' or f.Action() == 'M'))
3478 removed_paths = set(f.LocalPath()
3479 for f in input_api.AffectedFiles(include_deletes=True)
3480 if f.Action() == 'D')
3481
3482 affected_grds = [f for f in input_api.AffectedFiles()
3483 if (f.LocalPath().endswith('.grd') or
3484 f.LocalPath().endswith('.grdp'))]
3485 affected_png_paths = [f.AbsoluteLocalPath()
3486 for f in input_api.AffectedFiles()
3487 if (f.LocalPath().endswith('.png'))]
3488
3489 # Check for screenshots. Developers can upload screenshots using
3490 # tools/translation/upload_screenshots.py which finds and uploads
3491 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
3492 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
3493 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
3494 #
3495 # The logic here is as follows:
3496 #
3497 # - If the CL has a .png file under the screenshots directory for a grd
3498 # file, warn the developer. Actual images should never be checked into the
3499 # Chrome repo.
3500 #
3501 # - If the CL contains modified or new messages in grd files and doesn't
3502 # contain the corresponding .sha1 files, warn the developer to add images
3503 # and upload them via tools/translation/upload_screenshots.py.
3504 #
3505 # - If the CL contains modified or new messages in grd files and the
3506 # corresponding .sha1 files, everything looks good.
3507 #
3508 # - If the CL contains removed messages in grd files but the corresponding
3509 # .sha1 files aren't removed, warn the developer to remove them.
3510 unnecessary_screenshots = []
3511 missing_sha1 = []
3512 unnecessary_sha1_files = []
3513
3514
3515 def _CheckScreenshotAdded(screenshots_dir, message_id):
3516 sha1_path = input_api.os_path.join(
3517 screenshots_dir, message_id + '.png.sha1')
3518 if sha1_path not in new_or_added_paths:
3519 missing_sha1.append(sha1_path)
3520
3521
3522 def _CheckScreenshotRemoved(screenshots_dir, message_id):
3523 sha1_path = input_api.os_path.join(
3524 screenshots_dir, message_id + '.png.sha1')
3525 if sha1_path not in removed_paths:
3526 unnecessary_sha1_files.append(sha1_path)
3527
3528
3529 for f in affected_grds:
3530 file_path = f.LocalPath()
3531 old_id_to_msg_map = {}
3532 new_id_to_msg_map = {}
3533 if file_path.endswith('.grdp'):
3534 if f.OldContents():
3535 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393536 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143537 if f.NewContents():
3538 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393539 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143540 else:
3541 if f.OldContents():
3542 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393543 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143544 if f.NewContents():
3545 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393546 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143547
3548 # Compute added, removed and modified message IDs.
3549 old_ids = set(old_id_to_msg_map)
3550 new_ids = set(new_id_to_msg_map)
3551 added_ids = new_ids - old_ids
3552 removed_ids = old_ids - new_ids
3553 modified_ids = set([])
3554 for key in old_ids.intersection(new_ids):
3555 if (old_id_to_msg_map[key].FormatXml()
3556 != new_id_to_msg_map[key].FormatXml()):
3557 modified_ids.add(key)
3558
3559 grd_name, ext = input_api.os_path.splitext(
3560 input_api.os_path.basename(file_path))
3561 screenshots_dir = input_api.os_path.join(
3562 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
3563
3564 # Check the screenshot directory for .png files. Warn if there is any.
3565 for png_path in affected_png_paths:
3566 if png_path.startswith(screenshots_dir):
3567 unnecessary_screenshots.append(png_path)
3568
3569 for added_id in added_ids:
3570 _CheckScreenshotAdded(screenshots_dir, added_id)
3571
3572 for modified_id in modified_ids:
3573 _CheckScreenshotAdded(screenshots_dir, modified_id)
3574
3575 for removed_id in removed_ids:
3576 _CheckScreenshotRemoved(screenshots_dir, removed_id)
3577
3578 results = []
3579 if unnecessary_screenshots:
3580 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393581 'Do not include actual screenshots in the changelist. Run '
3582 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143583 sorted(unnecessary_screenshots)))
3584
3585 if missing_sha1:
3586 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393587 'You are adding or modifying UI strings.\n'
3588 'To ensure the best translations, take screenshots of the relevant UI '
3589 '(https://g.co/chrome/translation) and add these files to your '
3590 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143591
3592 if unnecessary_sha1_files:
3593 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393594 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143595 sorted(unnecessary_sha1_files)))
3596
3597 return results