blob: 119dfe657465957c18fcfcce0d851758d2b17f40 [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 (
thomasandersone7caaa9b2017-03-29 19:22:53212 r'\bNULL\b',
213 (
214 'New code should not use NULL. Use nullptr instead.',
215 ),
216 True,
217 (),
218 ),
Antonio Gomes07300d02019-03-13 20:59:57219 # Make sure that gtest's FRIEND_TEST() macro is not used; the
220 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
221 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53222 (
[email protected]23e6cbc2012-06-16 18:51:20223 'FRIEND_TEST(',
224 (
[email protected]e3c945502012-06-26 20:01:49225 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20226 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
227 ),
228 False,
[email protected]7345da02012-11-27 14:31:49229 (),
[email protected]23e6cbc2012-06-16 18:51:20230 ),
231 (
thomasanderson4b569052016-09-14 20:15:53232 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
233 (
234 'Chrome clients wishing to select events on X windows should use',
235 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
236 'you are selecting events from the GPU process, or if you are using',
237 'an XDisplay other than gfx::GetXDisplay().',
238 ),
239 True,
240 (
Egor Paskoce145c42018-09-28 19:31:04241 r"^ui[\\/]gl[\\/].*\.cc$",
242 r"^media[\\/]gpu[\\/].*\.cc$",
243 r"^gpu[\\/].*\.cc$",
thomasanderson4b569052016-09-14 20:15:53244 ),
245 ),
246 (
thomasandersone043e3ce2017-06-08 00:43:20247 r'XInternAtom|xcb_intern_atom',
248 (
thomasanderson11aa41d2017-06-08 22:22:38249 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20250 ),
251 True,
252 (
Egor Paskoce145c42018-09-28 19:31:04253 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
254 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
255 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20256 ),
257 ),
258 (
tomhudsone2c14d552016-05-26 17:07:46259 'setMatrixClip',
260 (
261 'Overriding setMatrixClip() is prohibited; ',
262 'the base function is deprecated. ',
263 ),
264 True,
265 (),
266 ),
267 (
[email protected]52657f62013-05-20 05:30:31268 'SkRefPtr',
269 (
270 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22271 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31272 ),
273 True,
274 (),
275 ),
276 (
277 'SkAutoRef',
278 (
279 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22280 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31281 ),
282 True,
283 (),
284 ),
285 (
286 'SkAutoTUnref',
287 (
288 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22289 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31290 ),
291 True,
292 (),
293 ),
294 (
295 'SkAutoUnref',
296 (
297 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
298 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22299 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31300 ),
301 True,
302 (),
303 ),
[email protected]d89eec82013-12-03 14:10:59304 (
305 r'/HANDLE_EINTR\(.*close',
306 (
307 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
308 'descriptor will be closed, and it is incorrect to retry the close.',
309 'Either call close directly and ignore its return value, or wrap close',
310 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
311 ),
312 True,
313 (),
314 ),
315 (
316 r'/IGNORE_EINTR\((?!.*close)',
317 (
318 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
319 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
320 ),
321 True,
322 (
323 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04324 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
325 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59326 ),
327 ),
[email protected]ec5b3f02014-04-04 18:43:43328 (
329 r'/v8::Extension\(',
330 (
331 'Do not introduce new v8::Extensions into the code base, use',
332 'gin::Wrappable instead. See http://crbug.com/334679',
333 ),
334 True,
[email protected]f55c90ee62014-04-12 00:50:03335 (
Egor Paskoce145c42018-09-28 19:31:04336 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03337 ),
[email protected]ec5b3f02014-04-04 18:43:43338 ),
skyostilf9469f72015-04-20 10:38:52339 (
jame2d1a952016-04-02 00:27:10340 '#pragma comment(lib,',
341 (
342 'Specify libraries to link with in build files and not in the source.',
343 ),
344 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41345 (
tzik3f295992018-12-04 20:32:23346 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04347 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41348 ),
jame2d1a952016-04-02 00:27:10349 ),
fdorayc4ac18d2017-05-01 21:39:59350 (
Gabriel Charette7cc6c432018-04-25 20:52:02351 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59352 (
353 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
354 ),
355 False,
356 (),
357 ),
358 (
Gabriel Charette7cc6c432018-04-25 20:52:02359 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59360 (
361 'Consider using THREAD_CHECKER macros instead of the class directly.',
362 ),
363 False,
364 (),
365 ),
dbeamb6f4fde2017-06-15 04:03:06366 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06367 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
368 (
369 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
370 'deprecated (http://crbug.com/634507). Please avoid converting away',
371 'from the Time types in Chromium code, especially if any math is',
372 'being done on time values. For interfacing with platform/library',
373 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
374 'type converter methods instead. For faking TimeXXX values (for unit',
375 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
376 'other use cases, please contact base/time/OWNERS.',
377 ),
378 False,
379 (),
380 ),
381 (
dbeamb6f4fde2017-06-15 04:03:06382 'CallJavascriptFunctionUnsafe',
383 (
384 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
385 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
386 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
387 ),
388 False,
389 (
Egor Paskoce145c42018-09-28 19:31:04390 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
391 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
392 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06393 ),
394 ),
dskiba1474c2bfd62017-07-20 02:19:24395 (
396 'leveldb::DB::Open',
397 (
398 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
399 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
400 "Chrome's tracing, making their memory usage visible.",
401 ),
402 True,
403 (
404 r'^third_party/leveldatabase/.*\.(cc|h)$',
405 ),
Gabriel Charette0592c3a2017-07-26 12:02:04406 ),
407 (
Chris Mumfordc38afb62017-10-09 17:55:08408 'leveldb::NewMemEnv',
409 (
410 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58411 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
412 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08413 ),
414 True,
415 (
416 r'^third_party/leveldatabase/.*\.(cc|h)$',
417 ),
418 ),
419 (
Gabriel Charetted9839bc2017-07-29 14:17:47420 'RunLoop::QuitCurrent',
421 (
Robert Liao64b7ab22017-08-04 23:03:43422 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
423 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47424 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41425 False,
Gabriel Charetted9839bc2017-07-29 14:17:47426 (),
Gabriel Charettea44975052017-08-21 23:14:04427 ),
428 (
429 'base::ScopedMockTimeMessageLoopTaskRunner',
430 (
Gabriel Charette87cc1af2018-04-25 20:52:51431 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
432 'ScopedTaskEnvironment::MainThreadType::MOCK_TIME. There are still a',
433 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
434 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
435 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04436 ),
Gabriel Charette87cc1af2018-04-25 20:52:51437 False,
Gabriel Charettea44975052017-08-21 23:14:04438 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57439 ),
440 (
441 r'std::regex',
442 (
443 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02444 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57445 ),
446 True,
447 (),
Francois Doray43670e32017-09-27 12:40:38448 ),
449 (
450 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
451 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
452 (
453 'Use the new API in base/threading/thread_restrictions.h.',
454 ),
Gabriel Charette04b138f2018-08-06 00:03:22455 False,
Francois Doray43670e32017-09-27 12:40:38456 (),
457 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38458 (
459 r'/\bbase::Bind\(',
460 (
Gabriel Charette147335ea2018-03-22 15:59:19461 'Please consider using base::Bind{Once,Repeating} instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02462 'of base::Bind. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38463 ),
464 False,
465 (),
466 ),
467 (
468 r'/\bbase::Callback<',
469 (
Gabriel Charette147335ea2018-03-22 15:59:19470 'Please consider using base::{Once,Repeating}Callback instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02471 'of base::Callback. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38472 ),
473 False,
474 (),
475 ),
476 (
477 r'/\bbase::Closure\b',
478 (
Gabriel Charette147335ea2018-03-22 15:59:19479 'Please consider using base::{Once,Repeating}Closure instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02480 'of base::Closure. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38481 ),
482 False,
483 (),
484 ),
Victor Costan3653df62018-02-08 21:38:16485 (
Gabriel Charette147335ea2018-03-22 15:59:19486 r'RunMessageLoop',
487 (
488 'RunMessageLoop is deprecated, use RunLoop instead.',
489 ),
490 False,
491 (),
492 ),
493 (
494 r'RunThisRunLoop',
495 (
496 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
497 ),
498 False,
499 (),
500 ),
501 (
502 r'RunAllPendingInMessageLoop()',
503 (
504 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
505 "if you're convinced you need this.",
506 ),
507 False,
508 (),
509 ),
510 (
511 r'RunAllPendingInMessageLoop(BrowserThread',
512 (
513 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
514 'BrowserThread::UI, TestBrowserThreadBundle::RunIOThreadUntilIdle',
515 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
516 'async events instead of flushing threads.',
517 ),
518 False,
519 (),
520 ),
521 (
522 r'MessageLoopRunner',
523 (
524 'MessageLoopRunner is deprecated, use RunLoop instead.',
525 ),
526 False,
527 (),
528 ),
529 (
530 r'GetDeferredQuitTaskForRunLoop',
531 (
532 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
533 "gab@ if you found a use case where this is the only solution.",
534 ),
535 False,
536 (),
537 ),
538 (
Victor Costan3653df62018-02-08 21:38:16539 'sqlite3_initialize',
540 (
541 'Instead of sqlite3_initialize, depend on //sql, ',
542 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
543 ),
544 True,
545 (
546 r'^sql/initialization\.(cc|h)$',
547 r'^third_party/sqlite/.*\.(c|cc|h)$',
548 ),
549 ),
Matt Menke7f520a82018-03-28 21:38:37550 (
551 'net::URLFetcher',
552 (
553 'net::URLFetcher should no longer be used in content embedders. ',
554 'Instead, use network::SimpleURLLoader instead, which supports ',
555 'an out-of-process network stack. ',
556 'net::URLFetcher may still be used in binaries that do not embed',
557 'content.',
558 ),
Matt Menke59716d02018-04-05 12:45:53559 False,
Matt Menke7f520a82018-03-28 21:38:37560 (
Egor Paskoce145c42018-09-28 19:31:04561 r'^ios[\\/].*\.(cc|h)$',
562 r'.*[\\/]ios[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:37563 r'.*_ios\.(cc|h)$',
Egor Paskoce145c42018-09-28 19:31:04564 r'^net[\\/].*\.(cc|h)$',
565 r'.*[\\/]tools[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:37566 ),
567 ),
jdoerried7d10ab2018-04-27 10:46:13568 (
tzik5de2157f2018-05-08 03:42:47569 r'std::random_shuffle',
570 (
571 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
572 'base::RandomShuffle instead.'
573 ),
574 True,
575 (),
576 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24577 (
578 'ios/web/public/test/http_server',
579 (
580 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
581 ),
582 False,
583 (),
584 ),
Robert Liao764c9492019-01-24 18:46:28585 (
586 'GetAddressOf',
587 (
588 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
589 'implicated in a few leaks. Use operator& instead.'
590 ),
591 True,
592 (),
593 ),
Antonio Gomes07300d02019-03-13 20:59:57594 (
595 'DEFINE_TYPE_CASTS',
596 (
597 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
598 '//third_party/blink/renderer/platform/casting.h.'
599 ),
600 True,
601 (
602 r'^third_party/blink/renderer/.*\.(cc|h)$',
603 ),
604 ),
[email protected]127f18ec2012-06-16 05:05:59605)
606
wnwenbdc444e2016-05-25 13:44:15607
mlamouria82272622014-09-16 18:45:04608_IPC_ENUM_TRAITS_DEPRECATED = (
609 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50610 'See http://www.chromium.org/Home/chromium-security/education/'
611 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:04612
Stephen Martinis97a394142018-06-07 23:06:05613_LONG_PATH_ERROR = (
614 'Some files included in this CL have file names that are too long (> 200'
615 ' characters). If committed, these files will cause issues on Windows. See'
616 ' https://crbug.com/612667 for more details.'
617)
618
Shenghua Zhangbfaa38b82017-11-16 21:58:02619_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:04620 r".*[\\/]BuildHooksAndroidImpl\.java",
621 r".*[\\/]LicenseContentProvider\.java",
622 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:28623 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:02624]
[email protected]127f18ec2012-06-16 05:05:59625
Sean Kau46e29bc2017-08-28 16:31:16626# These paths contain test data and other known invalid JSON files.
627_KNOWN_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:04628 r'test[\\/]data[\\/]',
629 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
630 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:04631 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:43632 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:16633]
634
635
[email protected]b00342e7f2013-03-26 16:21:54636_VALID_OS_MACROS = (
637 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08638 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54639 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:12640 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:54641 'OS_BSD',
642 'OS_CAT', # For testing.
643 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:04644 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:54645 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37646 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54647 'OS_IOS',
648 'OS_LINUX',
649 'OS_MACOSX',
650 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21651 'OS_NACL_NONSFI',
652 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12653 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54654 'OS_OPENBSD',
655 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37656 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54657 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54658 'OS_WIN',
659)
660
661
agrievef32bcc72016-04-04 14:57:40662_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:39663 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36664 'base/android/jni_generator/jni_generator.pydeps',
665 'base/android/jni_generator/jni_registration_generator.pydeps',
666 'build/android/gyp/aar.pydeps',
667 'build/android/gyp/aidl.pydeps',
668 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:38669 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36670 'build/android/gyp/bytecode_processor.pydeps',
671 'build/android/gyp/compile_resources.pydeps',
Andrew Grievef89e926c2019-02-07 18:36:57672 'build/android/gyp/create_app_bundle_minimal_apks.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36673 'build/android/gyp/create_bundle_wrapper_script.pydeps',
674 'build/android/gyp/copy_ex.pydeps',
675 'build/android/gyp/create_app_bundle.pydeps',
676 'build/android/gyp/create_apk_operations_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36677 'build/android/gyp/create_java_binary_script.pydeps',
Andrew Grieveb838d832019-02-11 16:55:22678 'build/android/gyp/create_size_info_files.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36679 'build/android/gyp/create_stack_script.pydeps',
680 'build/android/gyp/create_test_runner_script.pydeps',
681 'build/android/gyp/create_tool_wrapper.pydeps',
682 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:59683 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36684 'build/android/gyp/dex.pydeps',
685 'build/android/gyp/dist_aar.pydeps',
686 'build/android/gyp/emma_instr.pydeps',
687 'build/android/gyp/filter_zip.pydeps',
688 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:36689 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36690 'build/android/gyp/ijar.pydeps',
691 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:26692 'build/android/gyp/java_cpp_strings.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36693 'build/android/gyp/javac.pydeps',
694 'build/android/gyp/jinja_template.pydeps',
695 'build/android/gyp/lint.pydeps',
696 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36697 'build/android/gyp/merge_manifest.pydeps',
698 'build/android/gyp/prepare_resources.pydeps',
699 'build/android/gyp/proguard.pydeps',
700 'build/android/gyp/write_build_config.pydeps',
701 'build/android/gyp/write_ordered_libraries.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:56702 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36703 'build/android/incremental_install/generate_android_manifest.pydeps',
704 'build/android/incremental_install/write_installer_json.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22705 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:40706 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04707 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36708 'build/protoc_java.pydeps',
Sam Maier3599daa2018-11-26 18:02:59709 ('build/secondary/third_party/android_platform/'
710 'development/scripts/stack.pydeps'),
agrieve732db3a2016-04-26 19:18:19711 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40712]
713
wnwenbdc444e2016-05-25 13:44:15714
agrievef32bcc72016-04-04 14:57:40715_GENERIC_PYDEPS_FILES = [
John Chencde89192018-01-27 21:18:40716 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Cole Winstanley7045a1b2018-08-27 23:37:29717 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22718 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:40719]
720
wnwenbdc444e2016-05-25 13:44:15721
agrievef32bcc72016-04-04 14:57:40722_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
723
724
Eric Boren6fd2b932018-01-25 15:05:08725# Bypass the AUTHORS check for these accounts.
726_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:29727 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
728 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:08729 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
Eric Boren57cc805b2018-08-20 17:28:32730 'spirv', 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:59731 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:45732 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:59733 ) | set('%[email protected]' % s
Robert Ma7f024172018-11-01 20:59:22734 for s in ('v8-ci-autoroll-builder', 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:04735 ) | set('%[email protected]' % s
736 for s in ('chromium-autoroll',)
737 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:30738 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:08739
740
[email protected]55459852011-08-10 15:17:19741def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
742 """Attempts to prevent use of functions intended only for testing in
743 non-testing code. For now this is just a best-effort implementation
744 that ignores header files and may have some false positives. A
745 better implementation would probably need a proper C++ parser.
746 """
747 # We only scan .cc files and the like, as the declaration of
748 # for-testing functions in header files are hard to distinguish from
749 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49750 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:19751
jochenc0d4808c2015-07-27 09:25:42752 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19753 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09754 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19755 exclusion_pattern = input_api.re.compile(
756 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
757 base_function_pattern, base_function_pattern))
758
759 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44760 black_list = (_EXCLUDED_PATHS +
761 _TEST_CODE_EXCLUDED_PATHS +
762 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19763 return input_api.FilterSourceFile(
764 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49765 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:19766 black_list=black_list)
767
768 problems = []
769 for f in input_api.AffectedSourceFiles(FilterFile):
770 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24771 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03772 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46773 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03774 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19775 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03776 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19777
778 if problems:
[email protected]f7051d52013-04-02 18:31:42779 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03780 else:
781 return []
[email protected]55459852011-08-10 15:17:19782
783
Vaclav Brozek7dbc28c2018-03-27 08:35:23784def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
785 """This is a simplified version of
786 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
787 """
788 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
789 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
790 name_pattern = r'ForTest(s|ing)?'
791 # Describes an occurrence of "ForTest*" inside a // comment.
792 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
793 # Catch calls.
794 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
795 # Ignore definitions. (Comments are ignored separately.)
796 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
797
798 problems = []
799 sources = lambda x: input_api.FilterSourceFile(
800 x,
801 black_list=(('(?i).*test', r'.*\/junit\/')
802 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49803 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:23804 )
805 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
806 local_path = f.LocalPath()
807 is_inside_javadoc = False
808 for line_number, line in f.ChangedContents():
809 if is_inside_javadoc and javadoc_end_re.search(line):
810 is_inside_javadoc = False
811 if not is_inside_javadoc and javadoc_start_re.search(line):
812 is_inside_javadoc = True
813 if is_inside_javadoc:
814 continue
815 if (inclusion_re.search(line) and
816 not comment_re.search(line) and
817 not exclusion_re.search(line)):
818 problems.append(
819 '%s:%d\n %s' % (local_path, line_number, line.strip()))
820
821 if problems:
822 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
823 else:
824 return []
825
826
[email protected]10689ca2011-09-02 02:31:54827def _CheckNoIOStreamInHeaders(input_api, output_api):
828 """Checks to make sure no .h files include <iostream>."""
829 files = []
830 pattern = input_api.re.compile(r'^#include\s*<iostream>',
831 input_api.re.MULTILINE)
832 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
833 if not f.LocalPath().endswith('.h'):
834 continue
835 contents = input_api.ReadFile(f)
836 if pattern.search(contents):
837 files.append(f)
838
839 if len(files):
yolandyandaabc6d2016-04-18 18:29:39840 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06841 'Do not #include <iostream> in header files, since it inserts static '
842 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54843 '#include <ostream>. See http://crbug.com/94794',
844 files) ]
845 return []
846
Danil Chapovalov3518f362018-08-11 16:13:43847def _CheckNoStrCatRedefines(input_api, output_api):
848 """Checks no windows headers with StrCat redefined are included directly."""
849 files = []
850 pattern_deny = input_api.re.compile(
851 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
852 input_api.re.MULTILINE)
853 pattern_allow = input_api.re.compile(
854 r'^#include\s"base/win/windows_defines.inc"',
855 input_api.re.MULTILINE)
856 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
857 contents = input_api.ReadFile(f)
858 if pattern_deny.search(contents) and not pattern_allow.search(contents):
859 files.append(f.LocalPath())
860
861 if len(files):
862 return [output_api.PresubmitError(
863 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
864 'directly since they pollute code with StrCat macro. Instead, '
865 'include matching header from base/win. See http://crbug.com/856536',
866 files) ]
867 return []
868
[email protected]10689ca2011-09-02 02:31:54869
[email protected]72df4e782012-06-21 16:28:18870def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52871 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18872 problems = []
873 for f in input_api.AffectedFiles():
874 if (not f.LocalPath().endswith(('.cc', '.mm'))):
875 continue
876
877 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04878 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18879 problems.append(' %s:%d' % (f.LocalPath(), line_num))
880
881 if not problems:
882 return []
883 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
884 '\n'.join(problems))]
885
Dominic Battre033531052018-09-24 15:45:34886def _CheckNoDISABLETypoInTests(input_api, output_api):
887 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
888
889 This test warns if somebody tries to disable a test with the DISABLE_ prefix
890 instead of DISABLED_. To filter false positives, reports are only generated
891 if a corresponding MAYBE_ line exists.
892 """
893 problems = []
894
895 # The following two patterns are looked for in tandem - is a test labeled
896 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
897 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
898 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
899
900 # This is for the case that a test is disabled on all platforms.
901 full_disable_pattern = input_api.re.compile(
902 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
903 input_api.re.MULTILINE)
904
Katie Df13948e2018-09-25 07:33:44905 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:34906 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
907 continue
908
909 # Search for MABYE_, DISABLE_ pairs.
910 disable_lines = {} # Maps of test name to line number.
911 maybe_lines = {}
912 for line_num, line in f.ChangedContents():
913 disable_match = disable_pattern.search(line)
914 if disable_match:
915 disable_lines[disable_match.group(1)] = line_num
916 maybe_match = maybe_pattern.search(line)
917 if maybe_match:
918 maybe_lines[maybe_match.group(1)] = line_num
919
920 # Search for DISABLE_ occurrences within a TEST() macro.
921 disable_tests = set(disable_lines.keys())
922 maybe_tests = set(maybe_lines.keys())
923 for test in disable_tests.intersection(maybe_tests):
924 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
925
926 contents = input_api.ReadFile(f)
927 full_disable_match = full_disable_pattern.search(contents)
928 if full_disable_match:
929 problems.append(' %s' % f.LocalPath())
930
931 if not problems:
932 return []
933 return [
934 output_api.PresubmitPromptWarning(
935 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
936 '\n'.join(problems))
937 ]
938
[email protected]72df4e782012-06-21 16:28:18939
danakj61c1aa22015-10-26 19:55:52940def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57941 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52942 errors = []
943 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
944 input_api.re.MULTILINE)
945 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
946 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
947 continue
948 for lnum, line in f.ChangedContents():
949 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17950 errors.append(output_api.PresubmitError(
951 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57952 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17953 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52954 return errors
955
956
mcasasb7440c282015-02-04 14:52:19957def _FindHistogramNameInLine(histogram_name, line):
958 """Tries to find a histogram name or prefix in a line."""
959 if not "affected-histogram" in line:
960 return histogram_name in line
961 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
962 # the histogram_name.
963 if not '"' in line:
964 return False
965 histogram_prefix = line.split('\"')[1]
966 return histogram_prefix in histogram_name
967
968
969def _CheckUmaHistogramChanges(input_api, output_api):
970 """Check that UMA histogram names in touched lines can still be found in other
971 lines of the patch or in histograms.xml. Note that this check would not catch
972 the reverse: changes in histograms.xml not matched in the code itself."""
973 touched_histograms = []
974 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:47975 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
976 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
977 name_pattern = r'"(.*?)"'
978 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
979 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
980 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
981 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
982 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:17983 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:19984 for f in input_api.AffectedFiles():
985 # If histograms.xml itself is modified, keep the modified lines for later.
986 if f.LocalPath().endswith(('histograms.xml')):
987 histograms_xml_modifications = f.ChangedContents()
988 continue
Vaclav Brozekbdac817c2018-03-24 06:30:47989 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
990 single_line_re = single_line_c_re
991 split_line_prefix_re = split_line_c_prefix_re
992 elif f.LocalPath().endswith(('java')):
993 single_line_re = single_line_java_re
994 split_line_prefix_re = split_line_java_prefix_re
995 else:
mcasasb7440c282015-02-04 14:52:19996 continue
997 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:17998 if last_line_matched_prefix:
999 suffix_found = split_line_suffix_re.search(line)
1000 if suffix_found :
1001 touched_histograms.append([suffix_found.group(1), f, line_num])
1002 last_line_matched_prefix = False
1003 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061004 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191005 if found:
1006 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171007 continue
1008 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191009
1010 # Search for the touched histogram names in the local modifications to
1011 # histograms.xml, and, if not found, on the base histograms.xml file.
1012 unmatched_histograms = []
1013 for histogram_info in touched_histograms:
1014 histogram_name_found = False
1015 for line_num, line in histograms_xml_modifications:
1016 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
1017 if histogram_name_found:
1018 break
1019 if not histogram_name_found:
1020 unmatched_histograms.append(histogram_info)
1021
eromanb90c82e7e32015-04-01 15:13:491022 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191023 problems = []
1024 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491025 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191026 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451027 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191028 histogram_name_found = False
1029 for line in histograms_xml:
1030 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
1031 if histogram_name_found:
1032 break
1033 if not histogram_name_found:
1034 problems.append(' [%s:%d] %s' %
1035 (f.LocalPath(), line_num, histogram_name))
1036
1037 if not problems:
1038 return []
1039 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1040 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491041 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191042
wnwenbdc444e2016-05-25 13:44:151043
yolandyandaabc6d2016-04-18 18:29:391044def _CheckFlakyTestUsage(input_api, output_api):
1045 """Check that FlakyTest annotation is our own instead of the android one"""
1046 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1047 files = []
1048 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1049 if f.LocalPath().endswith('Test.java'):
1050 if pattern.search(input_api.ReadFile(f)):
1051 files.append(f)
1052 if len(files):
1053 return [output_api.PresubmitError(
1054 'Use org.chromium.base.test.util.FlakyTest instead of '
1055 'android.test.FlakyTest',
1056 files)]
1057 return []
mcasasb7440c282015-02-04 14:52:191058
wnwenbdc444e2016-05-25 13:44:151059
[email protected]8ea5d4b2011-09-13 21:49:221060def _CheckNoNewWStrings(input_api, output_api):
1061 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271062 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221063 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201064 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571065 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341066 '/win/' in f.LocalPath() or
1067 'chrome_elf' in f.LocalPath() or
1068 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201069 continue
[email protected]8ea5d4b2011-09-13 21:49:221070
[email protected]a11dbe9b2012-08-07 01:32:581071 allowWString = False
[email protected]b5c24292011-11-28 14:38:201072 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581073 if 'presubmit: allow wstring' in line:
1074 allowWString = True
1075 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271076 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581077 allowWString = False
1078 else:
1079 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221080
[email protected]55463aa62011-10-12 00:48:271081 if not problems:
1082 return []
1083 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581084 ' If you are calling a cross-platform API that accepts a wstring, '
1085 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271086 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221087
1088
[email protected]2a8ac9c2011-10-19 17:20:441089def _CheckNoDEPSGIT(input_api, output_api):
1090 """Make sure .DEPS.git is never modified manually."""
1091 if any(f.LocalPath().endswith('.DEPS.git') for f in
1092 input_api.AffectedFiles()):
1093 return [output_api.PresubmitError(
1094 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1095 'automated system based on what\'s in DEPS and your changes will be\n'
1096 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501097 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1098 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441099 'for more information')]
1100 return []
1101
1102
tandriief664692014-09-23 14:51:471103def _CheckValidHostsInDEPS(input_api, output_api):
1104 """Checks that DEPS file deps are from allowed_hosts."""
1105 # Run only if DEPS file has been modified to annoy fewer bystanders.
1106 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1107 return []
1108 # Outsource work to gclient verify
1109 try:
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201110 input_api.subprocess.check_output(['gclient', 'verify'],
1111 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471112 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201113 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471114 return [output_api.PresubmitError(
1115 'DEPS file must have only git dependencies.',
1116 long_text=error.output)]
1117
1118
[email protected]127f18ec2012-06-16 05:05:591119def _CheckNoBannedFunctions(input_api, output_api):
1120 """Make sure that banned functions are not used."""
1121 warnings = []
1122 errors = []
1123
wnwenbdc444e2016-05-25 13:44:151124 def IsBlacklisted(affected_file, blacklist):
1125 local_path = affected_file.LocalPath()
1126 for item in blacklist:
1127 if input_api.re.match(item, local_path):
1128 return True
1129 return False
1130
Sylvain Defresnea8b73d252018-02-28 15:45:541131 def IsIosObcjFile(affected_file):
1132 local_path = affected_file.LocalPath()
1133 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1134 return False
1135 basename = input_api.os_path.basename(local_path)
1136 if 'ios' in basename.split('_'):
1137 return True
1138 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1139 if sep and 'ios' in local_path.split(sep):
1140 return True
1141 return False
1142
wnwenbdc444e2016-05-25 13:44:151143 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
1144 matched = False
1145 if func_name[0:1] == '/':
1146 regex = func_name[1:]
1147 if input_api.re.search(regex, line):
1148 matched = True
1149 elif func_name in line:
dchenge07de812016-06-20 19:27:171150 matched = True
wnwenbdc444e2016-05-25 13:44:151151 if matched:
dchenge07de812016-06-20 19:27:171152 problems = warnings
wnwenbdc444e2016-05-25 13:44:151153 if error:
dchenge07de812016-06-20 19:27:171154 problems = errors
wnwenbdc444e2016-05-25 13:44:151155 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1156 for message_line in message:
1157 problems.append(' %s' % message_line)
1158
Eric Stevensona9a980972017-09-23 00:04:411159 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1160 for f in input_api.AffectedFiles(file_filter=file_filter):
1161 for line_num, line in f.ChangedContents():
1162 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1163 CheckForMatch(f, line_num, line, func_name, message, error)
1164
[email protected]127f18ec2012-06-16 05:05:591165 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1166 for f in input_api.AffectedFiles(file_filter=file_filter):
1167 for line_num, line in f.ChangedContents():
1168 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151169 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591170
Sylvain Defresnea8b73d252018-02-28 15:45:541171 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1172 for line_num, line in f.ChangedContents():
1173 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1174 CheckForMatch(f, line_num, line, func_name, message, error)
1175
[email protected]127f18ec2012-06-16 05:05:591176 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1177 for f in input_api.AffectedFiles(file_filter=file_filter):
1178 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491179 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491180 if IsBlacklisted(f, excluded_paths):
1181 continue
wnwenbdc444e2016-05-25 13:44:151182 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591183
1184 result = []
1185 if (warnings):
1186 result.append(output_api.PresubmitPromptWarning(
1187 'Banned functions were used.\n' + '\n'.join(warnings)))
1188 if (errors):
1189 result.append(output_api.PresubmitError(
1190 'Banned functions were used.\n' + '\n'.join(errors)))
1191 return result
1192
1193
[email protected]6c063c62012-07-11 19:11:061194def _CheckNoPragmaOnce(input_api, output_api):
1195 """Make sure that banned functions are not used."""
1196 files = []
1197 pattern = input_api.re.compile(r'^#pragma\s+once',
1198 input_api.re.MULTILINE)
1199 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1200 if not f.LocalPath().endswith('.h'):
1201 continue
1202 contents = input_api.ReadFile(f)
1203 if pattern.search(contents):
1204 files.append(f)
1205
1206 if files:
1207 return [output_api.PresubmitError(
1208 'Do not use #pragma once in header files.\n'
1209 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1210 files)]
1211 return []
1212
[email protected]127f18ec2012-06-16 05:05:591213
[email protected]e7479052012-09-19 00:26:121214def _CheckNoTrinaryTrueFalse(input_api, output_api):
1215 """Checks to make sure we don't introduce use of foo ? true : false."""
1216 problems = []
1217 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1218 for f in input_api.AffectedFiles():
1219 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1220 continue
1221
1222 for line_num, line in f.ChangedContents():
1223 if pattern.match(line):
1224 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1225
1226 if not problems:
1227 return []
1228 return [output_api.PresubmitPromptWarning(
1229 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1230 '\n'.join(problems))]
1231
1232
[email protected]55f9f382012-07-31 11:02:181233def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281234 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181235 change. Breaking - rules is an error, breaking ! rules is a
1236 warning.
1237 """
mohan.reddyf21db962014-10-16 12:26:471238 import sys
[email protected]55f9f382012-07-31 11:02:181239 # We need to wait until we have an input_api object and use this
1240 # roundabout construct to import checkdeps because this file is
1241 # eval-ed and thus doesn't have __file__.
1242 original_sys_path = sys.path
1243 try:
1244 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471245 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181246 import checkdeps
1247 from cpp_checker import CppChecker
Jinsuk Kim5a092672017-10-24 22:42:241248 from java_checker import JavaChecker
rhalavati08acd232017-04-03 07:23:281249 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:181250 from rules import Rule
1251 finally:
1252 # Restore sys.path to what it was before.
1253 sys.path = original_sys_path
1254
1255 added_includes = []
rhalavati08acd232017-04-03 07:23:281256 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241257 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181258 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:281259 if CppChecker.IsCppFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501260 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081261 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
rhalavati08acd232017-04-03 07:23:281262 elif ProtoChecker.IsProtoFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501263 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081264 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241265 elif JavaChecker.IsJavaFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501266 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081267 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181268
[email protected]26385172013-05-09 23:11:351269 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181270
1271 error_descriptions = []
1272 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281273 error_subjects = set()
1274 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181275 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1276 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081277 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181278 description_with_path = '%s\n %s' % (path, rule_description)
1279 if rule_type == Rule.DISALLOW:
1280 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281281 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181282 else:
1283 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281284 warning_subjects.add("#includes")
1285
1286 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1287 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081288 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281289 description_with_path = '%s\n %s' % (path, rule_description)
1290 if rule_type == Rule.DISALLOW:
1291 error_descriptions.append(description_with_path)
1292 error_subjects.add("imports")
1293 else:
1294 warning_descriptions.append(description_with_path)
1295 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181296
Jinsuk Kim5a092672017-10-24 22:42:241297 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021298 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081299 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241300 description_with_path = '%s\n %s' % (path, rule_description)
1301 if rule_type == Rule.DISALLOW:
1302 error_descriptions.append(description_with_path)
1303 error_subjects.add("imports")
1304 else:
1305 warning_descriptions.append(description_with_path)
1306 warning_subjects.add("imports")
1307
[email protected]55f9f382012-07-31 11:02:181308 results = []
1309 if error_descriptions:
1310 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281311 'You added one or more %s that violate checkdeps rules.'
1312 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181313 error_descriptions))
1314 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421315 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281316 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181317 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281318 '%s? See relevant DEPS file(s) for details and contacts.' %
1319 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181320 warning_descriptions))
1321 return results
1322
1323
[email protected]fbcafe5a2012-08-08 15:31:221324def _CheckFilePermissions(input_api, output_api):
1325 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151326 if input_api.platform == 'win32':
1327 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291328 checkperms_tool = input_api.os_path.join(
1329 input_api.PresubmitLocalPath(),
1330 'tools', 'checkperms', 'checkperms.py')
1331 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471332 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391333 with input_api.CreateTemporaryFile() as file_list:
1334 for f in input_api.AffectedFiles():
1335 # checkperms.py file/directory arguments must be relative to the
1336 # repository.
1337 file_list.write(f.LocalPath() + '\n')
1338 file_list.close()
1339 args += ['--file-list', file_list.name]
1340 try:
1341 input_api.subprocess.check_output(args)
1342 return []
1343 except input_api.subprocess.CalledProcessError as error:
1344 return [output_api.PresubmitError(
1345 'checkperms.py failed:',
1346 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221347
1348
robertocn832f5992017-01-04 19:01:301349def _CheckTeamTags(input_api, output_api):
1350 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1351 checkteamtags_tool = input_api.os_path.join(
1352 input_api.PresubmitLocalPath(),
1353 'tools', 'checkteamtags', 'checkteamtags.py')
1354 args = [input_api.python_executable, checkteamtags_tool,
1355 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221356 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301357 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1358 'OWNERS']
1359 try:
1360 if files:
1361 input_api.subprocess.check_output(args + files)
1362 return []
1363 except input_api.subprocess.CalledProcessError as error:
1364 return [output_api.PresubmitError(
1365 'checkteamtags.py failed:',
1366 long_text=error.output)]
1367
1368
[email protected]c8278b32012-10-30 20:35:491369def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1370 """Makes sure we don't include ui/aura/window_property.h
1371 in header files.
1372 """
1373 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1374 errors = []
1375 for f in input_api.AffectedFiles():
1376 if not f.LocalPath().endswith('.h'):
1377 continue
1378 for line_num, line in f.ChangedContents():
1379 if pattern.match(line):
1380 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1381
1382 results = []
1383 if errors:
1384 results.append(output_api.PresubmitError(
1385 'Header files should not include ui/aura/window_property.h', errors))
1386 return results
1387
1388
[email protected]70ca77752012-11-20 03:45:031389def _CheckForVersionControlConflictsInFile(input_api, f):
1390 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1391 errors = []
1392 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:161393 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:231394 # First-level headers in markdown look a lot like version control
1395 # conflict markers. http://daringfireball.net/projects/markdown/basics
1396 continue
[email protected]70ca77752012-11-20 03:45:031397 if pattern.match(line):
1398 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1399 return errors
1400
1401
1402def _CheckForVersionControlConflicts(input_api, output_api):
1403 """Usually this is not intentional and will cause a compile failure."""
1404 errors = []
1405 for f in input_api.AffectedFiles():
1406 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1407
1408 results = []
1409 if errors:
1410 results.append(output_api.PresubmitError(
1411 'Version control conflict markers found, please resolve.', errors))
1412 return results
1413
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201414
estadee17314a02017-01-12 16:22:161415def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1416 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1417 errors = []
1418 for f in input_api.AffectedFiles():
1419 for line_num, line in f.ChangedContents():
1420 if pattern.search(line):
1421 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1422
1423 results = []
1424 if errors:
1425 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501426 'Found Google support URL addressed by answer number. Please replace '
1427 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161428 return results
1429
[email protected]70ca77752012-11-20 03:45:031430
[email protected]06e6d0ff2012-12-11 01:36:441431def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1432 def FilterFile(affected_file):
1433 """Filter function for use with input_api.AffectedSourceFiles,
1434 below. This filters out everything except non-test files from
1435 top-level directories that generally speaking should not hard-code
1436 service URLs (e.g. src/android_webview/, src/content/ and others).
1437 """
1438 return input_api.FilterSourceFile(
1439 affected_file,
Egor Paskoce145c42018-09-28 19:31:041440 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:441441 black_list=(_EXCLUDED_PATHS +
1442 _TEST_CODE_EXCLUDED_PATHS +
1443 input_api.DEFAULT_BLACK_LIST))
1444
reillyi38965732015-11-16 18:27:331445 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1446 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461447 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1448 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441449 problems = [] # items are (filename, line_number, line)
1450 for f in input_api.AffectedSourceFiles(FilterFile):
1451 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461452 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441453 problems.append((f.LocalPath(), line_num, line))
1454
1455 if problems:
[email protected]f7051d52013-04-02 18:31:421456 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441457 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581458 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441459 [' %s:%d: %s' % (
1460 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031461 else:
1462 return []
[email protected]06e6d0ff2012-12-11 01:36:441463
1464
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491465# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:271466def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1467 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311468 The native_client_sdk directory is excluded because it has auto-generated PNG
1469 files for documentation.
[email protected]d2530012013-01-25 16:39:271470 """
[email protected]d2530012013-01-25 16:39:271471 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491472 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:041473 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:311474 file_filter = lambda f: input_api.FilterSourceFile(
1475 f, white_list=white_list, black_list=black_list)
1476 for f in input_api.AffectedFiles(include_deletes=False,
1477 file_filter=file_filter):
1478 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271479
1480 results = []
1481 if errors:
1482 results.append(output_api.PresubmitError(
1483 'The name of PNG files should not have abbreviations. \n'
1484 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1485 'Contact [email protected] if you have questions.', errors))
1486 return results
1487
1488
Daniel Cheng4dcdb6b2017-04-13 08:30:171489def _ExtractAddRulesFromParsedDeps(parsed_deps):
1490 """Extract the rules that add dependencies from a parsed DEPS file.
1491
1492 Args:
1493 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1494 add_rules = set()
1495 add_rules.update([
1496 rule[1:] for rule in parsed_deps.get('include_rules', [])
1497 if rule.startswith('+') or rule.startswith('!')
1498 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501499 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171500 {}).iteritems():
1501 add_rules.update([
1502 rule[1:] for rule in rules
1503 if rule.startswith('+') or rule.startswith('!')
1504 ])
1505 return add_rules
1506
1507
1508def _ParseDeps(contents):
1509 """Simple helper for parsing DEPS files."""
1510 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171511 class _VarImpl:
1512
1513 def __init__(self, local_scope):
1514 self._local_scope = local_scope
1515
1516 def Lookup(self, var_name):
1517 """Implements the Var syntax."""
1518 try:
1519 return self._local_scope['vars'][var_name]
1520 except KeyError:
1521 raise Exception('Var is not defined: %s' % var_name)
1522
1523 local_scope = {}
1524 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171525 'Var': _VarImpl(local_scope).Lookup,
1526 }
1527 exec contents in global_scope, local_scope
1528 return local_scope
1529
1530
1531def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081532 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411533 a set of DEPS entries that we should look up.
1534
1535 For a directory (rather than a specific filename) we fake a path to
1536 a specific filename by adding /DEPS. This is chosen as a file that
1537 will seldom or never be subject to per-file include_rules.
1538 """
[email protected]2b438d62013-11-14 17:54:141539 # We ignore deps entries on auto-generated directories.
1540 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081541
Daniel Cheng4dcdb6b2017-04-13 08:30:171542 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1543 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1544
1545 added_deps = new_deps.difference(old_deps)
1546
[email protected]2b438d62013-11-14 17:54:141547 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171548 for added_dep in added_deps:
1549 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1550 continue
1551 # Assume that a rule that ends in .h is a rule for a specific file.
1552 if added_dep.endswith('.h'):
1553 results.add(added_dep)
1554 else:
1555 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081556 return results
1557
1558
[email protected]e871964c2013-05-13 14:14:551559def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1560 """When a dependency prefixed with + is added to a DEPS file, we
1561 want to make sure that the change is reviewed by an OWNER of the
1562 target file or directory, to avoid layering violations from being
1563 introduced. This check verifies that this happens.
1564 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171565 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241566
1567 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:491568 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241569 for f in input_api.AffectedFiles(include_deletes=False,
1570 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551571 filename = input_api.os_path.basename(f.LocalPath())
1572 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171573 virtual_depended_on_files.update(_CalculateAddedDeps(
1574 input_api.os_path,
1575 '\n'.join(f.OldContents()),
1576 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551577
[email protected]e871964c2013-05-13 14:14:551578 if not virtual_depended_on_files:
1579 return []
1580
1581 if input_api.is_committing:
1582 if input_api.tbr:
1583 return [output_api.PresubmitNotifyResult(
1584 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271585 if input_api.dry_run:
1586 return [output_api.PresubmitNotifyResult(
1587 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551588 if not input_api.change.issue:
1589 return [output_api.PresubmitError(
1590 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401591 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551592 output = output_api.PresubmitError
1593 else:
1594 output = output_api.PresubmitNotifyResult
1595
1596 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501597 owner_email, reviewers = (
1598 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1599 input_api,
1600 owners_db.email_regexp,
1601 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551602
1603 owner_email = owner_email or input_api.change.author_email
1604
[email protected]de4f7d22013-05-23 14:27:461605 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511606 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461607 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551608 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1609 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411610
1611 # We strip the /DEPS part that was added by
1612 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1613 # directory.
1614 def StripDeps(path):
1615 start_deps = path.rfind('/DEPS')
1616 if start_deps != -1:
1617 return path[:start_deps]
1618 else:
1619 return path
1620 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551621 for path in missing_files]
1622
1623 if unapproved_dependencies:
1624 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151625 output('You need LGTM from owners of depends-on paths in DEPS that were '
1626 'modified in this CL:\n %s' %
1627 '\n '.join(sorted(unapproved_dependencies)))]
1628 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1629 output_list.append(output(
1630 'Suggested missing target path OWNERS:\n %s' %
1631 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551632 return output_list
1633
1634 return []
1635
1636
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491637# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:401638def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491639 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:401640 black_list = (_EXCLUDED_PATHS +
1641 _TEST_CODE_EXCLUDED_PATHS +
1642 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:041643 (r"^base[\\/]logging\.h$",
1644 r"^base[\\/]logging\.cc$",
1645 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
1646 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
1647 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:121648 r"startup_browser_creator\.cc$",
Egor Paskoce145c42018-09-28 19:31:041649 r"^chrome[\\/]installer[\\/]setup[\\/].*",
1650 r"^chrome[\\/]chrome_cleaner[\\/].*",
1651 r"chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031652 r"diagnostics_writer\.cc$",
Egor Paskoce145c42018-09-28 19:31:041653 r"^chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
1654 r"^chromecast[\\/]",
1655 r"^cloud_print[\\/]",
1656 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:481657 r"dump_stability_report_main_win.cc$",
Egor Paskoce145c42018-09-28 19:31:041658 r"^components[\\/]html_viewer[\\/]"
jochen34415e52015-07-10 08:34:311659 r"web_test_delegate_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041660 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:461661 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:041662 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:461663 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041664 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:251665 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:041666 r"^courgette[\\/]courgette_minimal_tool\.cc$",
1667 r"^courgette[\\/]courgette_tool\.cc$",
1668 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:271669 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331670 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:041671 r"^ipc[\\/]ipc_logging\.cc$",
1672 r"^native_client_sdk[\\/]",
1673 r"^remoting[\\/]base[\\/]logging\.h$",
1674 r"^remoting[\\/]host[\\/].*",
1675 r"^sandbox[\\/]linux[\\/].*",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331676 r"^storage[\\/]browser[\\/]fileapi[\\/]" +
1677 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:041678 r"^tools[\\/]",
1679 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
1680 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331681 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]"))
[email protected]85218562013-11-22 07:41:401682 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491683 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:401684
thomasanderson625d3932017-03-29 07:16:581685 log_info = set([])
1686 printf = set([])
[email protected]85218562013-11-22 07:41:401687
1688 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581689 for _, line in f.ChangedContents():
1690 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1691 log_info.add(f.LocalPath())
1692 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1693 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371694
thomasanderson625d3932017-03-29 07:16:581695 if input_api.re.search(r"\bprintf\(", line):
1696 printf.add(f.LocalPath())
1697 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1698 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401699
1700 if log_info:
1701 return [output_api.PresubmitError(
1702 'These files spam the console log with LOG(INFO):',
1703 items=log_info)]
1704 if printf:
1705 return [output_api.PresubmitError(
1706 'These files spam the console log with printf/fprintf:',
1707 items=printf)]
1708 return []
1709
1710
[email protected]49aa76a2013-12-04 06:59:161711def _CheckForAnonymousVariables(input_api, output_api):
1712 """These types are all expected to hold locks while in scope and
1713 so should never be anonymous (which causes them to be immediately
1714 destroyed)."""
1715 they_who_must_be_named = [
1716 'base::AutoLock',
1717 'base::AutoReset',
1718 'base::AutoUnlock',
1719 'SkAutoAlphaRestore',
1720 'SkAutoBitmapShaderInstall',
1721 'SkAutoBlitterChoose',
1722 'SkAutoBounderCommit',
1723 'SkAutoCallProc',
1724 'SkAutoCanvasRestore',
1725 'SkAutoCommentBlock',
1726 'SkAutoDescriptor',
1727 'SkAutoDisableDirectionCheck',
1728 'SkAutoDisableOvalCheck',
1729 'SkAutoFree',
1730 'SkAutoGlyphCache',
1731 'SkAutoHDC',
1732 'SkAutoLockColors',
1733 'SkAutoLockPixels',
1734 'SkAutoMalloc',
1735 'SkAutoMaskFreeImage',
1736 'SkAutoMutexAcquire',
1737 'SkAutoPathBoundsUpdate',
1738 'SkAutoPDFRelease',
1739 'SkAutoRasterClipValidate',
1740 'SkAutoRef',
1741 'SkAutoTime',
1742 'SkAutoTrace',
1743 'SkAutoUnref',
1744 ]
1745 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1746 # bad: base::AutoLock(lock.get());
1747 # not bad: base::AutoLock lock(lock.get());
1748 bad_pattern = input_api.re.compile(anonymous)
1749 # good: new base::AutoLock(lock.get())
1750 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1751 errors = []
1752
1753 for f in input_api.AffectedFiles():
1754 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1755 continue
1756 for linenum, line in f.ChangedContents():
1757 if bad_pattern.search(line) and not good_pattern.search(line):
1758 errors.append('%s:%d' % (f.LocalPath(), linenum))
1759
1760 if errors:
1761 return [output_api.PresubmitError(
1762 'These lines create anonymous variables that need to be named:',
1763 items=errors)]
1764 return []
1765
1766
Peter Kasting4844e46e2018-02-23 07:27:101767def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:531768 # Returns whether |template_str| is of the form <T, U...> for some types T
1769 # and U. Assumes that |template_str| is already in the form <...>.
1770 def HasMoreThanOneArg(template_str):
1771 # Level of <...> nesting.
1772 nesting = 0
1773 for c in template_str:
1774 if c == '<':
1775 nesting += 1
1776 elif c == '>':
1777 nesting -= 1
1778 elif c == ',' and nesting == 1:
1779 return True
1780 return False
1781
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491782 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:101783 sources = lambda affected_file: input_api.FilterSourceFile(
1784 affected_file,
1785 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1786 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491787 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:551788
1789 # Pattern to capture a single "<...>" block of template arguments. It can
1790 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
1791 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
1792 # latter would likely require counting that < and > match, which is not
1793 # expressible in regular languages. Should the need arise, one can introduce
1794 # limited counting (matching up to a total number of nesting depth), which
1795 # should cover all practical cases for already a low nesting limit.
1796 template_arg_pattern = (
1797 r'<[^>]*' # Opening block of <.
1798 r'>([^<]*>)?') # Closing block of >.
1799 # Prefix expressing that whatever follows is not already inside a <...>
1800 # block.
1801 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:101802 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:551803 not_inside_template_arg_pattern
1804 + r'\bstd::unique_ptr'
1805 + template_arg_pattern
1806 + r'\(\)')
1807
1808 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
1809 template_arg_no_array_pattern = (
1810 r'<[^>]*[^]]' # Opening block of <.
1811 r'>([^(<]*[^]]>)?') # Closing block of >.
1812 # Prefix saying that what follows is the start of an expression.
1813 start_of_expr_pattern = r'(=|\breturn|^)\s*'
1814 # Suffix saying that what follows are call parentheses with a non-empty list
1815 # of arguments.
1816 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:531817 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:551818 return_construct_pattern = input_api.re.compile(
1819 start_of_expr_pattern
1820 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:531821 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:551822 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:531823 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:551824 + nonempty_arg_list_pattern)
1825
Vaclav Brozek851d9602018-04-04 16:13:051826 problems_constructor = []
1827 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:101828 for f in input_api.AffectedSourceFiles(sources):
1829 for line_number, line in f.ChangedContents():
1830 # Disallow:
1831 # return std::unique_ptr<T>(foo);
1832 # bar = std::unique_ptr<T>(foo);
1833 # But allow:
1834 # return std::unique_ptr<T[]>(foo);
1835 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:531836 # And also allow cases when the second template argument is present. Those
1837 # cases cannot be handled by std::make_unique:
1838 # return std::unique_ptr<T, U>(foo);
1839 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:051840 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:531841 return_construct_result = return_construct_pattern.search(line)
1842 if return_construct_result and not HasMoreThanOneArg(
1843 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:051844 problems_constructor.append(
1845 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:101846 # Disallow:
1847 # std::unique_ptr<T>()
1848 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051849 problems_nullptr.append(
1850 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1851
1852 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:161853 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:051854 errors.append(output_api.PresubmitError(
1855 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161856 problems_nullptr))
1857 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:051858 errors.append(output_api.PresubmitError(
1859 'The following files use explicit std::unique_ptr constructor.'
1860 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161861 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:101862 return errors
1863
1864
[email protected]999261d2014-03-03 20:08:081865def _CheckUserActionUpdate(input_api, output_api):
1866 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521867 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081868 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521869 # If actions.xml is already included in the changelist, the PRESUBMIT
1870 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081871 return []
1872
[email protected]999261d2014-03-03 20:08:081873 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1874 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521875 current_actions = None
[email protected]999261d2014-03-03 20:08:081876 for f in input_api.AffectedFiles(file_filter=file_filter):
1877 for line_num, line in f.ChangedContents():
1878 match = input_api.re.search(action_re, line)
1879 if match:
[email protected]2f92dec2014-03-07 19:21:521880 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1881 # loaded only once.
1882 if not current_actions:
1883 with open('tools/metrics/actions/actions.xml') as actions_f:
1884 current_actions = actions_f.read()
1885 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081886 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521887 action = 'name="{0}"'.format(action_name)
1888 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081889 return [output_api.PresubmitPromptWarning(
1890 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521891 'tools/metrics/actions/actions.xml. Please run '
1892 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081893 % (f.LocalPath(), line_num, action_name))]
1894 return []
1895
1896
Daniel Cheng13ca61a882017-08-25 15:11:251897def _ImportJSONCommentEater(input_api):
1898 import sys
1899 sys.path = sys.path + [input_api.os_path.join(
1900 input_api.PresubmitLocalPath(),
1901 'tools', 'json_comment_eater')]
1902 import json_comment_eater
1903 return json_comment_eater
1904
1905
[email protected]99171a92014-06-03 08:44:471906def _GetJSONParseError(input_api, filename, eat_comments=True):
1907 try:
1908 contents = input_api.ReadFile(filename)
1909 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:251910 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:131911 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471912
1913 input_api.json.loads(contents)
1914 except ValueError as e:
1915 return e
1916 return None
1917
1918
1919def _GetIDLParseError(input_api, filename):
1920 try:
1921 contents = input_api.ReadFile(filename)
1922 idl_schema = input_api.os_path.join(
1923 input_api.PresubmitLocalPath(),
1924 'tools', 'json_schema_compiler', 'idl_schema.py')
1925 process = input_api.subprocess.Popen(
1926 [input_api.python_executable, idl_schema],
1927 stdin=input_api.subprocess.PIPE,
1928 stdout=input_api.subprocess.PIPE,
1929 stderr=input_api.subprocess.PIPE,
1930 universal_newlines=True)
1931 (_, error) = process.communicate(input=contents)
1932 return error or None
1933 except ValueError as e:
1934 return e
1935
1936
1937def _CheckParseErrors(input_api, output_api):
1938 """Check that IDL and JSON files do not contain syntax errors."""
1939 actions = {
1940 '.idl': _GetIDLParseError,
1941 '.json': _GetJSONParseError,
1942 }
[email protected]99171a92014-06-03 08:44:471943 # Most JSON files are preprocessed and support comments, but these do not.
1944 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:041945 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:471946 ]
1947 # Only run IDL checker on files in these directories.
1948 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:041949 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
1950 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:471951 ]
1952
1953 def get_action(affected_file):
1954 filename = affected_file.LocalPath()
1955 return actions.get(input_api.os_path.splitext(filename)[1])
1956
[email protected]99171a92014-06-03 08:44:471957 def FilterFile(affected_file):
1958 action = get_action(affected_file)
1959 if not action:
1960 return False
1961 path = affected_file.LocalPath()
1962
Sean Kau46e29bc2017-08-28 16:31:161963 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:471964 return False
1965
1966 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:161967 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:471968 return False
1969 return True
1970
1971 results = []
1972 for affected_file in input_api.AffectedFiles(
1973 file_filter=FilterFile, include_deletes=False):
1974 action = get_action(affected_file)
1975 kwargs = {}
1976 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:161977 _MatchesFile(input_api, json_no_comments_patterns,
1978 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:471979 kwargs['eat_comments'] = False
1980 parse_error = action(input_api,
1981 affected_file.AbsoluteLocalPath(),
1982 **kwargs)
1983 if parse_error:
1984 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1985 (affected_file.LocalPath(), parse_error)))
1986 return results
1987
1988
[email protected]760deea2013-12-10 19:33:491989def _CheckJavaStyle(input_api, output_api):
1990 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471991 import sys
[email protected]760deea2013-12-10 19:33:491992 original_sys_path = sys.path
1993 try:
1994 sys.path = sys.path + [input_api.os_path.join(
1995 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1996 import checkstyle
1997 finally:
1998 # Restore sys.path to what it was before.
1999 sys.path = original_sys_path
2000
2001 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092002 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:512003 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:492004
2005
Sean Kau46e29bc2017-08-28 16:31:162006def _MatchesFile(input_api, patterns, path):
2007 for pattern in patterns:
2008 if input_api.re.search(pattern, path):
2009 return True
2010 return False
2011
2012
Daniel Cheng7052cdf2017-11-21 19:23:292013def _GetOwnersFilesToCheckForIpcOwners(input_api):
2014 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172015
Daniel Cheng7052cdf2017-11-21 19:23:292016 Returns:
2017 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2018 contain to cover IPC-related files with noparent reviewer rules.
2019 """
2020 # Whether or not a file affects IPC is (mostly) determined by a simple list
2021 # of filename patterns.
dchenge07de812016-06-20 19:27:172022 file_patterns = [
palmerb19a0932017-01-24 04:00:312023 # Legacy IPC:
dchenge07de812016-06-20 19:27:172024 '*_messages.cc',
2025 '*_messages*.h',
2026 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312027 # Mojo IPC:
dchenge07de812016-06-20 19:27:172028 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472029 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172030 '*_struct_traits*.*',
2031 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312032 '*.typemap',
2033 # Android native IPC:
2034 '*.aidl',
2035 # Blink uses a different file naming convention:
2036 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472037 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172038 '*StructTraits*.*',
2039 '*TypeConverter*.*',
2040 ]
2041
scottmg7a6ed5ba2016-11-04 18:22:042042 # These third_party directories do not contain IPCs, but contain files
2043 # matching the above patterns, which trigger false positives.
2044 exclude_paths = [
2045 'third_party/crashpad/*',
Andres Medinae684cf42018-08-27 18:48:232046 'third_party/protobuf/benchmarks/python/*',
Daniel Chengebe635e2018-07-13 12:36:062047 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:292048 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:042049 ]
2050
dchenge07de812016-06-20 19:27:172051 # Dictionary mapping an OWNERS file path to Patterns.
2052 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2053 # rules ) to a PatternEntry.
2054 # PatternEntry is a dictionary with two keys:
2055 # - 'files': the files that are matched by this pattern
2056 # - 'rules': the per-file rules needed for this pattern
2057 # For example, if we expect OWNERS file to contain rules for *.mojom and
2058 # *_struct_traits*.*, Patterns might look like this:
2059 # {
2060 # '*.mojom': {
2061 # 'files': ...,
2062 # 'rules': [
2063 # 'per-file *.mojom=set noparent',
2064 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2065 # ],
2066 # },
2067 # '*_struct_traits*.*': {
2068 # 'files': ...,
2069 # 'rules': [
2070 # 'per-file *_struct_traits*.*=set noparent',
2071 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2072 # ],
2073 # },
2074 # }
2075 to_check = {}
2076
Daniel Cheng13ca61a882017-08-25 15:11:252077 def AddPatternToCheck(input_file, pattern):
2078 owners_file = input_api.os_path.join(
2079 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2080 if owners_file not in to_check:
2081 to_check[owners_file] = {}
2082 if pattern not in to_check[owners_file]:
2083 to_check[owners_file][pattern] = {
2084 'files': [],
2085 'rules': [
2086 'per-file %s=set noparent' % pattern,
2087 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2088 ]
2089 }
Vaclav Brozekd5de76a2018-03-17 07:57:502090 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252091
dchenge07de812016-06-20 19:27:172092 # Iterate through the affected files to see what we actually need to check
2093 # for. We should only nag patch authors about per-file rules if a file in that
2094 # directory would match that pattern. If a directory only contains *.mojom
2095 # files and no *_messages*.h files, we should only nag about rules for
2096 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252097 for f in input_api.AffectedFiles(include_deletes=False):
2098 # Manifest files don't have a strong naming convention. Instead, scan
Ken Rockot9f668262018-12-21 18:56:362099 # affected files for .json, .cc, and .h files which look like they contain
2100 # a manifest definition.
Sean Kau46e29bc2017-08-28 16:31:162101 if (f.LocalPath().endswith('.json') and
2102 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
2103 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:252104 json_comment_eater = _ImportJSONCommentEater(input_api)
2105 mostly_json_lines = '\n'.join(f.NewContents())
2106 # Comments aren't allowed in strict JSON, so filter them out.
2107 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:432108 try:
2109 json_content = input_api.json.loads(json_lines)
2110 except:
2111 # There's another PRESUBMIT check that already verifies that JSON files
2112 # are not invalid, so no need to emit another warning here.
2113 continue
Daniel Cheng13ca61a882017-08-25 15:11:252114 if 'interface_provider_specs' in json_content:
2115 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
Ken Rockot9f668262018-12-21 18:56:362116 else:
2117 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2118 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2119 if (manifest_pattern.search(f.LocalPath()) and not
2120 test_manifest_pattern.search(f.LocalPath())):
2121 # We expect all actual service manifest files to contain at least one
2122 # qualified reference to service_manager::Manifest.
2123 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2124 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172125 for pattern in file_patterns:
2126 if input_api.fnmatch.fnmatch(
2127 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042128 skip = False
2129 for exclude in exclude_paths:
2130 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2131 skip = True
2132 break
2133 if skip:
2134 continue
Daniel Cheng13ca61a882017-08-25 15:11:252135 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172136 break
2137
Daniel Cheng7052cdf2017-11-21 19:23:292138 return to_check
2139
2140
2141def _CheckIpcOwners(input_api, output_api):
2142 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2143 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2144
2145 if to_check:
2146 # If there are any OWNERS files to check, there are IPC-related changes in
2147 # this CL. Auto-CC the review list.
2148 output_api.AppendCC('[email protected]')
2149
2150 # Go through the OWNERS files to check, filtering out rules that are already
2151 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172152 for owners_file, patterns in to_check.iteritems():
2153 try:
2154 with file(owners_file) as f:
2155 lines = set(f.read().splitlines())
2156 for entry in patterns.itervalues():
2157 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2158 ]
2159 except IOError:
2160 # No OWNERS file, so all the rules are definitely missing.
2161 continue
2162
2163 # All the remaining lines weren't found in OWNERS files, so emit an error.
2164 errors = []
2165 for owners_file, patterns in to_check.iteritems():
2166 missing_lines = []
2167 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502168 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172169 missing_lines.extend(entry['rules'])
2170 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2171 if missing_lines:
2172 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052173 'Because of the presence of files:\n%s\n\n'
2174 '%s needs the following %d lines added:\n\n%s' %
2175 ('\n'.join(files), owners_file, len(missing_lines),
2176 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172177
2178 results = []
2179 if errors:
vabrf5ce3bf92016-07-11 14:52:412180 if input_api.is_committing:
2181 output = output_api.PresubmitError
2182 else:
2183 output = output_api.PresubmitPromptWarning
2184 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592185 'Found OWNERS files that need to be updated for IPC security ' +
2186 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172187 long_text='\n\n'.join(errors)))
2188
2189 return results
2190
2191
jbriance9e12f162016-11-25 07:57:502192def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312193 """Checks that added or removed lines in non third party affected
2194 header files do not lead to new useless class or struct forward
2195 declaration.
jbriance9e12f162016-11-25 07:57:502196 """
2197 results = []
2198 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2199 input_api.re.MULTILINE)
2200 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2201 input_api.re.MULTILINE)
2202 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312203 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192204 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:492205 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:312206 continue
2207
jbriance9e12f162016-11-25 07:57:502208 if not f.LocalPath().endswith('.h'):
2209 continue
2210
2211 contents = input_api.ReadFile(f)
2212 fwd_decls = input_api.re.findall(class_pattern, contents)
2213 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2214
2215 useless_fwd_decls = []
2216 for decl in fwd_decls:
2217 count = sum(1 for _ in input_api.re.finditer(
2218 r'\b%s\b' % input_api.re.escape(decl), contents))
2219 if count == 1:
2220 useless_fwd_decls.append(decl)
2221
2222 if not useless_fwd_decls:
2223 continue
2224
2225 for line in f.GenerateScmDiff().splitlines():
2226 if (line.startswith('-') and not line.startswith('--') or
2227 line.startswith('+') and not line.startswith('++')):
2228 for decl in useless_fwd_decls:
2229 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2230 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242231 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502232 (f.LocalPath(), decl)))
2233 useless_fwd_decls.remove(decl)
2234
2235 return results
2236
2237
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492238# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:292239def _CheckAndroidToastUsage(input_api, output_api):
2240 """Checks that code uses org.chromium.ui.widget.Toast instead of
2241 android.widget.Toast (Chromium Toast doesn't force hardware
2242 acceleration on low-end devices, saving memory).
2243 """
2244 toast_import_pattern = input_api.re.compile(
2245 r'^import android\.widget\.Toast;$')
2246
2247 errors = []
2248
2249 sources = lambda affected_file: input_api.FilterSourceFile(
2250 affected_file,
2251 black_list=(_EXCLUDED_PATHS +
2252 _TEST_CODE_EXCLUDED_PATHS +
2253 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042254 (r'^chromecast[\\/].*',
2255 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492256 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:292257
2258 for f in input_api.AffectedSourceFiles(sources):
2259 for line_num, line in f.ChangedContents():
2260 if toast_import_pattern.search(line):
2261 errors.append("%s:%d" % (f.LocalPath(), line_num))
2262
2263 results = []
2264
2265 if errors:
2266 results.append(output_api.PresubmitError(
2267 'android.widget.Toast usage is detected. Android toasts use hardware'
2268 ' acceleration, and can be\ncostly on low-end devices. Please use'
2269 ' org.chromium.ui.widget.Toast instead.\n'
2270 'Contact [email protected] if you have any questions.',
2271 errors))
2272
2273 return results
2274
2275
dgnaa68d5e2015-06-10 10:08:222276def _CheckAndroidCrLogUsage(input_api, output_api):
2277 """Checks that new logs using org.chromium.base.Log:
2278 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512279 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222280 """
pkotwicza1dd0b002016-05-16 14:41:042281
torne89540622017-03-24 19:41:302282 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042283 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302284 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:042285 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:302286 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:042287 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
2288 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:092289 # The customtabs_benchmark is a small app that does not depend on Chromium
2290 # java pieces.
Egor Paskoce145c42018-09-28 19:31:042291 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:042292 ]
2293
dgnaa68d5e2015-06-10 10:08:222294 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122295 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2296 class_in_base_pattern = input_api.re.compile(
2297 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2298 has_some_log_import_pattern = input_api.re.compile(
2299 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222300 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122301 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222302 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512303 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222304 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222305
Vincent Scheib16d7b272015-09-15 18:09:072306 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222307 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492308 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:042309 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122310
dgnaa68d5e2015-06-10 10:08:222311 tag_decl_errors = []
2312 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122313 tag_errors = []
dgn38736db2015-09-18 19:20:512314 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122315 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222316
2317 for f in input_api.AffectedSourceFiles(sources):
2318 file_content = input_api.ReadFile(f)
2319 has_modified_logs = False
2320
2321 # Per line checks
dgn87d9fb62015-06-12 09:15:122322 if (cr_log_import_pattern.search(file_content) or
2323 (class_in_base_pattern.search(file_content) and
2324 not has_some_log_import_pattern.search(file_content))):
2325 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222326 for line_num, line in f.ChangedContents():
2327
2328 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122329 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222330 if match:
2331 has_modified_logs = True
2332
2333 # Make sure it uses "TAG"
2334 if not match.group('tag') == 'TAG':
2335 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122336 else:
2337 # Report non cr Log function calls in changed lines
2338 for line_num, line in f.ChangedContents():
2339 if log_call_pattern.search(line):
2340 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222341
2342 # Per file checks
2343 if has_modified_logs:
2344 # Make sure the tag is using the "cr" prefix and is not too long
2345 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512346 tag_name = match.group('name') if match else None
2347 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222348 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512349 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222350 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512351 elif '.' in tag_name:
2352 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222353
2354 results = []
2355 if tag_decl_errors:
2356 results.append(output_api.PresubmitPromptWarning(
2357 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512358 '"private static final String TAG = "<package tag>".\n'
2359 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222360 tag_decl_errors))
2361
2362 if tag_length_errors:
2363 results.append(output_api.PresubmitError(
2364 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512365 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222366 tag_length_errors))
2367
2368 if tag_errors:
2369 results.append(output_api.PresubmitPromptWarning(
2370 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2371 tag_errors))
2372
dgn87d9fb62015-06-12 09:15:122373 if util_log_errors:
dgn4401aa52015-04-29 16:26:172374 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122375 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2376 util_log_errors))
2377
dgn38736db2015-09-18 19:20:512378 if tag_with_dot_errors:
2379 results.append(output_api.PresubmitPromptWarning(
2380 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2381 tag_with_dot_errors))
2382
dgn4401aa52015-04-29 16:26:172383 return results
2384
2385
Yoland Yanb92fa522017-08-28 17:37:062386def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2387 """Checks that junit.framework.* is no longer used."""
2388 deprecated_junit_framework_pattern = input_api.re.compile(
2389 r'^import junit\.framework\..*;',
2390 input_api.re.MULTILINE)
2391 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492392 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062393 errors = []
2394 for f in input_api.AffectedFiles(sources):
2395 for line_num, line in f.ChangedContents():
2396 if deprecated_junit_framework_pattern.search(line):
2397 errors.append("%s:%d" % (f.LocalPath(), line_num))
2398
2399 results = []
2400 if errors:
2401 results.append(output_api.PresubmitError(
2402 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2403 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2404 ' if you have any question.', errors))
2405 return results
2406
2407
2408def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2409 """Checks that if new Java test classes have inheritance.
2410 Either the new test class is JUnit3 test or it is a JUnit4 test class
2411 with a base class, either case is undesirable.
2412 """
2413 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2414
2415 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492416 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062417 errors = []
2418 for f in input_api.AffectedFiles(sources):
2419 if not f.OldContents():
2420 class_declaration_start_flag = False
2421 for line_num, line in f.ChangedContents():
2422 if class_declaration_pattern.search(line):
2423 class_declaration_start_flag = True
2424 if class_declaration_start_flag and ' extends ' in line:
2425 errors.append('%s:%d' % (f.LocalPath(), line_num))
2426 if '{' in line:
2427 class_declaration_start_flag = False
2428
2429 results = []
2430 if errors:
2431 results.append(output_api.PresubmitPromptWarning(
2432 'The newly created files include Test classes that inherits from base'
2433 ' class. Please do not use inheritance in JUnit4 tests or add new'
2434 ' JUnit3 tests. Contact [email protected] if you have any'
2435 ' questions.', errors))
2436 return results
2437
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202438
yolandyan45001472016-12-21 21:12:422439def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2440 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2441 deprecated_annotation_import_pattern = input_api.re.compile(
2442 r'^import android\.test\.suitebuilder\.annotation\..*;',
2443 input_api.re.MULTILINE)
2444 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492445 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:422446 errors = []
2447 for f in input_api.AffectedFiles(sources):
2448 for line_num, line in f.ChangedContents():
2449 if deprecated_annotation_import_pattern.search(line):
2450 errors.append("%s:%d" % (f.LocalPath(), line_num))
2451
2452 results = []
2453 if errors:
2454 results.append(output_api.PresubmitError(
2455 'Annotations in android.test.suitebuilder.annotation have been'
2456 ' deprecated since API level 24. Please use android.support.test.filters'
2457 ' from //third_party/android_support_test_runner:runner_java instead.'
2458 ' Contact [email protected] if you have any questions.', errors))
2459 return results
2460
2461
agrieve7b6479d82015-10-07 14:24:222462def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2463 """Checks if MDPI assets are placed in a correct directory."""
2464 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2465 ('/res/drawable/' in f.LocalPath() or
2466 '/res/drawable-ldrtl/' in f.LocalPath()))
2467 errors = []
2468 for f in input_api.AffectedFiles(include_deletes=False,
2469 file_filter=file_filter):
2470 errors.append(' %s' % f.LocalPath())
2471
2472 results = []
2473 if errors:
2474 results.append(output_api.PresubmitError(
2475 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2476 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2477 '/res/drawable-ldrtl/.\n'
2478 'Contact [email protected] if you have questions.', errors))
2479 return results
2480
2481
Nate Fischer535972b2017-09-16 01:06:182482def _CheckAndroidWebkitImports(input_api, output_api):
2483 """Checks that code uses org.chromium.base.Callback instead of
2484 android.widget.ValueCallback except in the WebView glue layer.
2485 """
2486 valuecallback_import_pattern = input_api.re.compile(
2487 r'^import android\.webkit\.ValueCallback;$')
2488
2489 errors = []
2490
2491 sources = lambda affected_file: input_api.FilterSourceFile(
2492 affected_file,
2493 black_list=(_EXCLUDED_PATHS +
2494 _TEST_CODE_EXCLUDED_PATHS +
2495 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042496 (r'^android_webview[\\/]glue[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492497 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:182498
2499 for f in input_api.AffectedSourceFiles(sources):
2500 for line_num, line in f.ChangedContents():
2501 if valuecallback_import_pattern.search(line):
2502 errors.append("%s:%d" % (f.LocalPath(), line_num))
2503
2504 results = []
2505
2506 if errors:
2507 results.append(output_api.PresubmitError(
2508 'android.webkit.ValueCallback usage is detected outside of the glue'
2509 ' layer. To stay compatible with the support library, android.webkit.*'
2510 ' classes should only be used inside the glue layer and'
2511 ' org.chromium.base.Callback should be used instead.',
2512 errors))
2513
2514 return results
2515
2516
Becky Zhou7c69b50992018-12-10 19:37:572517def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
2518 """Checks Android XML styles """
2519 import sys
2520 original_sys_path = sys.path
2521 try:
2522 sys.path = sys.path + [input_api.os_path.join(
2523 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
2524 import checkxmlstyle
2525 finally:
2526 # Restore sys.path to what it was before.
2527 sys.path = original_sys_path
2528
2529 if is_check_on_upload:
2530 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
2531 else:
2532 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
2533
2534
agrievef32bcc72016-04-04 14:57:402535class PydepsChecker(object):
2536 def __init__(self, input_api, pydeps_files):
2537 self._file_cache = {}
2538 self._input_api = input_api
2539 self._pydeps_files = pydeps_files
2540
2541 def _LoadFile(self, path):
2542 """Returns the list of paths within a .pydeps file relative to //."""
2543 if path not in self._file_cache:
2544 with open(path) as f:
2545 self._file_cache[path] = f.read()
2546 return self._file_cache[path]
2547
2548 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2549 """Returns an interable of paths within the .pydep, relativized to //."""
2550 os_path = self._input_api.os_path
2551 pydeps_dir = os_path.dirname(pydeps_path)
2552 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2553 if not l.startswith('*'))
2554 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2555
2556 def _CreateFilesToPydepsMap(self):
2557 """Returns a map of local_path -> list_of_pydeps."""
2558 ret = {}
2559 for pydep_local_path in self._pydeps_files:
2560 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2561 ret.setdefault(path, []).append(pydep_local_path)
2562 return ret
2563
2564 def ComputeAffectedPydeps(self):
2565 """Returns an iterable of .pydeps files that might need regenerating."""
2566 affected_pydeps = set()
2567 file_to_pydeps_map = None
2568 for f in self._input_api.AffectedFiles(include_deletes=True):
2569 local_path = f.LocalPath()
2570 if local_path == 'DEPS':
2571 return self._pydeps_files
2572 elif local_path.endswith('.pydeps'):
2573 if local_path in self._pydeps_files:
2574 affected_pydeps.add(local_path)
2575 elif local_path.endswith('.py'):
2576 if file_to_pydeps_map is None:
2577 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2578 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2579 return affected_pydeps
2580
2581 def DetermineIfStale(self, pydeps_path):
2582 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412583 import difflib
John Budorick47ca3fe2018-02-10 00:53:102584 import os
2585
agrievef32bcc72016-04-04 14:57:402586 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2587 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102588 env = dict(os.environ)
2589 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402590 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102591 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412592 old_contents = old_pydeps_data[2:]
2593 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402594 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412595 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402596
2597
2598def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2599 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402600 # This check is for Python dependency lists (.pydeps files), and involves
2601 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2602 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282603 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002604 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022605 # TODO(agrieve): Update when there's a better way to detect
2606 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402607 is_android = input_api.os_path.exists('third_party/android_tools')
2608 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2609 results = []
2610 # First, check for new / deleted .pydeps.
2611 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032612 # Check whether we are running the presubmit check for a file in src.
2613 # f.LocalPath is relative to repo (src, or internal repo).
2614 # os_path.exists is relative to src repo.
2615 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2616 # to src and we can conclude that the pydeps is in src.
2617 if input_api.os_path.exists(f.LocalPath()):
2618 if f.LocalPath().endswith('.pydeps'):
2619 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2620 results.append(output_api.PresubmitError(
2621 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2622 'remove %s' % f.LocalPath()))
2623 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2624 results.append(output_api.PresubmitError(
2625 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2626 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402627
2628 if results:
2629 return results
2630
2631 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2632
2633 for pydep_path in checker.ComputeAffectedPydeps():
2634 try:
phajdan.jr0d9878552016-11-04 10:49:412635 result = checker.DetermineIfStale(pydep_path)
2636 if result:
2637 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402638 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412639 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2640 'To regenerate, run:\n\n %s' %
2641 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402642 except input_api.subprocess.CalledProcessError as error:
2643 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2644 long_text=error.output)]
2645
2646 return results
2647
2648
glidere61efad2015-02-18 17:39:432649def _CheckSingletonInHeaders(input_api, output_api):
2650 """Checks to make sure no header files have |Singleton<|."""
2651 def FileFilter(affected_file):
2652 # It's ok for base/memory/singleton.h to have |Singleton<|.
2653 black_list = (_EXCLUDED_PATHS +
2654 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042655 (r"^base[\\/]memory[\\/]singleton\.h$",
2656 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:472657 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432658 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2659
sergeyu34d21222015-09-16 00:11:442660 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432661 files = []
2662 for f in input_api.AffectedSourceFiles(FileFilter):
2663 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2664 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2665 contents = input_api.ReadFile(f)
2666 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242667 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432668 pattern.search(line)):
2669 files.append(f)
2670 break
2671
2672 if files:
yolandyandaabc6d2016-04-18 18:29:392673 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442674 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432675 'Please move them to an appropriate source file so that the ' +
2676 'template gets instantiated in a single compilation unit.',
2677 files) ]
2678 return []
2679
2680
[email protected]fd20b902014-05-09 02:14:532681_DEPRECATED_CSS = [
2682 # Values
2683 ( "-webkit-box", "flex" ),
2684 ( "-webkit-inline-box", "inline-flex" ),
2685 ( "-webkit-flex", "flex" ),
2686 ( "-webkit-inline-flex", "inline-flex" ),
2687 ( "-webkit-min-content", "min-content" ),
2688 ( "-webkit-max-content", "max-content" ),
2689
2690 # Properties
2691 ( "-webkit-background-clip", "background-clip" ),
2692 ( "-webkit-background-origin", "background-origin" ),
2693 ( "-webkit-background-size", "background-size" ),
2694 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442695 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532696
2697 # Functions
2698 ( "-webkit-gradient", "gradient" ),
2699 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2700 ( "-webkit-linear-gradient", "linear-gradient" ),
2701 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2702 ( "-webkit-radial-gradient", "radial-gradient" ),
2703 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2704]
2705
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202706
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492707# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242708def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532709 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252710 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342711 documentation and iOS CSS for dom distiller
2712 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252713 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532714 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492715 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:252716 black_list = (_EXCLUDED_PATHS +
2717 _TEST_CODE_EXCLUDED_PATHS +
2718 input_api.DEFAULT_BLACK_LIST +
2719 (r"^chrome/common/extensions/docs",
2720 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342721 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442722 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252723 r"^native_client_sdk"))
2724 file_filter = lambda f: input_api.FilterSourceFile(
2725 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532726 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2727 for line_num, line in fpath.ChangedContents():
2728 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022729 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532730 results.append(output_api.PresubmitError(
2731 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2732 (fpath.LocalPath(), line_num, deprecated_value, value)))
2733 return results
2734
mohan.reddyf21db962014-10-16 12:26:472735
dbeam070cfe62014-10-22 06:44:022736_DEPRECATED_JS = [
2737 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2738 ( "__defineGetter__", "Object.defineProperty" ),
2739 ( "__defineSetter__", "Object.defineProperty" ),
2740]
2741
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202742
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492743# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242744def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022745 """Make sure that we don't use deprecated JS in Chrome code."""
2746 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492747 file_inclusion_pattern = [r".+\.js$"] # TODO(dbeam): .html?
dbeam070cfe62014-10-22 06:44:022748 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2749 input_api.DEFAULT_BLACK_LIST)
2750 file_filter = lambda f: input_api.FilterSourceFile(
2751 f, white_list=file_inclusion_pattern, black_list=black_list)
2752 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2753 for lnum, line in fpath.ChangedContents():
2754 for (deprecated, replacement) in _DEPRECATED_JS:
2755 if deprecated in line:
2756 results.append(output_api.PresubmitError(
2757 "%s:%d: Use of deprecated JS %s, use %s instead" %
2758 (fpath.LocalPath(), lnum, deprecated, replacement)))
2759 return results
2760
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202761
rlanday6802cf632017-05-30 17:48:362762def _CheckForRelativeIncludes(input_api, output_api):
2763 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2764 import sys
2765 original_sys_path = sys.path
2766 try:
2767 sys.path = sys.path + [input_api.os_path.join(
2768 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2769 from cpp_checker import CppChecker
2770 finally:
2771 # Restore sys.path to what it was before.
2772 sys.path = original_sys_path
2773
2774 bad_files = {}
2775 for f in input_api.AffectedFiles(include_deletes=False):
2776 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:492777 not f.LocalPath().startswith('third_party/blink') and
2778 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:362779 continue
2780
2781 if not CppChecker.IsCppFile(f.LocalPath()):
2782 continue
2783
Vaclav Brozekd5de76a2018-03-17 07:57:502784 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362785 if "#include" in line and "../" in line]
2786 if not relative_includes:
2787 continue
2788 bad_files[f.LocalPath()] = relative_includes
2789
2790 if not bad_files:
2791 return []
2792
2793 error_descriptions = []
2794 for file_path, bad_lines in bad_files.iteritems():
2795 error_description = file_path
2796 for line in bad_lines:
2797 error_description += '\n ' + line
2798 error_descriptions.append(error_description)
2799
2800 results = []
2801 results.append(output_api.PresubmitError(
2802 'You added one or more relative #include paths (including "../").\n'
2803 'These shouldn\'t be used because they can be used to include headers\n'
2804 'from code that\'s not correctly specified as a dependency in the\n'
2805 'relevant BUILD.gn file(s).',
2806 error_descriptions))
2807
2808 return results
2809
Takeshi Yoshinoe387aa32017-08-02 13:16:132810
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202811def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2812 if not isinstance(key, ast.Str):
2813 return 'Key at line %d must be a string literal' % key.lineno
2814 if not isinstance(value, ast.Dict):
2815 return 'Value at line %d must be a dict' % value.lineno
2816 if len(value.keys) != 1:
2817 return 'Dict at line %d must have single entry' % value.lineno
2818 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2819 return (
2820 'Entry at line %d must have a string literal \'filepath\' as key' %
2821 value.lineno)
2822 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132823
Takeshi Yoshinoe387aa32017-08-02 13:16:132824
Sergey Ulanov4af16052018-11-08 02:41:462825def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202826 if not isinstance(key, ast.Str):
2827 return 'Key at line %d must be a string literal' % key.lineno
2828 if not isinstance(value, ast.List):
2829 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:462830 for element in value.elts:
2831 if not isinstance(element, ast.Str):
2832 return 'Watchlist elements on line %d is not a string' % key.lineno
2833 if not email_regex.match(element.s):
2834 return ('Watchlist element on line %d doesn\'t look like a valid ' +
2835 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202836 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132837
Takeshi Yoshinoe387aa32017-08-02 13:16:132838
Sergey Ulanov4af16052018-11-08 02:41:462839def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202840 mismatch_template = (
2841 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2842 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132843
Sergey Ulanov4af16052018-11-08 02:41:462844 email_regex = input_api.re.compile(
2845 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
2846
2847 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202848 i = 0
2849 last_key = ''
2850 while True:
2851 if i >= len(wd_dict.keys):
2852 if i >= len(w_dict.keys):
2853 return None
2854 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2855 elif i >= len(w_dict.keys):
2856 return (
2857 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132858
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202859 wd_key = wd_dict.keys[i]
2860 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132861
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202862 result = _CheckWatchlistDefinitionsEntrySyntax(
2863 wd_key, wd_dict.values[i], ast)
2864 if result is not None:
2865 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132866
Sergey Ulanov4af16052018-11-08 02:41:462867 result = _CheckWatchlistsEntrySyntax(
2868 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202869 if result is not None:
2870 return 'Bad entry in WATCHLISTS dict: %s' % result
2871
2872 if wd_key.s != w_key.s:
2873 return mismatch_template % (
2874 '%s at line %d' % (wd_key.s, wd_key.lineno),
2875 '%s at line %d' % (w_key.s, w_key.lineno))
2876
2877 if wd_key.s < last_key:
2878 return (
2879 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2880 (wd_key.lineno, w_key.lineno))
2881 last_key = wd_key.s
2882
2883 i = i + 1
2884
2885
Sergey Ulanov4af16052018-11-08 02:41:462886def _CheckWATCHLISTSSyntax(expression, input_api):
2887 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202888 if not isinstance(expression, ast.Expression):
2889 return 'WATCHLISTS file must contain a valid expression'
2890 dictionary = expression.body
2891 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2892 return 'WATCHLISTS file must have single dict with exactly two entries'
2893
2894 first_key = dictionary.keys[0]
2895 first_value = dictionary.values[0]
2896 second_key = dictionary.keys[1]
2897 second_value = dictionary.values[1]
2898
2899 if (not isinstance(first_key, ast.Str) or
2900 first_key.s != 'WATCHLIST_DEFINITIONS' or
2901 not isinstance(first_value, ast.Dict)):
2902 return (
2903 'The first entry of the dict in WATCHLISTS file must be '
2904 'WATCHLIST_DEFINITIONS dict')
2905
2906 if (not isinstance(second_key, ast.Str) or
2907 second_key.s != 'WATCHLISTS' or
2908 not isinstance(second_value, ast.Dict)):
2909 return (
2910 'The second entry of the dict in WATCHLISTS file must be '
2911 'WATCHLISTS dict')
2912
Sergey Ulanov4af16052018-11-08 02:41:462913 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:132914
2915
2916def _CheckWATCHLISTS(input_api, output_api):
2917 for f in input_api.AffectedFiles(include_deletes=False):
2918 if f.LocalPath() == 'WATCHLISTS':
2919 contents = input_api.ReadFile(f, 'r')
2920
2921 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202922 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132923 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202924 # Get an AST tree for it and scan the tree for detailed style checking.
2925 expression = input_api.ast.parse(
2926 contents, filename='WATCHLISTS', mode='eval')
2927 except ValueError as e:
2928 return [output_api.PresubmitError(
2929 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2930 except SyntaxError as e:
2931 return [output_api.PresubmitError(
2932 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2933 except TypeError as e:
2934 return [output_api.PresubmitError(
2935 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132936
Sergey Ulanov4af16052018-11-08 02:41:462937 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202938 if result is not None:
2939 return [output_api.PresubmitError(result)]
2940 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132941
2942 return []
2943
2944
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192945def _CheckNewHeaderWithoutGnChange(input_api, output_api):
2946 """Checks that newly added header files have corresponding GN changes.
2947 Note that this is only a heuristic. To be precise, run script:
2948 build/check_gn_headers.py.
2949 """
2950
2951 def headers(f):
2952 return input_api.FilterSourceFile(
2953 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
2954
2955 new_headers = []
2956 for f in input_api.AffectedSourceFiles(headers):
2957 if f.Action() != 'A':
2958 continue
2959 new_headers.append(f.LocalPath())
2960
2961 def gn_files(f):
2962 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
2963
2964 all_gn_changed_contents = ''
2965 for f in input_api.AffectedSourceFiles(gn_files):
2966 for _, line in f.ChangedContents():
2967 all_gn_changed_contents += line
2968
2969 problems = []
2970 for header in new_headers:
2971 basename = input_api.os_path.basename(header)
2972 if basename not in all_gn_changed_contents:
2973 problems.append(header)
2974
2975 if problems:
2976 return [output_api.PresubmitPromptWarning(
2977 'Missing GN changes for new header files', items=sorted(problems),
2978 long_text='Please double check whether newly added header files need '
2979 'corresponding changes in gn or gni files.\nThis checking is only a '
2980 'heuristic. Run build/check_gn_headers.py to be precise.\n'
2981 'Read https://crbug.com/661774 for more info.')]
2982 return []
2983
2984
Michael Giuffridad3bc8672018-10-25 22:48:022985def _CheckCorrectProductNameInMessages(input_api, output_api):
2986 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
2987
2988 This assumes we won't intentionally reference one product from the other
2989 product.
2990 """
2991 all_problems = []
2992 test_cases = [{
2993 "filename_postfix": "google_chrome_strings.grd",
2994 "correct_name": "Chrome",
2995 "incorrect_name": "Chromium",
2996 }, {
2997 "filename_postfix": "chromium_strings.grd",
2998 "correct_name": "Chromium",
2999 "incorrect_name": "Chrome",
3000 }]
3001
3002 for test_case in test_cases:
3003 problems = []
3004 filename_filter = lambda x: x.LocalPath().endswith(
3005 test_case["filename_postfix"])
3006
3007 # Check each new line. Can yield false positives in multiline comments, but
3008 # easier than trying to parse the XML because messages can have nested
3009 # children, and associating message elements with affected lines is hard.
3010 for f in input_api.AffectedSourceFiles(filename_filter):
3011 for line_num, line in f.ChangedContents():
3012 if "<message" in line or "<!--" in line or "-->" in line:
3013 continue
3014 if test_case["incorrect_name"] in line:
3015 problems.append(
3016 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
3017
3018 if problems:
3019 message = (
3020 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
3021 % (test_case["correct_name"], test_case["correct_name"],
3022 test_case["incorrect_name"]))
3023 all_problems.append(
3024 output_api.PresubmitPromptWarning(message, items=problems))
3025
3026 return all_problems
3027
3028
dgnaa68d5e2015-06-10 10:08:223029def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:573030 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:223031 results = []
dgnaa68d5e2015-06-10 10:08:223032 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:223033 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:293034 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:063035 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
3036 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:423037 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:183038 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573039 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
3040 return results
3041
3042def _AndroidSpecificOnCommitChecks(input_api, output_api):
3043 """Groups commit checks that target android code."""
3044 results = []
3045 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:223046 return results
3047
3048
[email protected]22c9bd72011-03-27 16:47:393049def _CommonChecks(input_api, output_api):
3050 """Checks common to both upload and commit."""
3051 results = []
3052 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:383053 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:543054 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:083055
3056 author = input_api.change.author_email
3057 if author and author not in _KNOWN_ROBOTS:
3058 results.extend(
3059 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
3060
[email protected]55459852011-08-10 15:17:193061 results.extend(
[email protected]760deea2013-12-10 19:33:493062 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:233063 results.extend(
3064 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:543065 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:183066 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:343067 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:523068 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:223069 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:443070 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:593071 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:063072 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:123073 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:183074 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:223075 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:303076 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:493077 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:033078 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:493079 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:443080 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:273081 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:073082 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:543083 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:443084 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:393085 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:553086 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:043087 results.extend(
3088 input_api.canned_checks.CheckChangeHasNoTabs(
3089 input_api,
3090 output_api,
3091 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:403092 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:163093 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:083094 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:243095 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
3096 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:473097 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:043098 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:053099 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:143100 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:233101 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:433102 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:403103 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:153104 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:173105 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:503106 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:363107 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:133108 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:433109 results.extend(input_api.RunTests(
3110 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143111 results.extend(_CheckTranslationScreenshots(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:023112 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:243113
Vaclav Brozekcdc7defb2018-03-20 09:54:353114 for f in input_api.AffectedFiles():
3115 path, name = input_api.os_path.split(f.LocalPath())
3116 if name == 'PRESUBMIT.py':
3117 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:003118 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
3119 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:073120 # The PRESUBMIT.py file (and the directory containing it) might
3121 # have been affected by being moved or removed, so only try to
3122 # run the tests if they still exist.
3123 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
3124 input_api, output_api, full_path,
3125 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:393126 return results
[email protected]1f7b4172010-01-28 01:17:343127
[email protected]b337cb5b2011-01-23 21:24:053128
[email protected]b8079ae4a2012-12-05 19:56:493129def _CheckPatchFiles(input_api, output_api):
3130 problems = [f.LocalPath() for f in input_api.AffectedFiles()
3131 if f.LocalPath().endswith(('.orig', '.rej'))]
3132 if problems:
3133 return [output_api.PresubmitError(
3134 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:033135 else:
3136 return []
[email protected]b8079ae4a2012-12-05 19:56:493137
3138
Kent Tamura5a8755d2017-06-29 23:37:073139def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:213140 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
3141 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
3142 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:073143 include_re = input_api.re.compile(
3144 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
3145 extension_re = input_api.re.compile(r'\.[a-z]+$')
3146 errors = []
3147 for f in input_api.AffectedFiles():
3148 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
3149 continue
3150 found_line_number = None
3151 found_macro = None
3152 for line_num, line in f.ChangedContents():
3153 match = macro_re.search(line)
3154 if match:
3155 found_line_number = line_num
3156 found_macro = match.group(2)
3157 break
3158 if not found_line_number:
3159 continue
3160
3161 found_include = False
3162 for line in f.NewContents():
3163 if include_re.search(line):
3164 found_include = True
3165 break
3166 if found_include:
3167 continue
3168
3169 if not f.LocalPath().endswith('.h'):
3170 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
3171 try:
3172 content = input_api.ReadFile(primary_header_path, 'r')
3173 if include_re.search(content):
3174 continue
3175 except IOError:
3176 pass
3177 errors.append('%s:%d %s macro is used without including build/'
3178 'build_config.h.'
3179 % (f.LocalPath(), found_line_number, found_macro))
3180 if errors:
3181 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
3182 return []
3183
3184
[email protected]b00342e7f2013-03-26 16:21:543185def _DidYouMeanOSMacro(bad_macro):
3186 try:
3187 return {'A': 'OS_ANDROID',
3188 'B': 'OS_BSD',
3189 'C': 'OS_CHROMEOS',
3190 'F': 'OS_FREEBSD',
3191 'L': 'OS_LINUX',
3192 'M': 'OS_MACOSX',
3193 'N': 'OS_NACL',
3194 'O': 'OS_OPENBSD',
3195 'P': 'OS_POSIX',
3196 'S': 'OS_SOLARIS',
3197 'W': 'OS_WIN'}[bad_macro[3].upper()]
3198 except KeyError:
3199 return ''
3200
3201
3202def _CheckForInvalidOSMacrosInFile(input_api, f):
3203 """Check for sensible looking, totally invalid OS macros."""
3204 preprocessor_statement = input_api.re.compile(r'^\s*#')
3205 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
3206 results = []
3207 for lnum, line in f.ChangedContents():
3208 if preprocessor_statement.search(line):
3209 for match in os_macro.finditer(line):
3210 if not match.group(1) in _VALID_OS_MACROS:
3211 good = _DidYouMeanOSMacro(match.group(1))
3212 did_you_mean = ' (did you mean %s?)' % good if good else ''
3213 results.append(' %s:%d %s%s' % (f.LocalPath(),
3214 lnum,
3215 match.group(1),
3216 did_you_mean))
3217 return results
3218
3219
3220def _CheckForInvalidOSMacros(input_api, output_api):
3221 """Check all affected files for invalid OS macros."""
3222 bad_macros = []
tzik3f295992018-12-04 20:32:233223 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:473224 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:543225 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
3226
3227 if not bad_macros:
3228 return []
3229
3230 return [output_api.PresubmitError(
3231 'Possibly invalid OS macro[s] found. Please fix your code\n'
3232 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
3233
lliabraa35bab3932014-10-01 12:16:443234
3235def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
3236 """Check all affected files for invalid "if defined" macros."""
3237 ALWAYS_DEFINED_MACROS = (
3238 "TARGET_CPU_PPC",
3239 "TARGET_CPU_PPC64",
3240 "TARGET_CPU_68K",
3241 "TARGET_CPU_X86",
3242 "TARGET_CPU_ARM",
3243 "TARGET_CPU_MIPS",
3244 "TARGET_CPU_SPARC",
3245 "TARGET_CPU_ALPHA",
3246 "TARGET_IPHONE_SIMULATOR",
3247 "TARGET_OS_EMBEDDED",
3248 "TARGET_OS_IPHONE",
3249 "TARGET_OS_MAC",
3250 "TARGET_OS_UNIX",
3251 "TARGET_OS_WIN32",
3252 )
3253 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
3254 results = []
3255 for lnum, line in f.ChangedContents():
3256 for match in ifdef_macro.finditer(line):
3257 if match.group(1) in ALWAYS_DEFINED_MACROS:
3258 always_defined = ' %s is always defined. ' % match.group(1)
3259 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
3260 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
3261 lnum,
3262 always_defined,
3263 did_you_mean))
3264 return results
3265
3266
3267def _CheckForInvalidIfDefinedMacros(input_api, output_api):
3268 """Check all affected files for invalid "if defined" macros."""
3269 bad_macros = []
3270 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:213271 if f.LocalPath().startswith('third_party/sqlite/'):
3272 continue
lliabraa35bab3932014-10-01 12:16:443273 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3274 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3275
3276 if not bad_macros:
3277 return []
3278
3279 return [output_api.PresubmitError(
3280 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3281 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3282 bad_macros)]
3283
3284
mlamouria82272622014-09-16 18:45:043285def _CheckForIPCRules(input_api, output_api):
3286 """Check for same IPC rules described in
3287 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3288 """
3289 base_pattern = r'IPC_ENUM_TRAITS\('
3290 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3291 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3292
3293 problems = []
3294 for f in input_api.AffectedSourceFiles(None):
3295 local_path = f.LocalPath()
3296 if not local_path.endswith('.h'):
3297 continue
3298 for line_number, line in f.ChangedContents():
3299 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3300 problems.append(
3301 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3302
3303 if problems:
3304 return [output_api.PresubmitPromptWarning(
3305 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
3306 else:
3307 return []
3308
[email protected]b00342e7f2013-03-26 16:21:543309
Stephen Martinis97a394142018-06-07 23:06:053310def _CheckForLongPathnames(input_api, output_api):
3311 """Check to make sure no files being submitted have long paths.
3312 This causes issues on Windows.
3313 """
3314 problems = []
3315 for f in input_api.AffectedSourceFiles(None):
3316 local_path = f.LocalPath()
3317 # Windows has a path limit of 260 characters. Limit path length to 200 so
3318 # that we have some extra for the prefix on dev machines and the bots.
3319 if len(local_path) > 200:
3320 problems.append(local_path)
3321
3322 if problems:
3323 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
3324 else:
3325 return []
3326
3327
Daniel Bratell8ba52722018-03-02 16:06:143328def _CheckForIncludeGuards(input_api, output_api):
3329 """Check that header files have proper guards against multiple inclusion.
3330 If a file should not have such guards (and it probably should) then it
3331 should include the string "no-include-guard-because-multiply-included".
3332 """
Daniel Bratell6a75baef62018-06-04 10:04:453333 def is_chromium_header_file(f):
3334 # We only check header files under the control of the Chromium
3335 # project. That is, those outside third_party apart from
3336 # third_party/blink.
3337 file_with_path = input_api.os_path.normpath(f.LocalPath())
3338 return (file_with_path.endswith('.h') and
3339 (not file_with_path.startswith('third_party') or
3340 file_with_path.startswith(
3341 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:143342
3343 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:343344 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:143345
3346 errors = []
3347
Daniel Bratell6a75baef62018-06-04 10:04:453348 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:143349 guard_name = None
3350 guard_line_number = None
3351 seen_guard_end = False
3352
3353 file_with_path = input_api.os_path.normpath(f.LocalPath())
3354 base_file_name = input_api.os_path.splitext(
3355 input_api.os_path.basename(file_with_path))[0]
3356 upper_base_file_name = base_file_name.upper()
3357
3358 expected_guard = replace_special_with_underscore(
3359 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:143360
3361 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:573362 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
3363 # are too many (1000+) files with slight deviations from the
3364 # coding style. The most important part is that the include guard
3365 # is there, and that it's unique, not the name so this check is
3366 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:143367 #
3368 # As code becomes more uniform, this could be made stricter.
3369
3370 guard_name_pattern_list = [
3371 # Anything with the right suffix (maybe with an extra _).
3372 r'\w+_H__?',
3373
Daniel Bratell39b5b062018-05-16 18:09:573374 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:143375 r'\w+_h',
3376
3377 # Anything including the uppercase name of the file.
3378 r'\w*' + input_api.re.escape(replace_special_with_underscore(
3379 upper_base_file_name)) + r'\w*',
3380 ]
3381 guard_name_pattern = '|'.join(guard_name_pattern_list)
3382 guard_pattern = input_api.re.compile(
3383 r'#ifndef\s+(' + guard_name_pattern + ')')
3384
3385 for line_number, line in enumerate(f.NewContents()):
3386 if 'no-include-guard-because-multiply-included' in line:
3387 guard_name = 'DUMMY' # To not trigger check outside the loop.
3388 break
3389
3390 if guard_name is None:
3391 match = guard_pattern.match(line)
3392 if match:
3393 guard_name = match.group(1)
3394 guard_line_number = line_number
3395
Daniel Bratell39b5b062018-05-16 18:09:573396 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:453397 # don't match the chromium style guide, but new files should
3398 # get it right.
3399 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:573400 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:143401 errors.append(output_api.PresubmitPromptWarning(
3402 'Header using the wrong include guard name %s' % guard_name,
3403 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:573404 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:143405 else:
3406 # The line after #ifndef should have a #define of the same name.
3407 if line_number == guard_line_number + 1:
3408 expected_line = '#define %s' % guard_name
3409 if line != expected_line:
3410 errors.append(output_api.PresubmitPromptWarning(
3411 'Missing "%s" for include guard' % expected_line,
3412 ['%s:%d' % (f.LocalPath(), line_number + 1)],
3413 'Expected: %r\nGot: %r' % (expected_line, line)))
3414
3415 if not seen_guard_end and line == '#endif // %s' % guard_name:
3416 seen_guard_end = True
3417 elif seen_guard_end:
3418 if line.strip() != '':
3419 errors.append(output_api.PresubmitPromptWarning(
3420 'Include guard %s not covering the whole file' % (
3421 guard_name), [f.LocalPath()]))
3422 break # Nothing else to check and enough to warn once.
3423
3424 if guard_name is None:
3425 errors.append(output_api.PresubmitPromptWarning(
3426 'Missing include guard %s' % expected_guard,
3427 [f.LocalPath()],
3428 'Missing include guard in %s\n'
3429 'Recommended name: %s\n'
3430 'This check can be disabled by having the string\n'
3431 'no-include-guard-because-multiply-included in the header.' %
3432 (f.LocalPath(), expected_guard)))
3433
3434 return errors
3435
3436
mostynbb639aca52015-01-07 20:31:233437def _CheckForWindowsLineEndings(input_api, output_api):
3438 """Check source code and known ascii text files for Windows style line
3439 endings.
3440 """
earthdok1b5e0ee2015-03-10 15:19:103441 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233442
3443 file_inclusion_pattern = (
3444 known_text_files,
3445 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3446 )
3447
mostynbb639aca52015-01-07 20:31:233448 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533449 source_file_filter = lambda f: input_api.FilterSourceFile(
3450 f, white_list=file_inclusion_pattern, black_list=None)
3451 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503452 include_file = False
3453 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233454 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503455 include_file = True
3456 if include_file:
3457 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233458
3459 if problems:
3460 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3461 'these files to contain Windows style line endings?\n' +
3462 '\n'.join(problems))]
3463
3464 return []
3465
3466
Vaclav Brozekd5de76a2018-03-17 07:57:503467def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133468 """Checks that all source files use SYSLOG properly."""
3469 syslog_files = []
3470 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563471 for line_number, line in f.ChangedContents():
3472 if 'SYSLOG' in line:
3473 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3474
pastarmovj89f7ee12016-09-20 14:58:133475 if syslog_files:
3476 return [output_api.PresubmitPromptWarning(
3477 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3478 ' calls.\nFiles to check:\n', items=syslog_files)]
3479 return []
3480
3481
[email protected]1f7b4172010-01-28 01:17:343482def CheckChangeOnUpload(input_api, output_api):
3483 results = []
3484 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473485 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283486 results.extend(
jam93a6ee792017-02-08 23:59:223487 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193488 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223489 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133490 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163491 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:533492 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193493 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543494 return results
[email protected]ca8d1982009-02-19 16:33:123495
3496
[email protected]1bfb8322014-04-23 01:02:413497def GetTryServerMasterForBot(bot):
3498 """Returns the Try Server master for the given bot.
3499
[email protected]0bb112362014-07-26 04:38:323500 It tries to guess the master from the bot name, but may still fail
3501 and return None. There is no longer a default master.
3502 """
3503 # Potentially ambiguous bot names are listed explicitly.
3504 master_map = {
tandriie5587792016-07-14 00:34:503505 'chromium_presubmit': 'master.tryserver.chromium.linux',
3506 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413507 }
[email protected]0bb112362014-07-26 04:38:323508 master = master_map.get(bot)
3509 if not master:
wnwen4fbaab82016-05-25 12:54:363510 if 'android' in bot:
tandriie5587792016-07-14 00:34:503511 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363512 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503513 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323514 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503515 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323516 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503517 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323518 return master
[email protected]1bfb8322014-04-23 01:02:413519
3520
[email protected]ca8d1982009-02-19 16:33:123521def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543522 results = []
[email protected]1f7b4172010-01-28 01:17:343523 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573524 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543525 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273526 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343527 input_api,
3528 output_api,
[email protected]2fdd1f362013-01-16 03:56:033529 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273530
jam93a6ee792017-02-08 23:59:223531 results.extend(
3532 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543533 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3534 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413535 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3536 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543537 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143538
3539
3540def _CheckTranslationScreenshots(input_api, output_api):
3541 PART_FILE_TAG = "part"
3542 import os
3543 import sys
3544 from io import StringIO
3545
3546 try:
3547 old_sys_path = sys.path
3548 sys.path = sys.path + [input_api.os_path.join(
3549 input_api.PresubmitLocalPath(), 'tools', 'grit')]
3550 import grit.grd_reader
3551 import grit.node.message
3552 import grit.util
3553 finally:
3554 sys.path = old_sys_path
3555
3556 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
3557 """Load the grd file and return a dict of message ids to messages.
3558
3559 Ignores any nested grdp files pointed by <part> tag.
3560 """
3561 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
3562 stop_after=None, first_ids_file=None,
3563 debug=False, defines=None,
3564 tags_to_ignore=set([PART_FILE_TAG]))
3565 return {
3566 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
3567 grit.node.message.MessageNode)
3568 }
3569
3570 def _GetGrdpMessagesFromString(grdp_string):
3571 """Parses the contents of a grdp file given in grdp_string.
3572
3573 grd_reader can't parse grdp files directly. Instead, this creates a
3574 temporary directory with a grd file pointing to the grdp file, and loads the
3575 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
3576 """
3577 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
3578 <grit latest_public_release="1" current_release="1">
3579 <release seq="1">
3580 <messages>
3581 <part file="sub.grdp" />
3582 </messages>
3583 </release>
3584 </grit>
3585 """
3586 with grit.util.TempDir({'main.grd': WRAPPER,
3587 'sub.grdp': grdp_string}) as temp_dir:
3588 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
3589
3590 new_or_added_paths = set(f.LocalPath()
3591 for f in input_api.AffectedFiles()
3592 if (f.Action() == 'A' or f.Action() == 'M'))
3593 removed_paths = set(f.LocalPath()
3594 for f in input_api.AffectedFiles(include_deletes=True)
3595 if f.Action() == 'D')
3596
3597 affected_grds = [f for f in input_api.AffectedFiles()
3598 if (f.LocalPath().endswith('.grd') or
3599 f.LocalPath().endswith('.grdp'))]
3600 affected_png_paths = [f.AbsoluteLocalPath()
3601 for f in input_api.AffectedFiles()
3602 if (f.LocalPath().endswith('.png'))]
3603
3604 # Check for screenshots. Developers can upload screenshots using
3605 # tools/translation/upload_screenshots.py which finds and uploads
3606 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
3607 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
3608 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
3609 #
3610 # The logic here is as follows:
3611 #
3612 # - If the CL has a .png file under the screenshots directory for a grd
3613 # file, warn the developer. Actual images should never be checked into the
3614 # Chrome repo.
3615 #
3616 # - If the CL contains modified or new messages in grd files and doesn't
3617 # contain the corresponding .sha1 files, warn the developer to add images
3618 # and upload them via tools/translation/upload_screenshots.py.
3619 #
3620 # - If the CL contains modified or new messages in grd files and the
3621 # corresponding .sha1 files, everything looks good.
3622 #
3623 # - If the CL contains removed messages in grd files but the corresponding
3624 # .sha1 files aren't removed, warn the developer to remove them.
3625 unnecessary_screenshots = []
3626 missing_sha1 = []
3627 unnecessary_sha1_files = []
3628
3629
3630 def _CheckScreenshotAdded(screenshots_dir, message_id):
3631 sha1_path = input_api.os_path.join(
3632 screenshots_dir, message_id + '.png.sha1')
3633 if sha1_path not in new_or_added_paths:
3634 missing_sha1.append(sha1_path)
3635
3636
3637 def _CheckScreenshotRemoved(screenshots_dir, message_id):
3638 sha1_path = input_api.os_path.join(
3639 screenshots_dir, message_id + '.png.sha1')
3640 if sha1_path not in removed_paths:
3641 unnecessary_sha1_files.append(sha1_path)
3642
3643
3644 for f in affected_grds:
3645 file_path = f.LocalPath()
3646 old_id_to_msg_map = {}
3647 new_id_to_msg_map = {}
3648 if file_path.endswith('.grdp'):
3649 if f.OldContents():
3650 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393651 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143652 if f.NewContents():
3653 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393654 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143655 else:
3656 if f.OldContents():
3657 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393658 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143659 if f.NewContents():
3660 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393661 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143662
3663 # Compute added, removed and modified message IDs.
3664 old_ids = set(old_id_to_msg_map)
3665 new_ids = set(new_id_to_msg_map)
3666 added_ids = new_ids - old_ids
3667 removed_ids = old_ids - new_ids
3668 modified_ids = set([])
3669 for key in old_ids.intersection(new_ids):
3670 if (old_id_to_msg_map[key].FormatXml()
3671 != new_id_to_msg_map[key].FormatXml()):
3672 modified_ids.add(key)
3673
3674 grd_name, ext = input_api.os_path.splitext(
3675 input_api.os_path.basename(file_path))
3676 screenshots_dir = input_api.os_path.join(
3677 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
3678
3679 # Check the screenshot directory for .png files. Warn if there is any.
3680 for png_path in affected_png_paths:
3681 if png_path.startswith(screenshots_dir):
3682 unnecessary_screenshots.append(png_path)
3683
3684 for added_id in added_ids:
3685 _CheckScreenshotAdded(screenshots_dir, added_id)
3686
3687 for modified_id in modified_ids:
3688 _CheckScreenshotAdded(screenshots_dir, modified_id)
3689
3690 for removed_id in removed_ids:
3691 _CheckScreenshotRemoved(screenshots_dir, removed_id)
3692
3693 results = []
3694 if unnecessary_screenshots:
3695 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393696 'Do not include actual screenshots in the changelist. Run '
3697 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143698 sorted(unnecessary_screenshots)))
3699
3700 if missing_sha1:
3701 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393702 'You are adding or modifying UI strings.\n'
3703 'To ensure the best translations, take screenshots of the relevant UI '
3704 '(https://g.co/chrome/translation) and add these files to your '
3705 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143706
3707 if unnecessary_sha1_files:
3708 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393709 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143710 sorted(unnecessary_sha1_files)))
3711
3712 return results