blob: 7f2ec1b2f84aab14d7b54df3dff0eee524a61982 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0413 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
14 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
15 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
16 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
17 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4918 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0419 r"^third_party[\\/]breakpad[\\/].*",
20 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5421 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
Egor Paskoce145c42018-09-28 19:31:0423 r".+[\\/]pnacl_shim\.c$",
24 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
25 r"^chrome[\\/]browser[\\/]resources[\\/]pdf[\\/]index.js",
26 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1427 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0428 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5429 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0430 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4031)
[email protected]ca8d1982009-02-19 16:33:1232
wnwenbdc444e2016-05-25 13:44:1533
[email protected]06e6d0ff2012-12-11 01:36:4434# Fragment of a regular expression that matches C++ and Objective-C++
35# implementation files.
36_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
37
wnwenbdc444e2016-05-25 13:44:1538
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1939# Fragment of a regular expression that matches C++ and Objective-C++
40# header files.
41_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
42
43
[email protected]06e6d0ff2012-12-11 01:36:4444# Regular expression that matches code only used for test binaries
45# (best effort).
46_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0447 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4448 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4449 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1250 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4451 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0452 r'.*[\\/](test|tool(s)?)[\\/].*',
[email protected]ef070cc2013-05-03 11:53:0553 # content_shell is used for running layout tests.
Egor Paskoce145c42018-09-28 19:31:0454 r'content[\\/]shell[\\/].*',
[email protected]7b054982013-11-27 00:44:4755 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0456 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0857 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0458 r'testing[\\/]iossim[\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4459)
[email protected]ca8d1982009-02-19 16:33:1260
wnwenbdc444e2016-05-25 13:44:1561
[email protected]eea609a2011-11-18 13:10:1262_TEST_ONLY_WARNING = (
63 'You might be calling functions intended only for testing from\n'
64 'production code. It is OK to ignore this warning if you know what\n'
65 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5866 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1267
68
[email protected]cf9b78f2012-11-14 11:40:2869_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4070 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2171 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
72 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2873
wnwenbdc444e2016-05-25 13:44:1574
Eric Stevensona9a980972017-09-23 00:04:4175_BANNED_JAVA_FUNCTIONS = (
76 (
77 'StrictMode.allowThreadDiskReads()',
78 (
79 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
80 'directly.',
81 ),
82 False,
83 ),
84 (
85 'StrictMode.allowThreadDiskWrites()',
86 (
87 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
88 'directly.',
89 ),
90 False,
91 ),
92)
93
[email protected]127f18ec2012-06-16 05:05:5994_BANNED_OBJC_FUNCTIONS = (
95 (
96 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2097 (
98 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5999 'prohibited. Please use CrTrackingArea instead.',
100 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
101 ),
102 False,
103 ),
104 (
[email protected]eaae1972014-04-16 04:17:26105 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20106 (
107 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59108 'instead.',
109 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
110 ),
111 False,
112 ),
113 (
114 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20115 (
116 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59117 'Please use |convertPoint:(point) fromView:nil| instead.',
118 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
119 ),
120 True,
121 ),
122 (
123 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20124 (
125 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59126 'Please use |convertPoint:(point) toView:nil| instead.',
127 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
128 ),
129 True,
130 ),
131 (
132 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20133 (
134 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59135 'Please use |convertRect:(point) fromView:nil| instead.',
136 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
137 ),
138 True,
139 ),
140 (
141 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20142 (
143 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59144 'Please use |convertRect:(point) toView:nil| instead.',
145 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
146 ),
147 True,
148 ),
149 (
150 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20151 (
152 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59153 'Please use |convertSize:(point) fromView:nil| instead.',
154 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
155 ),
156 True,
157 ),
158 (
159 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20160 (
161 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59162 'Please use |convertSize:(point) toView:nil| instead.',
163 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
164 ),
165 True,
166 ),
jif65398702016-10-27 10:19:48167 (
168 r"/\s+UTF8String\s*]",
169 (
170 'The use of -[NSString UTF8String] is dangerous as it can return null',
171 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
172 'Please use |SysNSStringToUTF8| instead.',
173 ),
174 True,
175 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34176 (
177 r'__unsafe_unretained',
178 (
179 'The use of __unsafe_unretained is almost certainly wrong, unless',
180 'when interacting with NSFastEnumeration or NSInvocation.',
181 'Please use __weak in files build with ARC, nothing otherwise.',
182 ),
183 False,
184 ),
[email protected]127f18ec2012-06-16 05:05:59185)
186
Sylvain Defresnea8b73d252018-02-28 15:45:54187_BANNED_IOS_OBJC_FUNCTIONS = (
188 (
189 r'/\bTEST[(]',
190 (
191 'TEST() macro should not be used in Objective-C++ code as it does not ',
192 'drain the autorelease pool at the end of the test. Use TEST_F() ',
193 'macro instead with a fixture inheriting from PlatformTest (or a ',
194 'typedef).'
195 ),
196 True,
197 ),
198 (
199 r'/\btesting::Test\b',
200 (
201 'testing::Test should not be used in Objective-C++ code as it does ',
202 'not drain the autorelease pool at the end of the test. Use ',
203 'PlatformTest instead.'
204 ),
205 True,
206 ),
207)
208
[email protected]127f18ec2012-06-16 05:05:59209
210_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20211 # Make sure that gtest's FRIEND_TEST() macro is not used; the
212 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30213 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20214 (
thomasandersone7caaa9b2017-03-29 19:22:53215 r'\bNULL\b',
216 (
217 'New code should not use NULL. Use nullptr instead.',
218 ),
219 True,
220 (),
221 ),
222 (
[email protected]23e6cbc2012-06-16 18:51:20223 'FRIEND_TEST(',
224 (
[email protected]e3c945502012-06-26 20:01:49225 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20226 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
227 ),
228 False,
[email protected]7345da02012-11-27 14:31:49229 (),
[email protected]23e6cbc2012-06-16 18:51:20230 ),
231 (
thomasanderson4b569052016-09-14 20:15:53232 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
233 (
234 'Chrome clients wishing to select events on X windows should use',
235 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
236 'you are selecting events from the GPU process, or if you are using',
237 'an XDisplay other than gfx::GetXDisplay().',
238 ),
239 True,
240 (
Egor Paskoce145c42018-09-28 19:31:04241 r"^ui[\\/]gl[\\/].*\.cc$",
242 r"^media[\\/]gpu[\\/].*\.cc$",
243 r"^gpu[\\/].*\.cc$",
thomasanderson4b569052016-09-14 20:15:53244 ),
245 ),
246 (
thomasandersone043e3ce2017-06-08 00:43:20247 r'XInternAtom|xcb_intern_atom',
248 (
thomasanderson11aa41d2017-06-08 22:22:38249 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20250 ),
251 True,
252 (
Egor Paskoce145c42018-09-28 19:31:04253 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
254 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
255 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20256 ),
257 ),
258 (
tomhudsone2c14d552016-05-26 17:07:46259 'setMatrixClip',
260 (
261 'Overriding setMatrixClip() is prohibited; ',
262 'the base function is deprecated. ',
263 ),
264 True,
265 (),
266 ),
267 (
[email protected]52657f62013-05-20 05:30:31268 'SkRefPtr',
269 (
270 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22271 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31272 ),
273 True,
274 (),
275 ),
276 (
277 'SkAutoRef',
278 (
279 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22280 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31281 ),
282 True,
283 (),
284 ),
285 (
286 'SkAutoTUnref',
287 (
288 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22289 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31290 ),
291 True,
292 (),
293 ),
294 (
295 'SkAutoUnref',
296 (
297 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
298 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22299 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31300 ),
301 True,
302 (),
303 ),
[email protected]d89eec82013-12-03 14:10:59304 (
305 r'/HANDLE_EINTR\(.*close',
306 (
307 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
308 'descriptor will be closed, and it is incorrect to retry the close.',
309 'Either call close directly and ignore its return value, or wrap close',
310 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
311 ),
312 True,
313 (),
314 ),
315 (
316 r'/IGNORE_EINTR\((?!.*close)',
317 (
318 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
319 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
320 ),
321 True,
322 (
323 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04324 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
325 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59326 ),
327 ),
[email protected]ec5b3f02014-04-04 18:43:43328 (
329 r'/v8::Extension\(',
330 (
331 'Do not introduce new v8::Extensions into the code base, use',
332 'gin::Wrappable instead. See http://crbug.com/334679',
333 ),
334 True,
[email protected]f55c90ee62014-04-12 00:50:03335 (
Egor Paskoce145c42018-09-28 19:31:04336 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03337 ),
[email protected]ec5b3f02014-04-04 18:43:43338 ),
skyostilf9469f72015-04-20 10:38:52339 (
jame2d1a952016-04-02 00:27:10340 '#pragma comment(lib,',
341 (
342 'Specify libraries to link with in build files and not in the source.',
343 ),
344 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41345 (
tzik3f295992018-12-04 20:32:23346 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04347 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41348 ),
jame2d1a952016-04-02 00:27:10349 ),
fdorayc4ac18d2017-05-01 21:39:59350 (
Gabriel Charette7cc6c432018-04-25 20:52:02351 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59352 (
353 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
354 ),
355 False,
356 (),
357 ),
358 (
Gabriel Charette7cc6c432018-04-25 20:52:02359 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59360 (
361 'Consider using THREAD_CHECKER macros instead of the class directly.',
362 ),
363 False,
364 (),
365 ),
dbeamb6f4fde2017-06-15 04:03:06366 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06367 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
368 (
369 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
370 'deprecated (http://crbug.com/634507). Please avoid converting away',
371 'from the Time types in Chromium code, especially if any math is',
372 'being done on time values. For interfacing with platform/library',
373 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
374 'type converter methods instead. For faking TimeXXX values (for unit',
375 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
376 'other use cases, please contact base/time/OWNERS.',
377 ),
378 False,
379 (),
380 ),
381 (
dbeamb6f4fde2017-06-15 04:03:06382 'CallJavascriptFunctionUnsafe',
383 (
384 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
385 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
386 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
387 ),
388 False,
389 (
Egor Paskoce145c42018-09-28 19:31:04390 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
391 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
392 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06393 ),
394 ),
dskiba1474c2bfd62017-07-20 02:19:24395 (
396 'leveldb::DB::Open',
397 (
398 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
399 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
400 "Chrome's tracing, making their memory usage visible.",
401 ),
402 True,
403 (
404 r'^third_party/leveldatabase/.*\.(cc|h)$',
405 ),
Gabriel Charette0592c3a2017-07-26 12:02:04406 ),
407 (
Chris Mumfordc38afb62017-10-09 17:55:08408 'leveldb::NewMemEnv',
409 (
410 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58411 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
412 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08413 ),
414 True,
415 (
416 r'^third_party/leveldatabase/.*\.(cc|h)$',
417 ),
418 ),
419 (
Gabriel Charetted9839bc2017-07-29 14:17:47420 'RunLoop::QuitCurrent',
421 (
Robert Liao64b7ab22017-08-04 23:03:43422 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
423 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47424 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41425 False,
Gabriel Charetted9839bc2017-07-29 14:17:47426 (),
Gabriel Charettea44975052017-08-21 23:14:04427 ),
428 (
429 'base::ScopedMockTimeMessageLoopTaskRunner',
430 (
Gabriel Charette87cc1af2018-04-25 20:52:51431 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
432 'ScopedTaskEnvironment::MainThreadType::MOCK_TIME. There are still a',
433 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
434 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
435 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04436 ),
Gabriel Charette87cc1af2018-04-25 20:52:51437 False,
Gabriel Charettea44975052017-08-21 23:14:04438 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57439 ),
440 (
441 r'std::regex',
442 (
443 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02444 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57445 ),
446 True,
447 (),
Francois Doray43670e32017-09-27 12:40:38448 ),
449 (
450 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
451 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
452 (
453 'Use the new API in base/threading/thread_restrictions.h.',
454 ),
Gabriel Charette04b138f2018-08-06 00:03:22455 False,
Francois Doray43670e32017-09-27 12:40:38456 (),
457 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38458 (
459 r'/\bbase::Bind\(',
460 (
Gabriel Charette147335ea2018-03-22 15:59:19461 'Please consider using base::Bind{Once,Repeating} instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02462 'of base::Bind. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38463 ),
464 False,
465 (),
466 ),
467 (
468 r'/\bbase::Callback<',
469 (
Gabriel Charette147335ea2018-03-22 15:59:19470 'Please consider using base::{Once,Repeating}Callback instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02471 'of base::Callback. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38472 ),
473 False,
474 (),
475 ),
476 (
477 r'/\bbase::Closure\b',
478 (
Gabriel Charette147335ea2018-03-22 15:59:19479 'Please consider using base::{Once,Repeating}Closure instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02480 'of base::Closure. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38481 ),
482 False,
483 (),
484 ),
Victor Costan3653df62018-02-08 21:38:16485 (
Gabriel Charette147335ea2018-03-22 15:59:19486 r'RunMessageLoop',
487 (
488 'RunMessageLoop is deprecated, use RunLoop instead.',
489 ),
490 False,
491 (),
492 ),
493 (
494 r'RunThisRunLoop',
495 (
496 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
497 ),
498 False,
499 (),
500 ),
501 (
502 r'RunAllPendingInMessageLoop()',
503 (
504 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
505 "if you're convinced you need this.",
506 ),
507 False,
508 (),
509 ),
510 (
511 r'RunAllPendingInMessageLoop(BrowserThread',
512 (
513 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
514 'BrowserThread::UI, TestBrowserThreadBundle::RunIOThreadUntilIdle',
515 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
516 'async events instead of flushing threads.',
517 ),
518 False,
519 (),
520 ),
521 (
522 r'MessageLoopRunner',
523 (
524 'MessageLoopRunner is deprecated, use RunLoop instead.',
525 ),
526 False,
527 (),
528 ),
529 (
530 r'GetDeferredQuitTaskForRunLoop',
531 (
532 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
533 "gab@ if you found a use case where this is the only solution.",
534 ),
535 False,
536 (),
537 ),
538 (
Victor Costan3653df62018-02-08 21:38:16539 'sqlite3_initialize',
540 (
541 'Instead of sqlite3_initialize, depend on //sql, ',
542 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
543 ),
544 True,
545 (
546 r'^sql/initialization\.(cc|h)$',
547 r'^third_party/sqlite/.*\.(c|cc|h)$',
548 ),
549 ),
Matt Menke7f520a82018-03-28 21:38:37550 (
551 'net::URLFetcher',
552 (
553 'net::URLFetcher should no longer be used in content embedders. ',
554 'Instead, use network::SimpleURLLoader instead, which supports ',
555 'an out-of-process network stack. ',
556 'net::URLFetcher may still be used in binaries that do not embed',
557 'content.',
558 ),
Matt Menke59716d02018-04-05 12:45:53559 False,
Matt Menke7f520a82018-03-28 21:38:37560 (
Egor Paskoce145c42018-09-28 19:31:04561 r'^ios[\\/].*\.(cc|h)$',
562 r'.*[\\/]ios[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:37563 r'.*_ios\.(cc|h)$',
Egor Paskoce145c42018-09-28 19:31:04564 r'^net[\\/].*\.(cc|h)$',
565 r'.*[\\/]tools[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:37566 ),
567 ),
jdoerried7d10ab2018-04-27 10:46:13568 (
tzik5de2157f2018-05-08 03:42:47569 r'std::random_shuffle',
570 (
571 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
572 'base::RandomShuffle instead.'
573 ),
574 True,
575 (),
576 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24577 (
578 'ios/web/public/test/http_server',
579 (
580 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
581 ),
582 False,
583 (),
584 ),
Robert Liao764c9492019-01-24 18:46:28585 (
586 'GetAddressOf',
587 (
588 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
589 'implicated in a few leaks. Use operator& instead.'
590 ),
591 True,
592 (),
593 ),
[email protected]127f18ec2012-06-16 05:05:59594)
595
wnwenbdc444e2016-05-25 13:44:15596
mlamouria82272622014-09-16 18:45:04597_IPC_ENUM_TRAITS_DEPRECATED = (
598 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50599 'See http://www.chromium.org/Home/chromium-security/education/'
600 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:04601
Stephen Martinis97a394142018-06-07 23:06:05602_LONG_PATH_ERROR = (
603 'Some files included in this CL have file names that are too long (> 200'
604 ' characters). If committed, these files will cause issues on Windows. See'
605 ' https://crbug.com/612667 for more details.'
606)
607
Shenghua Zhangbfaa38b82017-11-16 21:58:02608_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:04609 r".*[\\/]BuildHooksAndroidImpl\.java",
610 r".*[\\/]LicenseContentProvider\.java",
611 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:28612 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:02613]
[email protected]127f18ec2012-06-16 05:05:59614
Sean Kau46e29bc2017-08-28 16:31:16615# These paths contain test data and other known invalid JSON files.
616_KNOWN_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:04617 r'test[\\/]data[\\/]',
618 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
619 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:04620 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:43621 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:16622]
623
624
[email protected]b00342e7f2013-03-26 16:21:54625_VALID_OS_MACROS = (
626 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08627 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54628 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:12629 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:54630 'OS_BSD',
631 'OS_CAT', # For testing.
632 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:04633 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:54634 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37635 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54636 'OS_IOS',
637 'OS_LINUX',
638 'OS_MACOSX',
639 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21640 'OS_NACL_NONSFI',
641 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12642 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54643 'OS_OPENBSD',
644 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37645 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54646 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54647 'OS_WIN',
648)
649
650
agrievef32bcc72016-04-04 14:57:40651_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:39652 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36653 'base/android/jni_generator/jni_generator.pydeps',
654 'base/android/jni_generator/jni_registration_generator.pydeps',
655 'build/android/gyp/aar.pydeps',
656 'build/android/gyp/aidl.pydeps',
657 'build/android/gyp/apkbuilder.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36658 'build/android/gyp/bytecode_processor.pydeps',
659 'build/android/gyp/compile_resources.pydeps',
660 'build/android/gyp/create_bundle_wrapper_script.pydeps',
661 'build/android/gyp/copy_ex.pydeps',
662 'build/android/gyp/create_app_bundle.pydeps',
663 'build/android/gyp/create_apk_operations_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36664 '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',
Sam Maier3599daa2018-11-26 18:02:59669 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36670 'build/android/gyp/dex.pydeps',
671 'build/android/gyp/dist_aar.pydeps',
672 'build/android/gyp/emma_instr.pydeps',
673 'build/android/gyp/filter_zip.pydeps',
674 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:36675 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36676 'build/android/gyp/ijar.pydeps',
677 'build/android/gyp/java_cpp_enum.pydeps',
678 'build/android/gyp/javac.pydeps',
679 'build/android/gyp/jinja_template.pydeps',
680 'build/android/gyp/lint.pydeps',
681 'build/android/gyp/main_dex_list.pydeps',
682 'build/android/gyp/merge_jar_info_files.pydeps',
683 'build/android/gyp/merge_manifest.pydeps',
684 'build/android/gyp/prepare_resources.pydeps',
685 'build/android/gyp/proguard.pydeps',
686 'build/android/gyp/write_build_config.pydeps',
687 'build/android/gyp/write_ordered_libraries.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:56688 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36689 'build/android/incremental_install/generate_android_manifest.pydeps',
690 'build/android/incremental_install/write_installer_json.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22691 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:40692 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04693 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36694 'build/protoc_java.pydeps',
Sam Maier3599daa2018-11-26 18:02:59695 ('build/secondary/third_party/android_platform/'
696 'development/scripts/stack.pydeps'),
agrieve732db3a2016-04-26 19:18:19697 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40698]
699
wnwenbdc444e2016-05-25 13:44:15700
agrievef32bcc72016-04-04 14:57:40701_GENERIC_PYDEPS_FILES = [
John Chencde89192018-01-27 21:18:40702 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Cole Winstanley7045a1b2018-08-27 23:37:29703 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22704 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:40705]
706
wnwenbdc444e2016-05-25 13:44:15707
agrievef32bcc72016-04-04 14:57:40708_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
709
710
Eric Boren6fd2b932018-01-25 15:05:08711# Bypass the AUTHORS check for these accounts.
712_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:29713 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
714 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:08715 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
Eric Boren57cc805b2018-08-20 17:28:32716 'spirv', 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:59717 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:45718 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:59719 ) | set('%[email protected]' % s
Robert Ma7f024172018-11-01 20:59:22720 for s in ('v8-ci-autoroll-builder', 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:04721 ) | set('%[email protected]' % s
722 for s in ('chromium-autoroll',)
723 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:30724 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:08725
726
[email protected]55459852011-08-10 15:17:19727def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
728 """Attempts to prevent use of functions intended only for testing in
729 non-testing code. For now this is just a best-effort implementation
730 that ignores header files and may have some false positives. A
731 better implementation would probably need a proper C++ parser.
732 """
733 # We only scan .cc files and the like, as the declaration of
734 # for-testing functions in header files are hard to distinguish from
735 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49736 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:19737
jochenc0d4808c2015-07-27 09:25:42738 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19739 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09740 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19741 exclusion_pattern = input_api.re.compile(
742 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
743 base_function_pattern, base_function_pattern))
744
745 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44746 black_list = (_EXCLUDED_PATHS +
747 _TEST_CODE_EXCLUDED_PATHS +
748 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19749 return input_api.FilterSourceFile(
750 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49751 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:19752 black_list=black_list)
753
754 problems = []
755 for f in input_api.AffectedSourceFiles(FilterFile):
756 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24757 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03758 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46759 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03760 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19761 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03762 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19763
764 if problems:
[email protected]f7051d52013-04-02 18:31:42765 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03766 else:
767 return []
[email protected]55459852011-08-10 15:17:19768
769
Vaclav Brozek7dbc28c2018-03-27 08:35:23770def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
771 """This is a simplified version of
772 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
773 """
774 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
775 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
776 name_pattern = r'ForTest(s|ing)?'
777 # Describes an occurrence of "ForTest*" inside a // comment.
778 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
779 # Catch calls.
780 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
781 # Ignore definitions. (Comments are ignored separately.)
782 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
783
784 problems = []
785 sources = lambda x: input_api.FilterSourceFile(
786 x,
787 black_list=(('(?i).*test', r'.*\/junit\/')
788 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49789 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:23790 )
791 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
792 local_path = f.LocalPath()
793 is_inside_javadoc = False
794 for line_number, line in f.ChangedContents():
795 if is_inside_javadoc and javadoc_end_re.search(line):
796 is_inside_javadoc = False
797 if not is_inside_javadoc and javadoc_start_re.search(line):
798 is_inside_javadoc = True
799 if is_inside_javadoc:
800 continue
801 if (inclusion_re.search(line) and
802 not comment_re.search(line) and
803 not exclusion_re.search(line)):
804 problems.append(
805 '%s:%d\n %s' % (local_path, line_number, line.strip()))
806
807 if problems:
808 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
809 else:
810 return []
811
812
[email protected]10689ca2011-09-02 02:31:54813def _CheckNoIOStreamInHeaders(input_api, output_api):
814 """Checks to make sure no .h files include <iostream>."""
815 files = []
816 pattern = input_api.re.compile(r'^#include\s*<iostream>',
817 input_api.re.MULTILINE)
818 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
819 if not f.LocalPath().endswith('.h'):
820 continue
821 contents = input_api.ReadFile(f)
822 if pattern.search(contents):
823 files.append(f)
824
825 if len(files):
yolandyandaabc6d2016-04-18 18:29:39826 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06827 'Do not #include <iostream> in header files, since it inserts static '
828 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54829 '#include <ostream>. See http://crbug.com/94794',
830 files) ]
831 return []
832
Danil Chapovalov3518f362018-08-11 16:13:43833def _CheckNoStrCatRedefines(input_api, output_api):
834 """Checks no windows headers with StrCat redefined are included directly."""
835 files = []
836 pattern_deny = input_api.re.compile(
837 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
838 input_api.re.MULTILINE)
839 pattern_allow = input_api.re.compile(
840 r'^#include\s"base/win/windows_defines.inc"',
841 input_api.re.MULTILINE)
842 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
843 contents = input_api.ReadFile(f)
844 if pattern_deny.search(contents) and not pattern_allow.search(contents):
845 files.append(f.LocalPath())
846
847 if len(files):
848 return [output_api.PresubmitError(
849 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
850 'directly since they pollute code with StrCat macro. Instead, '
851 'include matching header from base/win. See http://crbug.com/856536',
852 files) ]
853 return []
854
[email protected]10689ca2011-09-02 02:31:54855
[email protected]72df4e782012-06-21 16:28:18856def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52857 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18858 problems = []
859 for f in input_api.AffectedFiles():
860 if (not f.LocalPath().endswith(('.cc', '.mm'))):
861 continue
862
863 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04864 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18865 problems.append(' %s:%d' % (f.LocalPath(), line_num))
866
867 if not problems:
868 return []
869 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
870 '\n'.join(problems))]
871
Dominic Battre033531052018-09-24 15:45:34872def _CheckNoDISABLETypoInTests(input_api, output_api):
873 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
874
875 This test warns if somebody tries to disable a test with the DISABLE_ prefix
876 instead of DISABLED_. To filter false positives, reports are only generated
877 if a corresponding MAYBE_ line exists.
878 """
879 problems = []
880
881 # The following two patterns are looked for in tandem - is a test labeled
882 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
883 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
884 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
885
886 # This is for the case that a test is disabled on all platforms.
887 full_disable_pattern = input_api.re.compile(
888 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
889 input_api.re.MULTILINE)
890
Katie Df13948e2018-09-25 07:33:44891 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:34892 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
893 continue
894
895 # Search for MABYE_, DISABLE_ pairs.
896 disable_lines = {} # Maps of test name to line number.
897 maybe_lines = {}
898 for line_num, line in f.ChangedContents():
899 disable_match = disable_pattern.search(line)
900 if disable_match:
901 disable_lines[disable_match.group(1)] = line_num
902 maybe_match = maybe_pattern.search(line)
903 if maybe_match:
904 maybe_lines[maybe_match.group(1)] = line_num
905
906 # Search for DISABLE_ occurrences within a TEST() macro.
907 disable_tests = set(disable_lines.keys())
908 maybe_tests = set(maybe_lines.keys())
909 for test in disable_tests.intersection(maybe_tests):
910 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
911
912 contents = input_api.ReadFile(f)
913 full_disable_match = full_disable_pattern.search(contents)
914 if full_disable_match:
915 problems.append(' %s' % f.LocalPath())
916
917 if not problems:
918 return []
919 return [
920 output_api.PresubmitPromptWarning(
921 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
922 '\n'.join(problems))
923 ]
924
[email protected]72df4e782012-06-21 16:28:18925
danakj61c1aa22015-10-26 19:55:52926def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57927 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52928 errors = []
929 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
930 input_api.re.MULTILINE)
931 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
932 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
933 continue
934 for lnum, line in f.ChangedContents():
935 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17936 errors.append(output_api.PresubmitError(
937 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57938 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17939 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52940 return errors
941
942
mcasasb7440c282015-02-04 14:52:19943def _FindHistogramNameInLine(histogram_name, line):
944 """Tries to find a histogram name or prefix in a line."""
945 if not "affected-histogram" in line:
946 return histogram_name in line
947 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
948 # the histogram_name.
949 if not '"' in line:
950 return False
951 histogram_prefix = line.split('\"')[1]
952 return histogram_prefix in histogram_name
953
954
955def _CheckUmaHistogramChanges(input_api, output_api):
956 """Check that UMA histogram names in touched lines can still be found in other
957 lines of the patch or in histograms.xml. Note that this check would not catch
958 the reverse: changes in histograms.xml not matched in the code itself."""
959 touched_histograms = []
960 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:47961 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
962 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
963 name_pattern = r'"(.*?)"'
964 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
965 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
966 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
967 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
968 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:17969 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:19970 for f in input_api.AffectedFiles():
971 # If histograms.xml itself is modified, keep the modified lines for later.
972 if f.LocalPath().endswith(('histograms.xml')):
973 histograms_xml_modifications = f.ChangedContents()
974 continue
Vaclav Brozekbdac817c2018-03-24 06:30:47975 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
976 single_line_re = single_line_c_re
977 split_line_prefix_re = split_line_c_prefix_re
978 elif f.LocalPath().endswith(('java')):
979 single_line_re = single_line_java_re
980 split_line_prefix_re = split_line_java_prefix_re
981 else:
mcasasb7440c282015-02-04 14:52:19982 continue
983 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:17984 if last_line_matched_prefix:
985 suffix_found = split_line_suffix_re.search(line)
986 if suffix_found :
987 touched_histograms.append([suffix_found.group(1), f, line_num])
988 last_line_matched_prefix = False
989 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:06990 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:19991 if found:
992 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:17993 continue
994 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:19995
996 # Search for the touched histogram names in the local modifications to
997 # histograms.xml, and, if not found, on the base histograms.xml file.
998 unmatched_histograms = []
999 for histogram_info in touched_histograms:
1000 histogram_name_found = False
1001 for line_num, line in histograms_xml_modifications:
1002 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
1003 if histogram_name_found:
1004 break
1005 if not histogram_name_found:
1006 unmatched_histograms.append(histogram_info)
1007
eromanb90c82e7e32015-04-01 15:13:491008 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191009 problems = []
1010 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491011 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191012 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451013 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191014 histogram_name_found = False
1015 for line in histograms_xml:
1016 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
1017 if histogram_name_found:
1018 break
1019 if not histogram_name_found:
1020 problems.append(' [%s:%d] %s' %
1021 (f.LocalPath(), line_num, histogram_name))
1022
1023 if not problems:
1024 return []
1025 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1026 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491027 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191028
wnwenbdc444e2016-05-25 13:44:151029
yolandyandaabc6d2016-04-18 18:29:391030def _CheckFlakyTestUsage(input_api, output_api):
1031 """Check that FlakyTest annotation is our own instead of the android one"""
1032 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1033 files = []
1034 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1035 if f.LocalPath().endswith('Test.java'):
1036 if pattern.search(input_api.ReadFile(f)):
1037 files.append(f)
1038 if len(files):
1039 return [output_api.PresubmitError(
1040 'Use org.chromium.base.test.util.FlakyTest instead of '
1041 'android.test.FlakyTest',
1042 files)]
1043 return []
mcasasb7440c282015-02-04 14:52:191044
wnwenbdc444e2016-05-25 13:44:151045
[email protected]8ea5d4b2011-09-13 21:49:221046def _CheckNoNewWStrings(input_api, output_api):
1047 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271048 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221049 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201050 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571051 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341052 '/win/' in f.LocalPath() or
1053 'chrome_elf' in f.LocalPath() or
1054 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201055 continue
[email protected]8ea5d4b2011-09-13 21:49:221056
[email protected]a11dbe9b2012-08-07 01:32:581057 allowWString = False
[email protected]b5c24292011-11-28 14:38:201058 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581059 if 'presubmit: allow wstring' in line:
1060 allowWString = True
1061 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271062 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581063 allowWString = False
1064 else:
1065 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221066
[email protected]55463aa62011-10-12 00:48:271067 if not problems:
1068 return []
1069 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581070 ' If you are calling a cross-platform API that accepts a wstring, '
1071 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271072 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221073
1074
[email protected]2a8ac9c2011-10-19 17:20:441075def _CheckNoDEPSGIT(input_api, output_api):
1076 """Make sure .DEPS.git is never modified manually."""
1077 if any(f.LocalPath().endswith('.DEPS.git') for f in
1078 input_api.AffectedFiles()):
1079 return [output_api.PresubmitError(
1080 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1081 'automated system based on what\'s in DEPS and your changes will be\n'
1082 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501083 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1084 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441085 'for more information')]
1086 return []
1087
1088
tandriief664692014-09-23 14:51:471089def _CheckValidHostsInDEPS(input_api, output_api):
1090 """Checks that DEPS file deps are from allowed_hosts."""
1091 # Run only if DEPS file has been modified to annoy fewer bystanders.
1092 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1093 return []
1094 # Outsource work to gclient verify
1095 try:
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201096 input_api.subprocess.check_output(['gclient', 'verify'],
1097 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471098 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201099 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471100 return [output_api.PresubmitError(
1101 'DEPS file must have only git dependencies.',
1102 long_text=error.output)]
1103
1104
[email protected]127f18ec2012-06-16 05:05:591105def _CheckNoBannedFunctions(input_api, output_api):
1106 """Make sure that banned functions are not used."""
1107 warnings = []
1108 errors = []
1109
wnwenbdc444e2016-05-25 13:44:151110 def IsBlacklisted(affected_file, blacklist):
1111 local_path = affected_file.LocalPath()
1112 for item in blacklist:
1113 if input_api.re.match(item, local_path):
1114 return True
1115 return False
1116
Sylvain Defresnea8b73d252018-02-28 15:45:541117 def IsIosObcjFile(affected_file):
1118 local_path = affected_file.LocalPath()
1119 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1120 return False
1121 basename = input_api.os_path.basename(local_path)
1122 if 'ios' in basename.split('_'):
1123 return True
1124 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1125 if sep and 'ios' in local_path.split(sep):
1126 return True
1127 return False
1128
wnwenbdc444e2016-05-25 13:44:151129 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
1130 matched = False
1131 if func_name[0:1] == '/':
1132 regex = func_name[1:]
1133 if input_api.re.search(regex, line):
1134 matched = True
1135 elif func_name in line:
dchenge07de812016-06-20 19:27:171136 matched = True
wnwenbdc444e2016-05-25 13:44:151137 if matched:
dchenge07de812016-06-20 19:27:171138 problems = warnings
wnwenbdc444e2016-05-25 13:44:151139 if error:
dchenge07de812016-06-20 19:27:171140 problems = errors
wnwenbdc444e2016-05-25 13:44:151141 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1142 for message_line in message:
1143 problems.append(' %s' % message_line)
1144
Eric Stevensona9a980972017-09-23 00:04:411145 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1146 for f in input_api.AffectedFiles(file_filter=file_filter):
1147 for line_num, line in f.ChangedContents():
1148 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1149 CheckForMatch(f, line_num, line, func_name, message, error)
1150
[email protected]127f18ec2012-06-16 05:05:591151 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1152 for f in input_api.AffectedFiles(file_filter=file_filter):
1153 for line_num, line in f.ChangedContents():
1154 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151155 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591156
Sylvain Defresnea8b73d252018-02-28 15:45:541157 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1158 for line_num, line in f.ChangedContents():
1159 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1160 CheckForMatch(f, line_num, line, func_name, message, error)
1161
[email protected]127f18ec2012-06-16 05:05:591162 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1163 for f in input_api.AffectedFiles(file_filter=file_filter):
1164 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491165 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491166 if IsBlacklisted(f, excluded_paths):
1167 continue
wnwenbdc444e2016-05-25 13:44:151168 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591169
1170 result = []
1171 if (warnings):
1172 result.append(output_api.PresubmitPromptWarning(
1173 'Banned functions were used.\n' + '\n'.join(warnings)))
1174 if (errors):
1175 result.append(output_api.PresubmitError(
1176 'Banned functions were used.\n' + '\n'.join(errors)))
1177 return result
1178
1179
[email protected]6c063c62012-07-11 19:11:061180def _CheckNoPragmaOnce(input_api, output_api):
1181 """Make sure that banned functions are not used."""
1182 files = []
1183 pattern = input_api.re.compile(r'^#pragma\s+once',
1184 input_api.re.MULTILINE)
1185 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1186 if not f.LocalPath().endswith('.h'):
1187 continue
1188 contents = input_api.ReadFile(f)
1189 if pattern.search(contents):
1190 files.append(f)
1191
1192 if files:
1193 return [output_api.PresubmitError(
1194 'Do not use #pragma once in header files.\n'
1195 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1196 files)]
1197 return []
1198
[email protected]127f18ec2012-06-16 05:05:591199
[email protected]e7479052012-09-19 00:26:121200def _CheckNoTrinaryTrueFalse(input_api, output_api):
1201 """Checks to make sure we don't introduce use of foo ? true : false."""
1202 problems = []
1203 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1204 for f in input_api.AffectedFiles():
1205 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1206 continue
1207
1208 for line_num, line in f.ChangedContents():
1209 if pattern.match(line):
1210 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1211
1212 if not problems:
1213 return []
1214 return [output_api.PresubmitPromptWarning(
1215 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1216 '\n'.join(problems))]
1217
1218
[email protected]55f9f382012-07-31 11:02:181219def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281220 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181221 change. Breaking - rules is an error, breaking ! rules is a
1222 warning.
1223 """
mohan.reddyf21db962014-10-16 12:26:471224 import sys
[email protected]55f9f382012-07-31 11:02:181225 # We need to wait until we have an input_api object and use this
1226 # roundabout construct to import checkdeps because this file is
1227 # eval-ed and thus doesn't have __file__.
1228 original_sys_path = sys.path
1229 try:
1230 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471231 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181232 import checkdeps
1233 from cpp_checker import CppChecker
Jinsuk Kim5a092672017-10-24 22:42:241234 from java_checker import JavaChecker
rhalavati08acd232017-04-03 07:23:281235 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:181236 from rules import Rule
1237 finally:
1238 # Restore sys.path to what it was before.
1239 sys.path = original_sys_path
1240
1241 added_includes = []
rhalavati08acd232017-04-03 07:23:281242 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241243 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181244 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:281245 if CppChecker.IsCppFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501246 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081247 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
rhalavati08acd232017-04-03 07:23:281248 elif ProtoChecker.IsProtoFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501249 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081250 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241251 elif JavaChecker.IsJavaFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501252 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081253 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181254
[email protected]26385172013-05-09 23:11:351255 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181256
1257 error_descriptions = []
1258 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281259 error_subjects = set()
1260 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181261 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1262 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081263 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181264 description_with_path = '%s\n %s' % (path, rule_description)
1265 if rule_type == Rule.DISALLOW:
1266 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281267 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181268 else:
1269 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281270 warning_subjects.add("#includes")
1271
1272 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1273 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081274 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281275 description_with_path = '%s\n %s' % (path, rule_description)
1276 if rule_type == Rule.DISALLOW:
1277 error_descriptions.append(description_with_path)
1278 error_subjects.add("imports")
1279 else:
1280 warning_descriptions.append(description_with_path)
1281 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181282
Jinsuk Kim5a092672017-10-24 22:42:241283 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021284 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081285 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241286 description_with_path = '%s\n %s' % (path, rule_description)
1287 if rule_type == Rule.DISALLOW:
1288 error_descriptions.append(description_with_path)
1289 error_subjects.add("imports")
1290 else:
1291 warning_descriptions.append(description_with_path)
1292 warning_subjects.add("imports")
1293
[email protected]55f9f382012-07-31 11:02:181294 results = []
1295 if error_descriptions:
1296 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281297 'You added one or more %s that violate checkdeps rules.'
1298 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181299 error_descriptions))
1300 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421301 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281302 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181303 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281304 '%s? See relevant DEPS file(s) for details and contacts.' %
1305 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181306 warning_descriptions))
1307 return results
1308
1309
[email protected]fbcafe5a2012-08-08 15:31:221310def _CheckFilePermissions(input_api, output_api):
1311 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151312 if input_api.platform == 'win32':
1313 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291314 checkperms_tool = input_api.os_path.join(
1315 input_api.PresubmitLocalPath(),
1316 'tools', 'checkperms', 'checkperms.py')
1317 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471318 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391319 with input_api.CreateTemporaryFile() as file_list:
1320 for f in input_api.AffectedFiles():
1321 # checkperms.py file/directory arguments must be relative to the
1322 # repository.
1323 file_list.write(f.LocalPath() + '\n')
1324 file_list.close()
1325 args += ['--file-list', file_list.name]
1326 try:
1327 input_api.subprocess.check_output(args)
1328 return []
1329 except input_api.subprocess.CalledProcessError as error:
1330 return [output_api.PresubmitError(
1331 'checkperms.py failed:',
1332 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221333
1334
robertocn832f5992017-01-04 19:01:301335def _CheckTeamTags(input_api, output_api):
1336 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1337 checkteamtags_tool = input_api.os_path.join(
1338 input_api.PresubmitLocalPath(),
1339 'tools', 'checkteamtags', 'checkteamtags.py')
1340 args = [input_api.python_executable, checkteamtags_tool,
1341 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221342 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301343 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1344 'OWNERS']
1345 try:
1346 if files:
1347 input_api.subprocess.check_output(args + files)
1348 return []
1349 except input_api.subprocess.CalledProcessError as error:
1350 return [output_api.PresubmitError(
1351 'checkteamtags.py failed:',
1352 long_text=error.output)]
1353
1354
[email protected]c8278b32012-10-30 20:35:491355def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1356 """Makes sure we don't include ui/aura/window_property.h
1357 in header files.
1358 """
1359 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1360 errors = []
1361 for f in input_api.AffectedFiles():
1362 if not f.LocalPath().endswith('.h'):
1363 continue
1364 for line_num, line in f.ChangedContents():
1365 if pattern.match(line):
1366 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1367
1368 results = []
1369 if errors:
1370 results.append(output_api.PresubmitError(
1371 'Header files should not include ui/aura/window_property.h', errors))
1372 return results
1373
1374
[email protected]70ca77752012-11-20 03:45:031375def _CheckForVersionControlConflictsInFile(input_api, f):
1376 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1377 errors = []
1378 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:231379 if f.LocalPath().endswith('.md'):
1380 # First-level headers in markdown look a lot like version control
1381 # conflict markers. http://daringfireball.net/projects/markdown/basics
1382 continue
[email protected]70ca77752012-11-20 03:45:031383 if pattern.match(line):
1384 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1385 return errors
1386
1387
1388def _CheckForVersionControlConflicts(input_api, output_api):
1389 """Usually this is not intentional and will cause a compile failure."""
1390 errors = []
1391 for f in input_api.AffectedFiles():
1392 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1393
1394 results = []
1395 if errors:
1396 results.append(output_api.PresubmitError(
1397 'Version control conflict markers found, please resolve.', errors))
1398 return results
1399
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201400
estadee17314a02017-01-12 16:22:161401def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1402 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1403 errors = []
1404 for f in input_api.AffectedFiles():
1405 for line_num, line in f.ChangedContents():
1406 if pattern.search(line):
1407 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1408
1409 results = []
1410 if errors:
1411 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501412 'Found Google support URL addressed by answer number. Please replace '
1413 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161414 return results
1415
[email protected]70ca77752012-11-20 03:45:031416
[email protected]06e6d0ff2012-12-11 01:36:441417def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1418 def FilterFile(affected_file):
1419 """Filter function for use with input_api.AffectedSourceFiles,
1420 below. This filters out everything except non-test files from
1421 top-level directories that generally speaking should not hard-code
1422 service URLs (e.g. src/android_webview/, src/content/ and others).
1423 """
1424 return input_api.FilterSourceFile(
1425 affected_file,
Egor Paskoce145c42018-09-28 19:31:041426 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:441427 black_list=(_EXCLUDED_PATHS +
1428 _TEST_CODE_EXCLUDED_PATHS +
1429 input_api.DEFAULT_BLACK_LIST))
1430
reillyi38965732015-11-16 18:27:331431 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1432 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461433 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1434 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441435 problems = [] # items are (filename, line_number, line)
1436 for f in input_api.AffectedSourceFiles(FilterFile):
1437 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461438 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441439 problems.append((f.LocalPath(), line_num, line))
1440
1441 if problems:
[email protected]f7051d52013-04-02 18:31:421442 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441443 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581444 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441445 [' %s:%d: %s' % (
1446 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031447 else:
1448 return []
[email protected]06e6d0ff2012-12-11 01:36:441449
1450
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491451# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:271452def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1453 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311454 The native_client_sdk directory is excluded because it has auto-generated PNG
1455 files for documentation.
[email protected]d2530012013-01-25 16:39:271456 """
[email protected]d2530012013-01-25 16:39:271457 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491458 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:041459 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:311460 file_filter = lambda f: input_api.FilterSourceFile(
1461 f, white_list=white_list, black_list=black_list)
1462 for f in input_api.AffectedFiles(include_deletes=False,
1463 file_filter=file_filter):
1464 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271465
1466 results = []
1467 if errors:
1468 results.append(output_api.PresubmitError(
1469 'The name of PNG files should not have abbreviations. \n'
1470 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1471 'Contact [email protected] if you have questions.', errors))
1472 return results
1473
1474
Daniel Cheng4dcdb6b2017-04-13 08:30:171475def _ExtractAddRulesFromParsedDeps(parsed_deps):
1476 """Extract the rules that add dependencies from a parsed DEPS file.
1477
1478 Args:
1479 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1480 add_rules = set()
1481 add_rules.update([
1482 rule[1:] for rule in parsed_deps.get('include_rules', [])
1483 if rule.startswith('+') or rule.startswith('!')
1484 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501485 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171486 {}).iteritems():
1487 add_rules.update([
1488 rule[1:] for rule in rules
1489 if rule.startswith('+') or rule.startswith('!')
1490 ])
1491 return add_rules
1492
1493
1494def _ParseDeps(contents):
1495 """Simple helper for parsing DEPS files."""
1496 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171497 class _VarImpl:
1498
1499 def __init__(self, local_scope):
1500 self._local_scope = local_scope
1501
1502 def Lookup(self, var_name):
1503 """Implements the Var syntax."""
1504 try:
1505 return self._local_scope['vars'][var_name]
1506 except KeyError:
1507 raise Exception('Var is not defined: %s' % var_name)
1508
1509 local_scope = {}
1510 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171511 'Var': _VarImpl(local_scope).Lookup,
1512 }
1513 exec contents in global_scope, local_scope
1514 return local_scope
1515
1516
1517def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081518 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411519 a set of DEPS entries that we should look up.
1520
1521 For a directory (rather than a specific filename) we fake a path to
1522 a specific filename by adding /DEPS. This is chosen as a file that
1523 will seldom or never be subject to per-file include_rules.
1524 """
[email protected]2b438d62013-11-14 17:54:141525 # We ignore deps entries on auto-generated directories.
1526 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081527
Daniel Cheng4dcdb6b2017-04-13 08:30:171528 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1529 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1530
1531 added_deps = new_deps.difference(old_deps)
1532
[email protected]2b438d62013-11-14 17:54:141533 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171534 for added_dep in added_deps:
1535 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1536 continue
1537 # Assume that a rule that ends in .h is a rule for a specific file.
1538 if added_dep.endswith('.h'):
1539 results.add(added_dep)
1540 else:
1541 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081542 return results
1543
1544
[email protected]e871964c2013-05-13 14:14:551545def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1546 """When a dependency prefixed with + is added to a DEPS file, we
1547 want to make sure that the change is reviewed by an OWNER of the
1548 target file or directory, to avoid layering violations from being
1549 introduced. This check verifies that this happens.
1550 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171551 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241552
1553 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:491554 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241555 for f in input_api.AffectedFiles(include_deletes=False,
1556 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551557 filename = input_api.os_path.basename(f.LocalPath())
1558 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171559 virtual_depended_on_files.update(_CalculateAddedDeps(
1560 input_api.os_path,
1561 '\n'.join(f.OldContents()),
1562 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551563
[email protected]e871964c2013-05-13 14:14:551564 if not virtual_depended_on_files:
1565 return []
1566
1567 if input_api.is_committing:
1568 if input_api.tbr:
1569 return [output_api.PresubmitNotifyResult(
1570 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271571 if input_api.dry_run:
1572 return [output_api.PresubmitNotifyResult(
1573 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551574 if not input_api.change.issue:
1575 return [output_api.PresubmitError(
1576 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401577 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551578 output = output_api.PresubmitError
1579 else:
1580 output = output_api.PresubmitNotifyResult
1581
1582 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501583 owner_email, reviewers = (
1584 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1585 input_api,
1586 owners_db.email_regexp,
1587 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551588
1589 owner_email = owner_email or input_api.change.author_email
1590
[email protected]de4f7d22013-05-23 14:27:461591 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511592 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461593 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551594 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1595 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411596
1597 # We strip the /DEPS part that was added by
1598 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1599 # directory.
1600 def StripDeps(path):
1601 start_deps = path.rfind('/DEPS')
1602 if start_deps != -1:
1603 return path[:start_deps]
1604 else:
1605 return path
1606 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551607 for path in missing_files]
1608
1609 if unapproved_dependencies:
1610 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151611 output('You need LGTM from owners of depends-on paths in DEPS that were '
1612 'modified in this CL:\n %s' %
1613 '\n '.join(sorted(unapproved_dependencies)))]
1614 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1615 output_list.append(output(
1616 'Suggested missing target path OWNERS:\n %s' %
1617 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551618 return output_list
1619
1620 return []
1621
1622
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491623# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:401624def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491625 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:401626 black_list = (_EXCLUDED_PATHS +
1627 _TEST_CODE_EXCLUDED_PATHS +
1628 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:041629 (r"^base[\\/]logging\.h$",
1630 r"^base[\\/]logging\.cc$",
1631 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
1632 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
1633 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:121634 r"startup_browser_creator\.cc$",
Egor Paskoce145c42018-09-28 19:31:041635 r"^chrome[\\/]installer[\\/]setup[\\/].*",
1636 r"^chrome[\\/]chrome_cleaner[\\/].*",
1637 r"chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031638 r"diagnostics_writer\.cc$",
Egor Paskoce145c42018-09-28 19:31:041639 r"^chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
1640 r"^chromecast[\\/]",
1641 r"^cloud_print[\\/]",
1642 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:481643 r"dump_stability_report_main_win.cc$",
Egor Paskoce145c42018-09-28 19:31:041644 r"^components[\\/]html_viewer[\\/]"
jochen34415e52015-07-10 08:34:311645 r"web_test_delegate_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041646 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:461647 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:041648 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:461649 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041650 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:251651 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:041652 r"^courgette[\\/]courgette_minimal_tool\.cc$",
1653 r"^courgette[\\/]courgette_tool\.cc$",
1654 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331655 r"^fuchsia[\\/]browser[\\/]frame_impl.cc$",
1656 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:041657 r"^ipc[\\/]ipc_logging\.cc$",
1658 r"^native_client_sdk[\\/]",
1659 r"^remoting[\\/]base[\\/]logging\.h$",
1660 r"^remoting[\\/]host[\\/].*",
1661 r"^sandbox[\\/]linux[\\/].*",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331662 r"^storage[\\/]browser[\\/]fileapi[\\/]" +
1663 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:041664 r"^tools[\\/]",
1665 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
1666 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331667 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]"))
[email protected]85218562013-11-22 07:41:401668 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491669 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:401670
thomasanderson625d3932017-03-29 07:16:581671 log_info = set([])
1672 printf = set([])
[email protected]85218562013-11-22 07:41:401673
1674 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581675 for _, line in f.ChangedContents():
1676 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1677 log_info.add(f.LocalPath())
1678 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1679 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371680
thomasanderson625d3932017-03-29 07:16:581681 if input_api.re.search(r"\bprintf\(", line):
1682 printf.add(f.LocalPath())
1683 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1684 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401685
1686 if log_info:
1687 return [output_api.PresubmitError(
1688 'These files spam the console log with LOG(INFO):',
1689 items=log_info)]
1690 if printf:
1691 return [output_api.PresubmitError(
1692 'These files spam the console log with printf/fprintf:',
1693 items=printf)]
1694 return []
1695
1696
[email protected]49aa76a2013-12-04 06:59:161697def _CheckForAnonymousVariables(input_api, output_api):
1698 """These types are all expected to hold locks while in scope and
1699 so should never be anonymous (which causes them to be immediately
1700 destroyed)."""
1701 they_who_must_be_named = [
1702 'base::AutoLock',
1703 'base::AutoReset',
1704 'base::AutoUnlock',
1705 'SkAutoAlphaRestore',
1706 'SkAutoBitmapShaderInstall',
1707 'SkAutoBlitterChoose',
1708 'SkAutoBounderCommit',
1709 'SkAutoCallProc',
1710 'SkAutoCanvasRestore',
1711 'SkAutoCommentBlock',
1712 'SkAutoDescriptor',
1713 'SkAutoDisableDirectionCheck',
1714 'SkAutoDisableOvalCheck',
1715 'SkAutoFree',
1716 'SkAutoGlyphCache',
1717 'SkAutoHDC',
1718 'SkAutoLockColors',
1719 'SkAutoLockPixels',
1720 'SkAutoMalloc',
1721 'SkAutoMaskFreeImage',
1722 'SkAutoMutexAcquire',
1723 'SkAutoPathBoundsUpdate',
1724 'SkAutoPDFRelease',
1725 'SkAutoRasterClipValidate',
1726 'SkAutoRef',
1727 'SkAutoTime',
1728 'SkAutoTrace',
1729 'SkAutoUnref',
1730 ]
1731 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1732 # bad: base::AutoLock(lock.get());
1733 # not bad: base::AutoLock lock(lock.get());
1734 bad_pattern = input_api.re.compile(anonymous)
1735 # good: new base::AutoLock(lock.get())
1736 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1737 errors = []
1738
1739 for f in input_api.AffectedFiles():
1740 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1741 continue
1742 for linenum, line in f.ChangedContents():
1743 if bad_pattern.search(line) and not good_pattern.search(line):
1744 errors.append('%s:%d' % (f.LocalPath(), linenum))
1745
1746 if errors:
1747 return [output_api.PresubmitError(
1748 'These lines create anonymous variables that need to be named:',
1749 items=errors)]
1750 return []
1751
1752
Peter Kasting4844e46e2018-02-23 07:27:101753def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:531754 # Returns whether |template_str| is of the form <T, U...> for some types T
1755 # and U. Assumes that |template_str| is already in the form <...>.
1756 def HasMoreThanOneArg(template_str):
1757 # Level of <...> nesting.
1758 nesting = 0
1759 for c in template_str:
1760 if c == '<':
1761 nesting += 1
1762 elif c == '>':
1763 nesting -= 1
1764 elif c == ',' and nesting == 1:
1765 return True
1766 return False
1767
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491768 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:101769 sources = lambda affected_file: input_api.FilterSourceFile(
1770 affected_file,
1771 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1772 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491773 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:551774
1775 # Pattern to capture a single "<...>" block of template arguments. It can
1776 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
1777 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
1778 # latter would likely require counting that < and > match, which is not
1779 # expressible in regular languages. Should the need arise, one can introduce
1780 # limited counting (matching up to a total number of nesting depth), which
1781 # should cover all practical cases for already a low nesting limit.
1782 template_arg_pattern = (
1783 r'<[^>]*' # Opening block of <.
1784 r'>([^<]*>)?') # Closing block of >.
1785 # Prefix expressing that whatever follows is not already inside a <...>
1786 # block.
1787 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:101788 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:551789 not_inside_template_arg_pattern
1790 + r'\bstd::unique_ptr'
1791 + template_arg_pattern
1792 + r'\(\)')
1793
1794 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
1795 template_arg_no_array_pattern = (
1796 r'<[^>]*[^]]' # Opening block of <.
1797 r'>([^(<]*[^]]>)?') # Closing block of >.
1798 # Prefix saying that what follows is the start of an expression.
1799 start_of_expr_pattern = r'(=|\breturn|^)\s*'
1800 # Suffix saying that what follows are call parentheses with a non-empty list
1801 # of arguments.
1802 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:531803 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:551804 return_construct_pattern = input_api.re.compile(
1805 start_of_expr_pattern
1806 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:531807 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:551808 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:531809 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:551810 + nonempty_arg_list_pattern)
1811
Vaclav Brozek851d9602018-04-04 16:13:051812 problems_constructor = []
1813 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:101814 for f in input_api.AffectedSourceFiles(sources):
1815 for line_number, line in f.ChangedContents():
1816 # Disallow:
1817 # return std::unique_ptr<T>(foo);
1818 # bar = std::unique_ptr<T>(foo);
1819 # But allow:
1820 # return std::unique_ptr<T[]>(foo);
1821 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:531822 # And also allow cases when the second template argument is present. Those
1823 # cases cannot be handled by std::make_unique:
1824 # return std::unique_ptr<T, U>(foo);
1825 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:051826 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:531827 return_construct_result = return_construct_pattern.search(line)
1828 if return_construct_result and not HasMoreThanOneArg(
1829 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:051830 problems_constructor.append(
1831 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:101832 # Disallow:
1833 # std::unique_ptr<T>()
1834 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051835 problems_nullptr.append(
1836 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1837
1838 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:161839 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:051840 errors.append(output_api.PresubmitError(
1841 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161842 problems_nullptr))
1843 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:051844 errors.append(output_api.PresubmitError(
1845 'The following files use explicit std::unique_ptr constructor.'
1846 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161847 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:101848 return errors
1849
1850
[email protected]999261d2014-03-03 20:08:081851def _CheckUserActionUpdate(input_api, output_api):
1852 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521853 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081854 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521855 # If actions.xml is already included in the changelist, the PRESUBMIT
1856 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081857 return []
1858
[email protected]999261d2014-03-03 20:08:081859 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1860 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521861 current_actions = None
[email protected]999261d2014-03-03 20:08:081862 for f in input_api.AffectedFiles(file_filter=file_filter):
1863 for line_num, line in f.ChangedContents():
1864 match = input_api.re.search(action_re, line)
1865 if match:
[email protected]2f92dec2014-03-07 19:21:521866 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1867 # loaded only once.
1868 if not current_actions:
1869 with open('tools/metrics/actions/actions.xml') as actions_f:
1870 current_actions = actions_f.read()
1871 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081872 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521873 action = 'name="{0}"'.format(action_name)
1874 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081875 return [output_api.PresubmitPromptWarning(
1876 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521877 'tools/metrics/actions/actions.xml. Please run '
1878 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081879 % (f.LocalPath(), line_num, action_name))]
1880 return []
1881
1882
Daniel Cheng13ca61a882017-08-25 15:11:251883def _ImportJSONCommentEater(input_api):
1884 import sys
1885 sys.path = sys.path + [input_api.os_path.join(
1886 input_api.PresubmitLocalPath(),
1887 'tools', 'json_comment_eater')]
1888 import json_comment_eater
1889 return json_comment_eater
1890
1891
[email protected]99171a92014-06-03 08:44:471892def _GetJSONParseError(input_api, filename, eat_comments=True):
1893 try:
1894 contents = input_api.ReadFile(filename)
1895 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:251896 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:131897 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471898
1899 input_api.json.loads(contents)
1900 except ValueError as e:
1901 return e
1902 return None
1903
1904
1905def _GetIDLParseError(input_api, filename):
1906 try:
1907 contents = input_api.ReadFile(filename)
1908 idl_schema = input_api.os_path.join(
1909 input_api.PresubmitLocalPath(),
1910 'tools', 'json_schema_compiler', 'idl_schema.py')
1911 process = input_api.subprocess.Popen(
1912 [input_api.python_executable, idl_schema],
1913 stdin=input_api.subprocess.PIPE,
1914 stdout=input_api.subprocess.PIPE,
1915 stderr=input_api.subprocess.PIPE,
1916 universal_newlines=True)
1917 (_, error) = process.communicate(input=contents)
1918 return error or None
1919 except ValueError as e:
1920 return e
1921
1922
1923def _CheckParseErrors(input_api, output_api):
1924 """Check that IDL and JSON files do not contain syntax errors."""
1925 actions = {
1926 '.idl': _GetIDLParseError,
1927 '.json': _GetJSONParseError,
1928 }
[email protected]99171a92014-06-03 08:44:471929 # Most JSON files are preprocessed and support comments, but these do not.
1930 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:041931 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:471932 ]
1933 # Only run IDL checker on files in these directories.
1934 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:041935 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
1936 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:471937 ]
1938
1939 def get_action(affected_file):
1940 filename = affected_file.LocalPath()
1941 return actions.get(input_api.os_path.splitext(filename)[1])
1942
[email protected]99171a92014-06-03 08:44:471943 def FilterFile(affected_file):
1944 action = get_action(affected_file)
1945 if not action:
1946 return False
1947 path = affected_file.LocalPath()
1948
Sean Kau46e29bc2017-08-28 16:31:161949 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:471950 return False
1951
1952 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:161953 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:471954 return False
1955 return True
1956
1957 results = []
1958 for affected_file in input_api.AffectedFiles(
1959 file_filter=FilterFile, include_deletes=False):
1960 action = get_action(affected_file)
1961 kwargs = {}
1962 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:161963 _MatchesFile(input_api, json_no_comments_patterns,
1964 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:471965 kwargs['eat_comments'] = False
1966 parse_error = action(input_api,
1967 affected_file.AbsoluteLocalPath(),
1968 **kwargs)
1969 if parse_error:
1970 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1971 (affected_file.LocalPath(), parse_error)))
1972 return results
1973
1974
[email protected]760deea2013-12-10 19:33:491975def _CheckJavaStyle(input_api, output_api):
1976 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471977 import sys
[email protected]760deea2013-12-10 19:33:491978 original_sys_path = sys.path
1979 try:
1980 sys.path = sys.path + [input_api.os_path.join(
1981 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1982 import checkstyle
1983 finally:
1984 # Restore sys.path to what it was before.
1985 sys.path = original_sys_path
1986
1987 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091988 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511989 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491990
1991
Sean Kau46e29bc2017-08-28 16:31:161992def _MatchesFile(input_api, patterns, path):
1993 for pattern in patterns:
1994 if input_api.re.search(pattern, path):
1995 return True
1996 return False
1997
1998
Daniel Cheng7052cdf2017-11-21 19:23:291999def _GetOwnersFilesToCheckForIpcOwners(input_api):
2000 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172001
Daniel Cheng7052cdf2017-11-21 19:23:292002 Returns:
2003 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2004 contain to cover IPC-related files with noparent reviewer rules.
2005 """
2006 # Whether or not a file affects IPC is (mostly) determined by a simple list
2007 # of filename patterns.
dchenge07de812016-06-20 19:27:172008 file_patterns = [
palmerb19a0932017-01-24 04:00:312009 # Legacy IPC:
dchenge07de812016-06-20 19:27:172010 '*_messages.cc',
2011 '*_messages*.h',
2012 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312013 # Mojo IPC:
dchenge07de812016-06-20 19:27:172014 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472015 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172016 '*_struct_traits*.*',
2017 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312018 '*.typemap',
2019 # Android native IPC:
2020 '*.aidl',
2021 # Blink uses a different file naming convention:
2022 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472023 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172024 '*StructTraits*.*',
2025 '*TypeConverter*.*',
2026 ]
2027
scottmg7a6ed5ba2016-11-04 18:22:042028 # These third_party directories do not contain IPCs, but contain files
2029 # matching the above patterns, which trigger false positives.
2030 exclude_paths = [
2031 'third_party/crashpad/*',
Andres Medinae684cf42018-08-27 18:48:232032 'third_party/protobuf/benchmarks/python/*',
Daniel Chengebe635e2018-07-13 12:36:062033 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:292034 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:042035 ]
2036
dchenge07de812016-06-20 19:27:172037 # Dictionary mapping an OWNERS file path to Patterns.
2038 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2039 # rules ) to a PatternEntry.
2040 # PatternEntry is a dictionary with two keys:
2041 # - 'files': the files that are matched by this pattern
2042 # - 'rules': the per-file rules needed for this pattern
2043 # For example, if we expect OWNERS file to contain rules for *.mojom and
2044 # *_struct_traits*.*, Patterns might look like this:
2045 # {
2046 # '*.mojom': {
2047 # 'files': ...,
2048 # 'rules': [
2049 # 'per-file *.mojom=set noparent',
2050 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2051 # ],
2052 # },
2053 # '*_struct_traits*.*': {
2054 # 'files': ...,
2055 # 'rules': [
2056 # 'per-file *_struct_traits*.*=set noparent',
2057 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2058 # ],
2059 # },
2060 # }
2061 to_check = {}
2062
Daniel Cheng13ca61a882017-08-25 15:11:252063 def AddPatternToCheck(input_file, pattern):
2064 owners_file = input_api.os_path.join(
2065 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2066 if owners_file not in to_check:
2067 to_check[owners_file] = {}
2068 if pattern not in to_check[owners_file]:
2069 to_check[owners_file][pattern] = {
2070 'files': [],
2071 'rules': [
2072 'per-file %s=set noparent' % pattern,
2073 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2074 ]
2075 }
Vaclav Brozekd5de76a2018-03-17 07:57:502076 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252077
dchenge07de812016-06-20 19:27:172078 # Iterate through the affected files to see what we actually need to check
2079 # for. We should only nag patch authors about per-file rules if a file in that
2080 # directory would match that pattern. If a directory only contains *.mojom
2081 # files and no *_messages*.h files, we should only nag about rules for
2082 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252083 for f in input_api.AffectedFiles(include_deletes=False):
2084 # Manifest files don't have a strong naming convention. Instead, scan
Ken Rockot9f668262018-12-21 18:56:362085 # affected files for .json, .cc, and .h files which look like they contain
2086 # a manifest definition.
Sean Kau46e29bc2017-08-28 16:31:162087 if (f.LocalPath().endswith('.json') and
2088 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
2089 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:252090 json_comment_eater = _ImportJSONCommentEater(input_api)
2091 mostly_json_lines = '\n'.join(f.NewContents())
2092 # Comments aren't allowed in strict JSON, so filter them out.
2093 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:432094 try:
2095 json_content = input_api.json.loads(json_lines)
2096 except:
2097 # There's another PRESUBMIT check that already verifies that JSON files
2098 # are not invalid, so no need to emit another warning here.
2099 continue
Daniel Cheng13ca61a882017-08-25 15:11:252100 if 'interface_provider_specs' in json_content:
2101 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
Ken Rockot9f668262018-12-21 18:56:362102 else:
2103 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2104 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2105 if (manifest_pattern.search(f.LocalPath()) and not
2106 test_manifest_pattern.search(f.LocalPath())):
2107 # We expect all actual service manifest files to contain at least one
2108 # qualified reference to service_manager::Manifest.
2109 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2110 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172111 for pattern in file_patterns:
2112 if input_api.fnmatch.fnmatch(
2113 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042114 skip = False
2115 for exclude in exclude_paths:
2116 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2117 skip = True
2118 break
2119 if skip:
2120 continue
Daniel Cheng13ca61a882017-08-25 15:11:252121 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172122 break
2123
Daniel Cheng7052cdf2017-11-21 19:23:292124 return to_check
2125
2126
2127def _CheckIpcOwners(input_api, output_api):
2128 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2129 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2130
2131 if to_check:
2132 # If there are any OWNERS files to check, there are IPC-related changes in
2133 # this CL. Auto-CC the review list.
2134 output_api.AppendCC('[email protected]')
2135
2136 # Go through the OWNERS files to check, filtering out rules that are already
2137 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172138 for owners_file, patterns in to_check.iteritems():
2139 try:
2140 with file(owners_file) as f:
2141 lines = set(f.read().splitlines())
2142 for entry in patterns.itervalues():
2143 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2144 ]
2145 except IOError:
2146 # No OWNERS file, so all the rules are definitely missing.
2147 continue
2148
2149 # All the remaining lines weren't found in OWNERS files, so emit an error.
2150 errors = []
2151 for owners_file, patterns in to_check.iteritems():
2152 missing_lines = []
2153 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502154 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172155 missing_lines.extend(entry['rules'])
2156 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2157 if missing_lines:
2158 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052159 'Because of the presence of files:\n%s\n\n'
2160 '%s needs the following %d lines added:\n\n%s' %
2161 ('\n'.join(files), owners_file, len(missing_lines),
2162 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172163
2164 results = []
2165 if errors:
vabrf5ce3bf92016-07-11 14:52:412166 if input_api.is_committing:
2167 output = output_api.PresubmitError
2168 else:
2169 output = output_api.PresubmitPromptWarning
2170 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592171 'Found OWNERS files that need to be updated for IPC security ' +
2172 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172173 long_text='\n\n'.join(errors)))
2174
2175 return results
2176
2177
jbriance9e12f162016-11-25 07:57:502178def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312179 """Checks that added or removed lines in non third party affected
2180 header files do not lead to new useless class or struct forward
2181 declaration.
jbriance9e12f162016-11-25 07:57:502182 """
2183 results = []
2184 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2185 input_api.re.MULTILINE)
2186 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2187 input_api.re.MULTILINE)
2188 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312189 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192190 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:492191 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:312192 continue
2193
jbriance9e12f162016-11-25 07:57:502194 if not f.LocalPath().endswith('.h'):
2195 continue
2196
2197 contents = input_api.ReadFile(f)
2198 fwd_decls = input_api.re.findall(class_pattern, contents)
2199 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2200
2201 useless_fwd_decls = []
2202 for decl in fwd_decls:
2203 count = sum(1 for _ in input_api.re.finditer(
2204 r'\b%s\b' % input_api.re.escape(decl), contents))
2205 if count == 1:
2206 useless_fwd_decls.append(decl)
2207
2208 if not useless_fwd_decls:
2209 continue
2210
2211 for line in f.GenerateScmDiff().splitlines():
2212 if (line.startswith('-') and not line.startswith('--') or
2213 line.startswith('+') and not line.startswith('++')):
2214 for decl in useless_fwd_decls:
2215 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2216 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242217 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502218 (f.LocalPath(), decl)))
2219 useless_fwd_decls.remove(decl)
2220
2221 return results
2222
2223
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492224# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:292225def _CheckAndroidToastUsage(input_api, output_api):
2226 """Checks that code uses org.chromium.ui.widget.Toast instead of
2227 android.widget.Toast (Chromium Toast doesn't force hardware
2228 acceleration on low-end devices, saving memory).
2229 """
2230 toast_import_pattern = input_api.re.compile(
2231 r'^import android\.widget\.Toast;$')
2232
2233 errors = []
2234
2235 sources = lambda affected_file: input_api.FilterSourceFile(
2236 affected_file,
2237 black_list=(_EXCLUDED_PATHS +
2238 _TEST_CODE_EXCLUDED_PATHS +
2239 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042240 (r'^chromecast[\\/].*',
2241 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492242 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:292243
2244 for f in input_api.AffectedSourceFiles(sources):
2245 for line_num, line in f.ChangedContents():
2246 if toast_import_pattern.search(line):
2247 errors.append("%s:%d" % (f.LocalPath(), line_num))
2248
2249 results = []
2250
2251 if errors:
2252 results.append(output_api.PresubmitError(
2253 'android.widget.Toast usage is detected. Android toasts use hardware'
2254 ' acceleration, and can be\ncostly on low-end devices. Please use'
2255 ' org.chromium.ui.widget.Toast instead.\n'
2256 'Contact [email protected] if you have any questions.',
2257 errors))
2258
2259 return results
2260
2261
dgnaa68d5e2015-06-10 10:08:222262def _CheckAndroidCrLogUsage(input_api, output_api):
2263 """Checks that new logs using org.chromium.base.Log:
2264 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512265 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222266 """
pkotwicza1dd0b002016-05-16 14:41:042267
torne89540622017-03-24 19:41:302268 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042269 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302270 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:042271 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:302272 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:042273 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
2274 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:092275 # The customtabs_benchmark is a small app that does not depend on Chromium
2276 # java pieces.
Egor Paskoce145c42018-09-28 19:31:042277 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:042278 ]
2279
dgnaa68d5e2015-06-10 10:08:222280 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122281 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2282 class_in_base_pattern = input_api.re.compile(
2283 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2284 has_some_log_import_pattern = input_api.re.compile(
2285 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222286 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122287 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222288 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512289 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222290 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222291
Vincent Scheib16d7b272015-09-15 18:09:072292 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222293 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492294 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:042295 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122296
dgnaa68d5e2015-06-10 10:08:222297 tag_decl_errors = []
2298 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122299 tag_errors = []
dgn38736db2015-09-18 19:20:512300 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122301 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222302
2303 for f in input_api.AffectedSourceFiles(sources):
2304 file_content = input_api.ReadFile(f)
2305 has_modified_logs = False
2306
2307 # Per line checks
dgn87d9fb62015-06-12 09:15:122308 if (cr_log_import_pattern.search(file_content) or
2309 (class_in_base_pattern.search(file_content) and
2310 not has_some_log_import_pattern.search(file_content))):
2311 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222312 for line_num, line in f.ChangedContents():
2313
2314 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122315 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222316 if match:
2317 has_modified_logs = True
2318
2319 # Make sure it uses "TAG"
2320 if not match.group('tag') == 'TAG':
2321 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122322 else:
2323 # Report non cr Log function calls in changed lines
2324 for line_num, line in f.ChangedContents():
2325 if log_call_pattern.search(line):
2326 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222327
2328 # Per file checks
2329 if has_modified_logs:
2330 # Make sure the tag is using the "cr" prefix and is not too long
2331 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512332 tag_name = match.group('name') if match else None
2333 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222334 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512335 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222336 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512337 elif '.' in tag_name:
2338 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222339
2340 results = []
2341 if tag_decl_errors:
2342 results.append(output_api.PresubmitPromptWarning(
2343 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512344 '"private static final String TAG = "<package tag>".\n'
2345 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222346 tag_decl_errors))
2347
2348 if tag_length_errors:
2349 results.append(output_api.PresubmitError(
2350 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512351 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222352 tag_length_errors))
2353
2354 if tag_errors:
2355 results.append(output_api.PresubmitPromptWarning(
2356 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2357 tag_errors))
2358
dgn87d9fb62015-06-12 09:15:122359 if util_log_errors:
dgn4401aa52015-04-29 16:26:172360 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122361 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2362 util_log_errors))
2363
dgn38736db2015-09-18 19:20:512364 if tag_with_dot_errors:
2365 results.append(output_api.PresubmitPromptWarning(
2366 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2367 tag_with_dot_errors))
2368
dgn4401aa52015-04-29 16:26:172369 return results
2370
2371
Yoland Yanb92fa522017-08-28 17:37:062372def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2373 """Checks that junit.framework.* is no longer used."""
2374 deprecated_junit_framework_pattern = input_api.re.compile(
2375 r'^import junit\.framework\..*;',
2376 input_api.re.MULTILINE)
2377 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492378 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062379 errors = []
2380 for f in input_api.AffectedFiles(sources):
2381 for line_num, line in f.ChangedContents():
2382 if deprecated_junit_framework_pattern.search(line):
2383 errors.append("%s:%d" % (f.LocalPath(), line_num))
2384
2385 results = []
2386 if errors:
2387 results.append(output_api.PresubmitError(
2388 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2389 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2390 ' if you have any question.', errors))
2391 return results
2392
2393
2394def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2395 """Checks that if new Java test classes have inheritance.
2396 Either the new test class is JUnit3 test or it is a JUnit4 test class
2397 with a base class, either case is undesirable.
2398 """
2399 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2400
2401 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492402 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062403 errors = []
2404 for f in input_api.AffectedFiles(sources):
2405 if not f.OldContents():
2406 class_declaration_start_flag = False
2407 for line_num, line in f.ChangedContents():
2408 if class_declaration_pattern.search(line):
2409 class_declaration_start_flag = True
2410 if class_declaration_start_flag and ' extends ' in line:
2411 errors.append('%s:%d' % (f.LocalPath(), line_num))
2412 if '{' in line:
2413 class_declaration_start_flag = False
2414
2415 results = []
2416 if errors:
2417 results.append(output_api.PresubmitPromptWarning(
2418 'The newly created files include Test classes that inherits from base'
2419 ' class. Please do not use inheritance in JUnit4 tests or add new'
2420 ' JUnit3 tests. Contact [email protected] if you have any'
2421 ' questions.', errors))
2422 return results
2423
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202424
yolandyan45001472016-12-21 21:12:422425def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2426 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2427 deprecated_annotation_import_pattern = input_api.re.compile(
2428 r'^import android\.test\.suitebuilder\.annotation\..*;',
2429 input_api.re.MULTILINE)
2430 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492431 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:422432 errors = []
2433 for f in input_api.AffectedFiles(sources):
2434 for line_num, line in f.ChangedContents():
2435 if deprecated_annotation_import_pattern.search(line):
2436 errors.append("%s:%d" % (f.LocalPath(), line_num))
2437
2438 results = []
2439 if errors:
2440 results.append(output_api.PresubmitError(
2441 'Annotations in android.test.suitebuilder.annotation have been'
2442 ' deprecated since API level 24. Please use android.support.test.filters'
2443 ' from //third_party/android_support_test_runner:runner_java instead.'
2444 ' Contact [email protected] if you have any questions.', errors))
2445 return results
2446
2447
agrieve7b6479d82015-10-07 14:24:222448def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2449 """Checks if MDPI assets are placed in a correct directory."""
2450 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2451 ('/res/drawable/' in f.LocalPath() or
2452 '/res/drawable-ldrtl/' in f.LocalPath()))
2453 errors = []
2454 for f in input_api.AffectedFiles(include_deletes=False,
2455 file_filter=file_filter):
2456 errors.append(' %s' % f.LocalPath())
2457
2458 results = []
2459 if errors:
2460 results.append(output_api.PresubmitError(
2461 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2462 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2463 '/res/drawable-ldrtl/.\n'
2464 'Contact [email protected] if you have questions.', errors))
2465 return results
2466
2467
Nate Fischer535972b2017-09-16 01:06:182468def _CheckAndroidWebkitImports(input_api, output_api):
2469 """Checks that code uses org.chromium.base.Callback instead of
2470 android.widget.ValueCallback except in the WebView glue layer.
2471 """
2472 valuecallback_import_pattern = input_api.re.compile(
2473 r'^import android\.webkit\.ValueCallback;$')
2474
2475 errors = []
2476
2477 sources = lambda affected_file: input_api.FilterSourceFile(
2478 affected_file,
2479 black_list=(_EXCLUDED_PATHS +
2480 _TEST_CODE_EXCLUDED_PATHS +
2481 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042482 (r'^android_webview[\\/]glue[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492483 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:182484
2485 for f in input_api.AffectedSourceFiles(sources):
2486 for line_num, line in f.ChangedContents():
2487 if valuecallback_import_pattern.search(line):
2488 errors.append("%s:%d" % (f.LocalPath(), line_num))
2489
2490 results = []
2491
2492 if errors:
2493 results.append(output_api.PresubmitError(
2494 'android.webkit.ValueCallback usage is detected outside of the glue'
2495 ' layer. To stay compatible with the support library, android.webkit.*'
2496 ' classes should only be used inside the glue layer and'
2497 ' org.chromium.base.Callback should be used instead.',
2498 errors))
2499
2500 return results
2501
2502
Becky Zhou7c69b50992018-12-10 19:37:572503def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
2504 """Checks Android XML styles """
2505 import sys
2506 original_sys_path = sys.path
2507 try:
2508 sys.path = sys.path + [input_api.os_path.join(
2509 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
2510 import checkxmlstyle
2511 finally:
2512 # Restore sys.path to what it was before.
2513 sys.path = original_sys_path
2514
2515 if is_check_on_upload:
2516 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
2517 else:
2518 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
2519
2520
agrievef32bcc72016-04-04 14:57:402521class PydepsChecker(object):
2522 def __init__(self, input_api, pydeps_files):
2523 self._file_cache = {}
2524 self._input_api = input_api
2525 self._pydeps_files = pydeps_files
2526
2527 def _LoadFile(self, path):
2528 """Returns the list of paths within a .pydeps file relative to //."""
2529 if path not in self._file_cache:
2530 with open(path) as f:
2531 self._file_cache[path] = f.read()
2532 return self._file_cache[path]
2533
2534 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2535 """Returns an interable of paths within the .pydep, relativized to //."""
2536 os_path = self._input_api.os_path
2537 pydeps_dir = os_path.dirname(pydeps_path)
2538 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2539 if not l.startswith('*'))
2540 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2541
2542 def _CreateFilesToPydepsMap(self):
2543 """Returns a map of local_path -> list_of_pydeps."""
2544 ret = {}
2545 for pydep_local_path in self._pydeps_files:
2546 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2547 ret.setdefault(path, []).append(pydep_local_path)
2548 return ret
2549
2550 def ComputeAffectedPydeps(self):
2551 """Returns an iterable of .pydeps files that might need regenerating."""
2552 affected_pydeps = set()
2553 file_to_pydeps_map = None
2554 for f in self._input_api.AffectedFiles(include_deletes=True):
2555 local_path = f.LocalPath()
2556 if local_path == 'DEPS':
2557 return self._pydeps_files
2558 elif local_path.endswith('.pydeps'):
2559 if local_path in self._pydeps_files:
2560 affected_pydeps.add(local_path)
2561 elif local_path.endswith('.py'):
2562 if file_to_pydeps_map is None:
2563 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2564 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2565 return affected_pydeps
2566
2567 def DetermineIfStale(self, pydeps_path):
2568 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412569 import difflib
John Budorick47ca3fe2018-02-10 00:53:102570 import os
2571
agrievef32bcc72016-04-04 14:57:402572 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2573 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102574 env = dict(os.environ)
2575 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402576 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102577 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412578 old_contents = old_pydeps_data[2:]
2579 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402580 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412581 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402582
2583
2584def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2585 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402586 # This check is for Python dependency lists (.pydeps files), and involves
2587 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2588 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282589 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002590 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022591 # TODO(agrieve): Update when there's a better way to detect
2592 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402593 is_android = input_api.os_path.exists('third_party/android_tools')
2594 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2595 results = []
2596 # First, check for new / deleted .pydeps.
2597 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032598 # Check whether we are running the presubmit check for a file in src.
2599 # f.LocalPath is relative to repo (src, or internal repo).
2600 # os_path.exists is relative to src repo.
2601 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2602 # to src and we can conclude that the pydeps is in src.
2603 if input_api.os_path.exists(f.LocalPath()):
2604 if f.LocalPath().endswith('.pydeps'):
2605 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2606 results.append(output_api.PresubmitError(
2607 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2608 'remove %s' % f.LocalPath()))
2609 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2610 results.append(output_api.PresubmitError(
2611 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2612 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402613
2614 if results:
2615 return results
2616
2617 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2618
2619 for pydep_path in checker.ComputeAffectedPydeps():
2620 try:
phajdan.jr0d9878552016-11-04 10:49:412621 result = checker.DetermineIfStale(pydep_path)
2622 if result:
2623 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402624 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412625 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2626 'To regenerate, run:\n\n %s' %
2627 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402628 except input_api.subprocess.CalledProcessError as error:
2629 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2630 long_text=error.output)]
2631
2632 return results
2633
2634
glidere61efad2015-02-18 17:39:432635def _CheckSingletonInHeaders(input_api, output_api):
2636 """Checks to make sure no header files have |Singleton<|."""
2637 def FileFilter(affected_file):
2638 # It's ok for base/memory/singleton.h to have |Singleton<|.
2639 black_list = (_EXCLUDED_PATHS +
2640 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042641 (r"^base[\\/]memory[\\/]singleton\.h$",
2642 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:472643 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432644 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2645
sergeyu34d21222015-09-16 00:11:442646 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432647 files = []
2648 for f in input_api.AffectedSourceFiles(FileFilter):
2649 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2650 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2651 contents = input_api.ReadFile(f)
2652 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242653 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432654 pattern.search(line)):
2655 files.append(f)
2656 break
2657
2658 if files:
yolandyandaabc6d2016-04-18 18:29:392659 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442660 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432661 'Please move them to an appropriate source file so that the ' +
2662 'template gets instantiated in a single compilation unit.',
2663 files) ]
2664 return []
2665
2666
[email protected]fd20b902014-05-09 02:14:532667_DEPRECATED_CSS = [
2668 # Values
2669 ( "-webkit-box", "flex" ),
2670 ( "-webkit-inline-box", "inline-flex" ),
2671 ( "-webkit-flex", "flex" ),
2672 ( "-webkit-inline-flex", "inline-flex" ),
2673 ( "-webkit-min-content", "min-content" ),
2674 ( "-webkit-max-content", "max-content" ),
2675
2676 # Properties
2677 ( "-webkit-background-clip", "background-clip" ),
2678 ( "-webkit-background-origin", "background-origin" ),
2679 ( "-webkit-background-size", "background-size" ),
2680 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442681 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532682
2683 # Functions
2684 ( "-webkit-gradient", "gradient" ),
2685 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2686 ( "-webkit-linear-gradient", "linear-gradient" ),
2687 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2688 ( "-webkit-radial-gradient", "radial-gradient" ),
2689 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2690]
2691
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202692
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492693# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242694def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532695 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252696 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342697 documentation and iOS CSS for dom distiller
2698 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252699 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532700 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492701 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:252702 black_list = (_EXCLUDED_PATHS +
2703 _TEST_CODE_EXCLUDED_PATHS +
2704 input_api.DEFAULT_BLACK_LIST +
2705 (r"^chrome/common/extensions/docs",
2706 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342707 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442708 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252709 r"^native_client_sdk"))
2710 file_filter = lambda f: input_api.FilterSourceFile(
2711 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532712 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2713 for line_num, line in fpath.ChangedContents():
2714 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022715 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532716 results.append(output_api.PresubmitError(
2717 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2718 (fpath.LocalPath(), line_num, deprecated_value, value)))
2719 return results
2720
mohan.reddyf21db962014-10-16 12:26:472721
dbeam070cfe62014-10-22 06:44:022722_DEPRECATED_JS = [
2723 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2724 ( "__defineGetter__", "Object.defineProperty" ),
2725 ( "__defineSetter__", "Object.defineProperty" ),
2726]
2727
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202728
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492729# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242730def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022731 """Make sure that we don't use deprecated JS in Chrome code."""
2732 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492733 file_inclusion_pattern = [r".+\.js$"] # TODO(dbeam): .html?
dbeam070cfe62014-10-22 06:44:022734 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2735 input_api.DEFAULT_BLACK_LIST)
2736 file_filter = lambda f: input_api.FilterSourceFile(
2737 f, white_list=file_inclusion_pattern, black_list=black_list)
2738 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2739 for lnum, line in fpath.ChangedContents():
2740 for (deprecated, replacement) in _DEPRECATED_JS:
2741 if deprecated in line:
2742 results.append(output_api.PresubmitError(
2743 "%s:%d: Use of deprecated JS %s, use %s instead" %
2744 (fpath.LocalPath(), lnum, deprecated, replacement)))
2745 return results
2746
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202747
rlanday6802cf632017-05-30 17:48:362748def _CheckForRelativeIncludes(input_api, output_api):
2749 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2750 import sys
2751 original_sys_path = sys.path
2752 try:
2753 sys.path = sys.path + [input_api.os_path.join(
2754 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2755 from cpp_checker import CppChecker
2756 finally:
2757 # Restore sys.path to what it was before.
2758 sys.path = original_sys_path
2759
2760 bad_files = {}
2761 for f in input_api.AffectedFiles(include_deletes=False):
2762 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:492763 not f.LocalPath().startswith('third_party/blink') and
2764 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:362765 continue
2766
2767 if not CppChecker.IsCppFile(f.LocalPath()):
2768 continue
2769
Vaclav Brozekd5de76a2018-03-17 07:57:502770 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362771 if "#include" in line and "../" in line]
2772 if not relative_includes:
2773 continue
2774 bad_files[f.LocalPath()] = relative_includes
2775
2776 if not bad_files:
2777 return []
2778
2779 error_descriptions = []
2780 for file_path, bad_lines in bad_files.iteritems():
2781 error_description = file_path
2782 for line in bad_lines:
2783 error_description += '\n ' + line
2784 error_descriptions.append(error_description)
2785
2786 results = []
2787 results.append(output_api.PresubmitError(
2788 'You added one or more relative #include paths (including "../").\n'
2789 'These shouldn\'t be used because they can be used to include headers\n'
2790 'from code that\'s not correctly specified as a dependency in the\n'
2791 'relevant BUILD.gn file(s).',
2792 error_descriptions))
2793
2794 return results
2795
Takeshi Yoshinoe387aa32017-08-02 13:16:132796
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202797def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2798 if not isinstance(key, ast.Str):
2799 return 'Key at line %d must be a string literal' % key.lineno
2800 if not isinstance(value, ast.Dict):
2801 return 'Value at line %d must be a dict' % value.lineno
2802 if len(value.keys) != 1:
2803 return 'Dict at line %d must have single entry' % value.lineno
2804 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2805 return (
2806 'Entry at line %d must have a string literal \'filepath\' as key' %
2807 value.lineno)
2808 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132809
Takeshi Yoshinoe387aa32017-08-02 13:16:132810
Sergey Ulanov4af16052018-11-08 02:41:462811def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202812 if not isinstance(key, ast.Str):
2813 return 'Key at line %d must be a string literal' % key.lineno
2814 if not isinstance(value, ast.List):
2815 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:462816 for element in value.elts:
2817 if not isinstance(element, ast.Str):
2818 return 'Watchlist elements on line %d is not a string' % key.lineno
2819 if not email_regex.match(element.s):
2820 return ('Watchlist element on line %d doesn\'t look like a valid ' +
2821 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202822 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132823
Takeshi Yoshinoe387aa32017-08-02 13:16:132824
Sergey Ulanov4af16052018-11-08 02:41:462825def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202826 mismatch_template = (
2827 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2828 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132829
Sergey Ulanov4af16052018-11-08 02:41:462830 email_regex = input_api.re.compile(
2831 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
2832
2833 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202834 i = 0
2835 last_key = ''
2836 while True:
2837 if i >= len(wd_dict.keys):
2838 if i >= len(w_dict.keys):
2839 return None
2840 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2841 elif i >= len(w_dict.keys):
2842 return (
2843 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132844
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202845 wd_key = wd_dict.keys[i]
2846 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132847
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202848 result = _CheckWatchlistDefinitionsEntrySyntax(
2849 wd_key, wd_dict.values[i], ast)
2850 if result is not None:
2851 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132852
Sergey Ulanov4af16052018-11-08 02:41:462853 result = _CheckWatchlistsEntrySyntax(
2854 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202855 if result is not None:
2856 return 'Bad entry in WATCHLISTS dict: %s' % result
2857
2858 if wd_key.s != w_key.s:
2859 return mismatch_template % (
2860 '%s at line %d' % (wd_key.s, wd_key.lineno),
2861 '%s at line %d' % (w_key.s, w_key.lineno))
2862
2863 if wd_key.s < last_key:
2864 return (
2865 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2866 (wd_key.lineno, w_key.lineno))
2867 last_key = wd_key.s
2868
2869 i = i + 1
2870
2871
Sergey Ulanov4af16052018-11-08 02:41:462872def _CheckWATCHLISTSSyntax(expression, input_api):
2873 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202874 if not isinstance(expression, ast.Expression):
2875 return 'WATCHLISTS file must contain a valid expression'
2876 dictionary = expression.body
2877 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2878 return 'WATCHLISTS file must have single dict with exactly two entries'
2879
2880 first_key = dictionary.keys[0]
2881 first_value = dictionary.values[0]
2882 second_key = dictionary.keys[1]
2883 second_value = dictionary.values[1]
2884
2885 if (not isinstance(first_key, ast.Str) or
2886 first_key.s != 'WATCHLIST_DEFINITIONS' or
2887 not isinstance(first_value, ast.Dict)):
2888 return (
2889 'The first entry of the dict in WATCHLISTS file must be '
2890 'WATCHLIST_DEFINITIONS dict')
2891
2892 if (not isinstance(second_key, ast.Str) or
2893 second_key.s != 'WATCHLISTS' or
2894 not isinstance(second_value, ast.Dict)):
2895 return (
2896 'The second entry of the dict in WATCHLISTS file must be '
2897 'WATCHLISTS dict')
2898
Sergey Ulanov4af16052018-11-08 02:41:462899 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:132900
2901
2902def _CheckWATCHLISTS(input_api, output_api):
2903 for f in input_api.AffectedFiles(include_deletes=False):
2904 if f.LocalPath() == 'WATCHLISTS':
2905 contents = input_api.ReadFile(f, 'r')
2906
2907 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202908 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132909 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202910 # Get an AST tree for it and scan the tree for detailed style checking.
2911 expression = input_api.ast.parse(
2912 contents, filename='WATCHLISTS', mode='eval')
2913 except ValueError as e:
2914 return [output_api.PresubmitError(
2915 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2916 except SyntaxError as e:
2917 return [output_api.PresubmitError(
2918 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2919 except TypeError as e:
2920 return [output_api.PresubmitError(
2921 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132922
Sergey Ulanov4af16052018-11-08 02:41:462923 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202924 if result is not None:
2925 return [output_api.PresubmitError(result)]
2926 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132927
2928 return []
2929
2930
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192931def _CheckNewHeaderWithoutGnChange(input_api, output_api):
2932 """Checks that newly added header files have corresponding GN changes.
2933 Note that this is only a heuristic. To be precise, run script:
2934 build/check_gn_headers.py.
2935 """
2936
2937 def headers(f):
2938 return input_api.FilterSourceFile(
2939 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
2940
2941 new_headers = []
2942 for f in input_api.AffectedSourceFiles(headers):
2943 if f.Action() != 'A':
2944 continue
2945 new_headers.append(f.LocalPath())
2946
2947 def gn_files(f):
2948 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
2949
2950 all_gn_changed_contents = ''
2951 for f in input_api.AffectedSourceFiles(gn_files):
2952 for _, line in f.ChangedContents():
2953 all_gn_changed_contents += line
2954
2955 problems = []
2956 for header in new_headers:
2957 basename = input_api.os_path.basename(header)
2958 if basename not in all_gn_changed_contents:
2959 problems.append(header)
2960
2961 if problems:
2962 return [output_api.PresubmitPromptWarning(
2963 'Missing GN changes for new header files', items=sorted(problems),
2964 long_text='Please double check whether newly added header files need '
2965 'corresponding changes in gn or gni files.\nThis checking is only a '
2966 'heuristic. Run build/check_gn_headers.py to be precise.\n'
2967 'Read https://crbug.com/661774 for more info.')]
2968 return []
2969
2970
Michael Giuffridad3bc8672018-10-25 22:48:022971def _CheckCorrectProductNameInMessages(input_api, output_api):
2972 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
2973
2974 This assumes we won't intentionally reference one product from the other
2975 product.
2976 """
2977 all_problems = []
2978 test_cases = [{
2979 "filename_postfix": "google_chrome_strings.grd",
2980 "correct_name": "Chrome",
2981 "incorrect_name": "Chromium",
2982 }, {
2983 "filename_postfix": "chromium_strings.grd",
2984 "correct_name": "Chromium",
2985 "incorrect_name": "Chrome",
2986 }]
2987
2988 for test_case in test_cases:
2989 problems = []
2990 filename_filter = lambda x: x.LocalPath().endswith(
2991 test_case["filename_postfix"])
2992
2993 # Check each new line. Can yield false positives in multiline comments, but
2994 # easier than trying to parse the XML because messages can have nested
2995 # children, and associating message elements with affected lines is hard.
2996 for f in input_api.AffectedSourceFiles(filename_filter):
2997 for line_num, line in f.ChangedContents():
2998 if "<message" in line or "<!--" in line or "-->" in line:
2999 continue
3000 if test_case["incorrect_name"] in line:
3001 problems.append(
3002 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
3003
3004 if problems:
3005 message = (
3006 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
3007 % (test_case["correct_name"], test_case["correct_name"],
3008 test_case["incorrect_name"]))
3009 all_problems.append(
3010 output_api.PresubmitPromptWarning(message, items=problems))
3011
3012 return all_problems
3013
3014
dgnaa68d5e2015-06-10 10:08:223015def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:573016 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:223017 results = []
dgnaa68d5e2015-06-10 10:08:223018 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:223019 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:293020 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:063021 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
3022 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:423023 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:183024 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573025 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
3026 return results
3027
3028def _AndroidSpecificOnCommitChecks(input_api, output_api):
3029 """Groups commit checks that target android code."""
3030 results = []
3031 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:223032 return results
3033
3034
[email protected]22c9bd72011-03-27 16:47:393035def _CommonChecks(input_api, output_api):
3036 """Checks common to both upload and commit."""
3037 results = []
3038 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:383039 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:543040 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:083041
3042 author = input_api.change.author_email
3043 if author and author not in _KNOWN_ROBOTS:
3044 results.extend(
3045 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
3046
[email protected]55459852011-08-10 15:17:193047 results.extend(
[email protected]760deea2013-12-10 19:33:493048 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:233049 results.extend(
3050 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:543051 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:183052 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:343053 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:523054 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:223055 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:443056 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:593057 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:063058 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:123059 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:183060 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:223061 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:303062 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:493063 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:033064 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:493065 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:443066 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:273067 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:073068 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:543069 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:443070 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:393071 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:553072 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:043073 results.extend(
3074 input_api.canned_checks.CheckChangeHasNoTabs(
3075 input_api,
3076 output_api,
3077 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:403078 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:163079 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:083080 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:243081 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
3082 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:473083 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:043084 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:053085 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:143086 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:233087 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:433088 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:403089 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:153090 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:173091 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:503092 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:363093 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:133094 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:433095 results.extend(input_api.RunTests(
3096 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143097 results.extend(_CheckTranslationScreenshots(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:023098 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:243099
Vaclav Brozekcdc7defb2018-03-20 09:54:353100 for f in input_api.AffectedFiles():
3101 path, name = input_api.os_path.split(f.LocalPath())
3102 if name == 'PRESUBMIT.py':
3103 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:003104 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
3105 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:073106 # The PRESUBMIT.py file (and the directory containing it) might
3107 # have been affected by being moved or removed, so only try to
3108 # run the tests if they still exist.
3109 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
3110 input_api, output_api, full_path,
3111 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:393112 return results
[email protected]1f7b4172010-01-28 01:17:343113
[email protected]b337cb5b2011-01-23 21:24:053114
[email protected]b8079ae4a2012-12-05 19:56:493115def _CheckPatchFiles(input_api, output_api):
3116 problems = [f.LocalPath() for f in input_api.AffectedFiles()
3117 if f.LocalPath().endswith(('.orig', '.rej'))]
3118 if problems:
3119 return [output_api.PresubmitError(
3120 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:033121 else:
3122 return []
[email protected]b8079ae4a2012-12-05 19:56:493123
3124
Kent Tamura5a8755d2017-06-29 23:37:073125def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:213126 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
3127 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
3128 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:073129 include_re = input_api.re.compile(
3130 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
3131 extension_re = input_api.re.compile(r'\.[a-z]+$')
3132 errors = []
3133 for f in input_api.AffectedFiles():
3134 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
3135 continue
3136 found_line_number = None
3137 found_macro = None
3138 for line_num, line in f.ChangedContents():
3139 match = macro_re.search(line)
3140 if match:
3141 found_line_number = line_num
3142 found_macro = match.group(2)
3143 break
3144 if not found_line_number:
3145 continue
3146
3147 found_include = False
3148 for line in f.NewContents():
3149 if include_re.search(line):
3150 found_include = True
3151 break
3152 if found_include:
3153 continue
3154
3155 if not f.LocalPath().endswith('.h'):
3156 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
3157 try:
3158 content = input_api.ReadFile(primary_header_path, 'r')
3159 if include_re.search(content):
3160 continue
3161 except IOError:
3162 pass
3163 errors.append('%s:%d %s macro is used without including build/'
3164 'build_config.h.'
3165 % (f.LocalPath(), found_line_number, found_macro))
3166 if errors:
3167 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
3168 return []
3169
3170
[email protected]b00342e7f2013-03-26 16:21:543171def _DidYouMeanOSMacro(bad_macro):
3172 try:
3173 return {'A': 'OS_ANDROID',
3174 'B': 'OS_BSD',
3175 'C': 'OS_CHROMEOS',
3176 'F': 'OS_FREEBSD',
3177 'L': 'OS_LINUX',
3178 'M': 'OS_MACOSX',
3179 'N': 'OS_NACL',
3180 'O': 'OS_OPENBSD',
3181 'P': 'OS_POSIX',
3182 'S': 'OS_SOLARIS',
3183 'W': 'OS_WIN'}[bad_macro[3].upper()]
3184 except KeyError:
3185 return ''
3186
3187
3188def _CheckForInvalidOSMacrosInFile(input_api, f):
3189 """Check for sensible looking, totally invalid OS macros."""
3190 preprocessor_statement = input_api.re.compile(r'^\s*#')
3191 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
3192 results = []
3193 for lnum, line in f.ChangedContents():
3194 if preprocessor_statement.search(line):
3195 for match in os_macro.finditer(line):
3196 if not match.group(1) in _VALID_OS_MACROS:
3197 good = _DidYouMeanOSMacro(match.group(1))
3198 did_you_mean = ' (did you mean %s?)' % good if good else ''
3199 results.append(' %s:%d %s%s' % (f.LocalPath(),
3200 lnum,
3201 match.group(1),
3202 did_you_mean))
3203 return results
3204
3205
3206def _CheckForInvalidOSMacros(input_api, output_api):
3207 """Check all affected files for invalid OS macros."""
3208 bad_macros = []
tzik3f295992018-12-04 20:32:233209 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:473210 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:543211 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
3212
3213 if not bad_macros:
3214 return []
3215
3216 return [output_api.PresubmitError(
3217 'Possibly invalid OS macro[s] found. Please fix your code\n'
3218 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
3219
lliabraa35bab3932014-10-01 12:16:443220
3221def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
3222 """Check all affected files for invalid "if defined" macros."""
3223 ALWAYS_DEFINED_MACROS = (
3224 "TARGET_CPU_PPC",
3225 "TARGET_CPU_PPC64",
3226 "TARGET_CPU_68K",
3227 "TARGET_CPU_X86",
3228 "TARGET_CPU_ARM",
3229 "TARGET_CPU_MIPS",
3230 "TARGET_CPU_SPARC",
3231 "TARGET_CPU_ALPHA",
3232 "TARGET_IPHONE_SIMULATOR",
3233 "TARGET_OS_EMBEDDED",
3234 "TARGET_OS_IPHONE",
3235 "TARGET_OS_MAC",
3236 "TARGET_OS_UNIX",
3237 "TARGET_OS_WIN32",
3238 )
3239 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
3240 results = []
3241 for lnum, line in f.ChangedContents():
3242 for match in ifdef_macro.finditer(line):
3243 if match.group(1) in ALWAYS_DEFINED_MACROS:
3244 always_defined = ' %s is always defined. ' % match.group(1)
3245 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
3246 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
3247 lnum,
3248 always_defined,
3249 did_you_mean))
3250 return results
3251
3252
3253def _CheckForInvalidIfDefinedMacros(input_api, output_api):
3254 """Check all affected files for invalid "if defined" macros."""
3255 bad_macros = []
3256 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:213257 if f.LocalPath().startswith('third_party/sqlite/'):
3258 continue
lliabraa35bab3932014-10-01 12:16:443259 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3260 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3261
3262 if not bad_macros:
3263 return []
3264
3265 return [output_api.PresubmitError(
3266 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3267 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3268 bad_macros)]
3269
3270
mlamouria82272622014-09-16 18:45:043271def _CheckForIPCRules(input_api, output_api):
3272 """Check for same IPC rules described in
3273 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3274 """
3275 base_pattern = r'IPC_ENUM_TRAITS\('
3276 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3277 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3278
3279 problems = []
3280 for f in input_api.AffectedSourceFiles(None):
3281 local_path = f.LocalPath()
3282 if not local_path.endswith('.h'):
3283 continue
3284 for line_number, line in f.ChangedContents():
3285 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3286 problems.append(
3287 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3288
3289 if problems:
3290 return [output_api.PresubmitPromptWarning(
3291 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
3292 else:
3293 return []
3294
[email protected]b00342e7f2013-03-26 16:21:543295
Stephen Martinis97a394142018-06-07 23:06:053296def _CheckForLongPathnames(input_api, output_api):
3297 """Check to make sure no files being submitted have long paths.
3298 This causes issues on Windows.
3299 """
3300 problems = []
3301 for f in input_api.AffectedSourceFiles(None):
3302 local_path = f.LocalPath()
3303 # Windows has a path limit of 260 characters. Limit path length to 200 so
3304 # that we have some extra for the prefix on dev machines and the bots.
3305 if len(local_path) > 200:
3306 problems.append(local_path)
3307
3308 if problems:
3309 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
3310 else:
3311 return []
3312
3313
Daniel Bratell8ba52722018-03-02 16:06:143314def _CheckForIncludeGuards(input_api, output_api):
3315 """Check that header files have proper guards against multiple inclusion.
3316 If a file should not have such guards (and it probably should) then it
3317 should include the string "no-include-guard-because-multiply-included".
3318 """
Daniel Bratell6a75baef62018-06-04 10:04:453319 def is_chromium_header_file(f):
3320 # We only check header files under the control of the Chromium
3321 # project. That is, those outside third_party apart from
3322 # third_party/blink.
3323 file_with_path = input_api.os_path.normpath(f.LocalPath())
3324 return (file_with_path.endswith('.h') and
3325 (not file_with_path.startswith('third_party') or
3326 file_with_path.startswith(
3327 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:143328
3329 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:343330 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:143331
3332 errors = []
3333
Daniel Bratell6a75baef62018-06-04 10:04:453334 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:143335 guard_name = None
3336 guard_line_number = None
3337 seen_guard_end = False
3338
3339 file_with_path = input_api.os_path.normpath(f.LocalPath())
3340 base_file_name = input_api.os_path.splitext(
3341 input_api.os_path.basename(file_with_path))[0]
3342 upper_base_file_name = base_file_name.upper()
3343
3344 expected_guard = replace_special_with_underscore(
3345 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:143346
3347 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:573348 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
3349 # are too many (1000+) files with slight deviations from the
3350 # coding style. The most important part is that the include guard
3351 # is there, and that it's unique, not the name so this check is
3352 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:143353 #
3354 # As code becomes more uniform, this could be made stricter.
3355
3356 guard_name_pattern_list = [
3357 # Anything with the right suffix (maybe with an extra _).
3358 r'\w+_H__?',
3359
Daniel Bratell39b5b062018-05-16 18:09:573360 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:143361 r'\w+_h',
3362
3363 # Anything including the uppercase name of the file.
3364 r'\w*' + input_api.re.escape(replace_special_with_underscore(
3365 upper_base_file_name)) + r'\w*',
3366 ]
3367 guard_name_pattern = '|'.join(guard_name_pattern_list)
3368 guard_pattern = input_api.re.compile(
3369 r'#ifndef\s+(' + guard_name_pattern + ')')
3370
3371 for line_number, line in enumerate(f.NewContents()):
3372 if 'no-include-guard-because-multiply-included' in line:
3373 guard_name = 'DUMMY' # To not trigger check outside the loop.
3374 break
3375
3376 if guard_name is None:
3377 match = guard_pattern.match(line)
3378 if match:
3379 guard_name = match.group(1)
3380 guard_line_number = line_number
3381
Daniel Bratell39b5b062018-05-16 18:09:573382 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:453383 # don't match the chromium style guide, but new files should
3384 # get it right.
3385 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:573386 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:143387 errors.append(output_api.PresubmitPromptWarning(
3388 'Header using the wrong include guard name %s' % guard_name,
3389 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:573390 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:143391 else:
3392 # The line after #ifndef should have a #define of the same name.
3393 if line_number == guard_line_number + 1:
3394 expected_line = '#define %s' % guard_name
3395 if line != expected_line:
3396 errors.append(output_api.PresubmitPromptWarning(
3397 'Missing "%s" for include guard' % expected_line,
3398 ['%s:%d' % (f.LocalPath(), line_number + 1)],
3399 'Expected: %r\nGot: %r' % (expected_line, line)))
3400
3401 if not seen_guard_end and line == '#endif // %s' % guard_name:
3402 seen_guard_end = True
3403 elif seen_guard_end:
3404 if line.strip() != '':
3405 errors.append(output_api.PresubmitPromptWarning(
3406 'Include guard %s not covering the whole file' % (
3407 guard_name), [f.LocalPath()]))
3408 break # Nothing else to check and enough to warn once.
3409
3410 if guard_name is None:
3411 errors.append(output_api.PresubmitPromptWarning(
3412 'Missing include guard %s' % expected_guard,
3413 [f.LocalPath()],
3414 'Missing include guard in %s\n'
3415 'Recommended name: %s\n'
3416 'This check can be disabled by having the string\n'
3417 'no-include-guard-because-multiply-included in the header.' %
3418 (f.LocalPath(), expected_guard)))
3419
3420 return errors
3421
3422
mostynbb639aca52015-01-07 20:31:233423def _CheckForWindowsLineEndings(input_api, output_api):
3424 """Check source code and known ascii text files for Windows style line
3425 endings.
3426 """
earthdok1b5e0ee2015-03-10 15:19:103427 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233428
3429 file_inclusion_pattern = (
3430 known_text_files,
3431 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3432 )
3433
mostynbb639aca52015-01-07 20:31:233434 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533435 source_file_filter = lambda f: input_api.FilterSourceFile(
3436 f, white_list=file_inclusion_pattern, black_list=None)
3437 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503438 include_file = False
3439 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233440 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503441 include_file = True
3442 if include_file:
3443 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233444
3445 if problems:
3446 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3447 'these files to contain Windows style line endings?\n' +
3448 '\n'.join(problems))]
3449
3450 return []
3451
3452
Vaclav Brozekd5de76a2018-03-17 07:57:503453def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133454 """Checks that all source files use SYSLOG properly."""
3455 syslog_files = []
3456 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563457 for line_number, line in f.ChangedContents():
3458 if 'SYSLOG' in line:
3459 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3460
pastarmovj89f7ee12016-09-20 14:58:133461 if syslog_files:
3462 return [output_api.PresubmitPromptWarning(
3463 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3464 ' calls.\nFiles to check:\n', items=syslog_files)]
3465 return []
3466
3467
[email protected]1f7b4172010-01-28 01:17:343468def CheckChangeOnUpload(input_api, output_api):
3469 results = []
3470 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473471 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283472 results.extend(
jam93a6ee792017-02-08 23:59:223473 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193474 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223475 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133476 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163477 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:533478 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193479 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543480 return results
[email protected]ca8d1982009-02-19 16:33:123481
3482
[email protected]1bfb8322014-04-23 01:02:413483def GetTryServerMasterForBot(bot):
3484 """Returns the Try Server master for the given bot.
3485
[email protected]0bb112362014-07-26 04:38:323486 It tries to guess the master from the bot name, but may still fail
3487 and return None. There is no longer a default master.
3488 """
3489 # Potentially ambiguous bot names are listed explicitly.
3490 master_map = {
tandriie5587792016-07-14 00:34:503491 'chromium_presubmit': 'master.tryserver.chromium.linux',
3492 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413493 }
[email protected]0bb112362014-07-26 04:38:323494 master = master_map.get(bot)
3495 if not master:
wnwen4fbaab82016-05-25 12:54:363496 if 'android' in bot:
tandriie5587792016-07-14 00:34:503497 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363498 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503499 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323500 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503501 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323502 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503503 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323504 return master
[email protected]1bfb8322014-04-23 01:02:413505
3506
[email protected]ca8d1982009-02-19 16:33:123507def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543508 results = []
[email protected]1f7b4172010-01-28 01:17:343509 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573510 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543511 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273512 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343513 input_api,
3514 output_api,
[email protected]2fdd1f362013-01-16 03:56:033515 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273516
jam93a6ee792017-02-08 23:59:223517 results.extend(
3518 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543519 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3520 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413521 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3522 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543523 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143524
3525
3526def _CheckTranslationScreenshots(input_api, output_api):
3527 PART_FILE_TAG = "part"
3528 import os
3529 import sys
3530 from io import StringIO
3531
3532 try:
3533 old_sys_path = sys.path
3534 sys.path = sys.path + [input_api.os_path.join(
3535 input_api.PresubmitLocalPath(), 'tools', 'grit')]
3536 import grit.grd_reader
3537 import grit.node.message
3538 import grit.util
3539 finally:
3540 sys.path = old_sys_path
3541
3542 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
3543 """Load the grd file and return a dict of message ids to messages.
3544
3545 Ignores any nested grdp files pointed by <part> tag.
3546 """
3547 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
3548 stop_after=None, first_ids_file=None,
3549 debug=False, defines=None,
3550 tags_to_ignore=set([PART_FILE_TAG]))
3551 return {
3552 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
3553 grit.node.message.MessageNode)
3554 }
3555
3556 def _GetGrdpMessagesFromString(grdp_string):
3557 """Parses the contents of a grdp file given in grdp_string.
3558
3559 grd_reader can't parse grdp files directly. Instead, this creates a
3560 temporary directory with a grd file pointing to the grdp file, and loads the
3561 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
3562 """
3563 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
3564 <grit latest_public_release="1" current_release="1">
3565 <release seq="1">
3566 <messages>
3567 <part file="sub.grdp" />
3568 </messages>
3569 </release>
3570 </grit>
3571 """
3572 with grit.util.TempDir({'main.grd': WRAPPER,
3573 'sub.grdp': grdp_string}) as temp_dir:
3574 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
3575
3576 new_or_added_paths = set(f.LocalPath()
3577 for f in input_api.AffectedFiles()
3578 if (f.Action() == 'A' or f.Action() == 'M'))
3579 removed_paths = set(f.LocalPath()
3580 for f in input_api.AffectedFiles(include_deletes=True)
3581 if f.Action() == 'D')
3582
3583 affected_grds = [f for f in input_api.AffectedFiles()
3584 if (f.LocalPath().endswith('.grd') or
3585 f.LocalPath().endswith('.grdp'))]
3586 affected_png_paths = [f.AbsoluteLocalPath()
3587 for f in input_api.AffectedFiles()
3588 if (f.LocalPath().endswith('.png'))]
3589
3590 # Check for screenshots. Developers can upload screenshots using
3591 # tools/translation/upload_screenshots.py which finds and uploads
3592 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
3593 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
3594 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
3595 #
3596 # The logic here is as follows:
3597 #
3598 # - If the CL has a .png file under the screenshots directory for a grd
3599 # file, warn the developer. Actual images should never be checked into the
3600 # Chrome repo.
3601 #
3602 # - If the CL contains modified or new messages in grd files and doesn't
3603 # contain the corresponding .sha1 files, warn the developer to add images
3604 # and upload them via tools/translation/upload_screenshots.py.
3605 #
3606 # - If the CL contains modified or new messages in grd files and the
3607 # corresponding .sha1 files, everything looks good.
3608 #
3609 # - If the CL contains removed messages in grd files but the corresponding
3610 # .sha1 files aren't removed, warn the developer to remove them.
3611 unnecessary_screenshots = []
3612 missing_sha1 = []
3613 unnecessary_sha1_files = []
3614
3615
3616 def _CheckScreenshotAdded(screenshots_dir, message_id):
3617 sha1_path = input_api.os_path.join(
3618 screenshots_dir, message_id + '.png.sha1')
3619 if sha1_path not in new_or_added_paths:
3620 missing_sha1.append(sha1_path)
3621
3622
3623 def _CheckScreenshotRemoved(screenshots_dir, message_id):
3624 sha1_path = input_api.os_path.join(
3625 screenshots_dir, message_id + '.png.sha1')
3626 if sha1_path not in removed_paths:
3627 unnecessary_sha1_files.append(sha1_path)
3628
3629
3630 for f in affected_grds:
3631 file_path = f.LocalPath()
3632 old_id_to_msg_map = {}
3633 new_id_to_msg_map = {}
3634 if file_path.endswith('.grdp'):
3635 if f.OldContents():
3636 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393637 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143638 if f.NewContents():
3639 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393640 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143641 else:
3642 if f.OldContents():
3643 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393644 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143645 if f.NewContents():
3646 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393647 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143648
3649 # Compute added, removed and modified message IDs.
3650 old_ids = set(old_id_to_msg_map)
3651 new_ids = set(new_id_to_msg_map)
3652 added_ids = new_ids - old_ids
3653 removed_ids = old_ids - new_ids
3654 modified_ids = set([])
3655 for key in old_ids.intersection(new_ids):
3656 if (old_id_to_msg_map[key].FormatXml()
3657 != new_id_to_msg_map[key].FormatXml()):
3658 modified_ids.add(key)
3659
3660 grd_name, ext = input_api.os_path.splitext(
3661 input_api.os_path.basename(file_path))
3662 screenshots_dir = input_api.os_path.join(
3663 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
3664
3665 # Check the screenshot directory for .png files. Warn if there is any.
3666 for png_path in affected_png_paths:
3667 if png_path.startswith(screenshots_dir):
3668 unnecessary_screenshots.append(png_path)
3669
3670 for added_id in added_ids:
3671 _CheckScreenshotAdded(screenshots_dir, added_id)
3672
3673 for modified_id in modified_ids:
3674 _CheckScreenshotAdded(screenshots_dir, modified_id)
3675
3676 for removed_id in removed_ids:
3677 _CheckScreenshotRemoved(screenshots_dir, removed_id)
3678
3679 results = []
3680 if unnecessary_screenshots:
3681 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393682 'Do not include actual screenshots in the changelist. Run '
3683 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143684 sorted(unnecessary_screenshots)))
3685
3686 if missing_sha1:
3687 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393688 'You are adding or modifying UI strings.\n'
3689 'To ensure the best translations, take screenshots of the relevant UI '
3690 '(https://g.co/chrome/translation) and add these files to your '
3691 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143692
3693 if unnecessary_sha1_files:
3694 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393695 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143696 sorted(unnecessary_sha1_files)))
3697
3698 return results