blob: c0aec6cebe80d23ff55315cd881e0cff3120ae23 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0413 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
14 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
15 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
16 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
17 r"^skia[\\/].*",
18 r"^third_party[\\/](WebKit|blink)[\\/].*",
19 r"^third_party[\\/]breakpad[\\/].*",
20 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5421 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
Egor Paskoce145c42018-09-28 19:31:0423 r".+[\\/]pnacl_shim\.c$",
24 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
25 r"^chrome[\\/]browser[\\/]resources[\\/]pdf[\\/]index.js",
26 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1427 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0428 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5429 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0430 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4031)
[email protected]ca8d1982009-02-19 16:33:1232
wnwenbdc444e2016-05-25 13:44:1533
[email protected]06e6d0ff2012-12-11 01:36:4434# Fragment of a regular expression that matches C++ and Objective-C++
35# implementation files.
36_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
37
wnwenbdc444e2016-05-25 13:44:1538
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1939# Fragment of a regular expression that matches C++ and Objective-C++
40# header files.
41_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
42
43
[email protected]06e6d0ff2012-12-11 01:36:4444# Regular expression that matches code only used for test binaries
45# (best effort).
46_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0447 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4448 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4449 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1250 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4451 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0452 r'.*[\\/](test|tool(s)?)[\\/].*',
[email protected]ef070cc2013-05-03 11:53:0553 # content_shell is used for running layout tests.
Egor Paskoce145c42018-09-28 19:31:0454 r'content[\\/]shell[\\/].*',
[email protected]7b054982013-11-27 00:44:4755 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0456 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0857 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0458 r'testing[\\/]iossim[\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4459)
[email protected]ca8d1982009-02-19 16:33:1260
wnwenbdc444e2016-05-25 13:44:1561
[email protected]eea609a2011-11-18 13:10:1262_TEST_ONLY_WARNING = (
63 'You might be calling functions intended only for testing from\n'
64 'production code. It is OK to ignore this warning if you know what\n'
65 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5866 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1267
68
[email protected]cf9b78f2012-11-14 11:40:2869_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4070 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2171 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
72 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2873
wnwenbdc444e2016-05-25 13:44:1574
Eric Stevensona9a980972017-09-23 00:04:4175_BANNED_JAVA_FUNCTIONS = (
76 (
77 'StrictMode.allowThreadDiskReads()',
78 (
79 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
80 'directly.',
81 ),
82 False,
83 ),
84 (
85 'StrictMode.allowThreadDiskWrites()',
86 (
87 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
88 'directly.',
89 ),
90 False,
91 ),
92)
93
[email protected]127f18ec2012-06-16 05:05:5994_BANNED_OBJC_FUNCTIONS = (
95 (
96 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2097 (
98 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5999 'prohibited. Please use CrTrackingArea instead.',
100 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
101 ),
102 False,
103 ),
104 (
[email protected]eaae1972014-04-16 04:17:26105 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20106 (
107 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59108 'instead.',
109 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
110 ),
111 False,
112 ),
113 (
114 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20115 (
116 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59117 'Please use |convertPoint:(point) fromView:nil| instead.',
118 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
119 ),
120 True,
121 ),
122 (
123 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20124 (
125 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59126 'Please use |convertPoint:(point) toView:nil| instead.',
127 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
128 ),
129 True,
130 ),
131 (
132 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20133 (
134 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59135 'Please use |convertRect:(point) fromView:nil| instead.',
136 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
137 ),
138 True,
139 ),
140 (
141 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20142 (
143 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59144 'Please use |convertRect:(point) toView:nil| instead.',
145 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
146 ),
147 True,
148 ),
149 (
150 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20151 (
152 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59153 'Please use |convertSize:(point) fromView:nil| instead.',
154 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
155 ),
156 True,
157 ),
158 (
159 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20160 (
161 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59162 'Please use |convertSize:(point) toView:nil| instead.',
163 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
164 ),
165 True,
166 ),
jif65398702016-10-27 10:19:48167 (
168 r"/\s+UTF8String\s*]",
169 (
170 'The use of -[NSString UTF8String] is dangerous as it can return null',
171 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
172 'Please use |SysNSStringToUTF8| instead.',
173 ),
174 True,
175 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34176 (
177 r'__unsafe_unretained',
178 (
179 'The use of __unsafe_unretained is almost certainly wrong, unless',
180 'when interacting with NSFastEnumeration or NSInvocation.',
181 'Please use __weak in files build with ARC, nothing otherwise.',
182 ),
183 False,
184 ),
[email protected]127f18ec2012-06-16 05:05:59185)
186
Sylvain Defresnea8b73d252018-02-28 15:45:54187_BANNED_IOS_OBJC_FUNCTIONS = (
188 (
189 r'/\bTEST[(]',
190 (
191 'TEST() macro should not be used in Objective-C++ code as it does not ',
192 'drain the autorelease pool at the end of the test. Use TEST_F() ',
193 'macro instead with a fixture inheriting from PlatformTest (or a ',
194 'typedef).'
195 ),
196 True,
197 ),
198 (
199 r'/\btesting::Test\b',
200 (
201 'testing::Test should not be used in Objective-C++ code as it does ',
202 'not drain the autorelease pool at the end of the test. Use ',
203 'PlatformTest instead.'
204 ),
205 True,
206 ),
207)
208
[email protected]127f18ec2012-06-16 05:05:59209
210_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20211 # Make sure that gtest's FRIEND_TEST() macro is not used; the
212 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30213 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20214 (
thomasandersone7caaa9b2017-03-29 19:22:53215 r'\bNULL\b',
216 (
217 'New code should not use NULL. Use nullptr instead.',
218 ),
219 True,
220 (),
221 ),
222 (
[email protected]23e6cbc2012-06-16 18:51:20223 'FRIEND_TEST(',
224 (
[email protected]e3c945502012-06-26 20:01:49225 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20226 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
227 ),
228 False,
[email protected]7345da02012-11-27 14:31:49229 (),
[email protected]23e6cbc2012-06-16 18:51:20230 ),
231 (
thomasanderson4b569052016-09-14 20:15:53232 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
233 (
234 'Chrome clients wishing to select events on X windows should use',
235 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
236 'you are selecting events from the GPU process, or if you are using',
237 'an XDisplay other than gfx::GetXDisplay().',
238 ),
239 True,
240 (
Egor Paskoce145c42018-09-28 19:31:04241 r"^ui[\\/]gl[\\/].*\.cc$",
242 r"^media[\\/]gpu[\\/].*\.cc$",
243 r"^gpu[\\/].*\.cc$",
thomasanderson4b569052016-09-14 20:15:53244 ),
245 ),
246 (
thomasandersone043e3ce2017-06-08 00:43:20247 r'XInternAtom|xcb_intern_atom',
248 (
thomasanderson11aa41dc2017-06-08 22:22:38249 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20250 ),
251 True,
252 (
Egor Paskoce145c42018-09-28 19:31:04253 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
254 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
255 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20256 ),
257 ),
258 (
tomhudsone2c14d552016-05-26 17:07:46259 'setMatrixClip',
260 (
261 'Overriding setMatrixClip() is prohibited; ',
262 'the base function is deprecated. ',
263 ),
264 True,
265 (),
266 ),
267 (
[email protected]52657f62013-05-20 05:30:31268 'SkRefPtr',
269 (
270 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22271 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31272 ),
273 True,
274 (),
275 ),
276 (
277 'SkAutoRef',
278 (
279 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22280 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31281 ),
282 True,
283 (),
284 ),
285 (
286 'SkAutoTUnref',
287 (
288 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22289 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31290 ),
291 True,
292 (),
293 ),
294 (
295 'SkAutoUnref',
296 (
297 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
298 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22299 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31300 ),
301 True,
302 (),
303 ),
[email protected]d89eec82013-12-03 14:10:59304 (
305 r'/HANDLE_EINTR\(.*close',
306 (
307 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
308 'descriptor will be closed, and it is incorrect to retry the close.',
309 'Either call close directly and ignore its return value, or wrap close',
310 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
311 ),
312 True,
313 (),
314 ),
315 (
316 r'/IGNORE_EINTR\((?!.*close)',
317 (
318 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
319 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
320 ),
321 True,
322 (
323 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04324 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
325 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59326 ),
327 ),
[email protected]ec5b3f02014-04-04 18:43:43328 (
329 r'/v8::Extension\(',
330 (
331 'Do not introduce new v8::Extensions into the code base, use',
332 'gin::Wrappable instead. See http://crbug.com/334679',
333 ),
334 True,
[email protected]f55c90ee62014-04-12 00:50:03335 (
Egor Paskoce145c42018-09-28 19:31:04336 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03337 ),
[email protected]ec5b3f02014-04-04 18:43:43338 ),
skyostilf9469f72015-04-20 10:38:52339 (
jame2d1a952016-04-02 00:27:10340 '#pragma comment(lib,',
341 (
342 'Specify libraries to link with in build files and not in the source.',
343 ),
344 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41345 (
Egor Paskoce145c42018-09-28 19:31:04346 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41347 ),
jame2d1a952016-04-02 00:27:10348 ),
fdorayc4ac18d2017-05-01 21:39:59349 (
Gabriel Charette7cc6c432018-04-25 20:52:02350 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59351 (
352 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
353 ),
354 False,
355 (),
356 ),
357 (
Gabriel Charette7cc6c432018-04-25 20:52:02358 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59359 (
360 'Consider using THREAD_CHECKER macros instead of the class directly.',
361 ),
362 False,
363 (),
364 ),
dbeamb6f4fde2017-06-15 04:03:06365 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06366 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
367 (
368 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
369 'deprecated (http://crbug.com/634507). Please avoid converting away',
370 'from the Time types in Chromium code, especially if any math is',
371 'being done on time values. For interfacing with platform/library',
372 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
373 'type converter methods instead. For faking TimeXXX values (for unit',
374 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
375 'other use cases, please contact base/time/OWNERS.',
376 ),
377 False,
378 (),
379 ),
380 (
dbeamb6f4fde2017-06-15 04:03:06381 'CallJavascriptFunctionUnsafe',
382 (
383 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
384 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
385 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
386 ),
387 False,
388 (
Egor Paskoce145c42018-09-28 19:31:04389 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
390 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
391 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06392 ),
393 ),
dskiba1474c2bfd62017-07-20 02:19:24394 (
395 'leveldb::DB::Open',
396 (
397 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
398 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
399 "Chrome's tracing, making their memory usage visible.",
400 ),
401 True,
402 (
403 r'^third_party/leveldatabase/.*\.(cc|h)$',
404 ),
Gabriel Charette0592c3a2017-07-26 12:02:04405 ),
406 (
Chris Mumfordc38afb62017-10-09 17:55:08407 'leveldb::NewMemEnv',
408 (
409 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58410 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
411 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08412 ),
413 True,
414 (
415 r'^third_party/leveldatabase/.*\.(cc|h)$',
416 ),
417 ),
418 (
Gabriel Charetted9839bc2017-07-29 14:17:47419 'RunLoop::QuitCurrent',
420 (
Robert Liao64b7ab22017-08-04 23:03:43421 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
422 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47423 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41424 False,
Gabriel Charetted9839bc2017-07-29 14:17:47425 (),
Gabriel Charettea44975052017-08-21 23:14:04426 ),
427 (
428 'base::ScopedMockTimeMessageLoopTaskRunner',
429 (
Gabriel Charette87cc1af2018-04-25 20:52:51430 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
431 'ScopedTaskEnvironment::MainThreadType::MOCK_TIME. There are still a',
432 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
433 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
434 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04435 ),
Gabriel Charette87cc1af2018-04-25 20:52:51436 False,
Gabriel Charettea44975052017-08-21 23:14:04437 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57438 ),
439 (
440 r'std::regex',
441 (
442 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02443 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57444 ),
445 True,
446 (),
Francois Doray43670e32017-09-27 12:40:38447 ),
448 (
449 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
450 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
451 (
452 'Use the new API in base/threading/thread_restrictions.h.',
453 ),
Gabriel Charette04b138f2018-08-06 00:03:22454 False,
Francois Doray43670e32017-09-27 12:40:38455 (),
456 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38457 (
458 r'/\bbase::Bind\(',
459 (
Gabriel Charette147335ea2018-03-22 15:59:19460 'Please consider using base::Bind{Once,Repeating} instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02461 'of base::Bind. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38462 ),
463 False,
464 (),
465 ),
466 (
467 r'/\bbase::Callback<',
468 (
Gabriel Charette147335ea2018-03-22 15:59:19469 'Please consider using base::{Once,Repeating}Callback instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02470 'of base::Callback. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38471 ),
472 False,
473 (),
474 ),
475 (
476 r'/\bbase::Closure\b',
477 (
Gabriel Charette147335ea2018-03-22 15:59:19478 'Please consider using base::{Once,Repeating}Closure instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02479 'of base::Closure. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38480 ),
481 False,
482 (),
483 ),
Victor Costan3653df62018-02-08 21:38:16484 (
Gabriel Charette147335ea2018-03-22 15:59:19485 r'RunMessageLoop',
486 (
487 'RunMessageLoop is deprecated, use RunLoop instead.',
488 ),
489 False,
490 (),
491 ),
492 (
493 r'RunThisRunLoop',
494 (
495 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
496 ),
497 False,
498 (),
499 ),
500 (
501 r'RunAllPendingInMessageLoop()',
502 (
503 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
504 "if you're convinced you need this.",
505 ),
506 False,
507 (),
508 ),
509 (
510 r'RunAllPendingInMessageLoop(BrowserThread',
511 (
512 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
513 'BrowserThread::UI, TestBrowserThreadBundle::RunIOThreadUntilIdle',
514 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
515 'async events instead of flushing threads.',
516 ),
517 False,
518 (),
519 ),
520 (
521 r'MessageLoopRunner',
522 (
523 'MessageLoopRunner is deprecated, use RunLoop instead.',
524 ),
525 False,
526 (),
527 ),
528 (
529 r'GetDeferredQuitTaskForRunLoop',
530 (
531 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
532 "gab@ if you found a use case where this is the only solution.",
533 ),
534 False,
535 (),
536 ),
537 (
Victor Costan3653df62018-02-08 21:38:16538 'sqlite3_initialize',
539 (
540 'Instead of sqlite3_initialize, depend on //sql, ',
541 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
542 ),
543 True,
544 (
545 r'^sql/initialization\.(cc|h)$',
546 r'^third_party/sqlite/.*\.(c|cc|h)$',
547 ),
548 ),
Matt Menke7f520a82018-03-28 21:38:37549 (
550 'net::URLFetcher',
551 (
552 'net::URLFetcher should no longer be used in content embedders. ',
553 'Instead, use network::SimpleURLLoader instead, which supports ',
554 'an out-of-process network stack. ',
555 'net::URLFetcher may still be used in binaries that do not embed',
556 'content.',
557 ),
Matt Menke59716d02018-04-05 12:45:53558 False,
Matt Menke7f520a82018-03-28 21:38:37559 (
Egor Paskoce145c42018-09-28 19:31:04560 r'^ios[\\/].*\.(cc|h)$',
561 r'.*[\\/]ios[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:37562 r'.*_ios\.(cc|h)$',
Egor Paskoce145c42018-09-28 19:31:04563 r'^net[\\/].*\.(cc|h)$',
564 r'.*[\\/]tools[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:37565 ),
566 ),
jdoerried7d10ab2018-04-27 10:46:13567 (
568 r'/\barraysize\b',
569 (
570 "arraysize is deprecated, please use base::size(array) instead ",
571 "(https://crbug.com/837308). ",
572 ),
573 False,
574 (),
575 ),
tzik5de2157f2018-05-08 03:42:47576 (
577 r'std::random_shuffle',
578 (
579 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
580 'base::RandomShuffle instead.'
581 ),
582 True,
583 (),
584 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24585 (
586 'ios/web/public/test/http_server',
587 (
588 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
589 ),
590 False,
591 (),
592 ),
[email protected]127f18ec2012-06-16 05:05:59593)
594
wnwenbdc444e2016-05-25 13:44:15595
mlamouria82272622014-09-16 18:45:04596_IPC_ENUM_TRAITS_DEPRECATED = (
597 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50598 'See http://www.chromium.org/Home/chromium-security/education/'
599 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:04600
Stephen Martinis97a394142018-06-07 23:06:05601_LONG_PATH_ERROR = (
602 'Some files included in this CL have file names that are too long (> 200'
603 ' characters). If committed, these files will cause issues on Windows. See'
604 ' https://crbug.com/612667 for more details.'
605)
606
Shenghua Zhangbfaa38b82017-11-16 21:58:02607_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:04608 r".*[\\/]BuildHooksAndroidImpl\.java",
609 r".*[\\/]LicenseContentProvider\.java",
610 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:28611 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:02612]
[email protected]127f18ec2012-06-16 05:05:59613
Sean Kau46e29bc2017-08-28 16:31:16614# These paths contain test data and other known invalid JSON files.
615_KNOWN_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:04616 r'test[\\/]data[\\/]',
617 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
618 r'^third_party[\\/]protobuf[\\/]',
619 r'^third_party[\\/]WebKit[\\/]LayoutTests[\\/]external[\\/]wpt[\\/]',
620 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Sean Kau46e29bc2017-08-28 16:31:16621]
622
623
[email protected]b00342e7f2013-03-26 16:21:54624_VALID_OS_MACROS = (
625 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08626 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54627 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:12628 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:54629 'OS_BSD',
630 'OS_CAT', # For testing.
631 'OS_CHROMEOS',
632 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37633 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54634 'OS_IOS',
635 'OS_LINUX',
636 'OS_MACOSX',
637 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21638 'OS_NACL_NONSFI',
639 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12640 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54641 'OS_OPENBSD',
642 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37643 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54644 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54645 'OS_WIN',
646)
647
648
agrievef32bcc72016-04-04 14:57:40649_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:39650 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36651 'base/android/jni_generator/jni_generator.pydeps',
652 'base/android/jni_generator/jni_registration_generator.pydeps',
653 'build/android/gyp/aar.pydeps',
654 'build/android/gyp/aidl.pydeps',
655 'build/android/gyp/apkbuilder.pydeps',
656 'build/android/gyp/app_bundle_to_apks.pydeps',
657 'build/android/gyp/bytecode_processor.pydeps',
658 'build/android/gyp/compile_resources.pydeps',
659 'build/android/gyp/create_bundle_wrapper_script.pydeps',
660 'build/android/gyp/copy_ex.pydeps',
661 'build/android/gyp/create_app_bundle.pydeps',
662 'build/android/gyp/create_apk_operations_script.pydeps',
663 'build/android/gyp/create_dist_jar.pydeps',
664 'build/android/gyp/create_java_binary_script.pydeps',
665 'build/android/gyp/create_stack_script.pydeps',
666 'build/android/gyp/create_test_runner_script.pydeps',
667 'build/android/gyp/create_tool_wrapper.pydeps',
668 'build/android/gyp/desugar.pydeps',
669 'build/android/gyp/dex.pydeps',
670 'build/android/gyp/dist_aar.pydeps',
671 'build/android/gyp/emma_instr.pydeps',
672 'build/android/gyp/filter_zip.pydeps',
673 'build/android/gyp/gcc_preprocess.pydeps',
674 'build/android/gyp/generate_proguarded_module_jar.pydeps',
675 'build/android/gyp/ijar.pydeps',
676 'build/android/gyp/java_cpp_enum.pydeps',
677 'build/android/gyp/javac.pydeps',
678 'build/android/gyp/jinja_template.pydeps',
679 'build/android/gyp/lint.pydeps',
680 'build/android/gyp/main_dex_list.pydeps',
681 'build/android/gyp/merge_jar_info_files.pydeps',
682 'build/android/gyp/merge_manifest.pydeps',
683 'build/android/gyp/prepare_resources.pydeps',
684 'build/android/gyp/proguard.pydeps',
685 'build/android/gyp/write_build_config.pydeps',
686 'build/android/gyp/write_ordered_libraries.pydeps',
687 'build/android/incremental_install/generate_android_manifest.pydeps',
688 'build/android/incremental_install/write_installer_json.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22689 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:40690 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04691 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36692 'build/protoc_java.pydeps',
jbudorick276cc562017-04-29 01:34:58693 'build/secondary/third_party/android_platform/'
694 'development/scripts/stack.pydeps',
agrieve732db3a2016-04-26 19:18:19695 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40696]
697
wnwenbdc444e2016-05-25 13:44:15698
agrievef32bcc72016-04-04 14:57:40699_GENERIC_PYDEPS_FILES = [
John Chencde89192018-01-27 21:18:40700 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Cole Winstanley7045a1b2018-08-27 23:37:29701 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22702 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:40703]
704
wnwenbdc444e2016-05-25 13:44:15705
agrievef32bcc72016-04-04 14:57:40706_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
707
708
Eric Boren6fd2b932018-01-25 15:05:08709# Bypass the AUTHORS check for these accounts.
710_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:29711 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
712 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:08713 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
Eric Boren57cc805b2018-08-20 17:28:32714 'spirv', 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:59715 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:45716 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:59717 ) | set('%[email protected]' % s
Robert Ma7f024172018-11-01 20:59:22718 for s in ('v8-ci-autoroll-builder', 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:04719 ) | set('%[email protected]' % s
720 for s in ('chromium-autoroll',)
721 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:30722 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:08723
724
[email protected]55459852011-08-10 15:17:19725def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
726 """Attempts to prevent use of functions intended only for testing in
727 non-testing code. For now this is just a best-effort implementation
728 that ignores header files and may have some false positives. A
729 better implementation would probably need a proper C++ parser.
730 """
731 # We only scan .cc files and the like, as the declaration of
732 # for-testing functions in header files are hard to distinguish from
733 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49734 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:19735
jochenc0d4808c2015-07-27 09:25:42736 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19737 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09738 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19739 exclusion_pattern = input_api.re.compile(
740 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
741 base_function_pattern, base_function_pattern))
742
743 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44744 black_list = (_EXCLUDED_PATHS +
745 _TEST_CODE_EXCLUDED_PATHS +
746 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19747 return input_api.FilterSourceFile(
748 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49749 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:19750 black_list=black_list)
751
752 problems = []
753 for f in input_api.AffectedSourceFiles(FilterFile):
754 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24755 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03756 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46757 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03758 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19759 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03760 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19761
762 if problems:
[email protected]f7051d52013-04-02 18:31:42763 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03764 else:
765 return []
[email protected]55459852011-08-10 15:17:19766
767
Vaclav Brozek7dbc28c2018-03-27 08:35:23768def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
769 """This is a simplified version of
770 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
771 """
772 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
773 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
774 name_pattern = r'ForTest(s|ing)?'
775 # Describes an occurrence of "ForTest*" inside a // comment.
776 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
777 # Catch calls.
778 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
779 # Ignore definitions. (Comments are ignored separately.)
780 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
781
782 problems = []
783 sources = lambda x: input_api.FilterSourceFile(
784 x,
785 black_list=(('(?i).*test', r'.*\/junit\/')
786 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49787 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:23788 )
789 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
790 local_path = f.LocalPath()
791 is_inside_javadoc = False
792 for line_number, line in f.ChangedContents():
793 if is_inside_javadoc and javadoc_end_re.search(line):
794 is_inside_javadoc = False
795 if not is_inside_javadoc and javadoc_start_re.search(line):
796 is_inside_javadoc = True
797 if is_inside_javadoc:
798 continue
799 if (inclusion_re.search(line) and
800 not comment_re.search(line) and
801 not exclusion_re.search(line)):
802 problems.append(
803 '%s:%d\n %s' % (local_path, line_number, line.strip()))
804
805 if problems:
806 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
807 else:
808 return []
809
810
[email protected]10689ca2011-09-02 02:31:54811def _CheckNoIOStreamInHeaders(input_api, output_api):
812 """Checks to make sure no .h files include <iostream>."""
813 files = []
814 pattern = input_api.re.compile(r'^#include\s*<iostream>',
815 input_api.re.MULTILINE)
816 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
817 if not f.LocalPath().endswith('.h'):
818 continue
819 contents = input_api.ReadFile(f)
820 if pattern.search(contents):
821 files.append(f)
822
823 if len(files):
yolandyandaabc6d2016-04-18 18:29:39824 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06825 'Do not #include <iostream> in header files, since it inserts static '
826 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54827 '#include <ostream>. See http://crbug.com/94794',
828 files) ]
829 return []
830
Danil Chapovalov3518f362018-08-11 16:13:43831def _CheckNoStrCatRedefines(input_api, output_api):
832 """Checks no windows headers with StrCat redefined are included directly."""
833 files = []
834 pattern_deny = input_api.re.compile(
835 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
836 input_api.re.MULTILINE)
837 pattern_allow = input_api.re.compile(
838 r'^#include\s"base/win/windows_defines.inc"',
839 input_api.re.MULTILINE)
840 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
841 contents = input_api.ReadFile(f)
842 if pattern_deny.search(contents) and not pattern_allow.search(contents):
843 files.append(f.LocalPath())
844
845 if len(files):
846 return [output_api.PresubmitError(
847 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
848 'directly since they pollute code with StrCat macro. Instead, '
849 'include matching header from base/win. See http://crbug.com/856536',
850 files) ]
851 return []
852
[email protected]10689ca2011-09-02 02:31:54853
[email protected]72df4e782012-06-21 16:28:18854def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52855 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18856 problems = []
857 for f in input_api.AffectedFiles():
858 if (not f.LocalPath().endswith(('.cc', '.mm'))):
859 continue
860
861 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04862 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18863 problems.append(' %s:%d' % (f.LocalPath(), line_num))
864
865 if not problems:
866 return []
867 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
868 '\n'.join(problems))]
869
Dominic Battre033531052018-09-24 15:45:34870def _CheckNoDISABLETypoInTests(input_api, output_api):
871 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
872
873 This test warns if somebody tries to disable a test with the DISABLE_ prefix
874 instead of DISABLED_. To filter false positives, reports are only generated
875 if a corresponding MAYBE_ line exists.
876 """
877 problems = []
878
879 # The following two patterns are looked for in tandem - is a test labeled
880 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
881 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
882 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
883
884 # This is for the case that a test is disabled on all platforms.
885 full_disable_pattern = input_api.re.compile(
886 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
887 input_api.re.MULTILINE)
888
Katie Df13948e2018-09-25 07:33:44889 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:34890 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
891 continue
892
893 # Search for MABYE_, DISABLE_ pairs.
894 disable_lines = {} # Maps of test name to line number.
895 maybe_lines = {}
896 for line_num, line in f.ChangedContents():
897 disable_match = disable_pattern.search(line)
898 if disable_match:
899 disable_lines[disable_match.group(1)] = line_num
900 maybe_match = maybe_pattern.search(line)
901 if maybe_match:
902 maybe_lines[maybe_match.group(1)] = line_num
903
904 # Search for DISABLE_ occurrences within a TEST() macro.
905 disable_tests = set(disable_lines.keys())
906 maybe_tests = set(maybe_lines.keys())
907 for test in disable_tests.intersection(maybe_tests):
908 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
909
910 contents = input_api.ReadFile(f)
911 full_disable_match = full_disable_pattern.search(contents)
912 if full_disable_match:
913 problems.append(' %s' % f.LocalPath())
914
915 if not problems:
916 return []
917 return [
918 output_api.PresubmitPromptWarning(
919 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
920 '\n'.join(problems))
921 ]
922
[email protected]72df4e782012-06-21 16:28:18923
danakj61c1aa22015-10-26 19:55:52924def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57925 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52926 errors = []
927 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
928 input_api.re.MULTILINE)
929 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
930 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
931 continue
932 for lnum, line in f.ChangedContents():
933 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17934 errors.append(output_api.PresubmitError(
935 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57936 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17937 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52938 return errors
939
940
mcasasb7440c282015-02-04 14:52:19941def _FindHistogramNameInLine(histogram_name, line):
942 """Tries to find a histogram name or prefix in a line."""
943 if not "affected-histogram" in line:
944 return histogram_name in line
945 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
946 # the histogram_name.
947 if not '"' in line:
948 return False
949 histogram_prefix = line.split('\"')[1]
950 return histogram_prefix in histogram_name
951
952
953def _CheckUmaHistogramChanges(input_api, output_api):
954 """Check that UMA histogram names in touched lines can still be found in other
955 lines of the patch or in histograms.xml. Note that this check would not catch
956 the reverse: changes in histograms.xml not matched in the code itself."""
957 touched_histograms = []
958 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:47959 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
960 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
961 name_pattern = r'"(.*?)"'
962 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
963 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
964 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
965 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
966 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:17967 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:19968 for f in input_api.AffectedFiles():
969 # If histograms.xml itself is modified, keep the modified lines for later.
970 if f.LocalPath().endswith(('histograms.xml')):
971 histograms_xml_modifications = f.ChangedContents()
972 continue
Vaclav Brozekbdac817c2018-03-24 06:30:47973 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
974 single_line_re = single_line_c_re
975 split_line_prefix_re = split_line_c_prefix_re
976 elif f.LocalPath().endswith(('java')):
977 single_line_re = single_line_java_re
978 split_line_prefix_re = split_line_java_prefix_re
979 else:
mcasasb7440c282015-02-04 14:52:19980 continue
981 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:17982 if last_line_matched_prefix:
983 suffix_found = split_line_suffix_re.search(line)
984 if suffix_found :
985 touched_histograms.append([suffix_found.group(1), f, line_num])
986 last_line_matched_prefix = False
987 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:06988 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:19989 if found:
990 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:17991 continue
992 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:19993
994 # Search for the touched histogram names in the local modifications to
995 # histograms.xml, and, if not found, on the base histograms.xml file.
996 unmatched_histograms = []
997 for histogram_info in touched_histograms:
998 histogram_name_found = False
999 for line_num, line in histograms_xml_modifications:
1000 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
1001 if histogram_name_found:
1002 break
1003 if not histogram_name_found:
1004 unmatched_histograms.append(histogram_info)
1005
eromanb90c82e7e32015-04-01 15:13:491006 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191007 problems = []
1008 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491009 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191010 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451011 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191012 histogram_name_found = False
1013 for line in histograms_xml:
1014 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
1015 if histogram_name_found:
1016 break
1017 if not histogram_name_found:
1018 problems.append(' [%s:%d] %s' %
1019 (f.LocalPath(), line_num, histogram_name))
1020
1021 if not problems:
1022 return []
1023 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1024 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491025 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191026
wnwenbdc444e2016-05-25 13:44:151027
yolandyandaabc6d2016-04-18 18:29:391028def _CheckFlakyTestUsage(input_api, output_api):
1029 """Check that FlakyTest annotation is our own instead of the android one"""
1030 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1031 files = []
1032 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1033 if f.LocalPath().endswith('Test.java'):
1034 if pattern.search(input_api.ReadFile(f)):
1035 files.append(f)
1036 if len(files):
1037 return [output_api.PresubmitError(
1038 'Use org.chromium.base.test.util.FlakyTest instead of '
1039 'android.test.FlakyTest',
1040 files)]
1041 return []
mcasasb7440c282015-02-04 14:52:191042
wnwenbdc444e2016-05-25 13:44:151043
[email protected]8ea5d4b2011-09-13 21:49:221044def _CheckNoNewWStrings(input_api, output_api):
1045 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271046 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221047 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201048 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571049 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341050 '/win/' in f.LocalPath() or
1051 'chrome_elf' in f.LocalPath() or
1052 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201053 continue
[email protected]8ea5d4b2011-09-13 21:49:221054
[email protected]a11dbe9b2012-08-07 01:32:581055 allowWString = False
[email protected]b5c24292011-11-28 14:38:201056 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581057 if 'presubmit: allow wstring' in line:
1058 allowWString = True
1059 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271060 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581061 allowWString = False
1062 else:
1063 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221064
[email protected]55463aa62011-10-12 00:48:271065 if not problems:
1066 return []
1067 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581068 ' If you are calling a cross-platform API that accepts a wstring, '
1069 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271070 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221071
1072
[email protected]2a8ac9c2011-10-19 17:20:441073def _CheckNoDEPSGIT(input_api, output_api):
1074 """Make sure .DEPS.git is never modified manually."""
1075 if any(f.LocalPath().endswith('.DEPS.git') for f in
1076 input_api.AffectedFiles()):
1077 return [output_api.PresubmitError(
1078 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1079 'automated system based on what\'s in DEPS and your changes will be\n'
1080 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501081 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1082 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441083 'for more information')]
1084 return []
1085
1086
tandriief664692014-09-23 14:51:471087def _CheckValidHostsInDEPS(input_api, output_api):
1088 """Checks that DEPS file deps are from allowed_hosts."""
1089 # Run only if DEPS file has been modified to annoy fewer bystanders.
1090 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1091 return []
1092 # Outsource work to gclient verify
1093 try:
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201094 input_api.subprocess.check_output(['gclient', 'verify'],
1095 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471096 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201097 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471098 return [output_api.PresubmitError(
1099 'DEPS file must have only git dependencies.',
1100 long_text=error.output)]
1101
1102
[email protected]127f18ec2012-06-16 05:05:591103def _CheckNoBannedFunctions(input_api, output_api):
1104 """Make sure that banned functions are not used."""
1105 warnings = []
1106 errors = []
1107
wnwenbdc444e2016-05-25 13:44:151108 def IsBlacklisted(affected_file, blacklist):
1109 local_path = affected_file.LocalPath()
1110 for item in blacklist:
1111 if input_api.re.match(item, local_path):
1112 return True
1113 return False
1114
Sylvain Defresnea8b73d252018-02-28 15:45:541115 def IsIosObcjFile(affected_file):
1116 local_path = affected_file.LocalPath()
1117 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1118 return False
1119 basename = input_api.os_path.basename(local_path)
1120 if 'ios' in basename.split('_'):
1121 return True
1122 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1123 if sep and 'ios' in local_path.split(sep):
1124 return True
1125 return False
1126
wnwenbdc444e2016-05-25 13:44:151127 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
1128 matched = False
1129 if func_name[0:1] == '/':
1130 regex = func_name[1:]
1131 if input_api.re.search(regex, line):
1132 matched = True
1133 elif func_name in line:
dchenge07de812016-06-20 19:27:171134 matched = True
wnwenbdc444e2016-05-25 13:44:151135 if matched:
dchenge07de812016-06-20 19:27:171136 problems = warnings
wnwenbdc444e2016-05-25 13:44:151137 if error:
dchenge07de812016-06-20 19:27:171138 problems = errors
wnwenbdc444e2016-05-25 13:44:151139 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1140 for message_line in message:
1141 problems.append(' %s' % message_line)
1142
Eric Stevensona9a980972017-09-23 00:04:411143 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1144 for f in input_api.AffectedFiles(file_filter=file_filter):
1145 for line_num, line in f.ChangedContents():
1146 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1147 CheckForMatch(f, line_num, line, func_name, message, error)
1148
[email protected]127f18ec2012-06-16 05:05:591149 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1150 for f in input_api.AffectedFiles(file_filter=file_filter):
1151 for line_num, line in f.ChangedContents():
1152 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151153 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591154
Sylvain Defresnea8b73d252018-02-28 15:45:541155 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1156 for line_num, line in f.ChangedContents():
1157 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1158 CheckForMatch(f, line_num, line, func_name, message, error)
1159
[email protected]127f18ec2012-06-16 05:05:591160 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1161 for f in input_api.AffectedFiles(file_filter=file_filter):
1162 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491163 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491164 if IsBlacklisted(f, excluded_paths):
1165 continue
wnwenbdc444e2016-05-25 13:44:151166 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591167
1168 result = []
1169 if (warnings):
1170 result.append(output_api.PresubmitPromptWarning(
1171 'Banned functions were used.\n' + '\n'.join(warnings)))
1172 if (errors):
1173 result.append(output_api.PresubmitError(
1174 'Banned functions were used.\n' + '\n'.join(errors)))
1175 return result
1176
1177
[email protected]6c063c62012-07-11 19:11:061178def _CheckNoPragmaOnce(input_api, output_api):
1179 """Make sure that banned functions are not used."""
1180 files = []
1181 pattern = input_api.re.compile(r'^#pragma\s+once',
1182 input_api.re.MULTILINE)
1183 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1184 if not f.LocalPath().endswith('.h'):
1185 continue
1186 contents = input_api.ReadFile(f)
1187 if pattern.search(contents):
1188 files.append(f)
1189
1190 if files:
1191 return [output_api.PresubmitError(
1192 'Do not use #pragma once in header files.\n'
1193 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1194 files)]
1195 return []
1196
[email protected]127f18ec2012-06-16 05:05:591197
[email protected]e7479052012-09-19 00:26:121198def _CheckNoTrinaryTrueFalse(input_api, output_api):
1199 """Checks to make sure we don't introduce use of foo ? true : false."""
1200 problems = []
1201 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1202 for f in input_api.AffectedFiles():
1203 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1204 continue
1205
1206 for line_num, line in f.ChangedContents():
1207 if pattern.match(line):
1208 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1209
1210 if not problems:
1211 return []
1212 return [output_api.PresubmitPromptWarning(
1213 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1214 '\n'.join(problems))]
1215
1216
[email protected]55f9f382012-07-31 11:02:181217def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281218 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181219 change. Breaking - rules is an error, breaking ! rules is a
1220 warning.
1221 """
mohan.reddyf21db962014-10-16 12:26:471222 import sys
[email protected]55f9f382012-07-31 11:02:181223 # We need to wait until we have an input_api object and use this
1224 # roundabout construct to import checkdeps because this file is
1225 # eval-ed and thus doesn't have __file__.
1226 original_sys_path = sys.path
1227 try:
1228 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471229 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181230 import checkdeps
1231 from cpp_checker import CppChecker
Jinsuk Kim5a092672017-10-24 22:42:241232 from java_checker import JavaChecker
rhalavati08acd232017-04-03 07:23:281233 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:181234 from rules import Rule
1235 finally:
1236 # Restore sys.path to what it was before.
1237 sys.path = original_sys_path
1238
1239 added_includes = []
rhalavati08acd232017-04-03 07:23:281240 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241241 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181242 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:281243 if CppChecker.IsCppFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501244 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081245 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
rhalavati08acd232017-04-03 07:23:281246 elif ProtoChecker.IsProtoFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501247 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081248 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241249 elif JavaChecker.IsJavaFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501250 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081251 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181252
[email protected]26385172013-05-09 23:11:351253 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181254
1255 error_descriptions = []
1256 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281257 error_subjects = set()
1258 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181259 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1260 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081261 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181262 description_with_path = '%s\n %s' % (path, rule_description)
1263 if rule_type == Rule.DISALLOW:
1264 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281265 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181266 else:
1267 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281268 warning_subjects.add("#includes")
1269
1270 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1271 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081272 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281273 description_with_path = '%s\n %s' % (path, rule_description)
1274 if rule_type == Rule.DISALLOW:
1275 error_descriptions.append(description_with_path)
1276 error_subjects.add("imports")
1277 else:
1278 warning_descriptions.append(description_with_path)
1279 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181280
Jinsuk Kim5a092672017-10-24 22:42:241281 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021282 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081283 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241284 description_with_path = '%s\n %s' % (path, rule_description)
1285 if rule_type == Rule.DISALLOW:
1286 error_descriptions.append(description_with_path)
1287 error_subjects.add("imports")
1288 else:
1289 warning_descriptions.append(description_with_path)
1290 warning_subjects.add("imports")
1291
[email protected]55f9f382012-07-31 11:02:181292 results = []
1293 if error_descriptions:
1294 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281295 'You added one or more %s that violate checkdeps rules.'
1296 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181297 error_descriptions))
1298 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421299 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281300 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181301 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281302 '%s? See relevant DEPS file(s) for details and contacts.' %
1303 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181304 warning_descriptions))
1305 return results
1306
1307
[email protected]fbcafe5a2012-08-08 15:31:221308def _CheckFilePermissions(input_api, output_api):
1309 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151310 if input_api.platform == 'win32':
1311 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291312 checkperms_tool = input_api.os_path.join(
1313 input_api.PresubmitLocalPath(),
1314 'tools', 'checkperms', 'checkperms.py')
1315 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471316 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391317 with input_api.CreateTemporaryFile() as file_list:
1318 for f in input_api.AffectedFiles():
1319 # checkperms.py file/directory arguments must be relative to the
1320 # repository.
1321 file_list.write(f.LocalPath() + '\n')
1322 file_list.close()
1323 args += ['--file-list', file_list.name]
1324 try:
1325 input_api.subprocess.check_output(args)
1326 return []
1327 except input_api.subprocess.CalledProcessError as error:
1328 return [output_api.PresubmitError(
1329 'checkperms.py failed:',
1330 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221331
1332
robertocn832f5992017-01-04 19:01:301333def _CheckTeamTags(input_api, output_api):
1334 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1335 checkteamtags_tool = input_api.os_path.join(
1336 input_api.PresubmitLocalPath(),
1337 'tools', 'checkteamtags', 'checkteamtags.py')
1338 args = [input_api.python_executable, checkteamtags_tool,
1339 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221340 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301341 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1342 'OWNERS']
1343 try:
1344 if files:
1345 input_api.subprocess.check_output(args + files)
1346 return []
1347 except input_api.subprocess.CalledProcessError as error:
1348 return [output_api.PresubmitError(
1349 'checkteamtags.py failed:',
1350 long_text=error.output)]
1351
1352
[email protected]c8278b32012-10-30 20:35:491353def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1354 """Makes sure we don't include ui/aura/window_property.h
1355 in header files.
1356 """
1357 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1358 errors = []
1359 for f in input_api.AffectedFiles():
1360 if not f.LocalPath().endswith('.h'):
1361 continue
1362 for line_num, line in f.ChangedContents():
1363 if pattern.match(line):
1364 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1365
1366 results = []
1367 if errors:
1368 results.append(output_api.PresubmitError(
1369 'Header files should not include ui/aura/window_property.h', errors))
1370 return results
1371
1372
[email protected]70ca77752012-11-20 03:45:031373def _CheckForVersionControlConflictsInFile(input_api, f):
1374 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1375 errors = []
1376 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:231377 if f.LocalPath().endswith('.md'):
1378 # First-level headers in markdown look a lot like version control
1379 # conflict markers. http://daringfireball.net/projects/markdown/basics
1380 continue
[email protected]70ca77752012-11-20 03:45:031381 if pattern.match(line):
1382 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1383 return errors
1384
1385
1386def _CheckForVersionControlConflicts(input_api, output_api):
1387 """Usually this is not intentional and will cause a compile failure."""
1388 errors = []
1389 for f in input_api.AffectedFiles():
1390 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1391
1392 results = []
1393 if errors:
1394 results.append(output_api.PresubmitError(
1395 'Version control conflict markers found, please resolve.', errors))
1396 return results
1397
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201398
estadee17314a02017-01-12 16:22:161399def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1400 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1401 errors = []
1402 for f in input_api.AffectedFiles():
1403 for line_num, line in f.ChangedContents():
1404 if pattern.search(line):
1405 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1406
1407 results = []
1408 if errors:
1409 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501410 'Found Google support URL addressed by answer number. Please replace '
1411 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161412 return results
1413
[email protected]70ca77752012-11-20 03:45:031414
[email protected]06e6d0ff2012-12-11 01:36:441415def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1416 def FilterFile(affected_file):
1417 """Filter function for use with input_api.AffectedSourceFiles,
1418 below. This filters out everything except non-test files from
1419 top-level directories that generally speaking should not hard-code
1420 service URLs (e.g. src/android_webview/, src/content/ and others).
1421 """
1422 return input_api.FilterSourceFile(
1423 affected_file,
Egor Paskoce145c42018-09-28 19:31:041424 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:441425 black_list=(_EXCLUDED_PATHS +
1426 _TEST_CODE_EXCLUDED_PATHS +
1427 input_api.DEFAULT_BLACK_LIST))
1428
reillyi38965732015-11-16 18:27:331429 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1430 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461431 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1432 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441433 problems = [] # items are (filename, line_number, line)
1434 for f in input_api.AffectedSourceFiles(FilterFile):
1435 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461436 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441437 problems.append((f.LocalPath(), line_num, line))
1438
1439 if problems:
[email protected]f7051d52013-04-02 18:31:421440 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441441 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581442 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441443 [' %s:%d: %s' % (
1444 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031445 else:
1446 return []
[email protected]06e6d0ff2012-12-11 01:36:441447
1448
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491449# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:271450def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1451 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311452 The native_client_sdk directory is excluded because it has auto-generated PNG
1453 files for documentation.
[email protected]d2530012013-01-25 16:39:271454 """
[email protected]d2530012013-01-25 16:39:271455 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491456 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:041457 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:311458 file_filter = lambda f: input_api.FilterSourceFile(
1459 f, white_list=white_list, black_list=black_list)
1460 for f in input_api.AffectedFiles(include_deletes=False,
1461 file_filter=file_filter):
1462 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271463
1464 results = []
1465 if errors:
1466 results.append(output_api.PresubmitError(
1467 'The name of PNG files should not have abbreviations. \n'
1468 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1469 'Contact [email protected] if you have questions.', errors))
1470 return results
1471
1472
Daniel Cheng4dcdb6b2017-04-13 08:30:171473def _ExtractAddRulesFromParsedDeps(parsed_deps):
1474 """Extract the rules that add dependencies from a parsed DEPS file.
1475
1476 Args:
1477 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1478 add_rules = set()
1479 add_rules.update([
1480 rule[1:] for rule in parsed_deps.get('include_rules', [])
1481 if rule.startswith('+') or rule.startswith('!')
1482 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501483 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171484 {}).iteritems():
1485 add_rules.update([
1486 rule[1:] for rule in rules
1487 if rule.startswith('+') or rule.startswith('!')
1488 ])
1489 return add_rules
1490
1491
1492def _ParseDeps(contents):
1493 """Simple helper for parsing DEPS files."""
1494 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171495 class _VarImpl:
1496
1497 def __init__(self, local_scope):
1498 self._local_scope = local_scope
1499
1500 def Lookup(self, var_name):
1501 """Implements the Var syntax."""
1502 try:
1503 return self._local_scope['vars'][var_name]
1504 except KeyError:
1505 raise Exception('Var is not defined: %s' % var_name)
1506
1507 local_scope = {}
1508 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171509 'Var': _VarImpl(local_scope).Lookup,
1510 }
1511 exec contents in global_scope, local_scope
1512 return local_scope
1513
1514
1515def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081516 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411517 a set of DEPS entries that we should look up.
1518
1519 For a directory (rather than a specific filename) we fake a path to
1520 a specific filename by adding /DEPS. This is chosen as a file that
1521 will seldom or never be subject to per-file include_rules.
1522 """
[email protected]2b438d62013-11-14 17:54:141523 # We ignore deps entries on auto-generated directories.
1524 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081525
Daniel Cheng4dcdb6b2017-04-13 08:30:171526 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1527 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1528
1529 added_deps = new_deps.difference(old_deps)
1530
[email protected]2b438d62013-11-14 17:54:141531 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171532 for added_dep in added_deps:
1533 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1534 continue
1535 # Assume that a rule that ends in .h is a rule for a specific file.
1536 if added_dep.endswith('.h'):
1537 results.add(added_dep)
1538 else:
1539 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081540 return results
1541
1542
[email protected]e871964c2013-05-13 14:14:551543def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1544 """When a dependency prefixed with + is added to a DEPS file, we
1545 want to make sure that the change is reviewed by an OWNER of the
1546 target file or directory, to avoid layering violations from being
1547 introduced. This check verifies that this happens.
1548 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171549 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241550
1551 file_filter = lambda f: not input_api.re.match(
Egor Paskoce145c42018-09-28 19:31:041552 r"^third_party[\\/](WebKit|blink)[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241553 for f in input_api.AffectedFiles(include_deletes=False,
1554 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551555 filename = input_api.os_path.basename(f.LocalPath())
1556 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171557 virtual_depended_on_files.update(_CalculateAddedDeps(
1558 input_api.os_path,
1559 '\n'.join(f.OldContents()),
1560 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551561
[email protected]e871964c2013-05-13 14:14:551562 if not virtual_depended_on_files:
1563 return []
1564
1565 if input_api.is_committing:
1566 if input_api.tbr:
1567 return [output_api.PresubmitNotifyResult(
1568 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271569 if input_api.dry_run:
1570 return [output_api.PresubmitNotifyResult(
1571 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551572 if not input_api.change.issue:
1573 return [output_api.PresubmitError(
1574 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401575 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551576 output = output_api.PresubmitError
1577 else:
1578 output = output_api.PresubmitNotifyResult
1579
1580 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501581 owner_email, reviewers = (
1582 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1583 input_api,
1584 owners_db.email_regexp,
1585 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551586
1587 owner_email = owner_email or input_api.change.author_email
1588
[email protected]de4f7d22013-05-23 14:27:461589 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511590 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461591 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551592 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1593 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411594
1595 # We strip the /DEPS part that was added by
1596 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1597 # directory.
1598 def StripDeps(path):
1599 start_deps = path.rfind('/DEPS')
1600 if start_deps != -1:
1601 return path[:start_deps]
1602 else:
1603 return path
1604 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551605 for path in missing_files]
1606
1607 if unapproved_dependencies:
1608 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151609 output('You need LGTM from owners of depends-on paths in DEPS that were '
1610 'modified in this CL:\n %s' %
1611 '\n '.join(sorted(unapproved_dependencies)))]
1612 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1613 output_list.append(output(
1614 'Suggested missing target path OWNERS:\n %s' %
1615 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551616 return output_list
1617
1618 return []
1619
1620
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491621# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:401622def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491623 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:401624 black_list = (_EXCLUDED_PATHS +
1625 _TEST_CODE_EXCLUDED_PATHS +
1626 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:041627 (r"^base[\\/]logging\.h$",
1628 r"^base[\\/]logging\.cc$",
1629 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
1630 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
1631 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:121632 r"startup_browser_creator\.cc$",
Egor Paskoce145c42018-09-28 19:31:041633 r"^chrome[\\/]installer[\\/]setup[\\/].*",
1634 r"^chrome[\\/]chrome_cleaner[\\/].*",
1635 r"chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031636 r"diagnostics_writer\.cc$",
Egor Paskoce145c42018-09-28 19:31:041637 r"^chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
1638 r"^chromecast[\\/]",
1639 r"^cloud_print[\\/]",
1640 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:481641 r"dump_stability_report_main_win.cc$",
Egor Paskoce145c42018-09-28 19:31:041642 r"^components[\\/]html_viewer[\\/]"
jochen34415e52015-07-10 08:34:311643 r"web_test_delegate_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041644 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:461645 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:041646 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:461647 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041648 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:251649 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:041650 r"^courgette[\\/]courgette_minimal_tool\.cc$",
1651 r"^courgette[\\/]courgette_tool\.cc$",
1652 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
1653 r"^ipc[\\/]ipc_logging\.cc$",
1654 r"^native_client_sdk[\\/]",
1655 r"^remoting[\\/]base[\\/]logging\.h$",
1656 r"^remoting[\\/]host[\\/].*",
1657 r"^sandbox[\\/]linux[\\/].*",
1658 r"^tools[\\/]",
1659 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
1660 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
1661 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
Kevin Marshalla139bcc2018-11-09 02:26:361662 r"^webrunner[\\/]browser[\\/]frame_impl.cc$",
Egor Paskoce145c42018-09-28 19:31:041663 r"^storage[\\/]browser[\\/]fileapi[\\/]" +
skyostil87681be82016-12-19 12:46:351664 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:041665 r"^headless[\\/]app[\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401666 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491667 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:401668
thomasanderson625d3932017-03-29 07:16:581669 log_info = set([])
1670 printf = set([])
[email protected]85218562013-11-22 07:41:401671
1672 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581673 for _, line in f.ChangedContents():
1674 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1675 log_info.add(f.LocalPath())
1676 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1677 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371678
thomasanderson625d3932017-03-29 07:16:581679 if input_api.re.search(r"\bprintf\(", line):
1680 printf.add(f.LocalPath())
1681 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1682 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401683
1684 if log_info:
1685 return [output_api.PresubmitError(
1686 'These files spam the console log with LOG(INFO):',
1687 items=log_info)]
1688 if printf:
1689 return [output_api.PresubmitError(
1690 'These files spam the console log with printf/fprintf:',
1691 items=printf)]
1692 return []
1693
1694
[email protected]49aa76a2013-12-04 06:59:161695def _CheckForAnonymousVariables(input_api, output_api):
1696 """These types are all expected to hold locks while in scope and
1697 so should never be anonymous (which causes them to be immediately
1698 destroyed)."""
1699 they_who_must_be_named = [
1700 'base::AutoLock',
1701 'base::AutoReset',
1702 'base::AutoUnlock',
1703 'SkAutoAlphaRestore',
1704 'SkAutoBitmapShaderInstall',
1705 'SkAutoBlitterChoose',
1706 'SkAutoBounderCommit',
1707 'SkAutoCallProc',
1708 'SkAutoCanvasRestore',
1709 'SkAutoCommentBlock',
1710 'SkAutoDescriptor',
1711 'SkAutoDisableDirectionCheck',
1712 'SkAutoDisableOvalCheck',
1713 'SkAutoFree',
1714 'SkAutoGlyphCache',
1715 'SkAutoHDC',
1716 'SkAutoLockColors',
1717 'SkAutoLockPixels',
1718 'SkAutoMalloc',
1719 'SkAutoMaskFreeImage',
1720 'SkAutoMutexAcquire',
1721 'SkAutoPathBoundsUpdate',
1722 'SkAutoPDFRelease',
1723 'SkAutoRasterClipValidate',
1724 'SkAutoRef',
1725 'SkAutoTime',
1726 'SkAutoTrace',
1727 'SkAutoUnref',
1728 ]
1729 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1730 # bad: base::AutoLock(lock.get());
1731 # not bad: base::AutoLock lock(lock.get());
1732 bad_pattern = input_api.re.compile(anonymous)
1733 # good: new base::AutoLock(lock.get())
1734 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1735 errors = []
1736
1737 for f in input_api.AffectedFiles():
1738 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1739 continue
1740 for linenum, line in f.ChangedContents():
1741 if bad_pattern.search(line) and not good_pattern.search(line):
1742 errors.append('%s:%d' % (f.LocalPath(), linenum))
1743
1744 if errors:
1745 return [output_api.PresubmitError(
1746 'These lines create anonymous variables that need to be named:',
1747 items=errors)]
1748 return []
1749
1750
Peter Kasting4844e46e2018-02-23 07:27:101751def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:531752 # Returns whether |template_str| is of the form <T, U...> for some types T
1753 # and U. Assumes that |template_str| is already in the form <...>.
1754 def HasMoreThanOneArg(template_str):
1755 # Level of <...> nesting.
1756 nesting = 0
1757 for c in template_str:
1758 if c == '<':
1759 nesting += 1
1760 elif c == '>':
1761 nesting -= 1
1762 elif c == ',' and nesting == 1:
1763 return True
1764 return False
1765
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491766 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:101767 sources = lambda affected_file: input_api.FilterSourceFile(
1768 affected_file,
1769 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1770 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491771 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:551772
1773 # Pattern to capture a single "<...>" block of template arguments. It can
1774 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
1775 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
1776 # latter would likely require counting that < and > match, which is not
1777 # expressible in regular languages. Should the need arise, one can introduce
1778 # limited counting (matching up to a total number of nesting depth), which
1779 # should cover all practical cases for already a low nesting limit.
1780 template_arg_pattern = (
1781 r'<[^>]*' # Opening block of <.
1782 r'>([^<]*>)?') # Closing block of >.
1783 # Prefix expressing that whatever follows is not already inside a <...>
1784 # block.
1785 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:101786 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:551787 not_inside_template_arg_pattern
1788 + r'\bstd::unique_ptr'
1789 + template_arg_pattern
1790 + r'\(\)')
1791
1792 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
1793 template_arg_no_array_pattern = (
1794 r'<[^>]*[^]]' # Opening block of <.
1795 r'>([^(<]*[^]]>)?') # Closing block of >.
1796 # Prefix saying that what follows is the start of an expression.
1797 start_of_expr_pattern = r'(=|\breturn|^)\s*'
1798 # Suffix saying that what follows are call parentheses with a non-empty list
1799 # of arguments.
1800 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:531801 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:551802 return_construct_pattern = input_api.re.compile(
1803 start_of_expr_pattern
1804 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:531805 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:551806 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:531807 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:551808 + nonempty_arg_list_pattern)
1809
Vaclav Brozek851d9602018-04-04 16:13:051810 problems_constructor = []
1811 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:101812 for f in input_api.AffectedSourceFiles(sources):
1813 for line_number, line in f.ChangedContents():
1814 # Disallow:
1815 # return std::unique_ptr<T>(foo);
1816 # bar = std::unique_ptr<T>(foo);
1817 # But allow:
1818 # return std::unique_ptr<T[]>(foo);
1819 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:531820 # And also allow cases when the second template argument is present. Those
1821 # cases cannot be handled by std::make_unique:
1822 # return std::unique_ptr<T, U>(foo);
1823 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:051824 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:531825 return_construct_result = return_construct_pattern.search(line)
1826 if return_construct_result and not HasMoreThanOneArg(
1827 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:051828 problems_constructor.append(
1829 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:101830 # Disallow:
1831 # std::unique_ptr<T>()
1832 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051833 problems_nullptr.append(
1834 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1835
1836 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:161837 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:051838 errors.append(output_api.PresubmitError(
1839 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161840 problems_nullptr))
1841 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:051842 errors.append(output_api.PresubmitError(
1843 'The following files use explicit std::unique_ptr constructor.'
1844 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161845 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:101846 return errors
1847
1848
[email protected]999261d2014-03-03 20:08:081849def _CheckUserActionUpdate(input_api, output_api):
1850 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521851 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081852 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521853 # If actions.xml is already included in the changelist, the PRESUBMIT
1854 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081855 return []
1856
[email protected]999261d2014-03-03 20:08:081857 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1858 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521859 current_actions = None
[email protected]999261d2014-03-03 20:08:081860 for f in input_api.AffectedFiles(file_filter=file_filter):
1861 for line_num, line in f.ChangedContents():
1862 match = input_api.re.search(action_re, line)
1863 if match:
[email protected]2f92dec2014-03-07 19:21:521864 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1865 # loaded only once.
1866 if not current_actions:
1867 with open('tools/metrics/actions/actions.xml') as actions_f:
1868 current_actions = actions_f.read()
1869 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081870 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521871 action = 'name="{0}"'.format(action_name)
1872 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081873 return [output_api.PresubmitPromptWarning(
1874 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521875 'tools/metrics/actions/actions.xml. Please run '
1876 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081877 % (f.LocalPath(), line_num, action_name))]
1878 return []
1879
1880
Daniel Cheng13ca61a882017-08-25 15:11:251881def _ImportJSONCommentEater(input_api):
1882 import sys
1883 sys.path = sys.path + [input_api.os_path.join(
1884 input_api.PresubmitLocalPath(),
1885 'tools', 'json_comment_eater')]
1886 import json_comment_eater
1887 return json_comment_eater
1888
1889
[email protected]99171a92014-06-03 08:44:471890def _GetJSONParseError(input_api, filename, eat_comments=True):
1891 try:
1892 contents = input_api.ReadFile(filename)
1893 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:251894 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:131895 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471896
1897 input_api.json.loads(contents)
1898 except ValueError as e:
1899 return e
1900 return None
1901
1902
1903def _GetIDLParseError(input_api, filename):
1904 try:
1905 contents = input_api.ReadFile(filename)
1906 idl_schema = input_api.os_path.join(
1907 input_api.PresubmitLocalPath(),
1908 'tools', 'json_schema_compiler', 'idl_schema.py')
1909 process = input_api.subprocess.Popen(
1910 [input_api.python_executable, idl_schema],
1911 stdin=input_api.subprocess.PIPE,
1912 stdout=input_api.subprocess.PIPE,
1913 stderr=input_api.subprocess.PIPE,
1914 universal_newlines=True)
1915 (_, error) = process.communicate(input=contents)
1916 return error or None
1917 except ValueError as e:
1918 return e
1919
1920
1921def _CheckParseErrors(input_api, output_api):
1922 """Check that IDL and JSON files do not contain syntax errors."""
1923 actions = {
1924 '.idl': _GetIDLParseError,
1925 '.json': _GetJSONParseError,
1926 }
[email protected]99171a92014-06-03 08:44:471927 # Most JSON files are preprocessed and support comments, but these do not.
1928 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:041929 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:471930 ]
1931 # Only run IDL checker on files in these directories.
1932 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:041933 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
1934 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:471935 ]
1936
1937 def get_action(affected_file):
1938 filename = affected_file.LocalPath()
1939 return actions.get(input_api.os_path.splitext(filename)[1])
1940
[email protected]99171a92014-06-03 08:44:471941 def FilterFile(affected_file):
1942 action = get_action(affected_file)
1943 if not action:
1944 return False
1945 path = affected_file.LocalPath()
1946
Sean Kau46e29bc2017-08-28 16:31:161947 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:471948 return False
1949
1950 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:161951 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:471952 return False
1953 return True
1954
1955 results = []
1956 for affected_file in input_api.AffectedFiles(
1957 file_filter=FilterFile, include_deletes=False):
1958 action = get_action(affected_file)
1959 kwargs = {}
1960 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:161961 _MatchesFile(input_api, json_no_comments_patterns,
1962 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:471963 kwargs['eat_comments'] = False
1964 parse_error = action(input_api,
1965 affected_file.AbsoluteLocalPath(),
1966 **kwargs)
1967 if parse_error:
1968 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1969 (affected_file.LocalPath(), parse_error)))
1970 return results
1971
1972
[email protected]760deea2013-12-10 19:33:491973def _CheckJavaStyle(input_api, output_api):
1974 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471975 import sys
[email protected]760deea2013-12-10 19:33:491976 original_sys_path = sys.path
1977 try:
1978 sys.path = sys.path + [input_api.os_path.join(
1979 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1980 import checkstyle
1981 finally:
1982 # Restore sys.path to what it was before.
1983 sys.path = original_sys_path
1984
1985 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091986 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511987 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491988
1989
Sean Kau46e29bc2017-08-28 16:31:161990def _MatchesFile(input_api, patterns, path):
1991 for pattern in patterns:
1992 if input_api.re.search(pattern, path):
1993 return True
1994 return False
1995
1996
Daniel Cheng7052cdf2017-11-21 19:23:291997def _GetOwnersFilesToCheckForIpcOwners(input_api):
1998 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:171999
Daniel Cheng7052cdf2017-11-21 19:23:292000 Returns:
2001 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2002 contain to cover IPC-related files with noparent reviewer rules.
2003 """
2004 # Whether or not a file affects IPC is (mostly) determined by a simple list
2005 # of filename patterns.
dchenge07de812016-06-20 19:27:172006 file_patterns = [
palmerb19a0932017-01-24 04:00:312007 # Legacy IPC:
dchenge07de812016-06-20 19:27:172008 '*_messages.cc',
2009 '*_messages*.h',
2010 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312011 # Mojo IPC:
dchenge07de812016-06-20 19:27:172012 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472013 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172014 '*_struct_traits*.*',
2015 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312016 '*.typemap',
2017 # Android native IPC:
2018 '*.aidl',
2019 # Blink uses a different file naming convention:
2020 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472021 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172022 '*StructTraits*.*',
2023 '*TypeConverter*.*',
2024 ]
2025
scottmg7a6ed5ba2016-11-04 18:22:042026 # These third_party directories do not contain IPCs, but contain files
2027 # matching the above patterns, which trigger false positives.
2028 exclude_paths = [
2029 'third_party/crashpad/*',
Andres Medinae684cf42018-08-27 18:48:232030 'third_party/protobuf/benchmarks/python/*',
Daniel Chengebe635e2018-07-13 12:36:062031 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:292032 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:042033 ]
2034
dchenge07de812016-06-20 19:27:172035 # Dictionary mapping an OWNERS file path to Patterns.
2036 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2037 # rules ) to a PatternEntry.
2038 # PatternEntry is a dictionary with two keys:
2039 # - 'files': the files that are matched by this pattern
2040 # - 'rules': the per-file rules needed for this pattern
2041 # For example, if we expect OWNERS file to contain rules for *.mojom and
2042 # *_struct_traits*.*, Patterns might look like this:
2043 # {
2044 # '*.mojom': {
2045 # 'files': ...,
2046 # 'rules': [
2047 # 'per-file *.mojom=set noparent',
2048 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2049 # ],
2050 # },
2051 # '*_struct_traits*.*': {
2052 # 'files': ...,
2053 # 'rules': [
2054 # 'per-file *_struct_traits*.*=set noparent',
2055 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2056 # ],
2057 # },
2058 # }
2059 to_check = {}
2060
Daniel Cheng13ca61a882017-08-25 15:11:252061 def AddPatternToCheck(input_file, pattern):
2062 owners_file = input_api.os_path.join(
2063 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2064 if owners_file not in to_check:
2065 to_check[owners_file] = {}
2066 if pattern not in to_check[owners_file]:
2067 to_check[owners_file][pattern] = {
2068 'files': [],
2069 'rules': [
2070 'per-file %s=set noparent' % pattern,
2071 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2072 ]
2073 }
Vaclav Brozekd5de76a2018-03-17 07:57:502074 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252075
dchenge07de812016-06-20 19:27:172076 # Iterate through the affected files to see what we actually need to check
2077 # for. We should only nag patch authors about per-file rules if a file in that
2078 # directory would match that pattern. If a directory only contains *.mojom
2079 # files and no *_messages*.h files, we should only nag about rules for
2080 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252081 for f in input_api.AffectedFiles(include_deletes=False):
2082 # Manifest files don't have a strong naming convention. Instead, scan
2083 # affected files for .json files and see if they look like a manifest.
Sean Kau46e29bc2017-08-28 16:31:162084 if (f.LocalPath().endswith('.json') and
2085 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
2086 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:252087 json_comment_eater = _ImportJSONCommentEater(input_api)
2088 mostly_json_lines = '\n'.join(f.NewContents())
2089 # Comments aren't allowed in strict JSON, so filter them out.
2090 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:432091 try:
2092 json_content = input_api.json.loads(json_lines)
2093 except:
2094 # There's another PRESUBMIT check that already verifies that JSON files
2095 # are not invalid, so no need to emit another warning here.
2096 continue
Daniel Cheng13ca61a882017-08-25 15:11:252097 if 'interface_provider_specs' in json_content:
2098 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172099 for pattern in file_patterns:
2100 if input_api.fnmatch.fnmatch(
2101 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042102 skip = False
2103 for exclude in exclude_paths:
2104 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2105 skip = True
2106 break
2107 if skip:
2108 continue
Daniel Cheng13ca61a882017-08-25 15:11:252109 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172110 break
2111
Daniel Cheng7052cdf2017-11-21 19:23:292112 return to_check
2113
2114
2115def _CheckIpcOwners(input_api, output_api):
2116 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2117 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2118
2119 if to_check:
2120 # If there are any OWNERS files to check, there are IPC-related changes in
2121 # this CL. Auto-CC the review list.
2122 output_api.AppendCC('[email protected]')
2123
2124 # Go through the OWNERS files to check, filtering out rules that are already
2125 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172126 for owners_file, patterns in to_check.iteritems():
2127 try:
2128 with file(owners_file) as f:
2129 lines = set(f.read().splitlines())
2130 for entry in patterns.itervalues():
2131 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2132 ]
2133 except IOError:
2134 # No OWNERS file, so all the rules are definitely missing.
2135 continue
2136
2137 # All the remaining lines weren't found in OWNERS files, so emit an error.
2138 errors = []
2139 for owners_file, patterns in to_check.iteritems():
2140 missing_lines = []
2141 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502142 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172143 missing_lines.extend(entry['rules'])
2144 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2145 if missing_lines:
2146 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052147 'Because of the presence of files:\n%s\n\n'
2148 '%s needs the following %d lines added:\n\n%s' %
2149 ('\n'.join(files), owners_file, len(missing_lines),
2150 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172151
2152 results = []
2153 if errors:
vabrf5ce3bf92016-07-11 14:52:412154 if input_api.is_committing:
2155 output = output_api.PresubmitError
2156 else:
2157 output = output_api.PresubmitPromptWarning
2158 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592159 'Found OWNERS files that need to be updated for IPC security ' +
2160 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172161 long_text='\n\n'.join(errors)))
2162
2163 return results
2164
2165
jbriance9e12f162016-11-25 07:57:502166def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312167 """Checks that added or removed lines in non third party affected
2168 header files do not lead to new useless class or struct forward
2169 declaration.
jbriance9e12f162016-11-25 07:57:502170 """
2171 results = []
2172 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2173 input_api.re.MULTILINE)
2174 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2175 input_api.re.MULTILINE)
2176 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312177 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192178 not f.LocalPath().startswith('third_party/blink') and
2179 not f.LocalPath().startswith('third_party\\blink') and
jbriance2c51e821a2016-12-12 08:24:312180 not f.LocalPath().startswith('third_party/WebKit') and
2181 not f.LocalPath().startswith('third_party\\WebKit')):
2182 continue
2183
jbriance9e12f162016-11-25 07:57:502184 if not f.LocalPath().endswith('.h'):
2185 continue
2186
2187 contents = input_api.ReadFile(f)
2188 fwd_decls = input_api.re.findall(class_pattern, contents)
2189 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2190
2191 useless_fwd_decls = []
2192 for decl in fwd_decls:
2193 count = sum(1 for _ in input_api.re.finditer(
2194 r'\b%s\b' % input_api.re.escape(decl), contents))
2195 if count == 1:
2196 useless_fwd_decls.append(decl)
2197
2198 if not useless_fwd_decls:
2199 continue
2200
2201 for line in f.GenerateScmDiff().splitlines():
2202 if (line.startswith('-') and not line.startswith('--') or
2203 line.startswith('+') and not line.startswith('++')):
2204 for decl in useless_fwd_decls:
2205 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2206 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242207 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502208 (f.LocalPath(), decl)))
2209 useless_fwd_decls.remove(decl)
2210
2211 return results
2212
2213
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492214# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:292215def _CheckAndroidToastUsage(input_api, output_api):
2216 """Checks that code uses org.chromium.ui.widget.Toast instead of
2217 android.widget.Toast (Chromium Toast doesn't force hardware
2218 acceleration on low-end devices, saving memory).
2219 """
2220 toast_import_pattern = input_api.re.compile(
2221 r'^import android\.widget\.Toast;$')
2222
2223 errors = []
2224
2225 sources = lambda affected_file: input_api.FilterSourceFile(
2226 affected_file,
2227 black_list=(_EXCLUDED_PATHS +
2228 _TEST_CODE_EXCLUDED_PATHS +
2229 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042230 (r'^chromecast[\\/].*',
2231 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492232 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:292233
2234 for f in input_api.AffectedSourceFiles(sources):
2235 for line_num, line in f.ChangedContents():
2236 if toast_import_pattern.search(line):
2237 errors.append("%s:%d" % (f.LocalPath(), line_num))
2238
2239 results = []
2240
2241 if errors:
2242 results.append(output_api.PresubmitError(
2243 'android.widget.Toast usage is detected. Android toasts use hardware'
2244 ' acceleration, and can be\ncostly on low-end devices. Please use'
2245 ' org.chromium.ui.widget.Toast instead.\n'
2246 'Contact [email protected] if you have any questions.',
2247 errors))
2248
2249 return results
2250
2251
dgnaa68d5e2015-06-10 10:08:222252def _CheckAndroidCrLogUsage(input_api, output_api):
2253 """Checks that new logs using org.chromium.base.Log:
2254 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512255 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222256 """
pkotwicza1dd0b002016-05-16 14:41:042257
torne89540622017-03-24 19:41:302258 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042259 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302260 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:042261 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:302262 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:042263 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
2264 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:092265 # The customtabs_benchmark is a small app that does not depend on Chromium
2266 # java pieces.
Egor Paskoce145c42018-09-28 19:31:042267 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:042268 ]
2269
dgnaa68d5e2015-06-10 10:08:222270 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122271 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2272 class_in_base_pattern = input_api.re.compile(
2273 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2274 has_some_log_import_pattern = input_api.re.compile(
2275 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222276 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122277 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222278 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512279 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222280 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222281
Vincent Scheib16d7b272015-09-15 18:09:072282 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222283 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492284 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:042285 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122286
dgnaa68d5e2015-06-10 10:08:222287 tag_decl_errors = []
2288 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122289 tag_errors = []
dgn38736db2015-09-18 19:20:512290 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122291 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222292
2293 for f in input_api.AffectedSourceFiles(sources):
2294 file_content = input_api.ReadFile(f)
2295 has_modified_logs = False
2296
2297 # Per line checks
dgn87d9fb62015-06-12 09:15:122298 if (cr_log_import_pattern.search(file_content) or
2299 (class_in_base_pattern.search(file_content) and
2300 not has_some_log_import_pattern.search(file_content))):
2301 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222302 for line_num, line in f.ChangedContents():
2303
2304 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122305 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222306 if match:
2307 has_modified_logs = True
2308
2309 # Make sure it uses "TAG"
2310 if not match.group('tag') == 'TAG':
2311 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122312 else:
2313 # Report non cr Log function calls in changed lines
2314 for line_num, line in f.ChangedContents():
2315 if log_call_pattern.search(line):
2316 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222317
2318 # Per file checks
2319 if has_modified_logs:
2320 # Make sure the tag is using the "cr" prefix and is not too long
2321 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512322 tag_name = match.group('name') if match else None
2323 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222324 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512325 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222326 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512327 elif '.' in tag_name:
2328 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222329
2330 results = []
2331 if tag_decl_errors:
2332 results.append(output_api.PresubmitPromptWarning(
2333 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512334 '"private static final String TAG = "<package tag>".\n'
2335 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222336 tag_decl_errors))
2337
2338 if tag_length_errors:
2339 results.append(output_api.PresubmitError(
2340 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512341 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222342 tag_length_errors))
2343
2344 if tag_errors:
2345 results.append(output_api.PresubmitPromptWarning(
2346 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2347 tag_errors))
2348
dgn87d9fb62015-06-12 09:15:122349 if util_log_errors:
dgn4401aa52015-04-29 16:26:172350 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122351 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2352 util_log_errors))
2353
dgn38736db2015-09-18 19:20:512354 if tag_with_dot_errors:
2355 results.append(output_api.PresubmitPromptWarning(
2356 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2357 tag_with_dot_errors))
2358
dgn4401aa52015-04-29 16:26:172359 return results
2360
2361
Yoland Yanb92fa522017-08-28 17:37:062362def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2363 """Checks that junit.framework.* is no longer used."""
2364 deprecated_junit_framework_pattern = input_api.re.compile(
2365 r'^import junit\.framework\..*;',
2366 input_api.re.MULTILINE)
2367 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492368 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062369 errors = []
2370 for f in input_api.AffectedFiles(sources):
2371 for line_num, line in f.ChangedContents():
2372 if deprecated_junit_framework_pattern.search(line):
2373 errors.append("%s:%d" % (f.LocalPath(), line_num))
2374
2375 results = []
2376 if errors:
2377 results.append(output_api.PresubmitError(
2378 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2379 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2380 ' if you have any question.', errors))
2381 return results
2382
2383
2384def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2385 """Checks that if new Java test classes have inheritance.
2386 Either the new test class is JUnit3 test or it is a JUnit4 test class
2387 with a base class, either case is undesirable.
2388 """
2389 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2390
2391 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492392 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062393 errors = []
2394 for f in input_api.AffectedFiles(sources):
2395 if not f.OldContents():
2396 class_declaration_start_flag = False
2397 for line_num, line in f.ChangedContents():
2398 if class_declaration_pattern.search(line):
2399 class_declaration_start_flag = True
2400 if class_declaration_start_flag and ' extends ' in line:
2401 errors.append('%s:%d' % (f.LocalPath(), line_num))
2402 if '{' in line:
2403 class_declaration_start_flag = False
2404
2405 results = []
2406 if errors:
2407 results.append(output_api.PresubmitPromptWarning(
2408 'The newly created files include Test classes that inherits from base'
2409 ' class. Please do not use inheritance in JUnit4 tests or add new'
2410 ' JUnit3 tests. Contact [email protected] if you have any'
2411 ' questions.', errors))
2412 return results
2413
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202414
yolandyan45001472016-12-21 21:12:422415def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2416 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2417 deprecated_annotation_import_pattern = input_api.re.compile(
2418 r'^import android\.test\.suitebuilder\.annotation\..*;',
2419 input_api.re.MULTILINE)
2420 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492421 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:422422 errors = []
2423 for f in input_api.AffectedFiles(sources):
2424 for line_num, line in f.ChangedContents():
2425 if deprecated_annotation_import_pattern.search(line):
2426 errors.append("%s:%d" % (f.LocalPath(), line_num))
2427
2428 results = []
2429 if errors:
2430 results.append(output_api.PresubmitError(
2431 'Annotations in android.test.suitebuilder.annotation have been'
2432 ' deprecated since API level 24. Please use android.support.test.filters'
2433 ' from //third_party/android_support_test_runner:runner_java instead.'
2434 ' Contact [email protected] if you have any questions.', errors))
2435 return results
2436
2437
agrieve7b6479d82015-10-07 14:24:222438def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2439 """Checks if MDPI assets are placed in a correct directory."""
2440 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2441 ('/res/drawable/' in f.LocalPath() or
2442 '/res/drawable-ldrtl/' in f.LocalPath()))
2443 errors = []
2444 for f in input_api.AffectedFiles(include_deletes=False,
2445 file_filter=file_filter):
2446 errors.append(' %s' % f.LocalPath())
2447
2448 results = []
2449 if errors:
2450 results.append(output_api.PresubmitError(
2451 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2452 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2453 '/res/drawable-ldrtl/.\n'
2454 'Contact [email protected] if you have questions.', errors))
2455 return results
2456
2457
Nate Fischer535972b2017-09-16 01:06:182458def _CheckAndroidWebkitImports(input_api, output_api):
2459 """Checks that code uses org.chromium.base.Callback instead of
2460 android.widget.ValueCallback except in the WebView glue layer.
2461 """
2462 valuecallback_import_pattern = input_api.re.compile(
2463 r'^import android\.webkit\.ValueCallback;$')
2464
2465 errors = []
2466
2467 sources = lambda affected_file: input_api.FilterSourceFile(
2468 affected_file,
2469 black_list=(_EXCLUDED_PATHS +
2470 _TEST_CODE_EXCLUDED_PATHS +
2471 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042472 (r'^android_webview[\\/]glue[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492473 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:182474
2475 for f in input_api.AffectedSourceFiles(sources):
2476 for line_num, line in f.ChangedContents():
2477 if valuecallback_import_pattern.search(line):
2478 errors.append("%s:%d" % (f.LocalPath(), line_num))
2479
2480 results = []
2481
2482 if errors:
2483 results.append(output_api.PresubmitError(
2484 'android.webkit.ValueCallback usage is detected outside of the glue'
2485 ' layer. To stay compatible with the support library, android.webkit.*'
2486 ' classes should only be used inside the glue layer and'
2487 ' org.chromium.base.Callback should be used instead.',
2488 errors))
2489
2490 return results
2491
2492
agrievef32bcc72016-04-04 14:57:402493class PydepsChecker(object):
2494 def __init__(self, input_api, pydeps_files):
2495 self._file_cache = {}
2496 self._input_api = input_api
2497 self._pydeps_files = pydeps_files
2498
2499 def _LoadFile(self, path):
2500 """Returns the list of paths within a .pydeps file relative to //."""
2501 if path not in self._file_cache:
2502 with open(path) as f:
2503 self._file_cache[path] = f.read()
2504 return self._file_cache[path]
2505
2506 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2507 """Returns an interable of paths within the .pydep, relativized to //."""
2508 os_path = self._input_api.os_path
2509 pydeps_dir = os_path.dirname(pydeps_path)
2510 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2511 if not l.startswith('*'))
2512 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2513
2514 def _CreateFilesToPydepsMap(self):
2515 """Returns a map of local_path -> list_of_pydeps."""
2516 ret = {}
2517 for pydep_local_path in self._pydeps_files:
2518 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2519 ret.setdefault(path, []).append(pydep_local_path)
2520 return ret
2521
2522 def ComputeAffectedPydeps(self):
2523 """Returns an iterable of .pydeps files that might need regenerating."""
2524 affected_pydeps = set()
2525 file_to_pydeps_map = None
2526 for f in self._input_api.AffectedFiles(include_deletes=True):
2527 local_path = f.LocalPath()
2528 if local_path == 'DEPS':
2529 return self._pydeps_files
2530 elif local_path.endswith('.pydeps'):
2531 if local_path in self._pydeps_files:
2532 affected_pydeps.add(local_path)
2533 elif local_path.endswith('.py'):
2534 if file_to_pydeps_map is None:
2535 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2536 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2537 return affected_pydeps
2538
2539 def DetermineIfStale(self, pydeps_path):
2540 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412541 import difflib
John Budorick47ca3fe2018-02-10 00:53:102542 import os
2543
agrievef32bcc72016-04-04 14:57:402544 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2545 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102546 env = dict(os.environ)
2547 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402548 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102549 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412550 old_contents = old_pydeps_data[2:]
2551 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402552 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412553 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402554
2555
2556def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2557 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402558 # This check is for Python dependency lists (.pydeps files), and involves
2559 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2560 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282561 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002562 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022563 # TODO(agrieve): Update when there's a better way to detect
2564 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402565 is_android = input_api.os_path.exists('third_party/android_tools')
2566 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2567 results = []
2568 # First, check for new / deleted .pydeps.
2569 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032570 # Check whether we are running the presubmit check for a file in src.
2571 # f.LocalPath is relative to repo (src, or internal repo).
2572 # os_path.exists is relative to src repo.
2573 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2574 # to src and we can conclude that the pydeps is in src.
2575 if input_api.os_path.exists(f.LocalPath()):
2576 if f.LocalPath().endswith('.pydeps'):
2577 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2578 results.append(output_api.PresubmitError(
2579 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2580 'remove %s' % f.LocalPath()))
2581 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2582 results.append(output_api.PresubmitError(
2583 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2584 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402585
2586 if results:
2587 return results
2588
2589 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2590
2591 for pydep_path in checker.ComputeAffectedPydeps():
2592 try:
phajdan.jr0d9878552016-11-04 10:49:412593 result = checker.DetermineIfStale(pydep_path)
2594 if result:
2595 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402596 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412597 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2598 'To regenerate, run:\n\n %s' %
2599 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402600 except input_api.subprocess.CalledProcessError as error:
2601 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2602 long_text=error.output)]
2603
2604 return results
2605
2606
glidere61efad2015-02-18 17:39:432607def _CheckSingletonInHeaders(input_api, output_api):
2608 """Checks to make sure no header files have |Singleton<|."""
2609 def FileFilter(affected_file):
2610 # It's ok for base/memory/singleton.h to have |Singleton<|.
2611 black_list = (_EXCLUDED_PATHS +
2612 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042613 (r"^base[\\/]memory[\\/]singleton\.h$",
2614 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:472615 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432616 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2617
sergeyu34d21222015-09-16 00:11:442618 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432619 files = []
2620 for f in input_api.AffectedSourceFiles(FileFilter):
2621 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2622 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2623 contents = input_api.ReadFile(f)
2624 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242625 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432626 pattern.search(line)):
2627 files.append(f)
2628 break
2629
2630 if files:
yolandyandaabc6d2016-04-18 18:29:392631 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442632 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432633 'Please move them to an appropriate source file so that the ' +
2634 'template gets instantiated in a single compilation unit.',
2635 files) ]
2636 return []
2637
2638
[email protected]fd20b902014-05-09 02:14:532639_DEPRECATED_CSS = [
2640 # Values
2641 ( "-webkit-box", "flex" ),
2642 ( "-webkit-inline-box", "inline-flex" ),
2643 ( "-webkit-flex", "flex" ),
2644 ( "-webkit-inline-flex", "inline-flex" ),
2645 ( "-webkit-min-content", "min-content" ),
2646 ( "-webkit-max-content", "max-content" ),
2647
2648 # Properties
2649 ( "-webkit-background-clip", "background-clip" ),
2650 ( "-webkit-background-origin", "background-origin" ),
2651 ( "-webkit-background-size", "background-size" ),
2652 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442653 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532654
2655 # Functions
2656 ( "-webkit-gradient", "gradient" ),
2657 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2658 ( "-webkit-linear-gradient", "linear-gradient" ),
2659 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2660 ( "-webkit-radial-gradient", "radial-gradient" ),
2661 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2662]
2663
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202664
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492665# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242666def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532667 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252668 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342669 documentation and iOS CSS for dom distiller
2670 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252671 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532672 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492673 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:252674 black_list = (_EXCLUDED_PATHS +
2675 _TEST_CODE_EXCLUDED_PATHS +
2676 input_api.DEFAULT_BLACK_LIST +
2677 (r"^chrome/common/extensions/docs",
2678 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342679 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442680 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252681 r"^native_client_sdk"))
2682 file_filter = lambda f: input_api.FilterSourceFile(
2683 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532684 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2685 for line_num, line in fpath.ChangedContents():
2686 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022687 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532688 results.append(output_api.PresubmitError(
2689 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2690 (fpath.LocalPath(), line_num, deprecated_value, value)))
2691 return results
2692
mohan.reddyf21db962014-10-16 12:26:472693
dbeam070cfe62014-10-22 06:44:022694_DEPRECATED_JS = [
2695 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2696 ( "__defineGetter__", "Object.defineProperty" ),
2697 ( "__defineSetter__", "Object.defineProperty" ),
2698]
2699
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202700
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492701# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242702def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022703 """Make sure that we don't use deprecated JS in Chrome code."""
2704 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492705 file_inclusion_pattern = [r".+\.js$"] # TODO(dbeam): .html?
dbeam070cfe62014-10-22 06:44:022706 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2707 input_api.DEFAULT_BLACK_LIST)
2708 file_filter = lambda f: input_api.FilterSourceFile(
2709 f, white_list=file_inclusion_pattern, black_list=black_list)
2710 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2711 for lnum, line in fpath.ChangedContents():
2712 for (deprecated, replacement) in _DEPRECATED_JS:
2713 if deprecated in line:
2714 results.append(output_api.PresubmitError(
2715 "%s:%d: Use of deprecated JS %s, use %s instead" %
2716 (fpath.LocalPath(), lnum, deprecated, replacement)))
2717 return results
2718
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202719
dpapadd651231d82017-07-21 02:44:472720def _CheckForRiskyJsArrowFunction(line_number, line):
2721 if ' => ' in line:
2722 return "line %d, is using an => (arrow) function\n %s\n" % (
2723 line_number, line)
2724 return ''
2725
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202726
dpapadd651231d82017-07-21 02:44:472727def _CheckForRiskyJsConstLet(input_api, line_number, line):
2728 if input_api.re.match('^\s*(const|let)\s', line):
2729 return "line %d, is using const/let keyword\n %s\n" % (
2730 line_number, line)
2731 return ''
dbeam070cfe62014-10-22 06:44:022732
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202733
dbeam1ec68ac2016-12-15 05:22:242734def _CheckForRiskyJsFeatures(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492735 maybe_ios_js = [r"^(ios|components|ui\/webui\/resources)\/.+\.js$"]
Steven Bennetts90545f3cb2017-08-14 18:11:002736 # 'ui/webui/resources/cr_components are not allowed on ios'
2737 not_ios_filter = (r".*ui\/webui\/resources\/cr_components.*", )
Steven Bennetts9c7e3c22017-08-02 19:10:572738 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js,
Steven Bennetts90545f3cb2017-08-14 18:11:002739 black_list=not_ios_filter)
dpapadd651231d82017-07-21 02:44:472740 results = []
dbeam1ec68ac2016-12-15 05:22:242741 for f in input_api.AffectedFiles(file_filter=file_filter):
dpapadd651231d82017-07-21 02:44:472742 arrow_error_lines = []
2743 const_let_error_lines = []
dbeam1ec68ac2016-12-15 05:22:242744 for lnum, line in f.ChangedContents():
dpapadd651231d82017-07-21 02:44:472745 arrow_error_lines += filter(None, [
2746 _CheckForRiskyJsArrowFunction(lnum, line),
2747 ])
dbeam1ec68ac2016-12-15 05:22:242748
dpapadd651231d82017-07-21 02:44:472749 const_let_error_lines += filter(None, [
2750 _CheckForRiskyJsConstLet(input_api, lnum, line),
2751 ])
dbeam1ec68ac2016-12-15 05:22:242752
dpapadd651231d82017-07-21 02:44:472753 if arrow_error_lines:
2754 arrow_error_lines = map(
2755 lambda e: "%s:%s" % (f.LocalPath(), e), arrow_error_lines)
2756 results.append(
2757 output_api.PresubmitPromptWarning('\n'.join(arrow_error_lines + [
2758"""
2759Use of => (arrow) operator detected in:
dbeam1ec68ac2016-12-15 05:22:242760%s
2761Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
Dan Beamdd2470c2018-10-03 00:07:222762https://chromium.googlesource.com/chromium/src/+/master/styleguide/web/es6.md#Arrow-Functions
dpapadd651231d82017-07-21 02:44:472763""" % f.LocalPath()
2764 ])))
dbeam1ec68ac2016-12-15 05:22:242765
dpapadd651231d82017-07-21 02:44:472766 if const_let_error_lines:
2767 const_let_error_lines = map(
2768 lambda e: "%s:%s" % (f.LocalPath(), e), const_let_error_lines)
2769 results.append(
2770 output_api.PresubmitPromptWarning('\n'.join(const_let_error_lines + [
2771"""
2772Use of const/let keywords detected in:
2773%s
2774Please ensure your code does not run on iOS9 because const/let is not fully
2775supported.
Dan Beamdd2470c2018-10-03 00:07:222776https://chromium.googlesource.com/chromium/src/+/master/styleguide/web/es6.md#let-Block_Scoped-Variables
2777https://chromium.googlesource.com/chromium/src/+/master/styleguide/web/es6.md#const-Block_Scoped-Constants
dpapadd651231d82017-07-21 02:44:472778""" % f.LocalPath()
2779 ])))
2780
2781 return results
dbeam1ec68ac2016-12-15 05:22:242782
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202783
rlanday6802cf632017-05-30 17:48:362784def _CheckForRelativeIncludes(input_api, output_api):
2785 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2786 import sys
2787 original_sys_path = sys.path
2788 try:
2789 sys.path = sys.path + [input_api.os_path.join(
2790 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2791 from cpp_checker import CppChecker
2792 finally:
2793 # Restore sys.path to what it was before.
2794 sys.path = original_sys_path
2795
2796 bad_files = {}
2797 for f in input_api.AffectedFiles(include_deletes=False):
2798 if (f.LocalPath().startswith('third_party') and
2799 not f.LocalPath().startswith('third_party/WebKit') and
2800 not f.LocalPath().startswith('third_party\\WebKit')):
2801 continue
2802
2803 if not CppChecker.IsCppFile(f.LocalPath()):
2804 continue
2805
Vaclav Brozekd5de76a2018-03-17 07:57:502806 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362807 if "#include" in line and "../" in line]
2808 if not relative_includes:
2809 continue
2810 bad_files[f.LocalPath()] = relative_includes
2811
2812 if not bad_files:
2813 return []
2814
2815 error_descriptions = []
2816 for file_path, bad_lines in bad_files.iteritems():
2817 error_description = file_path
2818 for line in bad_lines:
2819 error_description += '\n ' + line
2820 error_descriptions.append(error_description)
2821
2822 results = []
2823 results.append(output_api.PresubmitError(
2824 'You added one or more relative #include paths (including "../").\n'
2825 'These shouldn\'t be used because they can be used to include headers\n'
2826 'from code that\'s not correctly specified as a dependency in the\n'
2827 'relevant BUILD.gn file(s).',
2828 error_descriptions))
2829
2830 return results
2831
Takeshi Yoshinoe387aa32017-08-02 13:16:132832
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202833def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2834 if not isinstance(key, ast.Str):
2835 return 'Key at line %d must be a string literal' % key.lineno
2836 if not isinstance(value, ast.Dict):
2837 return 'Value at line %d must be a dict' % value.lineno
2838 if len(value.keys) != 1:
2839 return 'Dict at line %d must have single entry' % value.lineno
2840 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2841 return (
2842 'Entry at line %d must have a string literal \'filepath\' as key' %
2843 value.lineno)
2844 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132845
Takeshi Yoshinoe387aa32017-08-02 13:16:132846
Sergey Ulanov4af16052018-11-08 02:41:462847def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202848 if not isinstance(key, ast.Str):
2849 return 'Key at line %d must be a string literal' % key.lineno
2850 if not isinstance(value, ast.List):
2851 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:462852 for element in value.elts:
2853 if not isinstance(element, ast.Str):
2854 return 'Watchlist elements on line %d is not a string' % key.lineno
2855 if not email_regex.match(element.s):
2856 return ('Watchlist element on line %d doesn\'t look like a valid ' +
2857 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202858 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132859
Takeshi Yoshinoe387aa32017-08-02 13:16:132860
Sergey Ulanov4af16052018-11-08 02:41:462861def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202862 mismatch_template = (
2863 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2864 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132865
Sergey Ulanov4af16052018-11-08 02:41:462866 email_regex = input_api.re.compile(
2867 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
2868
2869 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202870 i = 0
2871 last_key = ''
2872 while True:
2873 if i >= len(wd_dict.keys):
2874 if i >= len(w_dict.keys):
2875 return None
2876 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2877 elif i >= len(w_dict.keys):
2878 return (
2879 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132880
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202881 wd_key = wd_dict.keys[i]
2882 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132883
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202884 result = _CheckWatchlistDefinitionsEntrySyntax(
2885 wd_key, wd_dict.values[i], ast)
2886 if result is not None:
2887 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132888
Sergey Ulanov4af16052018-11-08 02:41:462889 result = _CheckWatchlistsEntrySyntax(
2890 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202891 if result is not None:
2892 return 'Bad entry in WATCHLISTS dict: %s' % result
2893
2894 if wd_key.s != w_key.s:
2895 return mismatch_template % (
2896 '%s at line %d' % (wd_key.s, wd_key.lineno),
2897 '%s at line %d' % (w_key.s, w_key.lineno))
2898
2899 if wd_key.s < last_key:
2900 return (
2901 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2902 (wd_key.lineno, w_key.lineno))
2903 last_key = wd_key.s
2904
2905 i = i + 1
2906
2907
Sergey Ulanov4af16052018-11-08 02:41:462908def _CheckWATCHLISTSSyntax(expression, input_api):
2909 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202910 if not isinstance(expression, ast.Expression):
2911 return 'WATCHLISTS file must contain a valid expression'
2912 dictionary = expression.body
2913 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2914 return 'WATCHLISTS file must have single dict with exactly two entries'
2915
2916 first_key = dictionary.keys[0]
2917 first_value = dictionary.values[0]
2918 second_key = dictionary.keys[1]
2919 second_value = dictionary.values[1]
2920
2921 if (not isinstance(first_key, ast.Str) or
2922 first_key.s != 'WATCHLIST_DEFINITIONS' or
2923 not isinstance(first_value, ast.Dict)):
2924 return (
2925 'The first entry of the dict in WATCHLISTS file must be '
2926 'WATCHLIST_DEFINITIONS dict')
2927
2928 if (not isinstance(second_key, ast.Str) or
2929 second_key.s != 'WATCHLISTS' or
2930 not isinstance(second_value, ast.Dict)):
2931 return (
2932 'The second entry of the dict in WATCHLISTS file must be '
2933 'WATCHLISTS dict')
2934
Sergey Ulanov4af16052018-11-08 02:41:462935 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:132936
2937
2938def _CheckWATCHLISTS(input_api, output_api):
2939 for f in input_api.AffectedFiles(include_deletes=False):
2940 if f.LocalPath() == 'WATCHLISTS':
2941 contents = input_api.ReadFile(f, 'r')
2942
2943 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202944 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132945 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202946 # Get an AST tree for it and scan the tree for detailed style checking.
2947 expression = input_api.ast.parse(
2948 contents, filename='WATCHLISTS', mode='eval')
2949 except ValueError as e:
2950 return [output_api.PresubmitError(
2951 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2952 except SyntaxError as e:
2953 return [output_api.PresubmitError(
2954 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2955 except TypeError as e:
2956 return [output_api.PresubmitError(
2957 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132958
Sergey Ulanov4af16052018-11-08 02:41:462959 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202960 if result is not None:
2961 return [output_api.PresubmitError(result)]
2962 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132963
2964 return []
2965
2966
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192967def _CheckNewHeaderWithoutGnChange(input_api, output_api):
2968 """Checks that newly added header files have corresponding GN changes.
2969 Note that this is only a heuristic. To be precise, run script:
2970 build/check_gn_headers.py.
2971 """
2972
2973 def headers(f):
2974 return input_api.FilterSourceFile(
2975 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
2976
2977 new_headers = []
2978 for f in input_api.AffectedSourceFiles(headers):
2979 if f.Action() != 'A':
2980 continue
2981 new_headers.append(f.LocalPath())
2982
2983 def gn_files(f):
2984 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
2985
2986 all_gn_changed_contents = ''
2987 for f in input_api.AffectedSourceFiles(gn_files):
2988 for _, line in f.ChangedContents():
2989 all_gn_changed_contents += line
2990
2991 problems = []
2992 for header in new_headers:
2993 basename = input_api.os_path.basename(header)
2994 if basename not in all_gn_changed_contents:
2995 problems.append(header)
2996
2997 if problems:
2998 return [output_api.PresubmitPromptWarning(
2999 'Missing GN changes for new header files', items=sorted(problems),
3000 long_text='Please double check whether newly added header files need '
3001 'corresponding changes in gn or gni files.\nThis checking is only a '
3002 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3003 'Read https://crbug.com/661774 for more info.')]
3004 return []
3005
3006
Michael Giuffridad3bc8672018-10-25 22:48:023007def _CheckCorrectProductNameInMessages(input_api, output_api):
3008 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
3009
3010 This assumes we won't intentionally reference one product from the other
3011 product.
3012 """
3013 all_problems = []
3014 test_cases = [{
3015 "filename_postfix": "google_chrome_strings.grd",
3016 "correct_name": "Chrome",
3017 "incorrect_name": "Chromium",
3018 }, {
3019 "filename_postfix": "chromium_strings.grd",
3020 "correct_name": "Chromium",
3021 "incorrect_name": "Chrome",
3022 }]
3023
3024 for test_case in test_cases:
3025 problems = []
3026 filename_filter = lambda x: x.LocalPath().endswith(
3027 test_case["filename_postfix"])
3028
3029 # Check each new line. Can yield false positives in multiline comments, but
3030 # easier than trying to parse the XML because messages can have nested
3031 # children, and associating message elements with affected lines is hard.
3032 for f in input_api.AffectedSourceFiles(filename_filter):
3033 for line_num, line in f.ChangedContents():
3034 if "<message" in line or "<!--" in line or "-->" in line:
3035 continue
3036 if test_case["incorrect_name"] in line:
3037 problems.append(
3038 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
3039
3040 if problems:
3041 message = (
3042 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
3043 % (test_case["correct_name"], test_case["correct_name"],
3044 test_case["incorrect_name"]))
3045 all_problems.append(
3046 output_api.PresubmitPromptWarning(message, items=problems))
3047
3048 return all_problems
3049
3050
dgnaa68d5e2015-06-10 10:08:223051def _AndroidSpecificOnUploadChecks(input_api, output_api):
3052 """Groups checks that target android code."""
3053 results = []
dgnaa68d5e2015-06-10 10:08:223054 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:223055 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:293056 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:063057 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
3058 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:423059 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:183060 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223061 return results
3062
3063
[email protected]22c9bd72011-03-27 16:47:393064def _CommonChecks(input_api, output_api):
3065 """Checks common to both upload and commit."""
3066 results = []
3067 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:383068 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:543069 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:083070
3071 author = input_api.change.author_email
3072 if author and author not in _KNOWN_ROBOTS:
3073 results.extend(
3074 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
3075
[email protected]55459852011-08-10 15:17:193076 results.extend(
[email protected]760deea2013-12-10 19:33:493077 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:233078 results.extend(
3079 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:543080 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:183081 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:343082 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:523083 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:223084 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:443085 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:593086 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:063087 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:123088 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:183089 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:223090 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:303091 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:493092 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:033093 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:493094 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:443095 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:273096 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:073097 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:543098 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:443099 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:393100 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:553101 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:043102 results.extend(
3103 input_api.canned_checks.CheckChangeHasNoTabs(
3104 input_api,
3105 output_api,
3106 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:403107 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:163108 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:083109 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:243110 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
3111 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:473112 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:043113 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:053114 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:143115 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:233116 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:433117 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:403118 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:153119 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:173120 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:503121 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:243122 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:363123 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:133124 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:433125 results.extend(input_api.RunTests(
3126 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143127 results.extend(_CheckTranslationScreenshots(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:023128 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:243129
Vaclav Brozekcdc7defb2018-03-20 09:54:353130 for f in input_api.AffectedFiles():
3131 path, name = input_api.os_path.split(f.LocalPath())
3132 if name == 'PRESUBMIT.py':
3133 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:003134 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
3135 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:073136 # The PRESUBMIT.py file (and the directory containing it) might
3137 # have been affected by being moved or removed, so only try to
3138 # run the tests if they still exist.
3139 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
3140 input_api, output_api, full_path,
3141 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:393142 return results
[email protected]1f7b4172010-01-28 01:17:343143
[email protected]b337cb5b2011-01-23 21:24:053144
[email protected]b8079ae4a2012-12-05 19:56:493145def _CheckPatchFiles(input_api, output_api):
3146 problems = [f.LocalPath() for f in input_api.AffectedFiles()
3147 if f.LocalPath().endswith(('.orig', '.rej'))]
3148 if problems:
3149 return [output_api.PresubmitError(
3150 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:033151 else:
3152 return []
[email protected]b8079ae4a2012-12-05 19:56:493153
3154
Kent Tamura5a8755d2017-06-29 23:37:073155def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:213156 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
3157 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
3158 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:073159 include_re = input_api.re.compile(
3160 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
3161 extension_re = input_api.re.compile(r'\.[a-z]+$')
3162 errors = []
3163 for f in input_api.AffectedFiles():
3164 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
3165 continue
3166 found_line_number = None
3167 found_macro = None
3168 for line_num, line in f.ChangedContents():
3169 match = macro_re.search(line)
3170 if match:
3171 found_line_number = line_num
3172 found_macro = match.group(2)
3173 break
3174 if not found_line_number:
3175 continue
3176
3177 found_include = False
3178 for line in f.NewContents():
3179 if include_re.search(line):
3180 found_include = True
3181 break
3182 if found_include:
3183 continue
3184
3185 if not f.LocalPath().endswith('.h'):
3186 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
3187 try:
3188 content = input_api.ReadFile(primary_header_path, 'r')
3189 if include_re.search(content):
3190 continue
3191 except IOError:
3192 pass
3193 errors.append('%s:%d %s macro is used without including build/'
3194 'build_config.h.'
3195 % (f.LocalPath(), found_line_number, found_macro))
3196 if errors:
3197 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
3198 return []
3199
3200
[email protected]b00342e7f2013-03-26 16:21:543201def _DidYouMeanOSMacro(bad_macro):
3202 try:
3203 return {'A': 'OS_ANDROID',
3204 'B': 'OS_BSD',
3205 'C': 'OS_CHROMEOS',
3206 'F': 'OS_FREEBSD',
3207 'L': 'OS_LINUX',
3208 'M': 'OS_MACOSX',
3209 'N': 'OS_NACL',
3210 'O': 'OS_OPENBSD',
3211 'P': 'OS_POSIX',
3212 'S': 'OS_SOLARIS',
3213 'W': 'OS_WIN'}[bad_macro[3].upper()]
3214 except KeyError:
3215 return ''
3216
3217
3218def _CheckForInvalidOSMacrosInFile(input_api, f):
3219 """Check for sensible looking, totally invalid OS macros."""
3220 preprocessor_statement = input_api.re.compile(r'^\s*#')
3221 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
3222 results = []
3223 for lnum, line in f.ChangedContents():
3224 if preprocessor_statement.search(line):
3225 for match in os_macro.finditer(line):
3226 if not match.group(1) in _VALID_OS_MACROS:
3227 good = _DidYouMeanOSMacro(match.group(1))
3228 did_you_mean = ' (did you mean %s?)' % good if good else ''
3229 results.append(' %s:%d %s%s' % (f.LocalPath(),
3230 lnum,
3231 match.group(1),
3232 did_you_mean))
3233 return results
3234
3235
3236def _CheckForInvalidOSMacros(input_api, output_api):
3237 """Check all affected files for invalid OS macros."""
3238 bad_macros = []
3239 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:473240 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:543241 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
3242
3243 if not bad_macros:
3244 return []
3245
3246 return [output_api.PresubmitError(
3247 'Possibly invalid OS macro[s] found. Please fix your code\n'
3248 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
3249
lliabraa35bab3932014-10-01 12:16:443250
3251def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
3252 """Check all affected files for invalid "if defined" macros."""
3253 ALWAYS_DEFINED_MACROS = (
3254 "TARGET_CPU_PPC",
3255 "TARGET_CPU_PPC64",
3256 "TARGET_CPU_68K",
3257 "TARGET_CPU_X86",
3258 "TARGET_CPU_ARM",
3259 "TARGET_CPU_MIPS",
3260 "TARGET_CPU_SPARC",
3261 "TARGET_CPU_ALPHA",
3262 "TARGET_IPHONE_SIMULATOR",
3263 "TARGET_OS_EMBEDDED",
3264 "TARGET_OS_IPHONE",
3265 "TARGET_OS_MAC",
3266 "TARGET_OS_UNIX",
3267 "TARGET_OS_WIN32",
3268 )
3269 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
3270 results = []
3271 for lnum, line in f.ChangedContents():
3272 for match in ifdef_macro.finditer(line):
3273 if match.group(1) in ALWAYS_DEFINED_MACROS:
3274 always_defined = ' %s is always defined. ' % match.group(1)
3275 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
3276 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
3277 lnum,
3278 always_defined,
3279 did_you_mean))
3280 return results
3281
3282
3283def _CheckForInvalidIfDefinedMacros(input_api, output_api):
3284 """Check all affected files for invalid "if defined" macros."""
3285 bad_macros = []
3286 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:213287 if f.LocalPath().startswith('third_party/sqlite/'):
3288 continue
lliabraa35bab3932014-10-01 12:16:443289 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3290 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3291
3292 if not bad_macros:
3293 return []
3294
3295 return [output_api.PresubmitError(
3296 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3297 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3298 bad_macros)]
3299
3300
mlamouria82272622014-09-16 18:45:043301def _CheckForIPCRules(input_api, output_api):
3302 """Check for same IPC rules described in
3303 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3304 """
3305 base_pattern = r'IPC_ENUM_TRAITS\('
3306 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3307 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3308
3309 problems = []
3310 for f in input_api.AffectedSourceFiles(None):
3311 local_path = f.LocalPath()
3312 if not local_path.endswith('.h'):
3313 continue
3314 for line_number, line in f.ChangedContents():
3315 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3316 problems.append(
3317 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3318
3319 if problems:
3320 return [output_api.PresubmitPromptWarning(
3321 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
3322 else:
3323 return []
3324
[email protected]b00342e7f2013-03-26 16:21:543325
Stephen Martinis97a394142018-06-07 23:06:053326def _CheckForLongPathnames(input_api, output_api):
3327 """Check to make sure no files being submitted have long paths.
3328 This causes issues on Windows.
3329 """
3330 problems = []
3331 for f in input_api.AffectedSourceFiles(None):
3332 local_path = f.LocalPath()
3333 # Windows has a path limit of 260 characters. Limit path length to 200 so
3334 # that we have some extra for the prefix on dev machines and the bots.
3335 if len(local_path) > 200:
3336 problems.append(local_path)
3337
3338 if problems:
3339 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
3340 else:
3341 return []
3342
3343
Daniel Bratell8ba52722018-03-02 16:06:143344def _CheckForIncludeGuards(input_api, output_api):
3345 """Check that header files have proper guards against multiple inclusion.
3346 If a file should not have such guards (and it probably should) then it
3347 should include the string "no-include-guard-because-multiply-included".
3348 """
Daniel Bratell6a75baef62018-06-04 10:04:453349 def is_chromium_header_file(f):
3350 # We only check header files under the control of the Chromium
3351 # project. That is, those outside third_party apart from
3352 # third_party/blink.
3353 file_with_path = input_api.os_path.normpath(f.LocalPath())
3354 return (file_with_path.endswith('.h') and
3355 (not file_with_path.startswith('third_party') or
3356 file_with_path.startswith(
3357 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:143358
3359 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:343360 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:143361
3362 errors = []
3363
Daniel Bratell6a75baef62018-06-04 10:04:453364 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:143365 guard_name = None
3366 guard_line_number = None
3367 seen_guard_end = False
3368
3369 file_with_path = input_api.os_path.normpath(f.LocalPath())
3370 base_file_name = input_api.os_path.splitext(
3371 input_api.os_path.basename(file_with_path))[0]
3372 upper_base_file_name = base_file_name.upper()
3373
3374 expected_guard = replace_special_with_underscore(
3375 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:143376
3377 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:573378 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
3379 # are too many (1000+) files with slight deviations from the
3380 # coding style. The most important part is that the include guard
3381 # is there, and that it's unique, not the name so this check is
3382 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:143383 #
3384 # As code becomes more uniform, this could be made stricter.
3385
3386 guard_name_pattern_list = [
3387 # Anything with the right suffix (maybe with an extra _).
3388 r'\w+_H__?',
3389
Daniel Bratell39b5b062018-05-16 18:09:573390 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:143391 r'\w+_h',
3392
3393 # Anything including the uppercase name of the file.
3394 r'\w*' + input_api.re.escape(replace_special_with_underscore(
3395 upper_base_file_name)) + r'\w*',
3396 ]
3397 guard_name_pattern = '|'.join(guard_name_pattern_list)
3398 guard_pattern = input_api.re.compile(
3399 r'#ifndef\s+(' + guard_name_pattern + ')')
3400
3401 for line_number, line in enumerate(f.NewContents()):
3402 if 'no-include-guard-because-multiply-included' in line:
3403 guard_name = 'DUMMY' # To not trigger check outside the loop.
3404 break
3405
3406 if guard_name is None:
3407 match = guard_pattern.match(line)
3408 if match:
3409 guard_name = match.group(1)
3410 guard_line_number = line_number
3411
Daniel Bratell39b5b062018-05-16 18:09:573412 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:453413 # don't match the chromium style guide, but new files should
3414 # get it right.
3415 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:573416 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:143417 errors.append(output_api.PresubmitPromptWarning(
3418 'Header using the wrong include guard name %s' % guard_name,
3419 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:573420 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:143421 else:
3422 # The line after #ifndef should have a #define of the same name.
3423 if line_number == guard_line_number + 1:
3424 expected_line = '#define %s' % guard_name
3425 if line != expected_line:
3426 errors.append(output_api.PresubmitPromptWarning(
3427 'Missing "%s" for include guard' % expected_line,
3428 ['%s:%d' % (f.LocalPath(), line_number + 1)],
3429 'Expected: %r\nGot: %r' % (expected_line, line)))
3430
3431 if not seen_guard_end and line == '#endif // %s' % guard_name:
3432 seen_guard_end = True
3433 elif seen_guard_end:
3434 if line.strip() != '':
3435 errors.append(output_api.PresubmitPromptWarning(
3436 'Include guard %s not covering the whole file' % (
3437 guard_name), [f.LocalPath()]))
3438 break # Nothing else to check and enough to warn once.
3439
3440 if guard_name is None:
3441 errors.append(output_api.PresubmitPromptWarning(
3442 'Missing include guard %s' % expected_guard,
3443 [f.LocalPath()],
3444 'Missing include guard in %s\n'
3445 'Recommended name: %s\n'
3446 'This check can be disabled by having the string\n'
3447 'no-include-guard-because-multiply-included in the header.' %
3448 (f.LocalPath(), expected_guard)))
3449
3450 return errors
3451
3452
mostynbb639aca52015-01-07 20:31:233453def _CheckForWindowsLineEndings(input_api, output_api):
3454 """Check source code and known ascii text files for Windows style line
3455 endings.
3456 """
earthdok1b5e0ee2015-03-10 15:19:103457 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233458
3459 file_inclusion_pattern = (
3460 known_text_files,
3461 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3462 )
3463
mostynbb639aca52015-01-07 20:31:233464 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533465 source_file_filter = lambda f: input_api.FilterSourceFile(
3466 f, white_list=file_inclusion_pattern, black_list=None)
3467 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503468 include_file = False
3469 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233470 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503471 include_file = True
3472 if include_file:
3473 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233474
3475 if problems:
3476 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3477 'these files to contain Windows style line endings?\n' +
3478 '\n'.join(problems))]
3479
3480 return []
3481
3482
Vaclav Brozekd5de76a2018-03-17 07:57:503483def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133484 """Checks that all source files use SYSLOG properly."""
3485 syslog_files = []
3486 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563487 for line_number, line in f.ChangedContents():
3488 if 'SYSLOG' in line:
3489 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3490
pastarmovj89f7ee12016-09-20 14:58:133491 if syslog_files:
3492 return [output_api.PresubmitPromptWarning(
3493 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3494 ' calls.\nFiles to check:\n', items=syslog_files)]
3495 return []
3496
3497
[email protected]1f7b4172010-01-28 01:17:343498def CheckChangeOnUpload(input_api, output_api):
3499 results = []
3500 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473501 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283502 results.extend(
jam93a6ee792017-02-08 23:59:223503 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193504 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223505 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133506 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163507 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:533508 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193509 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543510 return results
[email protected]ca8d1982009-02-19 16:33:123511
3512
[email protected]1bfb8322014-04-23 01:02:413513def GetTryServerMasterForBot(bot):
3514 """Returns the Try Server master for the given bot.
3515
[email protected]0bb112362014-07-26 04:38:323516 It tries to guess the master from the bot name, but may still fail
3517 and return None. There is no longer a default master.
3518 """
3519 # Potentially ambiguous bot names are listed explicitly.
3520 master_map = {
tandriie5587792016-07-14 00:34:503521 'chromium_presubmit': 'master.tryserver.chromium.linux',
3522 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413523 }
[email protected]0bb112362014-07-26 04:38:323524 master = master_map.get(bot)
3525 if not master:
wnwen4fbaab82016-05-25 12:54:363526 if 'android' in bot:
tandriie5587792016-07-14 00:34:503527 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363528 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503529 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323530 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503531 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323532 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503533 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323534 return master
[email protected]1bfb8322014-04-23 01:02:413535
3536
[email protected]ca8d1982009-02-19 16:33:123537def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543538 results = []
[email protected]1f7b4172010-01-28 01:17:343539 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543540 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273541 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343542 input_api,
3543 output_api,
[email protected]2fdd1f362013-01-16 03:56:033544 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273545
jam93a6ee792017-02-08 23:59:223546 results.extend(
3547 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543548 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3549 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413550 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3551 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543552 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143553
3554
3555def _CheckTranslationScreenshots(input_api, output_api):
3556 PART_FILE_TAG = "part"
3557 import os
3558 import sys
3559 from io import StringIO
3560
3561 try:
3562 old_sys_path = sys.path
3563 sys.path = sys.path + [input_api.os_path.join(
3564 input_api.PresubmitLocalPath(), 'tools', 'grit')]
3565 import grit.grd_reader
3566 import grit.node.message
3567 import grit.util
3568 finally:
3569 sys.path = old_sys_path
3570
3571 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
3572 """Load the grd file and return a dict of message ids to messages.
3573
3574 Ignores any nested grdp files pointed by <part> tag.
3575 """
3576 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
3577 stop_after=None, first_ids_file=None,
3578 debug=False, defines=None,
3579 tags_to_ignore=set([PART_FILE_TAG]))
3580 return {
3581 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
3582 grit.node.message.MessageNode)
3583 }
3584
3585 def _GetGrdpMessagesFromString(grdp_string):
3586 """Parses the contents of a grdp file given in grdp_string.
3587
3588 grd_reader can't parse grdp files directly. Instead, this creates a
3589 temporary directory with a grd file pointing to the grdp file, and loads the
3590 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
3591 """
3592 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
3593 <grit latest_public_release="1" current_release="1">
3594 <release seq="1">
3595 <messages>
3596 <part file="sub.grdp" />
3597 </messages>
3598 </release>
3599 </grit>
3600 """
3601 with grit.util.TempDir({'main.grd': WRAPPER,
3602 'sub.grdp': grdp_string}) as temp_dir:
3603 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
3604
3605 new_or_added_paths = set(f.LocalPath()
3606 for f in input_api.AffectedFiles()
3607 if (f.Action() == 'A' or f.Action() == 'M'))
3608 removed_paths = set(f.LocalPath()
3609 for f in input_api.AffectedFiles(include_deletes=True)
3610 if f.Action() == 'D')
3611
3612 affected_grds = [f for f in input_api.AffectedFiles()
3613 if (f.LocalPath().endswith('.grd') or
3614 f.LocalPath().endswith('.grdp'))]
3615 affected_png_paths = [f.AbsoluteLocalPath()
3616 for f in input_api.AffectedFiles()
3617 if (f.LocalPath().endswith('.png'))]
3618
3619 # Check for screenshots. Developers can upload screenshots using
3620 # tools/translation/upload_screenshots.py which finds and uploads
3621 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
3622 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
3623 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
3624 #
3625 # The logic here is as follows:
3626 #
3627 # - If the CL has a .png file under the screenshots directory for a grd
3628 # file, warn the developer. Actual images should never be checked into the
3629 # Chrome repo.
3630 #
3631 # - If the CL contains modified or new messages in grd files and doesn't
3632 # contain the corresponding .sha1 files, warn the developer to add images
3633 # and upload them via tools/translation/upload_screenshots.py.
3634 #
3635 # - If the CL contains modified or new messages in grd files and the
3636 # corresponding .sha1 files, everything looks good.
3637 #
3638 # - If the CL contains removed messages in grd files but the corresponding
3639 # .sha1 files aren't removed, warn the developer to remove them.
3640 unnecessary_screenshots = []
3641 missing_sha1 = []
3642 unnecessary_sha1_files = []
3643
3644
3645 def _CheckScreenshotAdded(screenshots_dir, message_id):
3646 sha1_path = input_api.os_path.join(
3647 screenshots_dir, message_id + '.png.sha1')
3648 if sha1_path not in new_or_added_paths:
3649 missing_sha1.append(sha1_path)
3650
3651
3652 def _CheckScreenshotRemoved(screenshots_dir, message_id):
3653 sha1_path = input_api.os_path.join(
3654 screenshots_dir, message_id + '.png.sha1')
3655 if sha1_path not in removed_paths:
3656 unnecessary_sha1_files.append(sha1_path)
3657
3658
3659 for f in affected_grds:
3660 file_path = f.LocalPath()
3661 old_id_to_msg_map = {}
3662 new_id_to_msg_map = {}
3663 if file_path.endswith('.grdp'):
3664 if f.OldContents():
3665 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393666 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143667 if f.NewContents():
3668 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393669 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143670 else:
3671 if f.OldContents():
3672 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393673 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143674 if f.NewContents():
3675 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393676 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143677
3678 # Compute added, removed and modified message IDs.
3679 old_ids = set(old_id_to_msg_map)
3680 new_ids = set(new_id_to_msg_map)
3681 added_ids = new_ids - old_ids
3682 removed_ids = old_ids - new_ids
3683 modified_ids = set([])
3684 for key in old_ids.intersection(new_ids):
3685 if (old_id_to_msg_map[key].FormatXml()
3686 != new_id_to_msg_map[key].FormatXml()):
3687 modified_ids.add(key)
3688
3689 grd_name, ext = input_api.os_path.splitext(
3690 input_api.os_path.basename(file_path))
3691 screenshots_dir = input_api.os_path.join(
3692 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
3693
3694 # Check the screenshot directory for .png files. Warn if there is any.
3695 for png_path in affected_png_paths:
3696 if png_path.startswith(screenshots_dir):
3697 unnecessary_screenshots.append(png_path)
3698
3699 for added_id in added_ids:
3700 _CheckScreenshotAdded(screenshots_dir, added_id)
3701
3702 for modified_id in modified_ids:
3703 _CheckScreenshotAdded(screenshots_dir, modified_id)
3704
3705 for removed_id in removed_ids:
3706 _CheckScreenshotRemoved(screenshots_dir, removed_id)
3707
3708 results = []
3709 if unnecessary_screenshots:
3710 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393711 'Do not include actual screenshots in the changelist. Run '
3712 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143713 sorted(unnecessary_screenshots)))
3714
3715 if missing_sha1:
3716 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393717 'You are adding or modifying UI strings.\n'
3718 'To ensure the best translations, take screenshots of the relevant UI '
3719 '(https://g.co/chrome/translation) and add these files to your '
3720 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143721
3722 if unnecessary_sha1_files:
3723 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393724 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143725 sorted(unnecessary_sha1_files)))
3726
3727 return results