blob: e8aa2db9bc3b7cafac8a384799de2130541c2636 [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 (
thomasanderson11aa41dc2017-06-08 22:22:38249 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20250 ),
251 True,
252 (
Egor Paskoce145c42018-09-28 19:31:04253 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
254 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
255 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20256 ),
257 ),
258 (
tomhudsone2c14d552016-05-26 17:07:46259 'setMatrixClip',
260 (
261 'Overriding setMatrixClip() is prohibited; ',
262 'the base function is deprecated. ',
263 ),
264 True,
265 (),
266 ),
267 (
[email protected]52657f62013-05-20 05:30:31268 'SkRefPtr',
269 (
270 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22271 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31272 ),
273 True,
274 (),
275 ),
276 (
277 'SkAutoRef',
278 (
279 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22280 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31281 ),
282 True,
283 (),
284 ),
285 (
286 'SkAutoTUnref',
287 (
288 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22289 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31290 ),
291 True,
292 (),
293 ),
294 (
295 'SkAutoUnref',
296 (
297 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
298 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22299 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31300 ),
301 True,
302 (),
303 ),
[email protected]d89eec82013-12-03 14:10:59304 (
305 r'/HANDLE_EINTR\(.*close',
306 (
307 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
308 'descriptor will be closed, and it is incorrect to retry the close.',
309 'Either call close directly and ignore its return value, or wrap close',
310 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
311 ),
312 True,
313 (),
314 ),
315 (
316 r'/IGNORE_EINTR\((?!.*close)',
317 (
318 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
319 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
320 ),
321 True,
322 (
323 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04324 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
325 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59326 ),
327 ),
[email protected]ec5b3f02014-04-04 18:43:43328 (
329 r'/v8::Extension\(',
330 (
331 'Do not introduce new v8::Extensions into the code base, use',
332 'gin::Wrappable instead. See http://crbug.com/334679',
333 ),
334 True,
[email protected]f55c90ee62014-04-12 00:50:03335 (
Egor Paskoce145c42018-09-28 19:31:04336 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03337 ),
[email protected]ec5b3f02014-04-04 18:43:43338 ),
skyostilf9469f72015-04-20 10:38:52339 (
jame2d1a952016-04-02 00:27:10340 '#pragma comment(lib,',
341 (
342 'Specify libraries to link with in build files and not in the source.',
343 ),
344 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41345 (
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',
Andrew Grievea417ad302019-02-06 19:54:38658 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36659 'build/android/gyp/bytecode_processor.pydeps',
660 'build/android/gyp/compile_resources.pydeps',
Andrew Grievef89e926c2019-02-07 18:36:57661 'build/android/gyp/create_app_bundle_minimal_apks.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36662 'build/android/gyp/create_bundle_wrapper_script.pydeps',
663 'build/android/gyp/copy_ex.pydeps',
664 'build/android/gyp/create_app_bundle.pydeps',
665 'build/android/gyp/create_apk_operations_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36666 'build/android/gyp/create_java_binary_script.pydeps',
667 'build/android/gyp/create_stack_script.pydeps',
668 'build/android/gyp/create_test_runner_script.pydeps',
669 'build/android/gyp/create_tool_wrapper.pydeps',
670 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:59671 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36672 'build/android/gyp/dex.pydeps',
673 'build/android/gyp/dist_aar.pydeps',
674 'build/android/gyp/emma_instr.pydeps',
675 'build/android/gyp/filter_zip.pydeps',
676 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:36677 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36678 'build/android/gyp/ijar.pydeps',
679 'build/android/gyp/java_cpp_enum.pydeps',
680 'build/android/gyp/javac.pydeps',
681 'build/android/gyp/jinja_template.pydeps',
682 'build/android/gyp/lint.pydeps',
683 'build/android/gyp/main_dex_list.pydeps',
684 'build/android/gyp/merge_jar_info_files.pydeps',
685 'build/android/gyp/merge_manifest.pydeps',
686 'build/android/gyp/prepare_resources.pydeps',
687 'build/android/gyp/proguard.pydeps',
688 'build/android/gyp/write_build_config.pydeps',
689 'build/android/gyp/write_ordered_libraries.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:56690 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36691 'build/android/incremental_install/generate_android_manifest.pydeps',
692 'build/android/incremental_install/write_installer_json.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22693 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:40694 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04695 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36696 'build/protoc_java.pydeps',
Sam Maier3599daa2018-11-26 18:02:59697 ('build/secondary/third_party/android_platform/'
698 'development/scripts/stack.pydeps'),
agrieve732db3a2016-04-26 19:18:19699 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40700]
701
wnwenbdc444e2016-05-25 13:44:15702
agrievef32bcc72016-04-04 14:57:40703_GENERIC_PYDEPS_FILES = [
John Chencde89192018-01-27 21:18:40704 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Cole Winstanley7045a1b2018-08-27 23:37:29705 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22706 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:40707]
708
wnwenbdc444e2016-05-25 13:44:15709
agrievef32bcc72016-04-04 14:57:40710_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
711
712
Eric Boren6fd2b932018-01-25 15:05:08713# Bypass the AUTHORS check for these accounts.
714_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:29715 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
716 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:08717 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
Eric Boren57cc805b2018-08-20 17:28:32718 'spirv', 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:59719 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:45720 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:59721 ) | set('%[email protected]' % s
Robert Ma7f024172018-11-01 20:59:22722 for s in ('v8-ci-autoroll-builder', 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:04723 ) | set('%[email protected]' % s
724 for s in ('chromium-autoroll',)
725 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:30726 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:08727
728
[email protected]55459852011-08-10 15:17:19729def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
730 """Attempts to prevent use of functions intended only for testing in
731 non-testing code. For now this is just a best-effort implementation
732 that ignores header files and may have some false positives. A
733 better implementation would probably need a proper C++ parser.
734 """
735 # We only scan .cc files and the like, as the declaration of
736 # for-testing functions in header files are hard to distinguish from
737 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49738 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:19739
jochenc0d4808c2015-07-27 09:25:42740 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19741 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09742 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19743 exclusion_pattern = input_api.re.compile(
744 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
745 base_function_pattern, base_function_pattern))
746
747 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44748 black_list = (_EXCLUDED_PATHS +
749 _TEST_CODE_EXCLUDED_PATHS +
750 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19751 return input_api.FilterSourceFile(
752 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49753 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:19754 black_list=black_list)
755
756 problems = []
757 for f in input_api.AffectedSourceFiles(FilterFile):
758 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24759 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03760 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46761 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03762 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19763 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03764 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19765
766 if problems:
[email protected]f7051d52013-04-02 18:31:42767 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03768 else:
769 return []
[email protected]55459852011-08-10 15:17:19770
771
Vaclav Brozek7dbc28c2018-03-27 08:35:23772def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
773 """This is a simplified version of
774 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
775 """
776 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
777 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
778 name_pattern = r'ForTest(s|ing)?'
779 # Describes an occurrence of "ForTest*" inside a // comment.
780 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
781 # Catch calls.
782 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
783 # Ignore definitions. (Comments are ignored separately.)
784 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
785
786 problems = []
787 sources = lambda x: input_api.FilterSourceFile(
788 x,
789 black_list=(('(?i).*test', r'.*\/junit\/')
790 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49791 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:23792 )
793 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
794 local_path = f.LocalPath()
795 is_inside_javadoc = False
796 for line_number, line in f.ChangedContents():
797 if is_inside_javadoc and javadoc_end_re.search(line):
798 is_inside_javadoc = False
799 if not is_inside_javadoc and javadoc_start_re.search(line):
800 is_inside_javadoc = True
801 if is_inside_javadoc:
802 continue
803 if (inclusion_re.search(line) and
804 not comment_re.search(line) and
805 not exclusion_re.search(line)):
806 problems.append(
807 '%s:%d\n %s' % (local_path, line_number, line.strip()))
808
809 if problems:
810 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
811 else:
812 return []
813
814
[email protected]10689ca2011-09-02 02:31:54815def _CheckNoIOStreamInHeaders(input_api, output_api):
816 """Checks to make sure no .h files include <iostream>."""
817 files = []
818 pattern = input_api.re.compile(r'^#include\s*<iostream>',
819 input_api.re.MULTILINE)
820 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
821 if not f.LocalPath().endswith('.h'):
822 continue
823 contents = input_api.ReadFile(f)
824 if pattern.search(contents):
825 files.append(f)
826
827 if len(files):
yolandyandaabc6d2016-04-18 18:29:39828 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06829 'Do not #include <iostream> in header files, since it inserts static '
830 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54831 '#include <ostream>. See http://crbug.com/94794',
832 files) ]
833 return []
834
Danil Chapovalov3518f362018-08-11 16:13:43835def _CheckNoStrCatRedefines(input_api, output_api):
836 """Checks no windows headers with StrCat redefined are included directly."""
837 files = []
838 pattern_deny = input_api.re.compile(
839 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
840 input_api.re.MULTILINE)
841 pattern_allow = input_api.re.compile(
842 r'^#include\s"base/win/windows_defines.inc"',
843 input_api.re.MULTILINE)
844 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
845 contents = input_api.ReadFile(f)
846 if pattern_deny.search(contents) and not pattern_allow.search(contents):
847 files.append(f.LocalPath())
848
849 if len(files):
850 return [output_api.PresubmitError(
851 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
852 'directly since they pollute code with StrCat macro. Instead, '
853 'include matching header from base/win. See http://crbug.com/856536',
854 files) ]
855 return []
856
[email protected]10689ca2011-09-02 02:31:54857
[email protected]72df4e782012-06-21 16:28:18858def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52859 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18860 problems = []
861 for f in input_api.AffectedFiles():
862 if (not f.LocalPath().endswith(('.cc', '.mm'))):
863 continue
864
865 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04866 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18867 problems.append(' %s:%d' % (f.LocalPath(), line_num))
868
869 if not problems:
870 return []
871 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
872 '\n'.join(problems))]
873
Dominic Battre033531052018-09-24 15:45:34874def _CheckNoDISABLETypoInTests(input_api, output_api):
875 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
876
877 This test warns if somebody tries to disable a test with the DISABLE_ prefix
878 instead of DISABLED_. To filter false positives, reports are only generated
879 if a corresponding MAYBE_ line exists.
880 """
881 problems = []
882
883 # The following two patterns are looked for in tandem - is a test labeled
884 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
885 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
886 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
887
888 # This is for the case that a test is disabled on all platforms.
889 full_disable_pattern = input_api.re.compile(
890 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
891 input_api.re.MULTILINE)
892
Katie Df13948e2018-09-25 07:33:44893 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:34894 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
895 continue
896
897 # Search for MABYE_, DISABLE_ pairs.
898 disable_lines = {} # Maps of test name to line number.
899 maybe_lines = {}
900 for line_num, line in f.ChangedContents():
901 disable_match = disable_pattern.search(line)
902 if disable_match:
903 disable_lines[disable_match.group(1)] = line_num
904 maybe_match = maybe_pattern.search(line)
905 if maybe_match:
906 maybe_lines[maybe_match.group(1)] = line_num
907
908 # Search for DISABLE_ occurrences within a TEST() macro.
909 disable_tests = set(disable_lines.keys())
910 maybe_tests = set(maybe_lines.keys())
911 for test in disable_tests.intersection(maybe_tests):
912 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
913
914 contents = input_api.ReadFile(f)
915 full_disable_match = full_disable_pattern.search(contents)
916 if full_disable_match:
917 problems.append(' %s' % f.LocalPath())
918
919 if not problems:
920 return []
921 return [
922 output_api.PresubmitPromptWarning(
923 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
924 '\n'.join(problems))
925 ]
926
[email protected]72df4e782012-06-21 16:28:18927
danakj61c1aa22015-10-26 19:55:52928def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57929 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52930 errors = []
931 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
932 input_api.re.MULTILINE)
933 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
934 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
935 continue
936 for lnum, line in f.ChangedContents():
937 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17938 errors.append(output_api.PresubmitError(
939 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57940 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17941 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52942 return errors
943
944
mcasasb7440c282015-02-04 14:52:19945def _FindHistogramNameInLine(histogram_name, line):
946 """Tries to find a histogram name or prefix in a line."""
947 if not "affected-histogram" in line:
948 return histogram_name in line
949 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
950 # the histogram_name.
951 if not '"' in line:
952 return False
953 histogram_prefix = line.split('\"')[1]
954 return histogram_prefix in histogram_name
955
956
957def _CheckUmaHistogramChanges(input_api, output_api):
958 """Check that UMA histogram names in touched lines can still be found in other
959 lines of the patch or in histograms.xml. Note that this check would not catch
960 the reverse: changes in histograms.xml not matched in the code itself."""
961 touched_histograms = []
962 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:47963 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
964 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
965 name_pattern = r'"(.*?)"'
966 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
967 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
968 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
969 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
970 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:17971 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:19972 for f in input_api.AffectedFiles():
973 # If histograms.xml itself is modified, keep the modified lines for later.
974 if f.LocalPath().endswith(('histograms.xml')):
975 histograms_xml_modifications = f.ChangedContents()
976 continue
Vaclav Brozekbdac817c2018-03-24 06:30:47977 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
978 single_line_re = single_line_c_re
979 split_line_prefix_re = split_line_c_prefix_re
980 elif f.LocalPath().endswith(('java')):
981 single_line_re = single_line_java_re
982 split_line_prefix_re = split_line_java_prefix_re
983 else:
mcasasb7440c282015-02-04 14:52:19984 continue
985 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:17986 if last_line_matched_prefix:
987 suffix_found = split_line_suffix_re.search(line)
988 if suffix_found :
989 touched_histograms.append([suffix_found.group(1), f, line_num])
990 last_line_matched_prefix = False
991 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:06992 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:19993 if found:
994 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:17995 continue
996 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:19997
998 # Search for the touched histogram names in the local modifications to
999 # histograms.xml, and, if not found, on the base histograms.xml file.
1000 unmatched_histograms = []
1001 for histogram_info in touched_histograms:
1002 histogram_name_found = False
1003 for line_num, line in histograms_xml_modifications:
1004 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
1005 if histogram_name_found:
1006 break
1007 if not histogram_name_found:
1008 unmatched_histograms.append(histogram_info)
1009
eromanb90c82e7e32015-04-01 15:13:491010 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191011 problems = []
1012 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491013 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191014 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451015 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191016 histogram_name_found = False
1017 for line in histograms_xml:
1018 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
1019 if histogram_name_found:
1020 break
1021 if not histogram_name_found:
1022 problems.append(' [%s:%d] %s' %
1023 (f.LocalPath(), line_num, histogram_name))
1024
1025 if not problems:
1026 return []
1027 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1028 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491029 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191030
wnwenbdc444e2016-05-25 13:44:151031
yolandyandaabc6d2016-04-18 18:29:391032def _CheckFlakyTestUsage(input_api, output_api):
1033 """Check that FlakyTest annotation is our own instead of the android one"""
1034 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1035 files = []
1036 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1037 if f.LocalPath().endswith('Test.java'):
1038 if pattern.search(input_api.ReadFile(f)):
1039 files.append(f)
1040 if len(files):
1041 return [output_api.PresubmitError(
1042 'Use org.chromium.base.test.util.FlakyTest instead of '
1043 'android.test.FlakyTest',
1044 files)]
1045 return []
mcasasb7440c282015-02-04 14:52:191046
wnwenbdc444e2016-05-25 13:44:151047
[email protected]8ea5d4b2011-09-13 21:49:221048def _CheckNoNewWStrings(input_api, output_api):
1049 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271050 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221051 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201052 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571053 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341054 '/win/' in f.LocalPath() or
1055 'chrome_elf' in f.LocalPath() or
1056 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201057 continue
[email protected]8ea5d4b2011-09-13 21:49:221058
[email protected]a11dbe9b2012-08-07 01:32:581059 allowWString = False
[email protected]b5c24292011-11-28 14:38:201060 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581061 if 'presubmit: allow wstring' in line:
1062 allowWString = True
1063 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271064 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581065 allowWString = False
1066 else:
1067 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221068
[email protected]55463aa62011-10-12 00:48:271069 if not problems:
1070 return []
1071 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581072 ' If you are calling a cross-platform API that accepts a wstring, '
1073 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271074 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221075
1076
[email protected]2a8ac9c2011-10-19 17:20:441077def _CheckNoDEPSGIT(input_api, output_api):
1078 """Make sure .DEPS.git is never modified manually."""
1079 if any(f.LocalPath().endswith('.DEPS.git') for f in
1080 input_api.AffectedFiles()):
1081 return [output_api.PresubmitError(
1082 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1083 'automated system based on what\'s in DEPS and your changes will be\n'
1084 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501085 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1086 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441087 'for more information')]
1088 return []
1089
1090
tandriief664692014-09-23 14:51:471091def _CheckValidHostsInDEPS(input_api, output_api):
1092 """Checks that DEPS file deps are from allowed_hosts."""
1093 # Run only if DEPS file has been modified to annoy fewer bystanders.
1094 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1095 return []
1096 # Outsource work to gclient verify
1097 try:
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201098 input_api.subprocess.check_output(['gclient', 'verify'],
1099 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471100 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201101 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471102 return [output_api.PresubmitError(
1103 'DEPS file must have only git dependencies.',
1104 long_text=error.output)]
1105
1106
[email protected]127f18ec2012-06-16 05:05:591107def _CheckNoBannedFunctions(input_api, output_api):
1108 """Make sure that banned functions are not used."""
1109 warnings = []
1110 errors = []
1111
wnwenbdc444e2016-05-25 13:44:151112 def IsBlacklisted(affected_file, blacklist):
1113 local_path = affected_file.LocalPath()
1114 for item in blacklist:
1115 if input_api.re.match(item, local_path):
1116 return True
1117 return False
1118
Sylvain Defresnea8b73d252018-02-28 15:45:541119 def IsIosObcjFile(affected_file):
1120 local_path = affected_file.LocalPath()
1121 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1122 return False
1123 basename = input_api.os_path.basename(local_path)
1124 if 'ios' in basename.split('_'):
1125 return True
1126 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1127 if sep and 'ios' in local_path.split(sep):
1128 return True
1129 return False
1130
wnwenbdc444e2016-05-25 13:44:151131 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
1132 matched = False
1133 if func_name[0:1] == '/':
1134 regex = func_name[1:]
1135 if input_api.re.search(regex, line):
1136 matched = True
1137 elif func_name in line:
dchenge07de812016-06-20 19:27:171138 matched = True
wnwenbdc444e2016-05-25 13:44:151139 if matched:
dchenge07de812016-06-20 19:27:171140 problems = warnings
wnwenbdc444e2016-05-25 13:44:151141 if error:
dchenge07de812016-06-20 19:27:171142 problems = errors
wnwenbdc444e2016-05-25 13:44:151143 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1144 for message_line in message:
1145 problems.append(' %s' % message_line)
1146
Eric Stevensona9a980972017-09-23 00:04:411147 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1148 for f in input_api.AffectedFiles(file_filter=file_filter):
1149 for line_num, line in f.ChangedContents():
1150 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1151 CheckForMatch(f, line_num, line, func_name, message, error)
1152
[email protected]127f18ec2012-06-16 05:05:591153 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1154 for f in input_api.AffectedFiles(file_filter=file_filter):
1155 for line_num, line in f.ChangedContents():
1156 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151157 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591158
Sylvain Defresnea8b73d252018-02-28 15:45:541159 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1160 for line_num, line in f.ChangedContents():
1161 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1162 CheckForMatch(f, line_num, line, func_name, message, error)
1163
[email protected]127f18ec2012-06-16 05:05:591164 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1165 for f in input_api.AffectedFiles(file_filter=file_filter):
1166 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491167 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491168 if IsBlacklisted(f, excluded_paths):
1169 continue
wnwenbdc444e2016-05-25 13:44:151170 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591171
1172 result = []
1173 if (warnings):
1174 result.append(output_api.PresubmitPromptWarning(
1175 'Banned functions were used.\n' + '\n'.join(warnings)))
1176 if (errors):
1177 result.append(output_api.PresubmitError(
1178 'Banned functions were used.\n' + '\n'.join(errors)))
1179 return result
1180
1181
[email protected]6c063c62012-07-11 19:11:061182def _CheckNoPragmaOnce(input_api, output_api):
1183 """Make sure that banned functions are not used."""
1184 files = []
1185 pattern = input_api.re.compile(r'^#pragma\s+once',
1186 input_api.re.MULTILINE)
1187 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1188 if not f.LocalPath().endswith('.h'):
1189 continue
1190 contents = input_api.ReadFile(f)
1191 if pattern.search(contents):
1192 files.append(f)
1193
1194 if files:
1195 return [output_api.PresubmitError(
1196 'Do not use #pragma once in header files.\n'
1197 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1198 files)]
1199 return []
1200
[email protected]127f18ec2012-06-16 05:05:591201
[email protected]e7479052012-09-19 00:26:121202def _CheckNoTrinaryTrueFalse(input_api, output_api):
1203 """Checks to make sure we don't introduce use of foo ? true : false."""
1204 problems = []
1205 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1206 for f in input_api.AffectedFiles():
1207 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1208 continue
1209
1210 for line_num, line in f.ChangedContents():
1211 if pattern.match(line):
1212 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1213
1214 if not problems:
1215 return []
1216 return [output_api.PresubmitPromptWarning(
1217 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1218 '\n'.join(problems))]
1219
1220
[email protected]55f9f382012-07-31 11:02:181221def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281222 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181223 change. Breaking - rules is an error, breaking ! rules is a
1224 warning.
1225 """
mohan.reddyf21db962014-10-16 12:26:471226 import sys
[email protected]55f9f382012-07-31 11:02:181227 # We need to wait until we have an input_api object and use this
1228 # roundabout construct to import checkdeps because this file is
1229 # eval-ed and thus doesn't have __file__.
1230 original_sys_path = sys.path
1231 try:
1232 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471233 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181234 import checkdeps
1235 from cpp_checker import CppChecker
Jinsuk Kim5a092672017-10-24 22:42:241236 from java_checker import JavaChecker
rhalavati08acd232017-04-03 07:23:281237 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:181238 from rules import Rule
1239 finally:
1240 # Restore sys.path to what it was before.
1241 sys.path = original_sys_path
1242
1243 added_includes = []
rhalavati08acd232017-04-03 07:23:281244 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241245 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181246 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:281247 if CppChecker.IsCppFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501248 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081249 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
rhalavati08acd232017-04-03 07:23:281250 elif ProtoChecker.IsProtoFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501251 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081252 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241253 elif JavaChecker.IsJavaFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501254 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081255 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181256
[email protected]26385172013-05-09 23:11:351257 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181258
1259 error_descriptions = []
1260 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281261 error_subjects = set()
1262 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181263 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1264 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081265 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181266 description_with_path = '%s\n %s' % (path, rule_description)
1267 if rule_type == Rule.DISALLOW:
1268 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281269 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181270 else:
1271 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281272 warning_subjects.add("#includes")
1273
1274 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1275 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081276 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281277 description_with_path = '%s\n %s' % (path, rule_description)
1278 if rule_type == Rule.DISALLOW:
1279 error_descriptions.append(description_with_path)
1280 error_subjects.add("imports")
1281 else:
1282 warning_descriptions.append(description_with_path)
1283 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181284
Jinsuk Kim5a092672017-10-24 22:42:241285 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021286 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081287 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241288 description_with_path = '%s\n %s' % (path, rule_description)
1289 if rule_type == Rule.DISALLOW:
1290 error_descriptions.append(description_with_path)
1291 error_subjects.add("imports")
1292 else:
1293 warning_descriptions.append(description_with_path)
1294 warning_subjects.add("imports")
1295
[email protected]55f9f382012-07-31 11:02:181296 results = []
1297 if error_descriptions:
1298 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281299 'You added one or more %s that violate checkdeps rules.'
1300 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181301 error_descriptions))
1302 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421303 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281304 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181305 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281306 '%s? See relevant DEPS file(s) for details and contacts.' %
1307 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181308 warning_descriptions))
1309 return results
1310
1311
[email protected]fbcafe5a2012-08-08 15:31:221312def _CheckFilePermissions(input_api, output_api):
1313 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151314 if input_api.platform == 'win32':
1315 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291316 checkperms_tool = input_api.os_path.join(
1317 input_api.PresubmitLocalPath(),
1318 'tools', 'checkperms', 'checkperms.py')
1319 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471320 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391321 with input_api.CreateTemporaryFile() as file_list:
1322 for f in input_api.AffectedFiles():
1323 # checkperms.py file/directory arguments must be relative to the
1324 # repository.
1325 file_list.write(f.LocalPath() + '\n')
1326 file_list.close()
1327 args += ['--file-list', file_list.name]
1328 try:
1329 input_api.subprocess.check_output(args)
1330 return []
1331 except input_api.subprocess.CalledProcessError as error:
1332 return [output_api.PresubmitError(
1333 'checkperms.py failed:',
1334 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221335
1336
robertocn832f5992017-01-04 19:01:301337def _CheckTeamTags(input_api, output_api):
1338 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1339 checkteamtags_tool = input_api.os_path.join(
1340 input_api.PresubmitLocalPath(),
1341 'tools', 'checkteamtags', 'checkteamtags.py')
1342 args = [input_api.python_executable, checkteamtags_tool,
1343 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221344 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301345 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1346 'OWNERS']
1347 try:
1348 if files:
1349 input_api.subprocess.check_output(args + files)
1350 return []
1351 except input_api.subprocess.CalledProcessError as error:
1352 return [output_api.PresubmitError(
1353 'checkteamtags.py failed:',
1354 long_text=error.output)]
1355
1356
[email protected]c8278b32012-10-30 20:35:491357def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1358 """Makes sure we don't include ui/aura/window_property.h
1359 in header files.
1360 """
1361 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1362 errors = []
1363 for f in input_api.AffectedFiles():
1364 if not f.LocalPath().endswith('.h'):
1365 continue
1366 for line_num, line in f.ChangedContents():
1367 if pattern.match(line):
1368 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1369
1370 results = []
1371 if errors:
1372 results.append(output_api.PresubmitError(
1373 'Header files should not include ui/aura/window_property.h', errors))
1374 return results
1375
1376
[email protected]70ca77752012-11-20 03:45:031377def _CheckForVersionControlConflictsInFile(input_api, f):
1378 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1379 errors = []
1380 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:231381 if f.LocalPath().endswith('.md'):
1382 # First-level headers in markdown look a lot like version control
1383 # conflict markers. http://daringfireball.net/projects/markdown/basics
1384 continue
[email protected]70ca77752012-11-20 03:45:031385 if pattern.match(line):
1386 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1387 return errors
1388
1389
1390def _CheckForVersionControlConflicts(input_api, output_api):
1391 """Usually this is not intentional and will cause a compile failure."""
1392 errors = []
1393 for f in input_api.AffectedFiles():
1394 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1395
1396 results = []
1397 if errors:
1398 results.append(output_api.PresubmitError(
1399 'Version control conflict markers found, please resolve.', errors))
1400 return results
1401
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201402
estadee17314a02017-01-12 16:22:161403def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1404 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1405 errors = []
1406 for f in input_api.AffectedFiles():
1407 for line_num, line in f.ChangedContents():
1408 if pattern.search(line):
1409 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1410
1411 results = []
1412 if errors:
1413 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501414 'Found Google support URL addressed by answer number. Please replace '
1415 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161416 return results
1417
[email protected]70ca77752012-11-20 03:45:031418
[email protected]06e6d0ff2012-12-11 01:36:441419def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1420 def FilterFile(affected_file):
1421 """Filter function for use with input_api.AffectedSourceFiles,
1422 below. This filters out everything except non-test files from
1423 top-level directories that generally speaking should not hard-code
1424 service URLs (e.g. src/android_webview/, src/content/ and others).
1425 """
1426 return input_api.FilterSourceFile(
1427 affected_file,
Egor Paskoce145c42018-09-28 19:31:041428 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:441429 black_list=(_EXCLUDED_PATHS +
1430 _TEST_CODE_EXCLUDED_PATHS +
1431 input_api.DEFAULT_BLACK_LIST))
1432
reillyi38965732015-11-16 18:27:331433 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1434 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461435 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1436 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441437 problems = [] # items are (filename, line_number, line)
1438 for f in input_api.AffectedSourceFiles(FilterFile):
1439 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461440 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441441 problems.append((f.LocalPath(), line_num, line))
1442
1443 if problems:
[email protected]f7051d52013-04-02 18:31:421444 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441445 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581446 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441447 [' %s:%d: %s' % (
1448 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031449 else:
1450 return []
[email protected]06e6d0ff2012-12-11 01:36:441451
1452
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491453# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:271454def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1455 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311456 The native_client_sdk directory is excluded because it has auto-generated PNG
1457 files for documentation.
[email protected]d2530012013-01-25 16:39:271458 """
[email protected]d2530012013-01-25 16:39:271459 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491460 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:041461 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:311462 file_filter = lambda f: input_api.FilterSourceFile(
1463 f, white_list=white_list, black_list=black_list)
1464 for f in input_api.AffectedFiles(include_deletes=False,
1465 file_filter=file_filter):
1466 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271467
1468 results = []
1469 if errors:
1470 results.append(output_api.PresubmitError(
1471 'The name of PNG files should not have abbreviations. \n'
1472 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1473 'Contact [email protected] if you have questions.', errors))
1474 return results
1475
1476
Daniel Cheng4dcdb6b2017-04-13 08:30:171477def _ExtractAddRulesFromParsedDeps(parsed_deps):
1478 """Extract the rules that add dependencies from a parsed DEPS file.
1479
1480 Args:
1481 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1482 add_rules = set()
1483 add_rules.update([
1484 rule[1:] for rule in parsed_deps.get('include_rules', [])
1485 if rule.startswith('+') or rule.startswith('!')
1486 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501487 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171488 {}).iteritems():
1489 add_rules.update([
1490 rule[1:] for rule in rules
1491 if rule.startswith('+') or rule.startswith('!')
1492 ])
1493 return add_rules
1494
1495
1496def _ParseDeps(contents):
1497 """Simple helper for parsing DEPS files."""
1498 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171499 class _VarImpl:
1500
1501 def __init__(self, local_scope):
1502 self._local_scope = local_scope
1503
1504 def Lookup(self, var_name):
1505 """Implements the Var syntax."""
1506 try:
1507 return self._local_scope['vars'][var_name]
1508 except KeyError:
1509 raise Exception('Var is not defined: %s' % var_name)
1510
1511 local_scope = {}
1512 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171513 'Var': _VarImpl(local_scope).Lookup,
1514 }
1515 exec contents in global_scope, local_scope
1516 return local_scope
1517
1518
1519def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081520 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411521 a set of DEPS entries that we should look up.
1522
1523 For a directory (rather than a specific filename) we fake a path to
1524 a specific filename by adding /DEPS. This is chosen as a file that
1525 will seldom or never be subject to per-file include_rules.
1526 """
[email protected]2b438d62013-11-14 17:54:141527 # We ignore deps entries on auto-generated directories.
1528 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081529
Daniel Cheng4dcdb6b2017-04-13 08:30:171530 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1531 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1532
1533 added_deps = new_deps.difference(old_deps)
1534
[email protected]2b438d62013-11-14 17:54:141535 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171536 for added_dep in added_deps:
1537 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1538 continue
1539 # Assume that a rule that ends in .h is a rule for a specific file.
1540 if added_dep.endswith('.h'):
1541 results.add(added_dep)
1542 else:
1543 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081544 return results
1545
1546
[email protected]e871964c2013-05-13 14:14:551547def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1548 """When a dependency prefixed with + is added to a DEPS file, we
1549 want to make sure that the change is reviewed by an OWNER of the
1550 target file or directory, to avoid layering violations from being
1551 introduced. This check verifies that this happens.
1552 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171553 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241554
1555 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:491556 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241557 for f in input_api.AffectedFiles(include_deletes=False,
1558 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551559 filename = input_api.os_path.basename(f.LocalPath())
1560 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171561 virtual_depended_on_files.update(_CalculateAddedDeps(
1562 input_api.os_path,
1563 '\n'.join(f.OldContents()),
1564 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551565
[email protected]e871964c2013-05-13 14:14:551566 if not virtual_depended_on_files:
1567 return []
1568
1569 if input_api.is_committing:
1570 if input_api.tbr:
1571 return [output_api.PresubmitNotifyResult(
1572 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271573 if input_api.dry_run:
1574 return [output_api.PresubmitNotifyResult(
1575 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551576 if not input_api.change.issue:
1577 return [output_api.PresubmitError(
1578 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401579 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551580 output = output_api.PresubmitError
1581 else:
1582 output = output_api.PresubmitNotifyResult
1583
1584 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501585 owner_email, reviewers = (
1586 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1587 input_api,
1588 owners_db.email_regexp,
1589 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551590
1591 owner_email = owner_email or input_api.change.author_email
1592
[email protected]de4f7d22013-05-23 14:27:461593 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511594 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461595 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551596 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1597 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411598
1599 # We strip the /DEPS part that was added by
1600 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1601 # directory.
1602 def StripDeps(path):
1603 start_deps = path.rfind('/DEPS')
1604 if start_deps != -1:
1605 return path[:start_deps]
1606 else:
1607 return path
1608 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551609 for path in missing_files]
1610
1611 if unapproved_dependencies:
1612 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151613 output('You need LGTM from owners of depends-on paths in DEPS that were '
1614 'modified in this CL:\n %s' %
1615 '\n '.join(sorted(unapproved_dependencies)))]
1616 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1617 output_list.append(output(
1618 'Suggested missing target path OWNERS:\n %s' %
1619 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551620 return output_list
1621
1622 return []
1623
1624
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491625# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:401626def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491627 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:401628 black_list = (_EXCLUDED_PATHS +
1629 _TEST_CODE_EXCLUDED_PATHS +
1630 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:041631 (r"^base[\\/]logging\.h$",
1632 r"^base[\\/]logging\.cc$",
1633 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
1634 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
1635 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:121636 r"startup_browser_creator\.cc$",
Egor Paskoce145c42018-09-28 19:31:041637 r"^chrome[\\/]installer[\\/]setup[\\/].*",
1638 r"^chrome[\\/]chrome_cleaner[\\/].*",
1639 r"chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031640 r"diagnostics_writer\.cc$",
Egor Paskoce145c42018-09-28 19:31:041641 r"^chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
1642 r"^chromecast[\\/]",
1643 r"^cloud_print[\\/]",
1644 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:481645 r"dump_stability_report_main_win.cc$",
Egor Paskoce145c42018-09-28 19:31:041646 r"^components[\\/]html_viewer[\\/]"
jochen34415e52015-07-10 08:34:311647 r"web_test_delegate_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041648 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:461649 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:041650 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:461651 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041652 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:251653 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:041654 r"^courgette[\\/]courgette_minimal_tool\.cc$",
1655 r"^courgette[\\/]courgette_tool\.cc$",
1656 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:271657 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331658 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:041659 r"^ipc[\\/]ipc_logging\.cc$",
1660 r"^native_client_sdk[\\/]",
1661 r"^remoting[\\/]base[\\/]logging\.h$",
1662 r"^remoting[\\/]host[\\/].*",
1663 r"^sandbox[\\/]linux[\\/].*",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331664 r"^storage[\\/]browser[\\/]fileapi[\\/]" +
1665 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:041666 r"^tools[\\/]",
1667 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
1668 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331669 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]"))
[email protected]85218562013-11-22 07:41:401670 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491671 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:401672
thomasanderson625d3932017-03-29 07:16:581673 log_info = set([])
1674 printf = set([])
[email protected]85218562013-11-22 07:41:401675
1676 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581677 for _, line in f.ChangedContents():
1678 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1679 log_info.add(f.LocalPath())
1680 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1681 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371682
thomasanderson625d3932017-03-29 07:16:581683 if input_api.re.search(r"\bprintf\(", line):
1684 printf.add(f.LocalPath())
1685 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1686 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401687
1688 if log_info:
1689 return [output_api.PresubmitError(
1690 'These files spam the console log with LOG(INFO):',
1691 items=log_info)]
1692 if printf:
1693 return [output_api.PresubmitError(
1694 'These files spam the console log with printf/fprintf:',
1695 items=printf)]
1696 return []
1697
1698
[email protected]49aa76a2013-12-04 06:59:161699def _CheckForAnonymousVariables(input_api, output_api):
1700 """These types are all expected to hold locks while in scope and
1701 so should never be anonymous (which causes them to be immediately
1702 destroyed)."""
1703 they_who_must_be_named = [
1704 'base::AutoLock',
1705 'base::AutoReset',
1706 'base::AutoUnlock',
1707 'SkAutoAlphaRestore',
1708 'SkAutoBitmapShaderInstall',
1709 'SkAutoBlitterChoose',
1710 'SkAutoBounderCommit',
1711 'SkAutoCallProc',
1712 'SkAutoCanvasRestore',
1713 'SkAutoCommentBlock',
1714 'SkAutoDescriptor',
1715 'SkAutoDisableDirectionCheck',
1716 'SkAutoDisableOvalCheck',
1717 'SkAutoFree',
1718 'SkAutoGlyphCache',
1719 'SkAutoHDC',
1720 'SkAutoLockColors',
1721 'SkAutoLockPixels',
1722 'SkAutoMalloc',
1723 'SkAutoMaskFreeImage',
1724 'SkAutoMutexAcquire',
1725 'SkAutoPathBoundsUpdate',
1726 'SkAutoPDFRelease',
1727 'SkAutoRasterClipValidate',
1728 'SkAutoRef',
1729 'SkAutoTime',
1730 'SkAutoTrace',
1731 'SkAutoUnref',
1732 ]
1733 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1734 # bad: base::AutoLock(lock.get());
1735 # not bad: base::AutoLock lock(lock.get());
1736 bad_pattern = input_api.re.compile(anonymous)
1737 # good: new base::AutoLock(lock.get())
1738 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1739 errors = []
1740
1741 for f in input_api.AffectedFiles():
1742 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1743 continue
1744 for linenum, line in f.ChangedContents():
1745 if bad_pattern.search(line) and not good_pattern.search(line):
1746 errors.append('%s:%d' % (f.LocalPath(), linenum))
1747
1748 if errors:
1749 return [output_api.PresubmitError(
1750 'These lines create anonymous variables that need to be named:',
1751 items=errors)]
1752 return []
1753
1754
Peter Kasting4844e46e2018-02-23 07:27:101755def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:531756 # Returns whether |template_str| is of the form <T, U...> for some types T
1757 # and U. Assumes that |template_str| is already in the form <...>.
1758 def HasMoreThanOneArg(template_str):
1759 # Level of <...> nesting.
1760 nesting = 0
1761 for c in template_str:
1762 if c == '<':
1763 nesting += 1
1764 elif c == '>':
1765 nesting -= 1
1766 elif c == ',' and nesting == 1:
1767 return True
1768 return False
1769
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491770 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:101771 sources = lambda affected_file: input_api.FilterSourceFile(
1772 affected_file,
1773 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1774 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491775 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:551776
1777 # Pattern to capture a single "<...>" block of template arguments. It can
1778 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
1779 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
1780 # latter would likely require counting that < and > match, which is not
1781 # expressible in regular languages. Should the need arise, one can introduce
1782 # limited counting (matching up to a total number of nesting depth), which
1783 # should cover all practical cases for already a low nesting limit.
1784 template_arg_pattern = (
1785 r'<[^>]*' # Opening block of <.
1786 r'>([^<]*>)?') # Closing block of >.
1787 # Prefix expressing that whatever follows is not already inside a <...>
1788 # block.
1789 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:101790 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:551791 not_inside_template_arg_pattern
1792 + r'\bstd::unique_ptr'
1793 + template_arg_pattern
1794 + r'\(\)')
1795
1796 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
1797 template_arg_no_array_pattern = (
1798 r'<[^>]*[^]]' # Opening block of <.
1799 r'>([^(<]*[^]]>)?') # Closing block of >.
1800 # Prefix saying that what follows is the start of an expression.
1801 start_of_expr_pattern = r'(=|\breturn|^)\s*'
1802 # Suffix saying that what follows are call parentheses with a non-empty list
1803 # of arguments.
1804 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:531805 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:551806 return_construct_pattern = input_api.re.compile(
1807 start_of_expr_pattern
1808 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:531809 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:551810 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:531811 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:551812 + nonempty_arg_list_pattern)
1813
Vaclav Brozek851d9602018-04-04 16:13:051814 problems_constructor = []
1815 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:101816 for f in input_api.AffectedSourceFiles(sources):
1817 for line_number, line in f.ChangedContents():
1818 # Disallow:
1819 # return std::unique_ptr<T>(foo);
1820 # bar = std::unique_ptr<T>(foo);
1821 # But allow:
1822 # return std::unique_ptr<T[]>(foo);
1823 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:531824 # And also allow cases when the second template argument is present. Those
1825 # cases cannot be handled by std::make_unique:
1826 # return std::unique_ptr<T, U>(foo);
1827 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:051828 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:531829 return_construct_result = return_construct_pattern.search(line)
1830 if return_construct_result and not HasMoreThanOneArg(
1831 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:051832 problems_constructor.append(
1833 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:101834 # Disallow:
1835 # std::unique_ptr<T>()
1836 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051837 problems_nullptr.append(
1838 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1839
1840 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:161841 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:051842 errors.append(output_api.PresubmitError(
1843 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161844 problems_nullptr))
1845 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:051846 errors.append(output_api.PresubmitError(
1847 'The following files use explicit std::unique_ptr constructor.'
1848 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161849 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:101850 return errors
1851
1852
[email protected]999261d2014-03-03 20:08:081853def _CheckUserActionUpdate(input_api, output_api):
1854 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521855 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081856 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521857 # If actions.xml is already included in the changelist, the PRESUBMIT
1858 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081859 return []
1860
[email protected]999261d2014-03-03 20:08:081861 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1862 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521863 current_actions = None
[email protected]999261d2014-03-03 20:08:081864 for f in input_api.AffectedFiles(file_filter=file_filter):
1865 for line_num, line in f.ChangedContents():
1866 match = input_api.re.search(action_re, line)
1867 if match:
[email protected]2f92dec2014-03-07 19:21:521868 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1869 # loaded only once.
1870 if not current_actions:
1871 with open('tools/metrics/actions/actions.xml') as actions_f:
1872 current_actions = actions_f.read()
1873 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081874 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521875 action = 'name="{0}"'.format(action_name)
1876 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081877 return [output_api.PresubmitPromptWarning(
1878 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521879 'tools/metrics/actions/actions.xml. Please run '
1880 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081881 % (f.LocalPath(), line_num, action_name))]
1882 return []
1883
1884
Daniel Cheng13ca61a882017-08-25 15:11:251885def _ImportJSONCommentEater(input_api):
1886 import sys
1887 sys.path = sys.path + [input_api.os_path.join(
1888 input_api.PresubmitLocalPath(),
1889 'tools', 'json_comment_eater')]
1890 import json_comment_eater
1891 return json_comment_eater
1892
1893
[email protected]99171a92014-06-03 08:44:471894def _GetJSONParseError(input_api, filename, eat_comments=True):
1895 try:
1896 contents = input_api.ReadFile(filename)
1897 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:251898 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:131899 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471900
1901 input_api.json.loads(contents)
1902 except ValueError as e:
1903 return e
1904 return None
1905
1906
1907def _GetIDLParseError(input_api, filename):
1908 try:
1909 contents = input_api.ReadFile(filename)
1910 idl_schema = input_api.os_path.join(
1911 input_api.PresubmitLocalPath(),
1912 'tools', 'json_schema_compiler', 'idl_schema.py')
1913 process = input_api.subprocess.Popen(
1914 [input_api.python_executable, idl_schema],
1915 stdin=input_api.subprocess.PIPE,
1916 stdout=input_api.subprocess.PIPE,
1917 stderr=input_api.subprocess.PIPE,
1918 universal_newlines=True)
1919 (_, error) = process.communicate(input=contents)
1920 return error or None
1921 except ValueError as e:
1922 return e
1923
1924
1925def _CheckParseErrors(input_api, output_api):
1926 """Check that IDL and JSON files do not contain syntax errors."""
1927 actions = {
1928 '.idl': _GetIDLParseError,
1929 '.json': _GetJSONParseError,
1930 }
[email protected]99171a92014-06-03 08:44:471931 # Most JSON files are preprocessed and support comments, but these do not.
1932 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:041933 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:471934 ]
1935 # Only run IDL checker on files in these directories.
1936 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:041937 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
1938 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:471939 ]
1940
1941 def get_action(affected_file):
1942 filename = affected_file.LocalPath()
1943 return actions.get(input_api.os_path.splitext(filename)[1])
1944
[email protected]99171a92014-06-03 08:44:471945 def FilterFile(affected_file):
1946 action = get_action(affected_file)
1947 if not action:
1948 return False
1949 path = affected_file.LocalPath()
1950
Sean Kau46e29bc2017-08-28 16:31:161951 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:471952 return False
1953
1954 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:161955 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:471956 return False
1957 return True
1958
1959 results = []
1960 for affected_file in input_api.AffectedFiles(
1961 file_filter=FilterFile, include_deletes=False):
1962 action = get_action(affected_file)
1963 kwargs = {}
1964 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:161965 _MatchesFile(input_api, json_no_comments_patterns,
1966 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:471967 kwargs['eat_comments'] = False
1968 parse_error = action(input_api,
1969 affected_file.AbsoluteLocalPath(),
1970 **kwargs)
1971 if parse_error:
1972 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1973 (affected_file.LocalPath(), parse_error)))
1974 return results
1975
1976
[email protected]760deea2013-12-10 19:33:491977def _CheckJavaStyle(input_api, output_api):
1978 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471979 import sys
[email protected]760deea2013-12-10 19:33:491980 original_sys_path = sys.path
1981 try:
1982 sys.path = sys.path + [input_api.os_path.join(
1983 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1984 import checkstyle
1985 finally:
1986 # Restore sys.path to what it was before.
1987 sys.path = original_sys_path
1988
1989 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091990 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511991 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491992
1993
Sean Kau46e29bc2017-08-28 16:31:161994def _MatchesFile(input_api, patterns, path):
1995 for pattern in patterns:
1996 if input_api.re.search(pattern, path):
1997 return True
1998 return False
1999
2000
Daniel Cheng7052cdf2017-11-21 19:23:292001def _GetOwnersFilesToCheckForIpcOwners(input_api):
2002 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172003
Daniel Cheng7052cdf2017-11-21 19:23:292004 Returns:
2005 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2006 contain to cover IPC-related files with noparent reviewer rules.
2007 """
2008 # Whether or not a file affects IPC is (mostly) determined by a simple list
2009 # of filename patterns.
dchenge07de812016-06-20 19:27:172010 file_patterns = [
palmerb19a0932017-01-24 04:00:312011 # Legacy IPC:
dchenge07de812016-06-20 19:27:172012 '*_messages.cc',
2013 '*_messages*.h',
2014 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312015 # Mojo IPC:
dchenge07de812016-06-20 19:27:172016 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472017 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172018 '*_struct_traits*.*',
2019 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312020 '*.typemap',
2021 # Android native IPC:
2022 '*.aidl',
2023 # Blink uses a different file naming convention:
2024 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472025 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172026 '*StructTraits*.*',
2027 '*TypeConverter*.*',
2028 ]
2029
scottmg7a6ed5ba2016-11-04 18:22:042030 # These third_party directories do not contain IPCs, but contain files
2031 # matching the above patterns, which trigger false positives.
2032 exclude_paths = [
2033 'third_party/crashpad/*',
Andres Medinae684cf42018-08-27 18:48:232034 'third_party/protobuf/benchmarks/python/*',
Daniel Chengebe635e2018-07-13 12:36:062035 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:292036 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:042037 ]
2038
dchenge07de812016-06-20 19:27:172039 # Dictionary mapping an OWNERS file path to Patterns.
2040 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2041 # rules ) to a PatternEntry.
2042 # PatternEntry is a dictionary with two keys:
2043 # - 'files': the files that are matched by this pattern
2044 # - 'rules': the per-file rules needed for this pattern
2045 # For example, if we expect OWNERS file to contain rules for *.mojom and
2046 # *_struct_traits*.*, Patterns might look like this:
2047 # {
2048 # '*.mojom': {
2049 # 'files': ...,
2050 # 'rules': [
2051 # 'per-file *.mojom=set noparent',
2052 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2053 # ],
2054 # },
2055 # '*_struct_traits*.*': {
2056 # 'files': ...,
2057 # 'rules': [
2058 # 'per-file *_struct_traits*.*=set noparent',
2059 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2060 # ],
2061 # },
2062 # }
2063 to_check = {}
2064
Daniel Cheng13ca61a882017-08-25 15:11:252065 def AddPatternToCheck(input_file, pattern):
2066 owners_file = input_api.os_path.join(
2067 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2068 if owners_file not in to_check:
2069 to_check[owners_file] = {}
2070 if pattern not in to_check[owners_file]:
2071 to_check[owners_file][pattern] = {
2072 'files': [],
2073 'rules': [
2074 'per-file %s=set noparent' % pattern,
2075 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2076 ]
2077 }
Vaclav Brozekd5de76a2018-03-17 07:57:502078 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252079
dchenge07de812016-06-20 19:27:172080 # Iterate through the affected files to see what we actually need to check
2081 # for. We should only nag patch authors about per-file rules if a file in that
2082 # directory would match that pattern. If a directory only contains *.mojom
2083 # files and no *_messages*.h files, we should only nag about rules for
2084 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252085 for f in input_api.AffectedFiles(include_deletes=False):
2086 # Manifest files don't have a strong naming convention. Instead, scan
Ken Rockot9f668262018-12-21 18:56:362087 # affected files for .json, .cc, and .h files which look like they contain
2088 # a manifest definition.
Sean Kau46e29bc2017-08-28 16:31:162089 if (f.LocalPath().endswith('.json') and
2090 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
2091 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:252092 json_comment_eater = _ImportJSONCommentEater(input_api)
2093 mostly_json_lines = '\n'.join(f.NewContents())
2094 # Comments aren't allowed in strict JSON, so filter them out.
2095 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:432096 try:
2097 json_content = input_api.json.loads(json_lines)
2098 except:
2099 # There's another PRESUBMIT check that already verifies that JSON files
2100 # are not invalid, so no need to emit another warning here.
2101 continue
Daniel Cheng13ca61a882017-08-25 15:11:252102 if 'interface_provider_specs' in json_content:
2103 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
Ken Rockot9f668262018-12-21 18:56:362104 else:
2105 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2106 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2107 if (manifest_pattern.search(f.LocalPath()) and not
2108 test_manifest_pattern.search(f.LocalPath())):
2109 # We expect all actual service manifest files to contain at least one
2110 # qualified reference to service_manager::Manifest.
2111 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2112 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172113 for pattern in file_patterns:
2114 if input_api.fnmatch.fnmatch(
2115 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042116 skip = False
2117 for exclude in exclude_paths:
2118 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2119 skip = True
2120 break
2121 if skip:
2122 continue
Daniel Cheng13ca61a882017-08-25 15:11:252123 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172124 break
2125
Daniel Cheng7052cdf2017-11-21 19:23:292126 return to_check
2127
2128
2129def _CheckIpcOwners(input_api, output_api):
2130 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2131 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2132
2133 if to_check:
2134 # If there are any OWNERS files to check, there are IPC-related changes in
2135 # this CL. Auto-CC the review list.
2136 output_api.AppendCC('[email protected]')
2137
2138 # Go through the OWNERS files to check, filtering out rules that are already
2139 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172140 for owners_file, patterns in to_check.iteritems():
2141 try:
2142 with file(owners_file) as f:
2143 lines = set(f.read().splitlines())
2144 for entry in patterns.itervalues():
2145 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2146 ]
2147 except IOError:
2148 # No OWNERS file, so all the rules are definitely missing.
2149 continue
2150
2151 # All the remaining lines weren't found in OWNERS files, so emit an error.
2152 errors = []
2153 for owners_file, patterns in to_check.iteritems():
2154 missing_lines = []
2155 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502156 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172157 missing_lines.extend(entry['rules'])
2158 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2159 if missing_lines:
2160 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052161 'Because of the presence of files:\n%s\n\n'
2162 '%s needs the following %d lines added:\n\n%s' %
2163 ('\n'.join(files), owners_file, len(missing_lines),
2164 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172165
2166 results = []
2167 if errors:
vabrf5ce3bf92016-07-11 14:52:412168 if input_api.is_committing:
2169 output = output_api.PresubmitError
2170 else:
2171 output = output_api.PresubmitPromptWarning
2172 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592173 'Found OWNERS files that need to be updated for IPC security ' +
2174 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172175 long_text='\n\n'.join(errors)))
2176
2177 return results
2178
2179
jbriance9e12f162016-11-25 07:57:502180def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312181 """Checks that added or removed lines in non third party affected
2182 header files do not lead to new useless class or struct forward
2183 declaration.
jbriance9e12f162016-11-25 07:57:502184 """
2185 results = []
2186 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2187 input_api.re.MULTILINE)
2188 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2189 input_api.re.MULTILINE)
2190 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312191 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192192 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:492193 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:312194 continue
2195
jbriance9e12f162016-11-25 07:57:502196 if not f.LocalPath().endswith('.h'):
2197 continue
2198
2199 contents = input_api.ReadFile(f)
2200 fwd_decls = input_api.re.findall(class_pattern, contents)
2201 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2202
2203 useless_fwd_decls = []
2204 for decl in fwd_decls:
2205 count = sum(1 for _ in input_api.re.finditer(
2206 r'\b%s\b' % input_api.re.escape(decl), contents))
2207 if count == 1:
2208 useless_fwd_decls.append(decl)
2209
2210 if not useless_fwd_decls:
2211 continue
2212
2213 for line in f.GenerateScmDiff().splitlines():
2214 if (line.startswith('-') and not line.startswith('--') or
2215 line.startswith('+') and not line.startswith('++')):
2216 for decl in useless_fwd_decls:
2217 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2218 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242219 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502220 (f.LocalPath(), decl)))
2221 useless_fwd_decls.remove(decl)
2222
2223 return results
2224
2225
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492226# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:292227def _CheckAndroidToastUsage(input_api, output_api):
2228 """Checks that code uses org.chromium.ui.widget.Toast instead of
2229 android.widget.Toast (Chromium Toast doesn't force hardware
2230 acceleration on low-end devices, saving memory).
2231 """
2232 toast_import_pattern = input_api.re.compile(
2233 r'^import android\.widget\.Toast;$')
2234
2235 errors = []
2236
2237 sources = lambda affected_file: input_api.FilterSourceFile(
2238 affected_file,
2239 black_list=(_EXCLUDED_PATHS +
2240 _TEST_CODE_EXCLUDED_PATHS +
2241 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042242 (r'^chromecast[\\/].*',
2243 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492244 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:292245
2246 for f in input_api.AffectedSourceFiles(sources):
2247 for line_num, line in f.ChangedContents():
2248 if toast_import_pattern.search(line):
2249 errors.append("%s:%d" % (f.LocalPath(), line_num))
2250
2251 results = []
2252
2253 if errors:
2254 results.append(output_api.PresubmitError(
2255 'android.widget.Toast usage is detected. Android toasts use hardware'
2256 ' acceleration, and can be\ncostly on low-end devices. Please use'
2257 ' org.chromium.ui.widget.Toast instead.\n'
2258 'Contact [email protected] if you have any questions.',
2259 errors))
2260
2261 return results
2262
2263
dgnaa68d5e2015-06-10 10:08:222264def _CheckAndroidCrLogUsage(input_api, output_api):
2265 """Checks that new logs using org.chromium.base.Log:
2266 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512267 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222268 """
pkotwicza1dd0b002016-05-16 14:41:042269
torne89540622017-03-24 19:41:302270 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042271 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302272 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:042273 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:302274 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:042275 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
2276 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:092277 # The customtabs_benchmark is a small app that does not depend on Chromium
2278 # java pieces.
Egor Paskoce145c42018-09-28 19:31:042279 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:042280 ]
2281
dgnaa68d5e2015-06-10 10:08:222282 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122283 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2284 class_in_base_pattern = input_api.re.compile(
2285 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2286 has_some_log_import_pattern = input_api.re.compile(
2287 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222288 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122289 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222290 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512291 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222292 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222293
Vincent Scheib16d7b272015-09-15 18:09:072294 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222295 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492296 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:042297 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122298
dgnaa68d5e2015-06-10 10:08:222299 tag_decl_errors = []
2300 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122301 tag_errors = []
dgn38736db2015-09-18 19:20:512302 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122303 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222304
2305 for f in input_api.AffectedSourceFiles(sources):
2306 file_content = input_api.ReadFile(f)
2307 has_modified_logs = False
2308
2309 # Per line checks
dgn87d9fb62015-06-12 09:15:122310 if (cr_log_import_pattern.search(file_content) or
2311 (class_in_base_pattern.search(file_content) and
2312 not has_some_log_import_pattern.search(file_content))):
2313 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222314 for line_num, line in f.ChangedContents():
2315
2316 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122317 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222318 if match:
2319 has_modified_logs = True
2320
2321 # Make sure it uses "TAG"
2322 if not match.group('tag') == 'TAG':
2323 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122324 else:
2325 # Report non cr Log function calls in changed lines
2326 for line_num, line in f.ChangedContents():
2327 if log_call_pattern.search(line):
2328 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222329
2330 # Per file checks
2331 if has_modified_logs:
2332 # Make sure the tag is using the "cr" prefix and is not too long
2333 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512334 tag_name = match.group('name') if match else None
2335 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222336 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512337 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222338 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512339 elif '.' in tag_name:
2340 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222341
2342 results = []
2343 if tag_decl_errors:
2344 results.append(output_api.PresubmitPromptWarning(
2345 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512346 '"private static final String TAG = "<package tag>".\n'
2347 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222348 tag_decl_errors))
2349
2350 if tag_length_errors:
2351 results.append(output_api.PresubmitError(
2352 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512353 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222354 tag_length_errors))
2355
2356 if tag_errors:
2357 results.append(output_api.PresubmitPromptWarning(
2358 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2359 tag_errors))
2360
dgn87d9fb62015-06-12 09:15:122361 if util_log_errors:
dgn4401aa52015-04-29 16:26:172362 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122363 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2364 util_log_errors))
2365
dgn38736db2015-09-18 19:20:512366 if tag_with_dot_errors:
2367 results.append(output_api.PresubmitPromptWarning(
2368 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2369 tag_with_dot_errors))
2370
dgn4401aa52015-04-29 16:26:172371 return results
2372
2373
Yoland Yanb92fa522017-08-28 17:37:062374def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2375 """Checks that junit.framework.* is no longer used."""
2376 deprecated_junit_framework_pattern = input_api.re.compile(
2377 r'^import junit\.framework\..*;',
2378 input_api.re.MULTILINE)
2379 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492380 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062381 errors = []
2382 for f in input_api.AffectedFiles(sources):
2383 for line_num, line in f.ChangedContents():
2384 if deprecated_junit_framework_pattern.search(line):
2385 errors.append("%s:%d" % (f.LocalPath(), line_num))
2386
2387 results = []
2388 if errors:
2389 results.append(output_api.PresubmitError(
2390 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2391 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2392 ' if you have any question.', errors))
2393 return results
2394
2395
2396def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2397 """Checks that if new Java test classes have inheritance.
2398 Either the new test class is JUnit3 test or it is a JUnit4 test class
2399 with a base class, either case is undesirable.
2400 """
2401 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2402
2403 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492404 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062405 errors = []
2406 for f in input_api.AffectedFiles(sources):
2407 if not f.OldContents():
2408 class_declaration_start_flag = False
2409 for line_num, line in f.ChangedContents():
2410 if class_declaration_pattern.search(line):
2411 class_declaration_start_flag = True
2412 if class_declaration_start_flag and ' extends ' in line:
2413 errors.append('%s:%d' % (f.LocalPath(), line_num))
2414 if '{' in line:
2415 class_declaration_start_flag = False
2416
2417 results = []
2418 if errors:
2419 results.append(output_api.PresubmitPromptWarning(
2420 'The newly created files include Test classes that inherits from base'
2421 ' class. Please do not use inheritance in JUnit4 tests or add new'
2422 ' JUnit3 tests. Contact [email protected] if you have any'
2423 ' questions.', errors))
2424 return results
2425
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202426
yolandyan45001472016-12-21 21:12:422427def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2428 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2429 deprecated_annotation_import_pattern = input_api.re.compile(
2430 r'^import android\.test\.suitebuilder\.annotation\..*;',
2431 input_api.re.MULTILINE)
2432 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492433 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:422434 errors = []
2435 for f in input_api.AffectedFiles(sources):
2436 for line_num, line in f.ChangedContents():
2437 if deprecated_annotation_import_pattern.search(line):
2438 errors.append("%s:%d" % (f.LocalPath(), line_num))
2439
2440 results = []
2441 if errors:
2442 results.append(output_api.PresubmitError(
2443 'Annotations in android.test.suitebuilder.annotation have been'
2444 ' deprecated since API level 24. Please use android.support.test.filters'
2445 ' from //third_party/android_support_test_runner:runner_java instead.'
2446 ' Contact [email protected] if you have any questions.', errors))
2447 return results
2448
2449
agrieve7b6479d82015-10-07 14:24:222450def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2451 """Checks if MDPI assets are placed in a correct directory."""
2452 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2453 ('/res/drawable/' in f.LocalPath() or
2454 '/res/drawable-ldrtl/' in f.LocalPath()))
2455 errors = []
2456 for f in input_api.AffectedFiles(include_deletes=False,
2457 file_filter=file_filter):
2458 errors.append(' %s' % f.LocalPath())
2459
2460 results = []
2461 if errors:
2462 results.append(output_api.PresubmitError(
2463 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2464 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2465 '/res/drawable-ldrtl/.\n'
2466 'Contact [email protected] if you have questions.', errors))
2467 return results
2468
2469
Nate Fischer535972b2017-09-16 01:06:182470def _CheckAndroidWebkitImports(input_api, output_api):
2471 """Checks that code uses org.chromium.base.Callback instead of
2472 android.widget.ValueCallback except in the WebView glue layer.
2473 """
2474 valuecallback_import_pattern = input_api.re.compile(
2475 r'^import android\.webkit\.ValueCallback;$')
2476
2477 errors = []
2478
2479 sources = lambda affected_file: input_api.FilterSourceFile(
2480 affected_file,
2481 black_list=(_EXCLUDED_PATHS +
2482 _TEST_CODE_EXCLUDED_PATHS +
2483 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042484 (r'^android_webview[\\/]glue[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492485 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:182486
2487 for f in input_api.AffectedSourceFiles(sources):
2488 for line_num, line in f.ChangedContents():
2489 if valuecallback_import_pattern.search(line):
2490 errors.append("%s:%d" % (f.LocalPath(), line_num))
2491
2492 results = []
2493
2494 if errors:
2495 results.append(output_api.PresubmitError(
2496 'android.webkit.ValueCallback usage is detected outside of the glue'
2497 ' layer. To stay compatible with the support library, android.webkit.*'
2498 ' classes should only be used inside the glue layer and'
2499 ' org.chromium.base.Callback should be used instead.',
2500 errors))
2501
2502 return results
2503
2504
Becky Zhou7c69b50992018-12-10 19:37:572505def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
2506 """Checks Android XML styles """
2507 import sys
2508 original_sys_path = sys.path
2509 try:
2510 sys.path = sys.path + [input_api.os_path.join(
2511 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
2512 import checkxmlstyle
2513 finally:
2514 # Restore sys.path to what it was before.
2515 sys.path = original_sys_path
2516
2517 if is_check_on_upload:
2518 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
2519 else:
2520 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
2521
2522
agrievef32bcc72016-04-04 14:57:402523class PydepsChecker(object):
2524 def __init__(self, input_api, pydeps_files):
2525 self._file_cache = {}
2526 self._input_api = input_api
2527 self._pydeps_files = pydeps_files
2528
2529 def _LoadFile(self, path):
2530 """Returns the list of paths within a .pydeps file relative to //."""
2531 if path not in self._file_cache:
2532 with open(path) as f:
2533 self._file_cache[path] = f.read()
2534 return self._file_cache[path]
2535
2536 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2537 """Returns an interable of paths within the .pydep, relativized to //."""
2538 os_path = self._input_api.os_path
2539 pydeps_dir = os_path.dirname(pydeps_path)
2540 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2541 if not l.startswith('*'))
2542 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2543
2544 def _CreateFilesToPydepsMap(self):
2545 """Returns a map of local_path -> list_of_pydeps."""
2546 ret = {}
2547 for pydep_local_path in self._pydeps_files:
2548 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2549 ret.setdefault(path, []).append(pydep_local_path)
2550 return ret
2551
2552 def ComputeAffectedPydeps(self):
2553 """Returns an iterable of .pydeps files that might need regenerating."""
2554 affected_pydeps = set()
2555 file_to_pydeps_map = None
2556 for f in self._input_api.AffectedFiles(include_deletes=True):
2557 local_path = f.LocalPath()
2558 if local_path == 'DEPS':
2559 return self._pydeps_files
2560 elif local_path.endswith('.pydeps'):
2561 if local_path in self._pydeps_files:
2562 affected_pydeps.add(local_path)
2563 elif local_path.endswith('.py'):
2564 if file_to_pydeps_map is None:
2565 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2566 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2567 return affected_pydeps
2568
2569 def DetermineIfStale(self, pydeps_path):
2570 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412571 import difflib
John Budorick47ca3fe2018-02-10 00:53:102572 import os
2573
agrievef32bcc72016-04-04 14:57:402574 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2575 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102576 env = dict(os.environ)
2577 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402578 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102579 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412580 old_contents = old_pydeps_data[2:]
2581 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402582 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412583 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402584
2585
2586def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2587 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402588 # This check is for Python dependency lists (.pydeps files), and involves
2589 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2590 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282591 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002592 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022593 # TODO(agrieve): Update when there's a better way to detect
2594 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402595 is_android = input_api.os_path.exists('third_party/android_tools')
2596 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2597 results = []
2598 # First, check for new / deleted .pydeps.
2599 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032600 # Check whether we are running the presubmit check for a file in src.
2601 # f.LocalPath is relative to repo (src, or internal repo).
2602 # os_path.exists is relative to src repo.
2603 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2604 # to src and we can conclude that the pydeps is in src.
2605 if input_api.os_path.exists(f.LocalPath()):
2606 if f.LocalPath().endswith('.pydeps'):
2607 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2608 results.append(output_api.PresubmitError(
2609 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2610 'remove %s' % f.LocalPath()))
2611 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2612 results.append(output_api.PresubmitError(
2613 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2614 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402615
2616 if results:
2617 return results
2618
2619 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2620
2621 for pydep_path in checker.ComputeAffectedPydeps():
2622 try:
phajdan.jr0d9878552016-11-04 10:49:412623 result = checker.DetermineIfStale(pydep_path)
2624 if result:
2625 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402626 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412627 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2628 'To regenerate, run:\n\n %s' %
2629 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402630 except input_api.subprocess.CalledProcessError as error:
2631 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2632 long_text=error.output)]
2633
2634 return results
2635
2636
glidere61efad2015-02-18 17:39:432637def _CheckSingletonInHeaders(input_api, output_api):
2638 """Checks to make sure no header files have |Singleton<|."""
2639 def FileFilter(affected_file):
2640 # It's ok for base/memory/singleton.h to have |Singleton<|.
2641 black_list = (_EXCLUDED_PATHS +
2642 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042643 (r"^base[\\/]memory[\\/]singleton\.h$",
2644 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:472645 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432646 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2647
sergeyu34d21222015-09-16 00:11:442648 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432649 files = []
2650 for f in input_api.AffectedSourceFiles(FileFilter):
2651 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2652 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2653 contents = input_api.ReadFile(f)
2654 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242655 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432656 pattern.search(line)):
2657 files.append(f)
2658 break
2659
2660 if files:
yolandyandaabc6d2016-04-18 18:29:392661 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442662 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432663 'Please move them to an appropriate source file so that the ' +
2664 'template gets instantiated in a single compilation unit.',
2665 files) ]
2666 return []
2667
2668
[email protected]fd20b902014-05-09 02:14:532669_DEPRECATED_CSS = [
2670 # Values
2671 ( "-webkit-box", "flex" ),
2672 ( "-webkit-inline-box", "inline-flex" ),
2673 ( "-webkit-flex", "flex" ),
2674 ( "-webkit-inline-flex", "inline-flex" ),
2675 ( "-webkit-min-content", "min-content" ),
2676 ( "-webkit-max-content", "max-content" ),
2677
2678 # Properties
2679 ( "-webkit-background-clip", "background-clip" ),
2680 ( "-webkit-background-origin", "background-origin" ),
2681 ( "-webkit-background-size", "background-size" ),
2682 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442683 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532684
2685 # Functions
2686 ( "-webkit-gradient", "gradient" ),
2687 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2688 ( "-webkit-linear-gradient", "linear-gradient" ),
2689 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2690 ( "-webkit-radial-gradient", "radial-gradient" ),
2691 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2692]
2693
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202694
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492695# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242696def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532697 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252698 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342699 documentation and iOS CSS for dom distiller
2700 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252701 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532702 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492703 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:252704 black_list = (_EXCLUDED_PATHS +
2705 _TEST_CODE_EXCLUDED_PATHS +
2706 input_api.DEFAULT_BLACK_LIST +
2707 (r"^chrome/common/extensions/docs",
2708 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342709 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442710 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252711 r"^native_client_sdk"))
2712 file_filter = lambda f: input_api.FilterSourceFile(
2713 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532714 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2715 for line_num, line in fpath.ChangedContents():
2716 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022717 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532718 results.append(output_api.PresubmitError(
2719 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2720 (fpath.LocalPath(), line_num, deprecated_value, value)))
2721 return results
2722
mohan.reddyf21db962014-10-16 12:26:472723
dbeam070cfe62014-10-22 06:44:022724_DEPRECATED_JS = [
2725 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2726 ( "__defineGetter__", "Object.defineProperty" ),
2727 ( "__defineSetter__", "Object.defineProperty" ),
2728]
2729
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202730
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492731# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242732def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022733 """Make sure that we don't use deprecated JS in Chrome code."""
2734 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492735 file_inclusion_pattern = [r".+\.js$"] # TODO(dbeam): .html?
dbeam070cfe62014-10-22 06:44:022736 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2737 input_api.DEFAULT_BLACK_LIST)
2738 file_filter = lambda f: input_api.FilterSourceFile(
2739 f, white_list=file_inclusion_pattern, black_list=black_list)
2740 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2741 for lnum, line in fpath.ChangedContents():
2742 for (deprecated, replacement) in _DEPRECATED_JS:
2743 if deprecated in line:
2744 results.append(output_api.PresubmitError(
2745 "%s:%d: Use of deprecated JS %s, use %s instead" %
2746 (fpath.LocalPath(), lnum, deprecated, replacement)))
2747 return results
2748
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202749
rlanday6802cf632017-05-30 17:48:362750def _CheckForRelativeIncludes(input_api, output_api):
2751 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2752 import sys
2753 original_sys_path = sys.path
2754 try:
2755 sys.path = sys.path + [input_api.os_path.join(
2756 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2757 from cpp_checker import CppChecker
2758 finally:
2759 # Restore sys.path to what it was before.
2760 sys.path = original_sys_path
2761
2762 bad_files = {}
2763 for f in input_api.AffectedFiles(include_deletes=False):
2764 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:492765 not f.LocalPath().startswith('third_party/blink') and
2766 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:362767 continue
2768
2769 if not CppChecker.IsCppFile(f.LocalPath()):
2770 continue
2771
Vaclav Brozekd5de76a2018-03-17 07:57:502772 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362773 if "#include" in line and "../" in line]
2774 if not relative_includes:
2775 continue
2776 bad_files[f.LocalPath()] = relative_includes
2777
2778 if not bad_files:
2779 return []
2780
2781 error_descriptions = []
2782 for file_path, bad_lines in bad_files.iteritems():
2783 error_description = file_path
2784 for line in bad_lines:
2785 error_description += '\n ' + line
2786 error_descriptions.append(error_description)
2787
2788 results = []
2789 results.append(output_api.PresubmitError(
2790 'You added one or more relative #include paths (including "../").\n'
2791 'These shouldn\'t be used because they can be used to include headers\n'
2792 'from code that\'s not correctly specified as a dependency in the\n'
2793 'relevant BUILD.gn file(s).',
2794 error_descriptions))
2795
2796 return results
2797
Takeshi Yoshinoe387aa32017-08-02 13:16:132798
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202799def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2800 if not isinstance(key, ast.Str):
2801 return 'Key at line %d must be a string literal' % key.lineno
2802 if not isinstance(value, ast.Dict):
2803 return 'Value at line %d must be a dict' % value.lineno
2804 if len(value.keys) != 1:
2805 return 'Dict at line %d must have single entry' % value.lineno
2806 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2807 return (
2808 'Entry at line %d must have a string literal \'filepath\' as key' %
2809 value.lineno)
2810 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132811
Takeshi Yoshinoe387aa32017-08-02 13:16:132812
Sergey Ulanov4af16052018-11-08 02:41:462813def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202814 if not isinstance(key, ast.Str):
2815 return 'Key at line %d must be a string literal' % key.lineno
2816 if not isinstance(value, ast.List):
2817 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:462818 for element in value.elts:
2819 if not isinstance(element, ast.Str):
2820 return 'Watchlist elements on line %d is not a string' % key.lineno
2821 if not email_regex.match(element.s):
2822 return ('Watchlist element on line %d doesn\'t look like a valid ' +
2823 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202824 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132825
Takeshi Yoshinoe387aa32017-08-02 13:16:132826
Sergey Ulanov4af16052018-11-08 02:41:462827def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202828 mismatch_template = (
2829 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2830 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132831
Sergey Ulanov4af16052018-11-08 02:41:462832 email_regex = input_api.re.compile(
2833 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
2834
2835 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202836 i = 0
2837 last_key = ''
2838 while True:
2839 if i >= len(wd_dict.keys):
2840 if i >= len(w_dict.keys):
2841 return None
2842 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2843 elif i >= len(w_dict.keys):
2844 return (
2845 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132846
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202847 wd_key = wd_dict.keys[i]
2848 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132849
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202850 result = _CheckWatchlistDefinitionsEntrySyntax(
2851 wd_key, wd_dict.values[i], ast)
2852 if result is not None:
2853 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132854
Sergey Ulanov4af16052018-11-08 02:41:462855 result = _CheckWatchlistsEntrySyntax(
2856 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202857 if result is not None:
2858 return 'Bad entry in WATCHLISTS dict: %s' % result
2859
2860 if wd_key.s != w_key.s:
2861 return mismatch_template % (
2862 '%s at line %d' % (wd_key.s, wd_key.lineno),
2863 '%s at line %d' % (w_key.s, w_key.lineno))
2864
2865 if wd_key.s < last_key:
2866 return (
2867 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2868 (wd_key.lineno, w_key.lineno))
2869 last_key = wd_key.s
2870
2871 i = i + 1
2872
2873
Sergey Ulanov4af16052018-11-08 02:41:462874def _CheckWATCHLISTSSyntax(expression, input_api):
2875 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202876 if not isinstance(expression, ast.Expression):
2877 return 'WATCHLISTS file must contain a valid expression'
2878 dictionary = expression.body
2879 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2880 return 'WATCHLISTS file must have single dict with exactly two entries'
2881
2882 first_key = dictionary.keys[0]
2883 first_value = dictionary.values[0]
2884 second_key = dictionary.keys[1]
2885 second_value = dictionary.values[1]
2886
2887 if (not isinstance(first_key, ast.Str) or
2888 first_key.s != 'WATCHLIST_DEFINITIONS' or
2889 not isinstance(first_value, ast.Dict)):
2890 return (
2891 'The first entry of the dict in WATCHLISTS file must be '
2892 'WATCHLIST_DEFINITIONS dict')
2893
2894 if (not isinstance(second_key, ast.Str) or
2895 second_key.s != 'WATCHLISTS' or
2896 not isinstance(second_value, ast.Dict)):
2897 return (
2898 'The second entry of the dict in WATCHLISTS file must be '
2899 'WATCHLISTS dict')
2900
Sergey Ulanov4af16052018-11-08 02:41:462901 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:132902
2903
2904def _CheckWATCHLISTS(input_api, output_api):
2905 for f in input_api.AffectedFiles(include_deletes=False):
2906 if f.LocalPath() == 'WATCHLISTS':
2907 contents = input_api.ReadFile(f, 'r')
2908
2909 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202910 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132911 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202912 # Get an AST tree for it and scan the tree for detailed style checking.
2913 expression = input_api.ast.parse(
2914 contents, filename='WATCHLISTS', mode='eval')
2915 except ValueError as e:
2916 return [output_api.PresubmitError(
2917 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2918 except SyntaxError as e:
2919 return [output_api.PresubmitError(
2920 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2921 except TypeError as e:
2922 return [output_api.PresubmitError(
2923 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132924
Sergey Ulanov4af16052018-11-08 02:41:462925 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202926 if result is not None:
2927 return [output_api.PresubmitError(result)]
2928 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132929
2930 return []
2931
2932
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192933def _CheckNewHeaderWithoutGnChange(input_api, output_api):
2934 """Checks that newly added header files have corresponding GN changes.
2935 Note that this is only a heuristic. To be precise, run script:
2936 build/check_gn_headers.py.
2937 """
2938
2939 def headers(f):
2940 return input_api.FilterSourceFile(
2941 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
2942
2943 new_headers = []
2944 for f in input_api.AffectedSourceFiles(headers):
2945 if f.Action() != 'A':
2946 continue
2947 new_headers.append(f.LocalPath())
2948
2949 def gn_files(f):
2950 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
2951
2952 all_gn_changed_contents = ''
2953 for f in input_api.AffectedSourceFiles(gn_files):
2954 for _, line in f.ChangedContents():
2955 all_gn_changed_contents += line
2956
2957 problems = []
2958 for header in new_headers:
2959 basename = input_api.os_path.basename(header)
2960 if basename not in all_gn_changed_contents:
2961 problems.append(header)
2962
2963 if problems:
2964 return [output_api.PresubmitPromptWarning(
2965 'Missing GN changes for new header files', items=sorted(problems),
2966 long_text='Please double check whether newly added header files need '
2967 'corresponding changes in gn or gni files.\nThis checking is only a '
2968 'heuristic. Run build/check_gn_headers.py to be precise.\n'
2969 'Read https://crbug.com/661774 for more info.')]
2970 return []
2971
2972
Michael Giuffridad3bc8672018-10-25 22:48:022973def _CheckCorrectProductNameInMessages(input_api, output_api):
2974 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
2975
2976 This assumes we won't intentionally reference one product from the other
2977 product.
2978 """
2979 all_problems = []
2980 test_cases = [{
2981 "filename_postfix": "google_chrome_strings.grd",
2982 "correct_name": "Chrome",
2983 "incorrect_name": "Chromium",
2984 }, {
2985 "filename_postfix": "chromium_strings.grd",
2986 "correct_name": "Chromium",
2987 "incorrect_name": "Chrome",
2988 }]
2989
2990 for test_case in test_cases:
2991 problems = []
2992 filename_filter = lambda x: x.LocalPath().endswith(
2993 test_case["filename_postfix"])
2994
2995 # Check each new line. Can yield false positives in multiline comments, but
2996 # easier than trying to parse the XML because messages can have nested
2997 # children, and associating message elements with affected lines is hard.
2998 for f in input_api.AffectedSourceFiles(filename_filter):
2999 for line_num, line in f.ChangedContents():
3000 if "<message" in line or "<!--" in line or "-->" in line:
3001 continue
3002 if test_case["incorrect_name"] in line:
3003 problems.append(
3004 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
3005
3006 if problems:
3007 message = (
3008 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
3009 % (test_case["correct_name"], test_case["correct_name"],
3010 test_case["incorrect_name"]))
3011 all_problems.append(
3012 output_api.PresubmitPromptWarning(message, items=problems))
3013
3014 return all_problems
3015
3016
dgnaa68d5e2015-06-10 10:08:223017def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:573018 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:223019 results = []
dgnaa68d5e2015-06-10 10:08:223020 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:223021 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:293022 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:063023 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
3024 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:423025 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:183026 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573027 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
3028 return results
3029
3030def _AndroidSpecificOnCommitChecks(input_api, output_api):
3031 """Groups commit checks that target android code."""
3032 results = []
3033 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:223034 return results
3035
3036
[email protected]22c9bd72011-03-27 16:47:393037def _CommonChecks(input_api, output_api):
3038 """Checks common to both upload and commit."""
3039 results = []
3040 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:383041 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:543042 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:083043
3044 author = input_api.change.author_email
3045 if author and author not in _KNOWN_ROBOTS:
3046 results.extend(
3047 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
3048
[email protected]55459852011-08-10 15:17:193049 results.extend(
[email protected]760deea2013-12-10 19:33:493050 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:233051 results.extend(
3052 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:543053 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:183054 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:343055 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:523056 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:223057 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:443058 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:593059 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:063060 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:123061 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:183062 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:223063 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:303064 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:493065 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:033066 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:493067 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:443068 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:273069 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:073070 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:543071 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:443072 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:393073 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:553074 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:043075 results.extend(
3076 input_api.canned_checks.CheckChangeHasNoTabs(
3077 input_api,
3078 output_api,
3079 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:403080 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:163081 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:083082 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:243083 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
3084 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:473085 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:043086 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:053087 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:143088 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:233089 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:433090 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:403091 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:153092 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:173093 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:503094 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:363095 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:133096 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:433097 results.extend(input_api.RunTests(
3098 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143099 results.extend(_CheckTranslationScreenshots(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:023100 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:243101
Vaclav Brozekcdc7defb2018-03-20 09:54:353102 for f in input_api.AffectedFiles():
3103 path, name = input_api.os_path.split(f.LocalPath())
3104 if name == 'PRESUBMIT.py':
3105 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:003106 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
3107 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:073108 # The PRESUBMIT.py file (and the directory containing it) might
3109 # have been affected by being moved or removed, so only try to
3110 # run the tests if they still exist.
3111 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
3112 input_api, output_api, full_path,
3113 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:393114 return results
[email protected]1f7b4172010-01-28 01:17:343115
[email protected]b337cb5b2011-01-23 21:24:053116
[email protected]b8079ae4a2012-12-05 19:56:493117def _CheckPatchFiles(input_api, output_api):
3118 problems = [f.LocalPath() for f in input_api.AffectedFiles()
3119 if f.LocalPath().endswith(('.orig', '.rej'))]
3120 if problems:
3121 return [output_api.PresubmitError(
3122 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:033123 else:
3124 return []
[email protected]b8079ae4a2012-12-05 19:56:493125
3126
Kent Tamura5a8755d2017-06-29 23:37:073127def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:213128 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
3129 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
3130 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:073131 include_re = input_api.re.compile(
3132 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
3133 extension_re = input_api.re.compile(r'\.[a-z]+$')
3134 errors = []
3135 for f in input_api.AffectedFiles():
3136 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
3137 continue
3138 found_line_number = None
3139 found_macro = None
3140 for line_num, line in f.ChangedContents():
3141 match = macro_re.search(line)
3142 if match:
3143 found_line_number = line_num
3144 found_macro = match.group(2)
3145 break
3146 if not found_line_number:
3147 continue
3148
3149 found_include = False
3150 for line in f.NewContents():
3151 if include_re.search(line):
3152 found_include = True
3153 break
3154 if found_include:
3155 continue
3156
3157 if not f.LocalPath().endswith('.h'):
3158 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
3159 try:
3160 content = input_api.ReadFile(primary_header_path, 'r')
3161 if include_re.search(content):
3162 continue
3163 except IOError:
3164 pass
3165 errors.append('%s:%d %s macro is used without including build/'
3166 'build_config.h.'
3167 % (f.LocalPath(), found_line_number, found_macro))
3168 if errors:
3169 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
3170 return []
3171
3172
[email protected]b00342e7f2013-03-26 16:21:543173def _DidYouMeanOSMacro(bad_macro):
3174 try:
3175 return {'A': 'OS_ANDROID',
3176 'B': 'OS_BSD',
3177 'C': 'OS_CHROMEOS',
3178 'F': 'OS_FREEBSD',
3179 'L': 'OS_LINUX',
3180 'M': 'OS_MACOSX',
3181 'N': 'OS_NACL',
3182 'O': 'OS_OPENBSD',
3183 'P': 'OS_POSIX',
3184 'S': 'OS_SOLARIS',
3185 'W': 'OS_WIN'}[bad_macro[3].upper()]
3186 except KeyError:
3187 return ''
3188
3189
3190def _CheckForInvalidOSMacrosInFile(input_api, f):
3191 """Check for sensible looking, totally invalid OS macros."""
3192 preprocessor_statement = input_api.re.compile(r'^\s*#')
3193 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
3194 results = []
3195 for lnum, line in f.ChangedContents():
3196 if preprocessor_statement.search(line):
3197 for match in os_macro.finditer(line):
3198 if not match.group(1) in _VALID_OS_MACROS:
3199 good = _DidYouMeanOSMacro(match.group(1))
3200 did_you_mean = ' (did you mean %s?)' % good if good else ''
3201 results.append(' %s:%d %s%s' % (f.LocalPath(),
3202 lnum,
3203 match.group(1),
3204 did_you_mean))
3205 return results
3206
3207
3208def _CheckForInvalidOSMacros(input_api, output_api):
3209 """Check all affected files for invalid OS macros."""
3210 bad_macros = []
tzik3f295992018-12-04 20:32:233211 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:473212 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:543213 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
3214
3215 if not bad_macros:
3216 return []
3217
3218 return [output_api.PresubmitError(
3219 'Possibly invalid OS macro[s] found. Please fix your code\n'
3220 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
3221
lliabraa35bab3932014-10-01 12:16:443222
3223def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
3224 """Check all affected files for invalid "if defined" macros."""
3225 ALWAYS_DEFINED_MACROS = (
3226 "TARGET_CPU_PPC",
3227 "TARGET_CPU_PPC64",
3228 "TARGET_CPU_68K",
3229 "TARGET_CPU_X86",
3230 "TARGET_CPU_ARM",
3231 "TARGET_CPU_MIPS",
3232 "TARGET_CPU_SPARC",
3233 "TARGET_CPU_ALPHA",
3234 "TARGET_IPHONE_SIMULATOR",
3235 "TARGET_OS_EMBEDDED",
3236 "TARGET_OS_IPHONE",
3237 "TARGET_OS_MAC",
3238 "TARGET_OS_UNIX",
3239 "TARGET_OS_WIN32",
3240 )
3241 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
3242 results = []
3243 for lnum, line in f.ChangedContents():
3244 for match in ifdef_macro.finditer(line):
3245 if match.group(1) in ALWAYS_DEFINED_MACROS:
3246 always_defined = ' %s is always defined. ' % match.group(1)
3247 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
3248 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
3249 lnum,
3250 always_defined,
3251 did_you_mean))
3252 return results
3253
3254
3255def _CheckForInvalidIfDefinedMacros(input_api, output_api):
3256 """Check all affected files for invalid "if defined" macros."""
3257 bad_macros = []
3258 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:213259 if f.LocalPath().startswith('third_party/sqlite/'):
3260 continue
lliabraa35bab3932014-10-01 12:16:443261 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3262 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3263
3264 if not bad_macros:
3265 return []
3266
3267 return [output_api.PresubmitError(
3268 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3269 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3270 bad_macros)]
3271
3272
mlamouria82272622014-09-16 18:45:043273def _CheckForIPCRules(input_api, output_api):
3274 """Check for same IPC rules described in
3275 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3276 """
3277 base_pattern = r'IPC_ENUM_TRAITS\('
3278 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3279 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3280
3281 problems = []
3282 for f in input_api.AffectedSourceFiles(None):
3283 local_path = f.LocalPath()
3284 if not local_path.endswith('.h'):
3285 continue
3286 for line_number, line in f.ChangedContents():
3287 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3288 problems.append(
3289 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3290
3291 if problems:
3292 return [output_api.PresubmitPromptWarning(
3293 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
3294 else:
3295 return []
3296
[email protected]b00342e7f2013-03-26 16:21:543297
Stephen Martinis97a394142018-06-07 23:06:053298def _CheckForLongPathnames(input_api, output_api):
3299 """Check to make sure no files being submitted have long paths.
3300 This causes issues on Windows.
3301 """
3302 problems = []
3303 for f in input_api.AffectedSourceFiles(None):
3304 local_path = f.LocalPath()
3305 # Windows has a path limit of 260 characters. Limit path length to 200 so
3306 # that we have some extra for the prefix on dev machines and the bots.
3307 if len(local_path) > 200:
3308 problems.append(local_path)
3309
3310 if problems:
3311 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
3312 else:
3313 return []
3314
3315
Daniel Bratell8ba52722018-03-02 16:06:143316def _CheckForIncludeGuards(input_api, output_api):
3317 """Check that header files have proper guards against multiple inclusion.
3318 If a file should not have such guards (and it probably should) then it
3319 should include the string "no-include-guard-because-multiply-included".
3320 """
Daniel Bratell6a75baef62018-06-04 10:04:453321 def is_chromium_header_file(f):
3322 # We only check header files under the control of the Chromium
3323 # project. That is, those outside third_party apart from
3324 # third_party/blink.
3325 file_with_path = input_api.os_path.normpath(f.LocalPath())
3326 return (file_with_path.endswith('.h') and
3327 (not file_with_path.startswith('third_party') or
3328 file_with_path.startswith(
3329 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:143330
3331 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:343332 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:143333
3334 errors = []
3335
Daniel Bratell6a75baef62018-06-04 10:04:453336 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:143337 guard_name = None
3338 guard_line_number = None
3339 seen_guard_end = False
3340
3341 file_with_path = input_api.os_path.normpath(f.LocalPath())
3342 base_file_name = input_api.os_path.splitext(
3343 input_api.os_path.basename(file_with_path))[0]
3344 upper_base_file_name = base_file_name.upper()
3345
3346 expected_guard = replace_special_with_underscore(
3347 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:143348
3349 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:573350 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
3351 # are too many (1000+) files with slight deviations from the
3352 # coding style. The most important part is that the include guard
3353 # is there, and that it's unique, not the name so this check is
3354 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:143355 #
3356 # As code becomes more uniform, this could be made stricter.
3357
3358 guard_name_pattern_list = [
3359 # Anything with the right suffix (maybe with an extra _).
3360 r'\w+_H__?',
3361
Daniel Bratell39b5b062018-05-16 18:09:573362 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:143363 r'\w+_h',
3364
3365 # Anything including the uppercase name of the file.
3366 r'\w*' + input_api.re.escape(replace_special_with_underscore(
3367 upper_base_file_name)) + r'\w*',
3368 ]
3369 guard_name_pattern = '|'.join(guard_name_pattern_list)
3370 guard_pattern = input_api.re.compile(
3371 r'#ifndef\s+(' + guard_name_pattern + ')')
3372
3373 for line_number, line in enumerate(f.NewContents()):
3374 if 'no-include-guard-because-multiply-included' in line:
3375 guard_name = 'DUMMY' # To not trigger check outside the loop.
3376 break
3377
3378 if guard_name is None:
3379 match = guard_pattern.match(line)
3380 if match:
3381 guard_name = match.group(1)
3382 guard_line_number = line_number
3383
Daniel Bratell39b5b062018-05-16 18:09:573384 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:453385 # don't match the chromium style guide, but new files should
3386 # get it right.
3387 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:573388 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:143389 errors.append(output_api.PresubmitPromptWarning(
3390 'Header using the wrong include guard name %s' % guard_name,
3391 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:573392 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:143393 else:
3394 # The line after #ifndef should have a #define of the same name.
3395 if line_number == guard_line_number + 1:
3396 expected_line = '#define %s' % guard_name
3397 if line != expected_line:
3398 errors.append(output_api.PresubmitPromptWarning(
3399 'Missing "%s" for include guard' % expected_line,
3400 ['%s:%d' % (f.LocalPath(), line_number + 1)],
3401 'Expected: %r\nGot: %r' % (expected_line, line)))
3402
3403 if not seen_guard_end and line == '#endif // %s' % guard_name:
3404 seen_guard_end = True
3405 elif seen_guard_end:
3406 if line.strip() != '':
3407 errors.append(output_api.PresubmitPromptWarning(
3408 'Include guard %s not covering the whole file' % (
3409 guard_name), [f.LocalPath()]))
3410 break # Nothing else to check and enough to warn once.
3411
3412 if guard_name is None:
3413 errors.append(output_api.PresubmitPromptWarning(
3414 'Missing include guard %s' % expected_guard,
3415 [f.LocalPath()],
3416 'Missing include guard in %s\n'
3417 'Recommended name: %s\n'
3418 'This check can be disabled by having the string\n'
3419 'no-include-guard-because-multiply-included in the header.' %
3420 (f.LocalPath(), expected_guard)))
3421
3422 return errors
3423
3424
mostynbb639aca52015-01-07 20:31:233425def _CheckForWindowsLineEndings(input_api, output_api):
3426 """Check source code and known ascii text files for Windows style line
3427 endings.
3428 """
earthdok1b5e0ee2015-03-10 15:19:103429 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233430
3431 file_inclusion_pattern = (
3432 known_text_files,
3433 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3434 )
3435
mostynbb639aca52015-01-07 20:31:233436 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533437 source_file_filter = lambda f: input_api.FilterSourceFile(
3438 f, white_list=file_inclusion_pattern, black_list=None)
3439 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503440 include_file = False
3441 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233442 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503443 include_file = True
3444 if include_file:
3445 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233446
3447 if problems:
3448 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3449 'these files to contain Windows style line endings?\n' +
3450 '\n'.join(problems))]
3451
3452 return []
3453
3454
Vaclav Brozekd5de76a2018-03-17 07:57:503455def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133456 """Checks that all source files use SYSLOG properly."""
3457 syslog_files = []
3458 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563459 for line_number, line in f.ChangedContents():
3460 if 'SYSLOG' in line:
3461 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3462
pastarmovj89f7ee12016-09-20 14:58:133463 if syslog_files:
3464 return [output_api.PresubmitPromptWarning(
3465 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3466 ' calls.\nFiles to check:\n', items=syslog_files)]
3467 return []
3468
3469
[email protected]1f7b4172010-01-28 01:17:343470def CheckChangeOnUpload(input_api, output_api):
3471 results = []
3472 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473473 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283474 results.extend(
jam93a6ee792017-02-08 23:59:223475 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193476 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223477 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133478 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163479 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:533480 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193481 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543482 return results
[email protected]ca8d1982009-02-19 16:33:123483
3484
[email protected]1bfb8322014-04-23 01:02:413485def GetTryServerMasterForBot(bot):
3486 """Returns the Try Server master for the given bot.
3487
[email protected]0bb112362014-07-26 04:38:323488 It tries to guess the master from the bot name, but may still fail
3489 and return None. There is no longer a default master.
3490 """
3491 # Potentially ambiguous bot names are listed explicitly.
3492 master_map = {
tandriie5587792016-07-14 00:34:503493 'chromium_presubmit': 'master.tryserver.chromium.linux',
3494 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413495 }
[email protected]0bb112362014-07-26 04:38:323496 master = master_map.get(bot)
3497 if not master:
wnwen4fbaab82016-05-25 12:54:363498 if 'android' in bot:
tandriie5587792016-07-14 00:34:503499 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363500 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503501 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323502 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503503 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323504 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503505 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323506 return master
[email protected]1bfb8322014-04-23 01:02:413507
3508
[email protected]ca8d1982009-02-19 16:33:123509def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543510 results = []
[email protected]1f7b4172010-01-28 01:17:343511 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573512 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543513 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273514 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343515 input_api,
3516 output_api,
[email protected]2fdd1f362013-01-16 03:56:033517 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273518
jam93a6ee792017-02-08 23:59:223519 results.extend(
3520 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543521 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3522 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413523 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3524 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543525 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143526
3527
3528def _CheckTranslationScreenshots(input_api, output_api):
3529 PART_FILE_TAG = "part"
3530 import os
3531 import sys
3532 from io import StringIO
3533
3534 try:
3535 old_sys_path = sys.path
3536 sys.path = sys.path + [input_api.os_path.join(
3537 input_api.PresubmitLocalPath(), 'tools', 'grit')]
3538 import grit.grd_reader
3539 import grit.node.message
3540 import grit.util
3541 finally:
3542 sys.path = old_sys_path
3543
3544 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
3545 """Load the grd file and return a dict of message ids to messages.
3546
3547 Ignores any nested grdp files pointed by <part> tag.
3548 """
3549 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
3550 stop_after=None, first_ids_file=None,
3551 debug=False, defines=None,
3552 tags_to_ignore=set([PART_FILE_TAG]))
3553 return {
3554 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
3555 grit.node.message.MessageNode)
3556 }
3557
3558 def _GetGrdpMessagesFromString(grdp_string):
3559 """Parses the contents of a grdp file given in grdp_string.
3560
3561 grd_reader can't parse grdp files directly. Instead, this creates a
3562 temporary directory with a grd file pointing to the grdp file, and loads the
3563 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
3564 """
3565 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
3566 <grit latest_public_release="1" current_release="1">
3567 <release seq="1">
3568 <messages>
3569 <part file="sub.grdp" />
3570 </messages>
3571 </release>
3572 </grit>
3573 """
3574 with grit.util.TempDir({'main.grd': WRAPPER,
3575 'sub.grdp': grdp_string}) as temp_dir:
3576 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
3577
3578 new_or_added_paths = set(f.LocalPath()
3579 for f in input_api.AffectedFiles()
3580 if (f.Action() == 'A' or f.Action() == 'M'))
3581 removed_paths = set(f.LocalPath()
3582 for f in input_api.AffectedFiles(include_deletes=True)
3583 if f.Action() == 'D')
3584
3585 affected_grds = [f for f in input_api.AffectedFiles()
3586 if (f.LocalPath().endswith('.grd') or
3587 f.LocalPath().endswith('.grdp'))]
3588 affected_png_paths = [f.AbsoluteLocalPath()
3589 for f in input_api.AffectedFiles()
3590 if (f.LocalPath().endswith('.png'))]
3591
3592 # Check for screenshots. Developers can upload screenshots using
3593 # tools/translation/upload_screenshots.py which finds and uploads
3594 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
3595 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
3596 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
3597 #
3598 # The logic here is as follows:
3599 #
3600 # - If the CL has a .png file under the screenshots directory for a grd
3601 # file, warn the developer. Actual images should never be checked into the
3602 # Chrome repo.
3603 #
3604 # - If the CL contains modified or new messages in grd files and doesn't
3605 # contain the corresponding .sha1 files, warn the developer to add images
3606 # and upload them via tools/translation/upload_screenshots.py.
3607 #
3608 # - If the CL contains modified or new messages in grd files and the
3609 # corresponding .sha1 files, everything looks good.
3610 #
3611 # - If the CL contains removed messages in grd files but the corresponding
3612 # .sha1 files aren't removed, warn the developer to remove them.
3613 unnecessary_screenshots = []
3614 missing_sha1 = []
3615 unnecessary_sha1_files = []
3616
3617
3618 def _CheckScreenshotAdded(screenshots_dir, message_id):
3619 sha1_path = input_api.os_path.join(
3620 screenshots_dir, message_id + '.png.sha1')
3621 if sha1_path not in new_or_added_paths:
3622 missing_sha1.append(sha1_path)
3623
3624
3625 def _CheckScreenshotRemoved(screenshots_dir, message_id):
3626 sha1_path = input_api.os_path.join(
3627 screenshots_dir, message_id + '.png.sha1')
3628 if sha1_path not in removed_paths:
3629 unnecessary_sha1_files.append(sha1_path)
3630
3631
3632 for f in affected_grds:
3633 file_path = f.LocalPath()
3634 old_id_to_msg_map = {}
3635 new_id_to_msg_map = {}
3636 if file_path.endswith('.grdp'):
3637 if f.OldContents():
3638 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393639 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143640 if f.NewContents():
3641 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393642 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143643 else:
3644 if f.OldContents():
3645 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393646 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143647 if f.NewContents():
3648 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393649 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143650
3651 # Compute added, removed and modified message IDs.
3652 old_ids = set(old_id_to_msg_map)
3653 new_ids = set(new_id_to_msg_map)
3654 added_ids = new_ids - old_ids
3655 removed_ids = old_ids - new_ids
3656 modified_ids = set([])
3657 for key in old_ids.intersection(new_ids):
3658 if (old_id_to_msg_map[key].FormatXml()
3659 != new_id_to_msg_map[key].FormatXml()):
3660 modified_ids.add(key)
3661
3662 grd_name, ext = input_api.os_path.splitext(
3663 input_api.os_path.basename(file_path))
3664 screenshots_dir = input_api.os_path.join(
3665 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
3666
3667 # Check the screenshot directory for .png files. Warn if there is any.
3668 for png_path in affected_png_paths:
3669 if png_path.startswith(screenshots_dir):
3670 unnecessary_screenshots.append(png_path)
3671
3672 for added_id in added_ids:
3673 _CheckScreenshotAdded(screenshots_dir, added_id)
3674
3675 for modified_id in modified_ids:
3676 _CheckScreenshotAdded(screenshots_dir, modified_id)
3677
3678 for removed_id in removed_ids:
3679 _CheckScreenshotRemoved(screenshots_dir, removed_id)
3680
3681 results = []
3682 if unnecessary_screenshots:
3683 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393684 'Do not include actual screenshots in the changelist. Run '
3685 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143686 sorted(unnecessary_screenshots)))
3687
3688 if missing_sha1:
3689 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393690 'You are adding or modifying UI strings.\n'
3691 'To ensure the best translations, take screenshots of the relevant UI '
3692 '(https://g.co/chrome/translation) and add these files to your '
3693 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143694
3695 if unnecessary_sha1_files:
3696 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393697 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143698 sorted(unnecessary_sha1_files)))
3699
3700 return results