blob: 15b2b018f88990cd34cde6942bbf8863f582db14 [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 = (
[email protected]40d1dbb2012-10-26 07:18:0013 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_rules.py",
14 r"^native_client_sdk[\\\/]src[\\\/]build_tools[\\\/]make_simple.py",
[email protected]8886ffcb2013-02-12 04:56:2815 r"^native_client_sdk[\\\/]src[\\\/]tools[\\\/].*.mk",
[email protected]a18130a2012-01-03 17:52:0816 r"^net[\\\/]tools[\\\/]spdyshark[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5417 r"^skia[\\\/].*",
Kent Tamurae9b3a9ec2017-08-31 02:20:1918 r"^third_party[\\\/](WebKit|blink)[\\\/].*",
Mark Mentovaiebb9ddd62017-09-25 17:24:4119 r"^third_party[\\\/]breakpad[\\\/].*",
[email protected]3e4eb112011-01-18 03:29:5420 r"^v8[\\\/].*",
21 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
[email protected]ce145c02012-09-06 09:49:3423 r".+[\\\/]pnacl_shim\.c$",
[email protected]e07b6ac72013-08-20 00:30:4224 r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
primiano0166ccc82015-10-06 12:12:2825 r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
vapierb2053f542017-03-09 19:46:1026 r"tools[\\\/]md_browser[\\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1427 # Test pages for Maps telemetry tests.
28 r"tools[\\\/]perf[\\\/]page_sets[\\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5429 # Test pages for WebRTC telemetry tests.
30 r"tools[\\\/]perf[\\\/]page_sets[\\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4031)
[email protected]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 = (
joaodasilva718f87672014-08-30 09:25:4947 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4448 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4449 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1250 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4451 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4952 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0553 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4954 r'content[\\\/]shell[\\\/].*',
[email protected]7b054982013-11-27 00:44:4755 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4956 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0857 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4958 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4459)
[email protected]ca8d1982009-02-19 16:33:1260
wnwenbdc444e2016-05-25 13:44:1561
[email protected]eea609a2011-11-18 13:10:1262_TEST_ONLY_WARNING = (
63 'You might be calling functions intended only for testing from\n'
64 'production code. It is OK to ignore this warning if you know what\n'
65 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5866 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1267
68
[email protected]cf9b78f2012-11-14 11:40:2869_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4070 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2171 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
72 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2873
wnwenbdc444e2016-05-25 13:44:1574
Eric Stevensona9a980972017-09-23 00:04:4175_BANNED_JAVA_FUNCTIONS = (
76 (
77 'StrictMode.allowThreadDiskReads()',
78 (
79 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
80 'directly.',
81 ),
82 False,
83 ),
84 (
85 'StrictMode.allowThreadDiskWrites()',
86 (
87 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
88 'directly.',
89 ),
90 False,
91 ),
92)
93
[email protected]127f18ec2012-06-16 05:05:5994_BANNED_OBJC_FUNCTIONS = (
95 (
96 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2097 (
98 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5999 'prohibited. Please use CrTrackingArea instead.',
100 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
101 ),
102 False,
103 ),
104 (
[email protected]eaae1972014-04-16 04:17:26105 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20106 (
107 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59108 'instead.',
109 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
110 ),
111 False,
112 ),
113 (
114 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20115 (
116 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59117 'Please use |convertPoint:(point) fromView:nil| instead.',
118 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
119 ),
120 True,
121 ),
122 (
123 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20124 (
125 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59126 'Please use |convertPoint:(point) toView:nil| instead.',
127 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
128 ),
129 True,
130 ),
131 (
132 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20133 (
134 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59135 'Please use |convertRect:(point) fromView:nil| instead.',
136 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
137 ),
138 True,
139 ),
140 (
141 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20142 (
143 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59144 'Please use |convertRect:(point) toView:nil| instead.',
145 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
146 ),
147 True,
148 ),
149 (
150 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20151 (
152 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59153 'Please use |convertSize:(point) fromView:nil| instead.',
154 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
155 ),
156 True,
157 ),
158 (
159 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20160 (
161 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59162 'Please use |convertSize:(point) toView:nil| instead.',
163 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
164 ),
165 True,
166 ),
jif65398702016-10-27 10:19:48167 (
168 r"/\s+UTF8String\s*]",
169 (
170 'The use of -[NSString UTF8String] is dangerous as it can return null',
171 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
172 'Please use |SysNSStringToUTF8| instead.',
173 ),
174 True,
175 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34176 (
177 r'__unsafe_unretained',
178 (
179 'The use of __unsafe_unretained is almost certainly wrong, unless',
180 'when interacting with NSFastEnumeration or NSInvocation.',
181 'Please use __weak in files build with ARC, nothing otherwise.',
182 ),
183 False,
184 ),
[email protected]127f18ec2012-06-16 05:05:59185)
186
Sylvain Defresnea8b73d252018-02-28 15:45:54187_BANNED_IOS_OBJC_FUNCTIONS = (
188 (
189 r'/\bTEST[(]',
190 (
191 'TEST() macro should not be used in Objective-C++ code as it does not ',
192 'drain the autorelease pool at the end of the test. Use TEST_F() ',
193 'macro instead with a fixture inheriting from PlatformTest (or a ',
194 'typedef).'
195 ),
196 True,
197 ),
198 (
199 r'/\btesting::Test\b',
200 (
201 'testing::Test should not be used in Objective-C++ code as it does ',
202 'not drain the autorelease pool at the end of the test. Use ',
203 'PlatformTest instead.'
204 ),
205 True,
206 ),
207)
208
[email protected]127f18ec2012-06-16 05:05:59209
210_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20211 # Make sure that gtest's FRIEND_TEST() macro is not used; the
212 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30213 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20214 (
thomasandersone7caaa9b2017-03-29 19:22:53215 r'\bNULL\b',
216 (
217 'New code should not use NULL. Use nullptr instead.',
218 ),
219 True,
220 (),
221 ),
222 (
[email protected]23e6cbc2012-06-16 18:51:20223 'FRIEND_TEST(',
224 (
[email protected]e3c945502012-06-26 20:01:49225 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20226 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
227 ),
228 False,
[email protected]7345da02012-11-27 14:31:49229 (),
[email protected]23e6cbc2012-06-16 18:51:20230 ),
231 (
thomasanderson4b569052016-09-14 20:15:53232 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
233 (
234 'Chrome clients wishing to select events on X windows should use',
235 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
236 'you are selecting events from the GPU process, or if you are using',
237 'an XDisplay other than gfx::GetXDisplay().',
238 ),
239 True,
240 (
241 r"^ui[\\\/]gl[\\\/].*\.cc$",
242 r"^media[\\\/]gpu[\\\/].*\.cc$",
243 r"^gpu[\\\/].*\.cc$",
244 ),
245 ),
246 (
thomasandersone043e3ce2017-06-08 00:43:20247 r'XInternAtom|xcb_intern_atom',
248 (
thomasanderson11aa41d2017-06-08 22:22:38249 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20250 ),
251 True,
252 (
thomasanderson11aa41d2017-06-08 22:22:38253 r"^gpu[\\\/]ipc[\\\/]service[\\\/]gpu_watchdog_thread\.cc$",
254 r"^remoting[\\\/]host[\\\/]linux[\\\/]x_server_clipboard\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20255 r"^ui[\\\/]gfx[\\\/]x[\\\/]x11_atom_cache\.cc$",
256 ),
257 ),
258 (
tomhudsone2c14d552016-05-26 17:07:46259 'setMatrixClip',
260 (
261 'Overriding setMatrixClip() is prohibited; ',
262 'the base function is deprecated. ',
263 ),
264 True,
265 (),
266 ),
267 (
[email protected]52657f62013-05-20 05:30:31268 'SkRefPtr',
269 (
270 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22271 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31272 ),
273 True,
274 (),
275 ),
276 (
277 'SkAutoRef',
278 (
279 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22280 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31281 ),
282 True,
283 (),
284 ),
285 (
286 'SkAutoTUnref',
287 (
288 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22289 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31290 ),
291 True,
292 (),
293 ),
294 (
295 'SkAutoUnref',
296 (
297 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
298 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22299 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31300 ),
301 True,
302 (),
303 ),
[email protected]d89eec82013-12-03 14:10:59304 (
305 r'/HANDLE_EINTR\(.*close',
306 (
307 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
308 'descriptor will be closed, and it is incorrect to retry the close.',
309 'Either call close directly and ignore its return value, or wrap close',
310 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
311 ),
312 True,
313 (),
314 ),
315 (
316 r'/IGNORE_EINTR\((?!.*close)',
317 (
318 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
319 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
320 ),
321 True,
322 (
323 # Files that #define IGNORE_EINTR.
324 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
325 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
326 ),
327 ),
[email protected]ec5b3f02014-04-04 18:43:43328 (
329 r'/v8::Extension\(',
330 (
331 'Do not introduce new v8::Extensions into the code base, use',
332 'gin::Wrappable instead. See http://crbug.com/334679',
333 ),
334 True,
[email protected]f55c90ee62014-04-12 00:50:03335 (
joaodasilva718f87672014-08-30 09:25:49336 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03337 ),
[email protected]ec5b3f02014-04-04 18:43:43338 ),
skyostilf9469f72015-04-20 10:38:52339 (
jame2d1a952016-04-02 00:27:10340 '#pragma comment(lib,',
341 (
342 'Specify libraries to link with in build files and not in the source.',
343 ),
344 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41345 (
346 r'^third_party[\\\/]abseil-cpp[\\\/].*',
347 ),
jame2d1a952016-04-02 00:27:10348 ),
fdorayc4ac18d2017-05-01 21:39:59349 (
Gabriel Charette7cc6c432018-04-25 20:52:02350 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59351 (
352 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
353 ),
354 False,
355 (),
356 ),
357 (
Gabriel Charette7cc6c432018-04-25 20:52:02358 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59359 (
360 'Consider using THREAD_CHECKER macros instead of the class directly.',
361 ),
362 False,
363 (),
364 ),
dbeamb6f4fde2017-06-15 04:03:06365 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06366 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
367 (
368 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
369 'deprecated (http://crbug.com/634507). Please avoid converting away',
370 'from the Time types in Chromium code, especially if any math is',
371 'being done on time values. For interfacing with platform/library',
372 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
373 'type converter methods instead. For faking TimeXXX values (for unit',
374 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
375 'other use cases, please contact base/time/OWNERS.',
376 ),
377 False,
378 (),
379 ),
380 (
dbeamb6f4fde2017-06-15 04:03:06381 'CallJavascriptFunctionUnsafe',
382 (
383 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
384 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
385 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
386 ),
387 False,
388 (
389 r'^content[\\\/]browser[\\\/]webui[\\\/]web_ui_impl\.(cc|h)$',
390 r'^content[\\\/]public[\\\/]browser[\\\/]web_ui\.h$',
391 r'^content[\\\/]public[\\\/]test[\\\/]test_web_ui\.(cc|h)$',
392 ),
393 ),
dskiba1474c2bfd62017-07-20 02:19:24394 (
395 'leveldb::DB::Open',
396 (
397 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
398 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
399 "Chrome's tracing, making their memory usage visible.",
400 ),
401 True,
402 (
403 r'^third_party/leveldatabase/.*\.(cc|h)$',
404 ),
Gabriel Charette0592c3a2017-07-26 12:02:04405 ),
406 (
Chris Mumfordc38afb62017-10-09 17:55:08407 'leveldb::NewMemEnv',
408 (
409 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58410 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
411 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08412 ),
413 True,
414 (
415 r'^third_party/leveldatabase/.*\.(cc|h)$',
416 ),
417 ),
418 (
Gabriel Charetted9839bc2017-07-29 14:17:47419 'RunLoop::QuitCurrent',
420 (
Robert Liao64b7ab22017-08-04 23:03:43421 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
422 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47423 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41424 False,
Gabriel Charetted9839bc2017-07-29 14:17:47425 (),
Gabriel Charettea44975052017-08-21 23:14:04426 ),
427 (
428 'base::ScopedMockTimeMessageLoopTaskRunner',
429 (
Gabriel Charette87cc1af2018-04-25 20:52:51430 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
431 'ScopedTaskEnvironment::MainThreadType::MOCK_TIME. There are still a',
432 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
433 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
434 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04435 ),
Gabriel Charette87cc1af2018-04-25 20:52:51436 False,
Gabriel Charettea44975052017-08-21 23:14:04437 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57438 ),
439 (
440 r'std::regex',
441 (
442 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02443 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57444 ),
445 True,
446 (),
Francois Doray43670e32017-09-27 12:40:38447 ),
448 (
449 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
450 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
451 (
452 'Use the new API in base/threading/thread_restrictions.h.',
453 ),
454 True,
455 (),
456 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38457 (
458 r'/\bbase::Bind\(',
459 (
Gabriel Charette147335ea2018-03-22 15:59:19460 'Please consider using base::Bind{Once,Repeating} instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02461 'of base::Bind. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38462 ),
463 False,
464 (),
465 ),
466 (
467 r'/\bbase::Callback<',
468 (
Gabriel Charette147335ea2018-03-22 15:59:19469 'Please consider using base::{Once,Repeating}Callback instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02470 'of base::Callback. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38471 ),
472 False,
473 (),
474 ),
475 (
476 r'/\bbase::Closure\b',
477 (
Gabriel Charette147335ea2018-03-22 15:59:19478 'Please consider using base::{Once,Repeating}Closure instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02479 'of base::Closure. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38480 ),
481 False,
482 (),
483 ),
Victor Costan3653df62018-02-08 21:38:16484 (
Gabriel Charette147335ea2018-03-22 15:59:19485 r'RunMessageLoop',
486 (
487 'RunMessageLoop is deprecated, use RunLoop instead.',
488 ),
489 False,
490 (),
491 ),
492 (
493 r'RunThisRunLoop',
494 (
495 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
496 ),
497 False,
498 (),
499 ),
500 (
501 r'RunAllPendingInMessageLoop()',
502 (
503 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
504 "if you're convinced you need this.",
505 ),
506 False,
507 (),
508 ),
509 (
510 r'RunAllPendingInMessageLoop(BrowserThread',
511 (
512 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
513 'BrowserThread::UI, TestBrowserThreadBundle::RunIOThreadUntilIdle',
514 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
515 'async events instead of flushing threads.',
516 ),
517 False,
518 (),
519 ),
520 (
521 r'MessageLoopRunner',
522 (
523 'MessageLoopRunner is deprecated, use RunLoop instead.',
524 ),
525 False,
526 (),
527 ),
528 (
529 r'GetDeferredQuitTaskForRunLoop',
530 (
531 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
532 "gab@ if you found a use case where this is the only solution.",
533 ),
534 False,
535 (),
536 ),
537 (
Victor Costan3653df62018-02-08 21:38:16538 'sqlite3_initialize',
539 (
540 'Instead of sqlite3_initialize, depend on //sql, ',
541 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
542 ),
543 True,
544 (
545 r'^sql/initialization\.(cc|h)$',
546 r'^third_party/sqlite/.*\.(c|cc|h)$',
547 ),
548 ),
Matt Menke7f520a82018-03-28 21:38:37549 (
550 'net::URLFetcher',
551 (
552 'net::URLFetcher should no longer be used in content embedders. ',
553 'Instead, use network::SimpleURLLoader instead, which supports ',
554 'an out-of-process network stack. ',
555 'net::URLFetcher may still be used in binaries that do not embed',
556 'content.',
557 ),
Matt Menke59716d02018-04-05 12:45:53558 False,
Matt Menke7f520a82018-03-28 21:38:37559 (
560 r'^ios[\\\/].*\.(cc|h)$',
561 r'.*[\\\/]ios[\\\/].*\.(cc|h)$',
562 r'.*_ios\.(cc|h)$',
563 r'^net[\\\/].*\.(cc|h)$',
564 r'.*[\\\/]tools[\\\/].*\.(cc|h)$',
565 ),
566 ),
jdoerried7d10ab2018-04-27 10:46:13567 (
568 r'/\barraysize\b',
569 (
570 "arraysize is deprecated, please use base::size(array) instead ",
571 "(https://crbug.com/837308). ",
572 ),
573 False,
574 (),
575 ),
tzik5de2157f2018-05-08 03:42:47576 (
577 r'std::random_shuffle',
578 (
579 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
580 'base::RandomShuffle instead.'
581 ),
582 True,
583 (),
584 ),
[email protected]127f18ec2012-06-16 05:05:59585)
586
wnwenbdc444e2016-05-25 13:44:15587
mlamouria82272622014-09-16 18:45:04588_IPC_ENUM_TRAITS_DEPRECATED = (
589 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50590 'See http://www.chromium.org/Home/chromium-security/education/'
591 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:04592
Stephen Martinis97a394142018-06-07 23:06:05593_LONG_PATH_ERROR = (
594 'Some files included in this CL have file names that are too long (> 200'
595 ' characters). If committed, these files will cause issues on Windows. See'
596 ' https://crbug.com/612667 for more details.'
597)
598
Shenghua Zhangbfaa38b82017-11-16 21:58:02599_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
600 r".*[\\\/]BuildHooksAndroidImpl\.java",
601 r".*[\\\/]LicenseContentProvider\.java",
James Wallace-Leef31ae6c2018-05-01 23:30:20602 r".*[\\\/]PlatformServiceBridgeImpl.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:02603]
[email protected]127f18ec2012-06-16 05:05:59604
Sean Kau46e29bc2017-08-28 16:31:16605# These paths contain test data and other known invalid JSON files.
606_KNOWN_INVALID_JSON_FILE_PATTERNS = [
607 r'test[\\\/]data[\\\/]',
608 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
609 r'^third_party[\\\/]protobuf[\\\/]',
Raphael Kubo da Costa211f3b472017-11-16 00:27:16610 r'^third_party[\\\/]WebKit[\\\/]LayoutTests[\\\/]external[\\\/]wpt[\\\/]',
Alexey Kozyatinskiya42a629f2018-04-17 17:49:38611 r'^third_party[\\\/]blink[\\\/]renderer[\\\/]devtools[\\\/]protocol\.json$',
Sean Kau46e29bc2017-08-28 16:31:16612]
613
614
[email protected]b00342e7f2013-03-26 16:21:54615_VALID_OS_MACROS = (
616 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08617 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54618 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:12619 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:54620 'OS_BSD',
621 'OS_CAT', # For testing.
622 'OS_CHROMEOS',
623 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37624 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54625 'OS_IOS',
626 'OS_LINUX',
627 'OS_MACOSX',
628 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21629 'OS_NACL_NONSFI',
630 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12631 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54632 'OS_OPENBSD',
633 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37634 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54635 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54636 'OS_WIN',
637)
638
639
agrievef32bcc72016-04-04 14:57:40640_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grievea7f1ee902018-05-18 16:17:22641 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:40642 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04643 'build/android/test_wrapper/logdog_wrapper.pydeps',
jbudorick276cc562017-04-29 01:34:58644 'build/secondary/third_party/android_platform/'
645 'development/scripts/stack.pydeps',
agrieve732db3a2016-04-26 19:18:19646 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40647]
648
wnwenbdc444e2016-05-25 13:44:15649
agrievef32bcc72016-04-04 14:57:40650_GENERIC_PYDEPS_FILES = [
John Chencde89192018-01-27 21:18:40651 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22652 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:40653]
654
wnwenbdc444e2016-05-25 13:44:15655
agrievef32bcc72016-04-04 14:57:40656_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
657
658
Eric Boren6fd2b932018-01-25 15:05:08659# Bypass the AUTHORS check for these accounts.
660_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:29661 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
662 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:08663 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
664 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:59665 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:45666 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:59667 ) | set('%[email protected]' % s
Sergiy Byelozyorovf78077a92018-06-14 08:07:11668 for s in ('v8-ci-autoroll-builder',))
Eric Boren6fd2b932018-01-25 15:05:08669
670
[email protected]55459852011-08-10 15:17:19671def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
672 """Attempts to prevent use of functions intended only for testing in
673 non-testing code. For now this is just a best-effort implementation
674 that ignores header files and may have some false positives. A
675 better implementation would probably need a proper C++ parser.
676 """
677 # We only scan .cc files and the like, as the declaration of
678 # for-testing functions in header files are hard to distinguish from
679 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49680 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:19681
jochenc0d4808c2015-07-27 09:25:42682 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19683 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09684 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19685 exclusion_pattern = input_api.re.compile(
686 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
687 base_function_pattern, base_function_pattern))
688
689 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44690 black_list = (_EXCLUDED_PATHS +
691 _TEST_CODE_EXCLUDED_PATHS +
692 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19693 return input_api.FilterSourceFile(
694 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49695 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:19696 black_list=black_list)
697
698 problems = []
699 for f in input_api.AffectedSourceFiles(FilterFile):
700 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24701 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03702 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46703 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03704 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19705 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03706 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19707
708 if problems:
[email protected]f7051d52013-04-02 18:31:42709 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03710 else:
711 return []
[email protected]55459852011-08-10 15:17:19712
713
Vaclav Brozek7dbc28c2018-03-27 08:35:23714def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
715 """This is a simplified version of
716 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
717 """
718 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
719 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
720 name_pattern = r'ForTest(s|ing)?'
721 # Describes an occurrence of "ForTest*" inside a // comment.
722 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
723 # Catch calls.
724 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
725 # Ignore definitions. (Comments are ignored separately.)
726 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
727
728 problems = []
729 sources = lambda x: input_api.FilterSourceFile(
730 x,
731 black_list=(('(?i).*test', r'.*\/junit\/')
732 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49733 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:23734 )
735 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
736 local_path = f.LocalPath()
737 is_inside_javadoc = False
738 for line_number, line in f.ChangedContents():
739 if is_inside_javadoc and javadoc_end_re.search(line):
740 is_inside_javadoc = False
741 if not is_inside_javadoc and javadoc_start_re.search(line):
742 is_inside_javadoc = True
743 if is_inside_javadoc:
744 continue
745 if (inclusion_re.search(line) and
746 not comment_re.search(line) and
747 not exclusion_re.search(line)):
748 problems.append(
749 '%s:%d\n %s' % (local_path, line_number, line.strip()))
750
751 if problems:
752 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
753 else:
754 return []
755
756
[email protected]10689ca2011-09-02 02:31:54757def _CheckNoIOStreamInHeaders(input_api, output_api):
758 """Checks to make sure no .h files include <iostream>."""
759 files = []
760 pattern = input_api.re.compile(r'^#include\s*<iostream>',
761 input_api.re.MULTILINE)
762 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
763 if not f.LocalPath().endswith('.h'):
764 continue
765 contents = input_api.ReadFile(f)
766 if pattern.search(contents):
767 files.append(f)
768
769 if len(files):
yolandyandaabc6d2016-04-18 18:29:39770 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06771 'Do not #include <iostream> in header files, since it inserts static '
772 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54773 '#include <ostream>. See http://crbug.com/94794',
774 files) ]
775 return []
776
777
[email protected]72df4e782012-06-21 16:28:18778def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52779 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18780 problems = []
781 for f in input_api.AffectedFiles():
782 if (not f.LocalPath().endswith(('.cc', '.mm'))):
783 continue
784
785 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04786 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18787 problems.append(' %s:%d' % (f.LocalPath(), line_num))
788
789 if not problems:
790 return []
791 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
792 '\n'.join(problems))]
793
794
danakj61c1aa22015-10-26 19:55:52795def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57796 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52797 errors = []
798 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
799 input_api.re.MULTILINE)
800 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
801 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
802 continue
803 for lnum, line in f.ChangedContents():
804 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17805 errors.append(output_api.PresubmitError(
806 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57807 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17808 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52809 return errors
810
811
mcasasb7440c282015-02-04 14:52:19812def _FindHistogramNameInLine(histogram_name, line):
813 """Tries to find a histogram name or prefix in a line."""
814 if not "affected-histogram" in line:
815 return histogram_name in line
816 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
817 # the histogram_name.
818 if not '"' in line:
819 return False
820 histogram_prefix = line.split('\"')[1]
821 return histogram_prefix in histogram_name
822
823
824def _CheckUmaHistogramChanges(input_api, output_api):
825 """Check that UMA histogram names in touched lines can still be found in other
826 lines of the patch or in histograms.xml. Note that this check would not catch
827 the reverse: changes in histograms.xml not matched in the code itself."""
828 touched_histograms = []
829 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:47830 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
831 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
832 name_pattern = r'"(.*?)"'
833 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
834 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
835 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
836 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
837 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:17838 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:19839 for f in input_api.AffectedFiles():
840 # If histograms.xml itself is modified, keep the modified lines for later.
841 if f.LocalPath().endswith(('histograms.xml')):
842 histograms_xml_modifications = f.ChangedContents()
843 continue
Vaclav Brozekbdac817c2018-03-24 06:30:47844 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
845 single_line_re = single_line_c_re
846 split_line_prefix_re = split_line_c_prefix_re
847 elif f.LocalPath().endswith(('java')):
848 single_line_re = single_line_java_re
849 split_line_prefix_re = split_line_java_prefix_re
850 else:
mcasasb7440c282015-02-04 14:52:19851 continue
852 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:17853 if last_line_matched_prefix:
854 suffix_found = split_line_suffix_re.search(line)
855 if suffix_found :
856 touched_histograms.append([suffix_found.group(1), f, line_num])
857 last_line_matched_prefix = False
858 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:06859 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:19860 if found:
861 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:17862 continue
863 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:19864
865 # Search for the touched histogram names in the local modifications to
866 # histograms.xml, and, if not found, on the base histograms.xml file.
867 unmatched_histograms = []
868 for histogram_info in touched_histograms:
869 histogram_name_found = False
870 for line_num, line in histograms_xml_modifications:
871 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
872 if histogram_name_found:
873 break
874 if not histogram_name_found:
875 unmatched_histograms.append(histogram_info)
876
eromanb90c82e7e32015-04-01 15:13:49877 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19878 problems = []
879 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49880 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19881 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45882 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19883 histogram_name_found = False
884 for line in histograms_xml:
885 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
886 if histogram_name_found:
887 break
888 if not histogram_name_found:
889 problems.append(' [%s:%d] %s' %
890 (f.LocalPath(), line_num, histogram_name))
891
892 if not problems:
893 return []
894 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
895 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49896 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19897
wnwenbdc444e2016-05-25 13:44:15898
yolandyandaabc6d2016-04-18 18:29:39899def _CheckFlakyTestUsage(input_api, output_api):
900 """Check that FlakyTest annotation is our own instead of the android one"""
901 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
902 files = []
903 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
904 if f.LocalPath().endswith('Test.java'):
905 if pattern.search(input_api.ReadFile(f)):
906 files.append(f)
907 if len(files):
908 return [output_api.PresubmitError(
909 'Use org.chromium.base.test.util.FlakyTest instead of '
910 'android.test.FlakyTest',
911 files)]
912 return []
mcasasb7440c282015-02-04 14:52:19913
wnwenbdc444e2016-05-25 13:44:15914
[email protected]8ea5d4b2011-09-13 21:49:22915def _CheckNoNewWStrings(input_api, output_api):
916 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27917 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22918 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20919 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57920 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34921 '/win/' in f.LocalPath() or
922 'chrome_elf' in f.LocalPath() or
923 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20924 continue
[email protected]8ea5d4b2011-09-13 21:49:22925
[email protected]a11dbe9b2012-08-07 01:32:58926 allowWString = False
[email protected]b5c24292011-11-28 14:38:20927 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58928 if 'presubmit: allow wstring' in line:
929 allowWString = True
930 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27931 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58932 allowWString = False
933 else:
934 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22935
[email protected]55463aa62011-10-12 00:48:27936 if not problems:
937 return []
938 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58939 ' If you are calling a cross-platform API that accepts a wstring, '
940 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27941 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22942
943
[email protected]2a8ac9c2011-10-19 17:20:44944def _CheckNoDEPSGIT(input_api, output_api):
945 """Make sure .DEPS.git is never modified manually."""
946 if any(f.LocalPath().endswith('.DEPS.git') for f in
947 input_api.AffectedFiles()):
948 return [output_api.PresubmitError(
949 'Never commit changes to .DEPS.git. This file is maintained by an\n'
950 'automated system based on what\'s in DEPS and your changes will be\n'
951 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50952 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
953 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:44954 'for more information')]
955 return []
956
957
tandriief664692014-09-23 14:51:47958def _CheckValidHostsInDEPS(input_api, output_api):
959 """Checks that DEPS file deps are from allowed_hosts."""
960 # Run only if DEPS file has been modified to annoy fewer bystanders.
961 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
962 return []
963 # Outsource work to gclient verify
964 try:
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:20965 input_api.subprocess.check_output(['gclient', 'verify'],
966 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:47967 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:20968 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:47969 return [output_api.PresubmitError(
970 'DEPS file must have only git dependencies.',
971 long_text=error.output)]
972
973
[email protected]127f18ec2012-06-16 05:05:59974def _CheckNoBannedFunctions(input_api, output_api):
975 """Make sure that banned functions are not used."""
976 warnings = []
977 errors = []
978
wnwenbdc444e2016-05-25 13:44:15979 def IsBlacklisted(affected_file, blacklist):
980 local_path = affected_file.LocalPath()
981 for item in blacklist:
982 if input_api.re.match(item, local_path):
983 return True
984 return False
985
Sylvain Defresnea8b73d252018-02-28 15:45:54986 def IsIosObcjFile(affected_file):
987 local_path = affected_file.LocalPath()
988 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
989 return False
990 basename = input_api.os_path.basename(local_path)
991 if 'ios' in basename.split('_'):
992 return True
993 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
994 if sep and 'ios' in local_path.split(sep):
995 return True
996 return False
997
wnwenbdc444e2016-05-25 13:44:15998 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
999 matched = False
1000 if func_name[0:1] == '/':
1001 regex = func_name[1:]
1002 if input_api.re.search(regex, line):
1003 matched = True
1004 elif func_name in line:
dchenge07de812016-06-20 19:27:171005 matched = True
wnwenbdc444e2016-05-25 13:44:151006 if matched:
dchenge07de812016-06-20 19:27:171007 problems = warnings
wnwenbdc444e2016-05-25 13:44:151008 if error:
dchenge07de812016-06-20 19:27:171009 problems = errors
wnwenbdc444e2016-05-25 13:44:151010 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1011 for message_line in message:
1012 problems.append(' %s' % message_line)
1013
Eric Stevensona9a980972017-09-23 00:04:411014 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1015 for f in input_api.AffectedFiles(file_filter=file_filter):
1016 for line_num, line in f.ChangedContents():
1017 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1018 CheckForMatch(f, line_num, line, func_name, message, error)
1019
[email protected]127f18ec2012-06-16 05:05:591020 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1021 for f in input_api.AffectedFiles(file_filter=file_filter):
1022 for line_num, line in f.ChangedContents():
1023 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151024 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591025
Sylvain Defresnea8b73d252018-02-28 15:45:541026 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1027 for line_num, line in f.ChangedContents():
1028 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1029 CheckForMatch(f, line_num, line, func_name, message, error)
1030
[email protected]127f18ec2012-06-16 05:05:591031 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1032 for f in input_api.AffectedFiles(file_filter=file_filter):
1033 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491034 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491035 if IsBlacklisted(f, excluded_paths):
1036 continue
wnwenbdc444e2016-05-25 13:44:151037 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591038
1039 result = []
1040 if (warnings):
1041 result.append(output_api.PresubmitPromptWarning(
1042 'Banned functions were used.\n' + '\n'.join(warnings)))
1043 if (errors):
1044 result.append(output_api.PresubmitError(
1045 'Banned functions were used.\n' + '\n'.join(errors)))
1046 return result
1047
1048
[email protected]6c063c62012-07-11 19:11:061049def _CheckNoPragmaOnce(input_api, output_api):
1050 """Make sure that banned functions are not used."""
1051 files = []
1052 pattern = input_api.re.compile(r'^#pragma\s+once',
1053 input_api.re.MULTILINE)
1054 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1055 if not f.LocalPath().endswith('.h'):
1056 continue
1057 contents = input_api.ReadFile(f)
1058 if pattern.search(contents):
1059 files.append(f)
1060
1061 if files:
1062 return [output_api.PresubmitError(
1063 'Do not use #pragma once in header files.\n'
1064 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1065 files)]
1066 return []
1067
[email protected]127f18ec2012-06-16 05:05:591068
[email protected]e7479052012-09-19 00:26:121069def _CheckNoTrinaryTrueFalse(input_api, output_api):
1070 """Checks to make sure we don't introduce use of foo ? true : false."""
1071 problems = []
1072 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1073 for f in input_api.AffectedFiles():
1074 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1075 continue
1076
1077 for line_num, line in f.ChangedContents():
1078 if pattern.match(line):
1079 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1080
1081 if not problems:
1082 return []
1083 return [output_api.PresubmitPromptWarning(
1084 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1085 '\n'.join(problems))]
1086
1087
[email protected]55f9f382012-07-31 11:02:181088def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281089 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181090 change. Breaking - rules is an error, breaking ! rules is a
1091 warning.
1092 """
mohan.reddyf21db962014-10-16 12:26:471093 import sys
[email protected]55f9f382012-07-31 11:02:181094 # We need to wait until we have an input_api object and use this
1095 # roundabout construct to import checkdeps because this file is
1096 # eval-ed and thus doesn't have __file__.
1097 original_sys_path = sys.path
1098 try:
1099 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471100 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181101 import checkdeps
1102 from cpp_checker import CppChecker
Jinsuk Kim5a092672017-10-24 22:42:241103 from java_checker import JavaChecker
rhalavati08acd232017-04-03 07:23:281104 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:181105 from rules import Rule
1106 finally:
1107 # Restore sys.path to what it was before.
1108 sys.path = original_sys_path
1109
1110 added_includes = []
rhalavati08acd232017-04-03 07:23:281111 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241112 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181113 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:281114 if CppChecker.IsCppFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501115 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081116 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
rhalavati08acd232017-04-03 07:23:281117 elif ProtoChecker.IsProtoFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501118 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081119 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241120 elif JavaChecker.IsJavaFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501121 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081122 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181123
[email protected]26385172013-05-09 23:11:351124 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181125
1126 error_descriptions = []
1127 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281128 error_subjects = set()
1129 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181130 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1131 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081132 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181133 description_with_path = '%s\n %s' % (path, rule_description)
1134 if rule_type == Rule.DISALLOW:
1135 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281136 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181137 else:
1138 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281139 warning_subjects.add("#includes")
1140
1141 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1142 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081143 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281144 description_with_path = '%s\n %s' % (path, rule_description)
1145 if rule_type == Rule.DISALLOW:
1146 error_descriptions.append(description_with_path)
1147 error_subjects.add("imports")
1148 else:
1149 warning_descriptions.append(description_with_path)
1150 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181151
Jinsuk Kim5a092672017-10-24 22:42:241152 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021153 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081154 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241155 description_with_path = '%s\n %s' % (path, rule_description)
1156 if rule_type == Rule.DISALLOW:
1157 error_descriptions.append(description_with_path)
1158 error_subjects.add("imports")
1159 else:
1160 warning_descriptions.append(description_with_path)
1161 warning_subjects.add("imports")
1162
[email protected]55f9f382012-07-31 11:02:181163 results = []
1164 if error_descriptions:
1165 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281166 'You added one or more %s that violate checkdeps rules.'
1167 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181168 error_descriptions))
1169 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421170 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281171 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181172 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281173 '%s? See relevant DEPS file(s) for details and contacts.' %
1174 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181175 warning_descriptions))
1176 return results
1177
1178
[email protected]fbcafe5a2012-08-08 15:31:221179def _CheckFilePermissions(input_api, output_api):
1180 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151181 if input_api.platform == 'win32':
1182 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291183 checkperms_tool = input_api.os_path.join(
1184 input_api.PresubmitLocalPath(),
1185 'tools', 'checkperms', 'checkperms.py')
1186 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471187 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391188 with input_api.CreateTemporaryFile() as file_list:
1189 for f in input_api.AffectedFiles():
1190 # checkperms.py file/directory arguments must be relative to the
1191 # repository.
1192 file_list.write(f.LocalPath() + '\n')
1193 file_list.close()
1194 args += ['--file-list', file_list.name]
1195 try:
1196 input_api.subprocess.check_output(args)
1197 return []
1198 except input_api.subprocess.CalledProcessError as error:
1199 return [output_api.PresubmitError(
1200 'checkperms.py failed:',
1201 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221202
1203
robertocn832f5992017-01-04 19:01:301204def _CheckTeamTags(input_api, output_api):
1205 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1206 checkteamtags_tool = input_api.os_path.join(
1207 input_api.PresubmitLocalPath(),
1208 'tools', 'checkteamtags', 'checkteamtags.py')
1209 args = [input_api.python_executable, checkteamtags_tool,
1210 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221211 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301212 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1213 'OWNERS']
1214 try:
1215 if files:
1216 input_api.subprocess.check_output(args + files)
1217 return []
1218 except input_api.subprocess.CalledProcessError as error:
1219 return [output_api.PresubmitError(
1220 'checkteamtags.py failed:',
1221 long_text=error.output)]
1222
1223
[email protected]c8278b32012-10-30 20:35:491224def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1225 """Makes sure we don't include ui/aura/window_property.h
1226 in header files.
1227 """
1228 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1229 errors = []
1230 for f in input_api.AffectedFiles():
1231 if not f.LocalPath().endswith('.h'):
1232 continue
1233 for line_num, line in f.ChangedContents():
1234 if pattern.match(line):
1235 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1236
1237 results = []
1238 if errors:
1239 results.append(output_api.PresubmitError(
1240 'Header files should not include ui/aura/window_property.h', errors))
1241 return results
1242
1243
[email protected]70ca77752012-11-20 03:45:031244def _CheckForVersionControlConflictsInFile(input_api, f):
1245 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1246 errors = []
1247 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:231248 if f.LocalPath().endswith('.md'):
1249 # First-level headers in markdown look a lot like version control
1250 # conflict markers. http://daringfireball.net/projects/markdown/basics
1251 continue
[email protected]70ca77752012-11-20 03:45:031252 if pattern.match(line):
1253 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1254 return errors
1255
1256
1257def _CheckForVersionControlConflicts(input_api, output_api):
1258 """Usually this is not intentional and will cause a compile failure."""
1259 errors = []
1260 for f in input_api.AffectedFiles():
1261 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1262
1263 results = []
1264 if errors:
1265 results.append(output_api.PresubmitError(
1266 'Version control conflict markers found, please resolve.', errors))
1267 return results
1268
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201269
estadee17314a02017-01-12 16:22:161270def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1271 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1272 errors = []
1273 for f in input_api.AffectedFiles():
1274 for line_num, line in f.ChangedContents():
1275 if pattern.search(line):
1276 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1277
1278 results = []
1279 if errors:
1280 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501281 'Found Google support URL addressed by answer number. Please replace '
1282 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161283 return results
1284
[email protected]70ca77752012-11-20 03:45:031285
[email protected]06e6d0ff2012-12-11 01:36:441286def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1287 def FilterFile(affected_file):
1288 """Filter function for use with input_api.AffectedSourceFiles,
1289 below. This filters out everything except non-test files from
1290 top-level directories that generally speaking should not hard-code
1291 service URLs (e.g. src/android_webview/, src/content/ and others).
1292 """
1293 return input_api.FilterSourceFile(
1294 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491295 white_list=[r'^(android_webview|base|content|net)[\\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:441296 black_list=(_EXCLUDED_PATHS +
1297 _TEST_CODE_EXCLUDED_PATHS +
1298 input_api.DEFAULT_BLACK_LIST))
1299
reillyi38965732015-11-16 18:27:331300 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1301 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461302 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1303 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441304 problems = [] # items are (filename, line_number, line)
1305 for f in input_api.AffectedSourceFiles(FilterFile):
1306 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461307 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441308 problems.append((f.LocalPath(), line_num, line))
1309
1310 if problems:
[email protected]f7051d52013-04-02 18:31:421311 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441312 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581313 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441314 [' %s:%d: %s' % (
1315 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031316 else:
1317 return []
[email protected]06e6d0ff2012-12-11 01:36:441318
1319
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491320# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:271321def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1322 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311323 The native_client_sdk directory is excluded because it has auto-generated PNG
1324 files for documentation.
[email protected]d2530012013-01-25 16:39:271325 """
[email protected]d2530012013-01-25 16:39:271326 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491327 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
1328 black_list = [r'^native_client_sdk[\\\/]']
binji0dcdf342014-12-12 18:32:311329 file_filter = lambda f: input_api.FilterSourceFile(
1330 f, white_list=white_list, black_list=black_list)
1331 for f in input_api.AffectedFiles(include_deletes=False,
1332 file_filter=file_filter):
1333 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271334
1335 results = []
1336 if errors:
1337 results.append(output_api.PresubmitError(
1338 'The name of PNG files should not have abbreviations. \n'
1339 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1340 'Contact [email protected] if you have questions.', errors))
1341 return results
1342
1343
Daniel Cheng4dcdb6b2017-04-13 08:30:171344def _ExtractAddRulesFromParsedDeps(parsed_deps):
1345 """Extract the rules that add dependencies from a parsed DEPS file.
1346
1347 Args:
1348 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1349 add_rules = set()
1350 add_rules.update([
1351 rule[1:] for rule in parsed_deps.get('include_rules', [])
1352 if rule.startswith('+') or rule.startswith('!')
1353 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501354 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171355 {}).iteritems():
1356 add_rules.update([
1357 rule[1:] for rule in rules
1358 if rule.startswith('+') or rule.startswith('!')
1359 ])
1360 return add_rules
1361
1362
1363def _ParseDeps(contents):
1364 """Simple helper for parsing DEPS files."""
1365 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171366 class _VarImpl:
1367
1368 def __init__(self, local_scope):
1369 self._local_scope = local_scope
1370
1371 def Lookup(self, var_name):
1372 """Implements the Var syntax."""
1373 try:
1374 return self._local_scope['vars'][var_name]
1375 except KeyError:
1376 raise Exception('Var is not defined: %s' % var_name)
1377
1378 local_scope = {}
1379 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171380 'Var': _VarImpl(local_scope).Lookup,
1381 }
1382 exec contents in global_scope, local_scope
1383 return local_scope
1384
1385
1386def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081387 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411388 a set of DEPS entries that we should look up.
1389
1390 For a directory (rather than a specific filename) we fake a path to
1391 a specific filename by adding /DEPS. This is chosen as a file that
1392 will seldom or never be subject to per-file include_rules.
1393 """
[email protected]2b438d62013-11-14 17:54:141394 # We ignore deps entries on auto-generated directories.
1395 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081396
Daniel Cheng4dcdb6b2017-04-13 08:30:171397 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1398 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1399
1400 added_deps = new_deps.difference(old_deps)
1401
[email protected]2b438d62013-11-14 17:54:141402 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171403 for added_dep in added_deps:
1404 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1405 continue
1406 # Assume that a rule that ends in .h is a rule for a specific file.
1407 if added_dep.endswith('.h'):
1408 results.add(added_dep)
1409 else:
1410 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081411 return results
1412
1413
[email protected]e871964c2013-05-13 14:14:551414def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1415 """When a dependency prefixed with + is added to a DEPS file, we
1416 want to make sure that the change is reviewed by an OWNER of the
1417 target file or directory, to avoid layering violations from being
1418 introduced. This check verifies that this happens.
1419 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171420 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241421
1422 file_filter = lambda f: not input_api.re.match(
Kent Tamurae9b3a9ec2017-08-31 02:20:191423 r"^third_party[\\\/](WebKit|blink)[\\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241424 for f in input_api.AffectedFiles(include_deletes=False,
1425 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551426 filename = input_api.os_path.basename(f.LocalPath())
1427 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171428 virtual_depended_on_files.update(_CalculateAddedDeps(
1429 input_api.os_path,
1430 '\n'.join(f.OldContents()),
1431 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551432
[email protected]e871964c2013-05-13 14:14:551433 if not virtual_depended_on_files:
1434 return []
1435
1436 if input_api.is_committing:
1437 if input_api.tbr:
1438 return [output_api.PresubmitNotifyResult(
1439 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271440 if input_api.dry_run:
1441 return [output_api.PresubmitNotifyResult(
1442 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551443 if not input_api.change.issue:
1444 return [output_api.PresubmitError(
1445 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401446 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551447 output = output_api.PresubmitError
1448 else:
1449 output = output_api.PresubmitNotifyResult
1450
1451 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501452 owner_email, reviewers = (
1453 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1454 input_api,
1455 owners_db.email_regexp,
1456 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551457
1458 owner_email = owner_email or input_api.change.author_email
1459
[email protected]de4f7d22013-05-23 14:27:461460 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511461 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461462 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551463 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1464 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411465
1466 # We strip the /DEPS part that was added by
1467 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1468 # directory.
1469 def StripDeps(path):
1470 start_deps = path.rfind('/DEPS')
1471 if start_deps != -1:
1472 return path[:start_deps]
1473 else:
1474 return path
1475 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551476 for path in missing_files]
1477
1478 if unapproved_dependencies:
1479 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151480 output('You need LGTM from owners of depends-on paths in DEPS that were '
1481 'modified in this CL:\n %s' %
1482 '\n '.join(sorted(unapproved_dependencies)))]
1483 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1484 output_list.append(output(
1485 'Suggested missing target path OWNERS:\n %s' %
1486 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551487 return output_list
1488
1489 return []
1490
1491
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491492# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:401493def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491494 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:401495 black_list = (_EXCLUDED_PATHS +
1496 _TEST_CODE_EXCLUDED_PATHS +
1497 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501498 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191499 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481500 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461501 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121502 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1503 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581504 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
Olivier Liec4400b22018-07-31 19:50:441505 r"^chrome[\\\/]chrome_cleaner[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161506 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031507 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151508 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1509 r"^chromecast[\\\/]",
1510 r"^cloud_print[\\\/]",
manzagop85e629e2017-05-09 22:11:481511 r"^components[\\\/]browser_watcher[\\\/]"
1512 r"dump_stability_report_main_win.cc$",
jochen34415e52015-07-10 08:34:311513 r"^components[\\\/]html_viewer[\\\/]"
1514 r"web_test_delegate_impl\.cc$",
Samuel Huang577ef6c2018-03-13 18:19:341515 r"^components[\\\/]zucchini[\\\/].*",
peter80739bb2015-10-20 11:17:461516 # TODO(peter): Remove this exception. https://crbug.com/534537
1517 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1518 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251519 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1520 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241521 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111522 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151523 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111524 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521525 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501526 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361527 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311528 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131529 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001530 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441531 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451532 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021533 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351534 r"dump_file_system.cc$",
1535 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401536 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491537 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:401538
thomasanderson625d3932017-03-29 07:16:581539 log_info = set([])
1540 printf = set([])
[email protected]85218562013-11-22 07:41:401541
1542 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581543 for _, line in f.ChangedContents():
1544 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1545 log_info.add(f.LocalPath())
1546 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1547 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371548
thomasanderson625d3932017-03-29 07:16:581549 if input_api.re.search(r"\bprintf\(", line):
1550 printf.add(f.LocalPath())
1551 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1552 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401553
1554 if log_info:
1555 return [output_api.PresubmitError(
1556 'These files spam the console log with LOG(INFO):',
1557 items=log_info)]
1558 if printf:
1559 return [output_api.PresubmitError(
1560 'These files spam the console log with printf/fprintf:',
1561 items=printf)]
1562 return []
1563
1564
[email protected]49aa76a2013-12-04 06:59:161565def _CheckForAnonymousVariables(input_api, output_api):
1566 """These types are all expected to hold locks while in scope and
1567 so should never be anonymous (which causes them to be immediately
1568 destroyed)."""
1569 they_who_must_be_named = [
1570 'base::AutoLock',
1571 'base::AutoReset',
1572 'base::AutoUnlock',
1573 'SkAutoAlphaRestore',
1574 'SkAutoBitmapShaderInstall',
1575 'SkAutoBlitterChoose',
1576 'SkAutoBounderCommit',
1577 'SkAutoCallProc',
1578 'SkAutoCanvasRestore',
1579 'SkAutoCommentBlock',
1580 'SkAutoDescriptor',
1581 'SkAutoDisableDirectionCheck',
1582 'SkAutoDisableOvalCheck',
1583 'SkAutoFree',
1584 'SkAutoGlyphCache',
1585 'SkAutoHDC',
1586 'SkAutoLockColors',
1587 'SkAutoLockPixels',
1588 'SkAutoMalloc',
1589 'SkAutoMaskFreeImage',
1590 'SkAutoMutexAcquire',
1591 'SkAutoPathBoundsUpdate',
1592 'SkAutoPDFRelease',
1593 'SkAutoRasterClipValidate',
1594 'SkAutoRef',
1595 'SkAutoTime',
1596 'SkAutoTrace',
1597 'SkAutoUnref',
1598 ]
1599 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1600 # bad: base::AutoLock(lock.get());
1601 # not bad: base::AutoLock lock(lock.get());
1602 bad_pattern = input_api.re.compile(anonymous)
1603 # good: new base::AutoLock(lock.get())
1604 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1605 errors = []
1606
1607 for f in input_api.AffectedFiles():
1608 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1609 continue
1610 for linenum, line in f.ChangedContents():
1611 if bad_pattern.search(line) and not good_pattern.search(line):
1612 errors.append('%s:%d' % (f.LocalPath(), linenum))
1613
1614 if errors:
1615 return [output_api.PresubmitError(
1616 'These lines create anonymous variables that need to be named:',
1617 items=errors)]
1618 return []
1619
1620
Peter Kasting4844e46e2018-02-23 07:27:101621def _CheckUniquePtr(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491622 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:101623 sources = lambda affected_file: input_api.FilterSourceFile(
1624 affected_file,
1625 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1626 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491627 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:551628
1629 # Pattern to capture a single "<...>" block of template arguments. It can
1630 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
1631 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
1632 # latter would likely require counting that < and > match, which is not
1633 # expressible in regular languages. Should the need arise, one can introduce
1634 # limited counting (matching up to a total number of nesting depth), which
1635 # should cover all practical cases for already a low nesting limit.
1636 template_arg_pattern = (
1637 r'<[^>]*' # Opening block of <.
1638 r'>([^<]*>)?') # Closing block of >.
1639 # Prefix expressing that whatever follows is not already inside a <...>
1640 # block.
1641 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:101642 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:551643 not_inside_template_arg_pattern
1644 + r'\bstd::unique_ptr'
1645 + template_arg_pattern
1646 + r'\(\)')
1647
1648 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
1649 template_arg_no_array_pattern = (
1650 r'<[^>]*[^]]' # Opening block of <.
1651 r'>([^(<]*[^]]>)?') # Closing block of >.
1652 # Prefix saying that what follows is the start of an expression.
1653 start_of_expr_pattern = r'(=|\breturn|^)\s*'
1654 # Suffix saying that what follows are call parentheses with a non-empty list
1655 # of arguments.
1656 nonempty_arg_list_pattern = r'\(([^)]|$)'
1657 return_construct_pattern = input_api.re.compile(
1658 start_of_expr_pattern
1659 + r'std::unique_ptr'
1660 + template_arg_no_array_pattern
1661 + nonempty_arg_list_pattern)
1662
Vaclav Brozek851d9602018-04-04 16:13:051663 problems_constructor = []
1664 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:101665 for f in input_api.AffectedSourceFiles(sources):
1666 for line_number, line in f.ChangedContents():
1667 # Disallow:
1668 # return std::unique_ptr<T>(foo);
1669 # bar = std::unique_ptr<T>(foo);
1670 # But allow:
1671 # return std::unique_ptr<T[]>(foo);
1672 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozek851d9602018-04-04 16:13:051673 local_path = f.LocalPath()
Peter Kasting4844e46e2018-02-23 07:27:101674 if return_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051675 problems_constructor.append(
1676 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:101677 # Disallow:
1678 # std::unique_ptr<T>()
1679 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051680 problems_nullptr.append(
1681 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1682
1683 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:161684 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:051685 errors.append(output_api.PresubmitError(
1686 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161687 problems_nullptr))
1688 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:051689 errors.append(output_api.PresubmitError(
1690 'The following files use explicit std::unique_ptr constructor.'
1691 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161692 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:101693 return errors
1694
1695
[email protected]999261d2014-03-03 20:08:081696def _CheckUserActionUpdate(input_api, output_api):
1697 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521698 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081699 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521700 # If actions.xml is already included in the changelist, the PRESUBMIT
1701 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081702 return []
1703
[email protected]999261d2014-03-03 20:08:081704 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1705 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521706 current_actions = None
[email protected]999261d2014-03-03 20:08:081707 for f in input_api.AffectedFiles(file_filter=file_filter):
1708 for line_num, line in f.ChangedContents():
1709 match = input_api.re.search(action_re, line)
1710 if match:
[email protected]2f92dec2014-03-07 19:21:521711 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1712 # loaded only once.
1713 if not current_actions:
1714 with open('tools/metrics/actions/actions.xml') as actions_f:
1715 current_actions = actions_f.read()
1716 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081717 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521718 action = 'name="{0}"'.format(action_name)
1719 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081720 return [output_api.PresubmitPromptWarning(
1721 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521722 'tools/metrics/actions/actions.xml. Please run '
1723 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081724 % (f.LocalPath(), line_num, action_name))]
1725 return []
1726
1727
Daniel Cheng13ca61a882017-08-25 15:11:251728def _ImportJSONCommentEater(input_api):
1729 import sys
1730 sys.path = sys.path + [input_api.os_path.join(
1731 input_api.PresubmitLocalPath(),
1732 'tools', 'json_comment_eater')]
1733 import json_comment_eater
1734 return json_comment_eater
1735
1736
[email protected]99171a92014-06-03 08:44:471737def _GetJSONParseError(input_api, filename, eat_comments=True):
1738 try:
1739 contents = input_api.ReadFile(filename)
1740 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:251741 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:131742 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471743
1744 input_api.json.loads(contents)
1745 except ValueError as e:
1746 return e
1747 return None
1748
1749
1750def _GetIDLParseError(input_api, filename):
1751 try:
1752 contents = input_api.ReadFile(filename)
1753 idl_schema = input_api.os_path.join(
1754 input_api.PresubmitLocalPath(),
1755 'tools', 'json_schema_compiler', 'idl_schema.py')
1756 process = input_api.subprocess.Popen(
1757 [input_api.python_executable, idl_schema],
1758 stdin=input_api.subprocess.PIPE,
1759 stdout=input_api.subprocess.PIPE,
1760 stderr=input_api.subprocess.PIPE,
1761 universal_newlines=True)
1762 (_, error) = process.communicate(input=contents)
1763 return error or None
1764 except ValueError as e:
1765 return e
1766
1767
1768def _CheckParseErrors(input_api, output_api):
1769 """Check that IDL and JSON files do not contain syntax errors."""
1770 actions = {
1771 '.idl': _GetIDLParseError,
1772 '.json': _GetJSONParseError,
1773 }
[email protected]99171a92014-06-03 08:44:471774 # Most JSON files are preprocessed and support comments, but these do not.
1775 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491776 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471777 ]
1778 # Only run IDL checker on files in these directories.
1779 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491780 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1781 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471782 ]
1783
1784 def get_action(affected_file):
1785 filename = affected_file.LocalPath()
1786 return actions.get(input_api.os_path.splitext(filename)[1])
1787
[email protected]99171a92014-06-03 08:44:471788 def FilterFile(affected_file):
1789 action = get_action(affected_file)
1790 if not action:
1791 return False
1792 path = affected_file.LocalPath()
1793
Sean Kau46e29bc2017-08-28 16:31:161794 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:471795 return False
1796
1797 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:161798 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:471799 return False
1800 return True
1801
1802 results = []
1803 for affected_file in input_api.AffectedFiles(
1804 file_filter=FilterFile, include_deletes=False):
1805 action = get_action(affected_file)
1806 kwargs = {}
1807 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:161808 _MatchesFile(input_api, json_no_comments_patterns,
1809 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:471810 kwargs['eat_comments'] = False
1811 parse_error = action(input_api,
1812 affected_file.AbsoluteLocalPath(),
1813 **kwargs)
1814 if parse_error:
1815 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1816 (affected_file.LocalPath(), parse_error)))
1817 return results
1818
1819
[email protected]760deea2013-12-10 19:33:491820def _CheckJavaStyle(input_api, output_api):
1821 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471822 import sys
[email protected]760deea2013-12-10 19:33:491823 original_sys_path = sys.path
1824 try:
1825 sys.path = sys.path + [input_api.os_path.join(
1826 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1827 import checkstyle
1828 finally:
1829 # Restore sys.path to what it was before.
1830 sys.path = original_sys_path
1831
1832 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091833 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511834 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491835
1836
Sean Kau46e29bc2017-08-28 16:31:161837def _MatchesFile(input_api, patterns, path):
1838 for pattern in patterns:
1839 if input_api.re.search(pattern, path):
1840 return True
1841 return False
1842
1843
Daniel Cheng7052cdf2017-11-21 19:23:291844def _GetOwnersFilesToCheckForIpcOwners(input_api):
1845 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:171846
Daniel Cheng7052cdf2017-11-21 19:23:291847 Returns:
1848 A dictionary mapping an OWNER file to the list of OWNERS rules it must
1849 contain to cover IPC-related files with noparent reviewer rules.
1850 """
1851 # Whether or not a file affects IPC is (mostly) determined by a simple list
1852 # of filename patterns.
dchenge07de812016-06-20 19:27:171853 file_patterns = [
palmerb19a0932017-01-24 04:00:311854 # Legacy IPC:
dchenge07de812016-06-20 19:27:171855 '*_messages.cc',
1856 '*_messages*.h',
1857 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311858 # Mojo IPC:
dchenge07de812016-06-20 19:27:171859 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:471860 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:171861 '*_struct_traits*.*',
1862 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311863 '*.typemap',
1864 # Android native IPC:
1865 '*.aidl',
1866 # Blink uses a different file naming convention:
1867 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:471868 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:171869 '*StructTraits*.*',
1870 '*TypeConverter*.*',
1871 ]
1872
scottmg7a6ed5ba2016-11-04 18:22:041873 # These third_party directories do not contain IPCs, but contain files
1874 # matching the above patterns, which trigger false positives.
1875 exclude_paths = [
1876 'third_party/crashpad/*',
Daniel Chengebe635e2018-07-13 12:36:061877 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:291878 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:041879 ]
1880
dchenge07de812016-06-20 19:27:171881 # Dictionary mapping an OWNERS file path to Patterns.
1882 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1883 # rules ) to a PatternEntry.
1884 # PatternEntry is a dictionary with two keys:
1885 # - 'files': the files that are matched by this pattern
1886 # - 'rules': the per-file rules needed for this pattern
1887 # For example, if we expect OWNERS file to contain rules for *.mojom and
1888 # *_struct_traits*.*, Patterns might look like this:
1889 # {
1890 # '*.mojom': {
1891 # 'files': ...,
1892 # 'rules': [
1893 # 'per-file *.mojom=set noparent',
1894 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1895 # ],
1896 # },
1897 # '*_struct_traits*.*': {
1898 # 'files': ...,
1899 # 'rules': [
1900 # 'per-file *_struct_traits*.*=set noparent',
1901 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1902 # ],
1903 # },
1904 # }
1905 to_check = {}
1906
Daniel Cheng13ca61a882017-08-25 15:11:251907 def AddPatternToCheck(input_file, pattern):
1908 owners_file = input_api.os_path.join(
1909 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
1910 if owners_file not in to_check:
1911 to_check[owners_file] = {}
1912 if pattern not in to_check[owners_file]:
1913 to_check[owners_file][pattern] = {
1914 'files': [],
1915 'rules': [
1916 'per-file %s=set noparent' % pattern,
1917 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1918 ]
1919 }
Vaclav Brozekd5de76a2018-03-17 07:57:501920 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:251921
dchenge07de812016-06-20 19:27:171922 # Iterate through the affected files to see what we actually need to check
1923 # for. We should only nag patch authors about per-file rules if a file in that
1924 # directory would match that pattern. If a directory only contains *.mojom
1925 # files and no *_messages*.h files, we should only nag about rules for
1926 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:251927 for f in input_api.AffectedFiles(include_deletes=False):
1928 # Manifest files don't have a strong naming convention. Instead, scan
1929 # affected files for .json files and see if they look like a manifest.
Sean Kau46e29bc2017-08-28 16:31:161930 if (f.LocalPath().endswith('.json') and
1931 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
1932 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:251933 json_comment_eater = _ImportJSONCommentEater(input_api)
1934 mostly_json_lines = '\n'.join(f.NewContents())
1935 # Comments aren't allowed in strict JSON, so filter them out.
1936 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:431937 try:
1938 json_content = input_api.json.loads(json_lines)
1939 except:
1940 # There's another PRESUBMIT check that already verifies that JSON files
1941 # are not invalid, so no need to emit another warning here.
1942 continue
Daniel Cheng13ca61a882017-08-25 15:11:251943 if 'interface_provider_specs' in json_content:
1944 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:171945 for pattern in file_patterns:
1946 if input_api.fnmatch.fnmatch(
1947 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041948 skip = False
1949 for exclude in exclude_paths:
1950 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1951 skip = True
1952 break
1953 if skip:
1954 continue
Daniel Cheng13ca61a882017-08-25 15:11:251955 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:171956 break
1957
Daniel Cheng7052cdf2017-11-21 19:23:291958 return to_check
1959
1960
1961def _CheckIpcOwners(input_api, output_api):
1962 """Checks that affected files involving IPC have an IPC OWNERS rule."""
1963 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
1964
1965 if to_check:
1966 # If there are any OWNERS files to check, there are IPC-related changes in
1967 # this CL. Auto-CC the review list.
1968 output_api.AppendCC('[email protected]')
1969
1970 # Go through the OWNERS files to check, filtering out rules that are already
1971 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:171972 for owners_file, patterns in to_check.iteritems():
1973 try:
1974 with file(owners_file) as f:
1975 lines = set(f.read().splitlines())
1976 for entry in patterns.itervalues():
1977 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1978 ]
1979 except IOError:
1980 # No OWNERS file, so all the rules are definitely missing.
1981 continue
1982
1983 # All the remaining lines weren't found in OWNERS files, so emit an error.
1984 errors = []
1985 for owners_file, patterns in to_check.iteritems():
1986 missing_lines = []
1987 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:501988 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:171989 missing_lines.extend(entry['rules'])
1990 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1991 if missing_lines:
1992 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:051993 'Because of the presence of files:\n%s\n\n'
1994 '%s needs the following %d lines added:\n\n%s' %
1995 ('\n'.join(files), owners_file, len(missing_lines),
1996 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:171997
1998 results = []
1999 if errors:
vabrf5ce3bf92016-07-11 14:52:412000 if input_api.is_committing:
2001 output = output_api.PresubmitError
2002 else:
2003 output = output_api.PresubmitPromptWarning
2004 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592005 'Found OWNERS files that need to be updated for IPC security ' +
2006 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172007 long_text='\n\n'.join(errors)))
2008
2009 return results
2010
2011
jbriance9e12f162016-11-25 07:57:502012def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312013 """Checks that added or removed lines in non third party affected
2014 header files do not lead to new useless class or struct forward
2015 declaration.
jbriance9e12f162016-11-25 07:57:502016 """
2017 results = []
2018 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2019 input_api.re.MULTILINE)
2020 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2021 input_api.re.MULTILINE)
2022 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312023 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192024 not f.LocalPath().startswith('third_party/blink') and
2025 not f.LocalPath().startswith('third_party\\blink') and
jbriance2c51e821a2016-12-12 08:24:312026 not f.LocalPath().startswith('third_party/WebKit') and
2027 not f.LocalPath().startswith('third_party\\WebKit')):
2028 continue
2029
jbriance9e12f162016-11-25 07:57:502030 if not f.LocalPath().endswith('.h'):
2031 continue
2032
2033 contents = input_api.ReadFile(f)
2034 fwd_decls = input_api.re.findall(class_pattern, contents)
2035 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2036
2037 useless_fwd_decls = []
2038 for decl in fwd_decls:
2039 count = sum(1 for _ in input_api.re.finditer(
2040 r'\b%s\b' % input_api.re.escape(decl), contents))
2041 if count == 1:
2042 useless_fwd_decls.append(decl)
2043
2044 if not useless_fwd_decls:
2045 continue
2046
2047 for line in f.GenerateScmDiff().splitlines():
2048 if (line.startswith('-') and not line.startswith('--') or
2049 line.startswith('+') and not line.startswith('++')):
2050 for decl in useless_fwd_decls:
2051 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2052 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242053 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502054 (f.LocalPath(), decl)))
2055 useless_fwd_decls.remove(decl)
2056
2057 return results
2058
2059
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492060# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:292061def _CheckAndroidToastUsage(input_api, output_api):
2062 """Checks that code uses org.chromium.ui.widget.Toast instead of
2063 android.widget.Toast (Chromium Toast doesn't force hardware
2064 acceleration on low-end devices, saving memory).
2065 """
2066 toast_import_pattern = input_api.re.compile(
2067 r'^import android\.widget\.Toast;$')
2068
2069 errors = []
2070
2071 sources = lambda affected_file: input_api.FilterSourceFile(
2072 affected_file,
2073 black_list=(_EXCLUDED_PATHS +
2074 _TEST_CODE_EXCLUDED_PATHS +
2075 input_api.DEFAULT_BLACK_LIST +
2076 (r'^chromecast[\\\/].*',
2077 r'^remoting[\\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492078 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:292079
2080 for f in input_api.AffectedSourceFiles(sources):
2081 for line_num, line in f.ChangedContents():
2082 if toast_import_pattern.search(line):
2083 errors.append("%s:%d" % (f.LocalPath(), line_num))
2084
2085 results = []
2086
2087 if errors:
2088 results.append(output_api.PresubmitError(
2089 'android.widget.Toast usage is detected. Android toasts use hardware'
2090 ' acceleration, and can be\ncostly on low-end devices. Please use'
2091 ' org.chromium.ui.widget.Toast instead.\n'
2092 'Contact [email protected] if you have any questions.',
2093 errors))
2094
2095 return results
2096
2097
dgnaa68d5e2015-06-10 10:08:222098def _CheckAndroidCrLogUsage(input_api, output_api):
2099 """Checks that new logs using org.chromium.base.Log:
2100 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512101 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222102 """
pkotwicza1dd0b002016-05-16 14:41:042103
torne89540622017-03-24 19:41:302104 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042105 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302106 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:042107 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:302108 # WebView license viewer code cannot depend on //base; used in stub APK.
2109 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
2110 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:042111 ]
2112
dgnaa68d5e2015-06-10 10:08:222113 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122114 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2115 class_in_base_pattern = input_api.re.compile(
2116 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2117 has_some_log_import_pattern = input_api.re.compile(
2118 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222119 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122120 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222121 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512122 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222123 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222124
Vincent Scheib16d7b272015-09-15 18:09:072125 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222126 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492127 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:042128 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122129
dgnaa68d5e2015-06-10 10:08:222130 tag_decl_errors = []
2131 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122132 tag_errors = []
dgn38736db2015-09-18 19:20:512133 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122134 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222135
2136 for f in input_api.AffectedSourceFiles(sources):
2137 file_content = input_api.ReadFile(f)
2138 has_modified_logs = False
2139
2140 # Per line checks
dgn87d9fb62015-06-12 09:15:122141 if (cr_log_import_pattern.search(file_content) or
2142 (class_in_base_pattern.search(file_content) and
2143 not has_some_log_import_pattern.search(file_content))):
2144 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222145 for line_num, line in f.ChangedContents():
2146
2147 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122148 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222149 if match:
2150 has_modified_logs = True
2151
2152 # Make sure it uses "TAG"
2153 if not match.group('tag') == 'TAG':
2154 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122155 else:
2156 # Report non cr Log function calls in changed lines
2157 for line_num, line in f.ChangedContents():
2158 if log_call_pattern.search(line):
2159 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222160
2161 # Per file checks
2162 if has_modified_logs:
2163 # Make sure the tag is using the "cr" prefix and is not too long
2164 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512165 tag_name = match.group('name') if match else None
2166 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222167 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512168 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222169 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512170 elif '.' in tag_name:
2171 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222172
2173 results = []
2174 if tag_decl_errors:
2175 results.append(output_api.PresubmitPromptWarning(
2176 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512177 '"private static final String TAG = "<package tag>".\n'
2178 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222179 tag_decl_errors))
2180
2181 if tag_length_errors:
2182 results.append(output_api.PresubmitError(
2183 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512184 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222185 tag_length_errors))
2186
2187 if tag_errors:
2188 results.append(output_api.PresubmitPromptWarning(
2189 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2190 tag_errors))
2191
dgn87d9fb62015-06-12 09:15:122192 if util_log_errors:
dgn4401aa52015-04-29 16:26:172193 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122194 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2195 util_log_errors))
2196
dgn38736db2015-09-18 19:20:512197 if tag_with_dot_errors:
2198 results.append(output_api.PresubmitPromptWarning(
2199 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2200 tag_with_dot_errors))
2201
dgn4401aa52015-04-29 16:26:172202 return results
2203
2204
Yoland Yanb92fa522017-08-28 17:37:062205def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2206 """Checks that junit.framework.* is no longer used."""
2207 deprecated_junit_framework_pattern = input_api.re.compile(
2208 r'^import junit\.framework\..*;',
2209 input_api.re.MULTILINE)
2210 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492211 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062212 errors = []
2213 for f in input_api.AffectedFiles(sources):
2214 for line_num, line in f.ChangedContents():
2215 if deprecated_junit_framework_pattern.search(line):
2216 errors.append("%s:%d" % (f.LocalPath(), line_num))
2217
2218 results = []
2219 if errors:
2220 results.append(output_api.PresubmitError(
2221 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2222 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2223 ' if you have any question.', errors))
2224 return results
2225
2226
2227def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2228 """Checks that if new Java test classes have inheritance.
2229 Either the new test class is JUnit3 test or it is a JUnit4 test class
2230 with a base class, either case is undesirable.
2231 """
2232 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2233
2234 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492235 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062236 errors = []
2237 for f in input_api.AffectedFiles(sources):
2238 if not f.OldContents():
2239 class_declaration_start_flag = False
2240 for line_num, line in f.ChangedContents():
2241 if class_declaration_pattern.search(line):
2242 class_declaration_start_flag = True
2243 if class_declaration_start_flag and ' extends ' in line:
2244 errors.append('%s:%d' % (f.LocalPath(), line_num))
2245 if '{' in line:
2246 class_declaration_start_flag = False
2247
2248 results = []
2249 if errors:
2250 results.append(output_api.PresubmitPromptWarning(
2251 'The newly created files include Test classes that inherits from base'
2252 ' class. Please do not use inheritance in JUnit4 tests or add new'
2253 ' JUnit3 tests. Contact [email protected] if you have any'
2254 ' questions.', errors))
2255 return results
2256
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202257
yolandyan45001472016-12-21 21:12:422258def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2259 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2260 deprecated_annotation_import_pattern = input_api.re.compile(
2261 r'^import android\.test\.suitebuilder\.annotation\..*;',
2262 input_api.re.MULTILINE)
2263 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492264 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:422265 errors = []
2266 for f in input_api.AffectedFiles(sources):
2267 for line_num, line in f.ChangedContents():
2268 if deprecated_annotation_import_pattern.search(line):
2269 errors.append("%s:%d" % (f.LocalPath(), line_num))
2270
2271 results = []
2272 if errors:
2273 results.append(output_api.PresubmitError(
2274 'Annotations in android.test.suitebuilder.annotation have been'
2275 ' deprecated since API level 24. Please use android.support.test.filters'
2276 ' from //third_party/android_support_test_runner:runner_java instead.'
2277 ' Contact [email protected] if you have any questions.', errors))
2278 return results
2279
2280
agrieve7b6479d82015-10-07 14:24:222281def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2282 """Checks if MDPI assets are placed in a correct directory."""
2283 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2284 ('/res/drawable/' in f.LocalPath() or
2285 '/res/drawable-ldrtl/' in f.LocalPath()))
2286 errors = []
2287 for f in input_api.AffectedFiles(include_deletes=False,
2288 file_filter=file_filter):
2289 errors.append(' %s' % f.LocalPath())
2290
2291 results = []
2292 if errors:
2293 results.append(output_api.PresubmitError(
2294 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2295 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2296 '/res/drawable-ldrtl/.\n'
2297 'Contact [email protected] if you have questions.', errors))
2298 return results
2299
2300
Nate Fischer535972b2017-09-16 01:06:182301def _CheckAndroidWebkitImports(input_api, output_api):
2302 """Checks that code uses org.chromium.base.Callback instead of
2303 android.widget.ValueCallback except in the WebView glue layer.
2304 """
2305 valuecallback_import_pattern = input_api.re.compile(
2306 r'^import android\.webkit\.ValueCallback;$')
2307
2308 errors = []
2309
2310 sources = lambda affected_file: input_api.FilterSourceFile(
2311 affected_file,
2312 black_list=(_EXCLUDED_PATHS +
2313 _TEST_CODE_EXCLUDED_PATHS +
2314 input_api.DEFAULT_BLACK_LIST +
2315 (r'^android_webview[\\\/]glue[\\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492316 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:182317
2318 for f in input_api.AffectedSourceFiles(sources):
2319 for line_num, line in f.ChangedContents():
2320 if valuecallback_import_pattern.search(line):
2321 errors.append("%s:%d" % (f.LocalPath(), line_num))
2322
2323 results = []
2324
2325 if errors:
2326 results.append(output_api.PresubmitError(
2327 'android.webkit.ValueCallback usage is detected outside of the glue'
2328 ' layer. To stay compatible with the support library, android.webkit.*'
2329 ' classes should only be used inside the glue layer and'
2330 ' org.chromium.base.Callback should be used instead.',
2331 errors))
2332
2333 return results
2334
2335
agrievef32bcc72016-04-04 14:57:402336class PydepsChecker(object):
2337 def __init__(self, input_api, pydeps_files):
2338 self._file_cache = {}
2339 self._input_api = input_api
2340 self._pydeps_files = pydeps_files
2341
2342 def _LoadFile(self, path):
2343 """Returns the list of paths within a .pydeps file relative to //."""
2344 if path not in self._file_cache:
2345 with open(path) as f:
2346 self._file_cache[path] = f.read()
2347 return self._file_cache[path]
2348
2349 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2350 """Returns an interable of paths within the .pydep, relativized to //."""
2351 os_path = self._input_api.os_path
2352 pydeps_dir = os_path.dirname(pydeps_path)
2353 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2354 if not l.startswith('*'))
2355 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2356
2357 def _CreateFilesToPydepsMap(self):
2358 """Returns a map of local_path -> list_of_pydeps."""
2359 ret = {}
2360 for pydep_local_path in self._pydeps_files:
2361 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2362 ret.setdefault(path, []).append(pydep_local_path)
2363 return ret
2364
2365 def ComputeAffectedPydeps(self):
2366 """Returns an iterable of .pydeps files that might need regenerating."""
2367 affected_pydeps = set()
2368 file_to_pydeps_map = None
2369 for f in self._input_api.AffectedFiles(include_deletes=True):
2370 local_path = f.LocalPath()
2371 if local_path == 'DEPS':
2372 return self._pydeps_files
2373 elif local_path.endswith('.pydeps'):
2374 if local_path in self._pydeps_files:
2375 affected_pydeps.add(local_path)
2376 elif local_path.endswith('.py'):
2377 if file_to_pydeps_map is None:
2378 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2379 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2380 return affected_pydeps
2381
2382 def DetermineIfStale(self, pydeps_path):
2383 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412384 import difflib
John Budorick47ca3fe2018-02-10 00:53:102385 import os
2386
agrievef32bcc72016-04-04 14:57:402387 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2388 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102389 env = dict(os.environ)
2390 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402391 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102392 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412393 old_contents = old_pydeps_data[2:]
2394 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402395 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412396 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402397
2398
2399def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2400 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402401 # This check is for Python dependency lists (.pydeps files), and involves
2402 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2403 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282404 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002405 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022406 # TODO(agrieve): Update when there's a better way to detect
2407 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402408 is_android = input_api.os_path.exists('third_party/android_tools')
2409 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2410 results = []
2411 # First, check for new / deleted .pydeps.
2412 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032413 # Check whether we are running the presubmit check for a file in src.
2414 # f.LocalPath is relative to repo (src, or internal repo).
2415 # os_path.exists is relative to src repo.
2416 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2417 # to src and we can conclude that the pydeps is in src.
2418 if input_api.os_path.exists(f.LocalPath()):
2419 if f.LocalPath().endswith('.pydeps'):
2420 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2421 results.append(output_api.PresubmitError(
2422 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2423 'remove %s' % f.LocalPath()))
2424 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2425 results.append(output_api.PresubmitError(
2426 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2427 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402428
2429 if results:
2430 return results
2431
2432 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2433
2434 for pydep_path in checker.ComputeAffectedPydeps():
2435 try:
phajdan.jr0d9878552016-11-04 10:49:412436 result = checker.DetermineIfStale(pydep_path)
2437 if result:
2438 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402439 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412440 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2441 'To regenerate, run:\n\n %s' %
2442 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402443 except input_api.subprocess.CalledProcessError as error:
2444 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2445 long_text=error.output)]
2446
2447 return results
2448
2449
glidere61efad2015-02-18 17:39:432450def _CheckSingletonInHeaders(input_api, output_api):
2451 """Checks to make sure no header files have |Singleton<|."""
2452 def FileFilter(affected_file):
2453 # It's ok for base/memory/singleton.h to have |Singleton<|.
2454 black_list = (_EXCLUDED_PATHS +
2455 input_api.DEFAULT_BLACK_LIST +
Michael Warrese4451492018-03-07 04:42:472456 (r"^base[\\\/]memory[\\\/]singleton\.h$",
2457 r"^net[\\\/]quic[\\\/]platform[\\\/]impl[\\\/]"
2458 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432459 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2460
sergeyu34d21222015-09-16 00:11:442461 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432462 files = []
2463 for f in input_api.AffectedSourceFiles(FileFilter):
2464 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2465 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2466 contents = input_api.ReadFile(f)
2467 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242468 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432469 pattern.search(line)):
2470 files.append(f)
2471 break
2472
2473 if files:
yolandyandaabc6d2016-04-18 18:29:392474 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442475 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432476 'Please move them to an appropriate source file so that the ' +
2477 'template gets instantiated in a single compilation unit.',
2478 files) ]
2479 return []
2480
2481
[email protected]fd20b902014-05-09 02:14:532482_DEPRECATED_CSS = [
2483 # Values
2484 ( "-webkit-box", "flex" ),
2485 ( "-webkit-inline-box", "inline-flex" ),
2486 ( "-webkit-flex", "flex" ),
2487 ( "-webkit-inline-flex", "inline-flex" ),
2488 ( "-webkit-min-content", "min-content" ),
2489 ( "-webkit-max-content", "max-content" ),
2490
2491 # Properties
2492 ( "-webkit-background-clip", "background-clip" ),
2493 ( "-webkit-background-origin", "background-origin" ),
2494 ( "-webkit-background-size", "background-size" ),
2495 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442496 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532497
2498 # Functions
2499 ( "-webkit-gradient", "gradient" ),
2500 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2501 ( "-webkit-linear-gradient", "linear-gradient" ),
2502 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2503 ( "-webkit-radial-gradient", "radial-gradient" ),
2504 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2505]
2506
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202507
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492508# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242509def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532510 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252511 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342512 documentation and iOS CSS for dom distiller
2513 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252514 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532515 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492516 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:252517 black_list = (_EXCLUDED_PATHS +
2518 _TEST_CODE_EXCLUDED_PATHS +
2519 input_api.DEFAULT_BLACK_LIST +
2520 (r"^chrome/common/extensions/docs",
2521 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342522 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442523 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252524 r"^native_client_sdk"))
2525 file_filter = lambda f: input_api.FilterSourceFile(
2526 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532527 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2528 for line_num, line in fpath.ChangedContents():
2529 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022530 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532531 results.append(output_api.PresubmitError(
2532 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2533 (fpath.LocalPath(), line_num, deprecated_value, value)))
2534 return results
2535
mohan.reddyf21db962014-10-16 12:26:472536
dbeam070cfe62014-10-22 06:44:022537_DEPRECATED_JS = [
2538 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2539 ( "__defineGetter__", "Object.defineProperty" ),
2540 ( "__defineSetter__", "Object.defineProperty" ),
2541]
2542
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202543
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492544# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242545def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022546 """Make sure that we don't use deprecated JS in Chrome code."""
2547 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492548 file_inclusion_pattern = [r".+\.js$"] # TODO(dbeam): .html?
dbeam070cfe62014-10-22 06:44:022549 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2550 input_api.DEFAULT_BLACK_LIST)
2551 file_filter = lambda f: input_api.FilterSourceFile(
2552 f, white_list=file_inclusion_pattern, black_list=black_list)
2553 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2554 for lnum, line in fpath.ChangedContents():
2555 for (deprecated, replacement) in _DEPRECATED_JS:
2556 if deprecated in line:
2557 results.append(output_api.PresubmitError(
2558 "%s:%d: Use of deprecated JS %s, use %s instead" %
2559 (fpath.LocalPath(), lnum, deprecated, replacement)))
2560 return results
2561
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202562
dpapadd651231d82017-07-21 02:44:472563def _CheckForRiskyJsArrowFunction(line_number, line):
2564 if ' => ' in line:
2565 return "line %d, is using an => (arrow) function\n %s\n" % (
2566 line_number, line)
2567 return ''
2568
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202569
dpapadd651231d82017-07-21 02:44:472570def _CheckForRiskyJsConstLet(input_api, line_number, line):
2571 if input_api.re.match('^\s*(const|let)\s', line):
2572 return "line %d, is using const/let keyword\n %s\n" % (
2573 line_number, line)
2574 return ''
dbeam070cfe62014-10-22 06:44:022575
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202576
dbeam1ec68ac2016-12-15 05:22:242577def _CheckForRiskyJsFeatures(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492578 maybe_ios_js = [r"^(ios|components|ui\/webui\/resources)\/.+\.js$"]
Steven Bennetts90545f3cb2017-08-14 18:11:002579 # 'ui/webui/resources/cr_components are not allowed on ios'
2580 not_ios_filter = (r".*ui\/webui\/resources\/cr_components.*", )
Steven Bennetts9c7e3c22017-08-02 19:10:572581 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js,
Steven Bennetts90545f3cb2017-08-14 18:11:002582 black_list=not_ios_filter)
dpapadd651231d82017-07-21 02:44:472583 results = []
dbeam1ec68ac2016-12-15 05:22:242584 for f in input_api.AffectedFiles(file_filter=file_filter):
dpapadd651231d82017-07-21 02:44:472585 arrow_error_lines = []
2586 const_let_error_lines = []
dbeam1ec68ac2016-12-15 05:22:242587 for lnum, line in f.ChangedContents():
dpapadd651231d82017-07-21 02:44:472588 arrow_error_lines += filter(None, [
2589 _CheckForRiskyJsArrowFunction(lnum, line),
2590 ])
dbeam1ec68ac2016-12-15 05:22:242591
dpapadd651231d82017-07-21 02:44:472592 const_let_error_lines += filter(None, [
2593 _CheckForRiskyJsConstLet(input_api, lnum, line),
2594 ])
dbeam1ec68ac2016-12-15 05:22:242595
dpapadd651231d82017-07-21 02:44:472596 if arrow_error_lines:
2597 arrow_error_lines = map(
2598 lambda e: "%s:%s" % (f.LocalPath(), e), arrow_error_lines)
2599 results.append(
2600 output_api.PresubmitPromptWarning('\n'.join(arrow_error_lines + [
2601"""
2602Use of => (arrow) operator detected in:
dbeam1ec68ac2016-12-15 05:22:242603%s
2604Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2605https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
dpapadd651231d82017-07-21 02:44:472606""" % f.LocalPath()
2607 ])))
dbeam1ec68ac2016-12-15 05:22:242608
dpapadd651231d82017-07-21 02:44:472609 if const_let_error_lines:
2610 const_let_error_lines = map(
2611 lambda e: "%s:%s" % (f.LocalPath(), e), const_let_error_lines)
2612 results.append(
2613 output_api.PresubmitPromptWarning('\n'.join(const_let_error_lines + [
2614"""
2615Use of const/let keywords detected in:
2616%s
2617Please ensure your code does not run on iOS9 because const/let is not fully
2618supported.
2619https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#let-Block_Scoped-Variables
2620https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#const-Block_Scoped-Constants
2621""" % f.LocalPath()
2622 ])))
2623
2624 return results
dbeam1ec68ac2016-12-15 05:22:242625
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202626
rlanday6802cf632017-05-30 17:48:362627def _CheckForRelativeIncludes(input_api, output_api):
2628 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2629 import sys
2630 original_sys_path = sys.path
2631 try:
2632 sys.path = sys.path + [input_api.os_path.join(
2633 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2634 from cpp_checker import CppChecker
2635 finally:
2636 # Restore sys.path to what it was before.
2637 sys.path = original_sys_path
2638
2639 bad_files = {}
2640 for f in input_api.AffectedFiles(include_deletes=False):
2641 if (f.LocalPath().startswith('third_party') and
2642 not f.LocalPath().startswith('third_party/WebKit') and
2643 not f.LocalPath().startswith('third_party\\WebKit')):
2644 continue
2645
2646 if not CppChecker.IsCppFile(f.LocalPath()):
2647 continue
2648
Vaclav Brozekd5de76a2018-03-17 07:57:502649 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362650 if "#include" in line and "../" in line]
2651 if not relative_includes:
2652 continue
2653 bad_files[f.LocalPath()] = relative_includes
2654
2655 if not bad_files:
2656 return []
2657
2658 error_descriptions = []
2659 for file_path, bad_lines in bad_files.iteritems():
2660 error_description = file_path
2661 for line in bad_lines:
2662 error_description += '\n ' + line
2663 error_descriptions.append(error_description)
2664
2665 results = []
2666 results.append(output_api.PresubmitError(
2667 'You added one or more relative #include paths (including "../").\n'
2668 'These shouldn\'t be used because they can be used to include headers\n'
2669 'from code that\'s not correctly specified as a dependency in the\n'
2670 'relevant BUILD.gn file(s).',
2671 error_descriptions))
2672
2673 return results
2674
Takeshi Yoshinoe387aa32017-08-02 13:16:132675
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202676def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2677 if not isinstance(key, ast.Str):
2678 return 'Key at line %d must be a string literal' % key.lineno
2679 if not isinstance(value, ast.Dict):
2680 return 'Value at line %d must be a dict' % value.lineno
2681 if len(value.keys) != 1:
2682 return 'Dict at line %d must have single entry' % value.lineno
2683 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2684 return (
2685 'Entry at line %d must have a string literal \'filepath\' as key' %
2686 value.lineno)
2687 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132688
Takeshi Yoshinoe387aa32017-08-02 13:16:132689
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202690def _CheckWatchlistsEntrySyntax(key, value, ast):
2691 if not isinstance(key, ast.Str):
2692 return 'Key at line %d must be a string literal' % key.lineno
2693 if not isinstance(value, ast.List):
2694 return 'Value at line %d must be a list' % value.lineno
2695 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132696
Takeshi Yoshinoe387aa32017-08-02 13:16:132697
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202698def _CheckWATCHLISTSEntries(wd_dict, w_dict, ast):
2699 mismatch_template = (
2700 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2701 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132702
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202703 i = 0
2704 last_key = ''
2705 while True:
2706 if i >= len(wd_dict.keys):
2707 if i >= len(w_dict.keys):
2708 return None
2709 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2710 elif i >= len(w_dict.keys):
2711 return (
2712 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132713
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202714 wd_key = wd_dict.keys[i]
2715 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132716
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202717 result = _CheckWatchlistDefinitionsEntrySyntax(
2718 wd_key, wd_dict.values[i], ast)
2719 if result is not None:
2720 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132721
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202722 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast)
2723 if result is not None:
2724 return 'Bad entry in WATCHLISTS dict: %s' % result
2725
2726 if wd_key.s != w_key.s:
2727 return mismatch_template % (
2728 '%s at line %d' % (wd_key.s, wd_key.lineno),
2729 '%s at line %d' % (w_key.s, w_key.lineno))
2730
2731 if wd_key.s < last_key:
2732 return (
2733 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2734 (wd_key.lineno, w_key.lineno))
2735 last_key = wd_key.s
2736
2737 i = i + 1
2738
2739
2740def _CheckWATCHLISTSSyntax(expression, ast):
2741 if not isinstance(expression, ast.Expression):
2742 return 'WATCHLISTS file must contain a valid expression'
2743 dictionary = expression.body
2744 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2745 return 'WATCHLISTS file must have single dict with exactly two entries'
2746
2747 first_key = dictionary.keys[0]
2748 first_value = dictionary.values[0]
2749 second_key = dictionary.keys[1]
2750 second_value = dictionary.values[1]
2751
2752 if (not isinstance(first_key, ast.Str) or
2753 first_key.s != 'WATCHLIST_DEFINITIONS' or
2754 not isinstance(first_value, ast.Dict)):
2755 return (
2756 'The first entry of the dict in WATCHLISTS file must be '
2757 'WATCHLIST_DEFINITIONS dict')
2758
2759 if (not isinstance(second_key, ast.Str) or
2760 second_key.s != 'WATCHLISTS' or
2761 not isinstance(second_value, ast.Dict)):
2762 return (
2763 'The second entry of the dict in WATCHLISTS file must be '
2764 'WATCHLISTS dict')
2765
2766 return _CheckWATCHLISTSEntries(first_value, second_value, ast)
Takeshi Yoshinoe387aa32017-08-02 13:16:132767
2768
2769def _CheckWATCHLISTS(input_api, output_api):
2770 for f in input_api.AffectedFiles(include_deletes=False):
2771 if f.LocalPath() == 'WATCHLISTS':
2772 contents = input_api.ReadFile(f, 'r')
2773
2774 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202775 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132776 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202777 # Get an AST tree for it and scan the tree for detailed style checking.
2778 expression = input_api.ast.parse(
2779 contents, filename='WATCHLISTS', mode='eval')
2780 except ValueError as e:
2781 return [output_api.PresubmitError(
2782 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2783 except SyntaxError as e:
2784 return [output_api.PresubmitError(
2785 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2786 except TypeError as e:
2787 return [output_api.PresubmitError(
2788 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132789
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202790 result = _CheckWATCHLISTSSyntax(expression, input_api.ast)
2791 if result is not None:
2792 return [output_api.PresubmitError(result)]
2793 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132794
2795 return []
2796
2797
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192798def _CheckNewHeaderWithoutGnChange(input_api, output_api):
2799 """Checks that newly added header files have corresponding GN changes.
2800 Note that this is only a heuristic. To be precise, run script:
2801 build/check_gn_headers.py.
2802 """
2803
2804 def headers(f):
2805 return input_api.FilterSourceFile(
2806 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
2807
2808 new_headers = []
2809 for f in input_api.AffectedSourceFiles(headers):
2810 if f.Action() != 'A':
2811 continue
2812 new_headers.append(f.LocalPath())
2813
2814 def gn_files(f):
2815 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
2816
2817 all_gn_changed_contents = ''
2818 for f in input_api.AffectedSourceFiles(gn_files):
2819 for _, line in f.ChangedContents():
2820 all_gn_changed_contents += line
2821
2822 problems = []
2823 for header in new_headers:
2824 basename = input_api.os_path.basename(header)
2825 if basename not in all_gn_changed_contents:
2826 problems.append(header)
2827
2828 if problems:
2829 return [output_api.PresubmitPromptWarning(
2830 'Missing GN changes for new header files', items=sorted(problems),
2831 long_text='Please double check whether newly added header files need '
2832 'corresponding changes in gn or gni files.\nThis checking is only a '
2833 'heuristic. Run build/check_gn_headers.py to be precise.\n'
2834 'Read https://crbug.com/661774 for more info.')]
2835 return []
2836
2837
dgnaa68d5e2015-06-10 10:08:222838def _AndroidSpecificOnUploadChecks(input_api, output_api):
2839 """Groups checks that target android code."""
2840 results = []
dgnaa68d5e2015-06-10 10:08:222841 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222842 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292843 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:062844 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
2845 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:422846 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:182847 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222848 return results
2849
2850
[email protected]22c9bd72011-03-27 16:47:392851def _CommonChecks(input_api, output_api):
2852 """Checks common to both upload and commit."""
2853 results = []
2854 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382855 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542856 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:082857
2858 author = input_api.change.author_email
2859 if author and author not in _KNOWN_ROBOTS:
2860 results.extend(
2861 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
2862
[email protected]55459852011-08-10 15:17:192863 results.extend(
[email protected]760deea2013-12-10 19:33:492864 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:232865 results.extend(
2866 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542867 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182868 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522869 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222870 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442871 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592872 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062873 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122874 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182875 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222876 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302877 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492878 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032879 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492880 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442881 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272882 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:072883 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542884 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442885 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392886 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552887 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042888 results.extend(
2889 input_api.canned_checks.CheckChangeHasNoTabs(
2890 input_api,
2891 output_api,
2892 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402893 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162894 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082895 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242896 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2897 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472898 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042899 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:052900 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:142901 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232902 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432903 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402904 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152905 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172906 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502907 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242908 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:362909 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:132910 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:432911 results.extend(input_api.RunTests(
2912 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:142913 results.extend(_CheckTranslationScreenshots(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:242914
Vaclav Brozekcdc7defb2018-03-20 09:54:352915 for f in input_api.AffectedFiles():
2916 path, name = input_api.os_path.split(f.LocalPath())
2917 if name == 'PRESUBMIT.py':
2918 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:002919 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
2920 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:072921 # The PRESUBMIT.py file (and the directory containing it) might
2922 # have been affected by being moved or removed, so only try to
2923 # run the tests if they still exist.
2924 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2925 input_api, output_api, full_path,
2926 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392927 return results
[email protected]1f7b4172010-01-28 01:17:342928
[email protected]b337cb5b2011-01-23 21:24:052929
[email protected]b8079ae4a2012-12-05 19:56:492930def _CheckPatchFiles(input_api, output_api):
2931 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2932 if f.LocalPath().endswith(('.orig', '.rej'))]
2933 if problems:
2934 return [output_api.PresubmitError(
2935 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032936 else:
2937 return []
[email protected]b8079ae4a2012-12-05 19:56:492938
2939
Kent Tamura5a8755d2017-06-29 23:37:072940def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:212941 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
2942 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
2943 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:072944 include_re = input_api.re.compile(
2945 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
2946 extension_re = input_api.re.compile(r'\.[a-z]+$')
2947 errors = []
2948 for f in input_api.AffectedFiles():
2949 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
2950 continue
2951 found_line_number = None
2952 found_macro = None
2953 for line_num, line in f.ChangedContents():
2954 match = macro_re.search(line)
2955 if match:
2956 found_line_number = line_num
2957 found_macro = match.group(2)
2958 break
2959 if not found_line_number:
2960 continue
2961
2962 found_include = False
2963 for line in f.NewContents():
2964 if include_re.search(line):
2965 found_include = True
2966 break
2967 if found_include:
2968 continue
2969
2970 if not f.LocalPath().endswith('.h'):
2971 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
2972 try:
2973 content = input_api.ReadFile(primary_header_path, 'r')
2974 if include_re.search(content):
2975 continue
2976 except IOError:
2977 pass
2978 errors.append('%s:%d %s macro is used without including build/'
2979 'build_config.h.'
2980 % (f.LocalPath(), found_line_number, found_macro))
2981 if errors:
2982 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
2983 return []
2984
2985
[email protected]b00342e7f2013-03-26 16:21:542986def _DidYouMeanOSMacro(bad_macro):
2987 try:
2988 return {'A': 'OS_ANDROID',
2989 'B': 'OS_BSD',
2990 'C': 'OS_CHROMEOS',
2991 'F': 'OS_FREEBSD',
2992 'L': 'OS_LINUX',
2993 'M': 'OS_MACOSX',
2994 'N': 'OS_NACL',
2995 'O': 'OS_OPENBSD',
2996 'P': 'OS_POSIX',
2997 'S': 'OS_SOLARIS',
2998 'W': 'OS_WIN'}[bad_macro[3].upper()]
2999 except KeyError:
3000 return ''
3001
3002
3003def _CheckForInvalidOSMacrosInFile(input_api, f):
3004 """Check for sensible looking, totally invalid OS macros."""
3005 preprocessor_statement = input_api.re.compile(r'^\s*#')
3006 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
3007 results = []
3008 for lnum, line in f.ChangedContents():
3009 if preprocessor_statement.search(line):
3010 for match in os_macro.finditer(line):
3011 if not match.group(1) in _VALID_OS_MACROS:
3012 good = _DidYouMeanOSMacro(match.group(1))
3013 did_you_mean = ' (did you mean %s?)' % good if good else ''
3014 results.append(' %s:%d %s%s' % (f.LocalPath(),
3015 lnum,
3016 match.group(1),
3017 did_you_mean))
3018 return results
3019
3020
3021def _CheckForInvalidOSMacros(input_api, output_api):
3022 """Check all affected files for invalid OS macros."""
3023 bad_macros = []
3024 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:473025 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:543026 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
3027
3028 if not bad_macros:
3029 return []
3030
3031 return [output_api.PresubmitError(
3032 'Possibly invalid OS macro[s] found. Please fix your code\n'
3033 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
3034
lliabraa35bab3932014-10-01 12:16:443035
3036def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
3037 """Check all affected files for invalid "if defined" macros."""
3038 ALWAYS_DEFINED_MACROS = (
3039 "TARGET_CPU_PPC",
3040 "TARGET_CPU_PPC64",
3041 "TARGET_CPU_68K",
3042 "TARGET_CPU_X86",
3043 "TARGET_CPU_ARM",
3044 "TARGET_CPU_MIPS",
3045 "TARGET_CPU_SPARC",
3046 "TARGET_CPU_ALPHA",
3047 "TARGET_IPHONE_SIMULATOR",
3048 "TARGET_OS_EMBEDDED",
3049 "TARGET_OS_IPHONE",
3050 "TARGET_OS_MAC",
3051 "TARGET_OS_UNIX",
3052 "TARGET_OS_WIN32",
3053 )
3054 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
3055 results = []
3056 for lnum, line in f.ChangedContents():
3057 for match in ifdef_macro.finditer(line):
3058 if match.group(1) in ALWAYS_DEFINED_MACROS:
3059 always_defined = ' %s is always defined. ' % match.group(1)
3060 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
3061 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
3062 lnum,
3063 always_defined,
3064 did_you_mean))
3065 return results
3066
3067
3068def _CheckForInvalidIfDefinedMacros(input_api, output_api):
3069 """Check all affected files for invalid "if defined" macros."""
3070 bad_macros = []
3071 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:213072 if f.LocalPath().startswith('third_party/sqlite/'):
3073 continue
lliabraa35bab3932014-10-01 12:16:443074 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3075 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3076
3077 if not bad_macros:
3078 return []
3079
3080 return [output_api.PresubmitError(
3081 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3082 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3083 bad_macros)]
3084
3085
mlamouria82272622014-09-16 18:45:043086def _CheckForIPCRules(input_api, output_api):
3087 """Check for same IPC rules described in
3088 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3089 """
3090 base_pattern = r'IPC_ENUM_TRAITS\('
3091 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3092 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3093
3094 problems = []
3095 for f in input_api.AffectedSourceFiles(None):
3096 local_path = f.LocalPath()
3097 if not local_path.endswith('.h'):
3098 continue
3099 for line_number, line in f.ChangedContents():
3100 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3101 problems.append(
3102 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3103
3104 if problems:
3105 return [output_api.PresubmitPromptWarning(
3106 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
3107 else:
3108 return []
3109
[email protected]b00342e7f2013-03-26 16:21:543110
Stephen Martinis97a394142018-06-07 23:06:053111def _CheckForLongPathnames(input_api, output_api):
3112 """Check to make sure no files being submitted have long paths.
3113 This causes issues on Windows.
3114 """
3115 problems = []
3116 for f in input_api.AffectedSourceFiles(None):
3117 local_path = f.LocalPath()
3118 # Windows has a path limit of 260 characters. Limit path length to 200 so
3119 # that we have some extra for the prefix on dev machines and the bots.
3120 if len(local_path) > 200:
3121 problems.append(local_path)
3122
3123 if problems:
3124 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
3125 else:
3126 return []
3127
3128
Daniel Bratell8ba52722018-03-02 16:06:143129def _CheckForIncludeGuards(input_api, output_api):
3130 """Check that header files have proper guards against multiple inclusion.
3131 If a file should not have such guards (and it probably should) then it
3132 should include the string "no-include-guard-because-multiply-included".
3133 """
Daniel Bratell6a75baef62018-06-04 10:04:453134 def is_chromium_header_file(f):
3135 # We only check header files under the control of the Chromium
3136 # project. That is, those outside third_party apart from
3137 # third_party/blink.
3138 file_with_path = input_api.os_path.normpath(f.LocalPath())
3139 return (file_with_path.endswith('.h') and
3140 (not file_with_path.startswith('third_party') or
3141 file_with_path.startswith(
3142 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:143143
3144 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:343145 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:143146
3147 errors = []
3148
Daniel Bratell6a75baef62018-06-04 10:04:453149 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:143150 guard_name = None
3151 guard_line_number = None
3152 seen_guard_end = False
3153
3154 file_with_path = input_api.os_path.normpath(f.LocalPath())
3155 base_file_name = input_api.os_path.splitext(
3156 input_api.os_path.basename(file_with_path))[0]
3157 upper_base_file_name = base_file_name.upper()
3158
3159 expected_guard = replace_special_with_underscore(
3160 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:143161
3162 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:573163 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
3164 # are too many (1000+) files with slight deviations from the
3165 # coding style. The most important part is that the include guard
3166 # is there, and that it's unique, not the name so this check is
3167 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:143168 #
3169 # As code becomes more uniform, this could be made stricter.
3170
3171 guard_name_pattern_list = [
3172 # Anything with the right suffix (maybe with an extra _).
3173 r'\w+_H__?',
3174
Daniel Bratell39b5b062018-05-16 18:09:573175 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:143176 r'\w+_h',
3177
3178 # Anything including the uppercase name of the file.
3179 r'\w*' + input_api.re.escape(replace_special_with_underscore(
3180 upper_base_file_name)) + r'\w*',
3181 ]
3182 guard_name_pattern = '|'.join(guard_name_pattern_list)
3183 guard_pattern = input_api.re.compile(
3184 r'#ifndef\s+(' + guard_name_pattern + ')')
3185
3186 for line_number, line in enumerate(f.NewContents()):
3187 if 'no-include-guard-because-multiply-included' in line:
3188 guard_name = 'DUMMY' # To not trigger check outside the loop.
3189 break
3190
3191 if guard_name is None:
3192 match = guard_pattern.match(line)
3193 if match:
3194 guard_name = match.group(1)
3195 guard_line_number = line_number
3196
Daniel Bratell39b5b062018-05-16 18:09:573197 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:453198 # don't match the chromium style guide, but new files should
3199 # get it right.
3200 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:573201 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:143202 errors.append(output_api.PresubmitPromptWarning(
3203 'Header using the wrong include guard name %s' % guard_name,
3204 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:573205 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:143206 else:
3207 # The line after #ifndef should have a #define of the same name.
3208 if line_number == guard_line_number + 1:
3209 expected_line = '#define %s' % guard_name
3210 if line != expected_line:
3211 errors.append(output_api.PresubmitPromptWarning(
3212 'Missing "%s" for include guard' % expected_line,
3213 ['%s:%d' % (f.LocalPath(), line_number + 1)],
3214 'Expected: %r\nGot: %r' % (expected_line, line)))
3215
3216 if not seen_guard_end and line == '#endif // %s' % guard_name:
3217 seen_guard_end = True
3218 elif seen_guard_end:
3219 if line.strip() != '':
3220 errors.append(output_api.PresubmitPromptWarning(
3221 'Include guard %s not covering the whole file' % (
3222 guard_name), [f.LocalPath()]))
3223 break # Nothing else to check and enough to warn once.
3224
3225 if guard_name is None:
3226 errors.append(output_api.PresubmitPromptWarning(
3227 'Missing include guard %s' % expected_guard,
3228 [f.LocalPath()],
3229 'Missing include guard in %s\n'
3230 'Recommended name: %s\n'
3231 'This check can be disabled by having the string\n'
3232 'no-include-guard-because-multiply-included in the header.' %
3233 (f.LocalPath(), expected_guard)))
3234
3235 return errors
3236
3237
mostynbb639aca52015-01-07 20:31:233238def _CheckForWindowsLineEndings(input_api, output_api):
3239 """Check source code and known ascii text files for Windows style line
3240 endings.
3241 """
earthdok1b5e0ee2015-03-10 15:19:103242 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233243
3244 file_inclusion_pattern = (
3245 known_text_files,
3246 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3247 )
3248
mostynbb639aca52015-01-07 20:31:233249 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533250 source_file_filter = lambda f: input_api.FilterSourceFile(
3251 f, white_list=file_inclusion_pattern, black_list=None)
3252 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503253 include_file = False
3254 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233255 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503256 include_file = True
3257 if include_file:
3258 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233259
3260 if problems:
3261 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3262 'these files to contain Windows style line endings?\n' +
3263 '\n'.join(problems))]
3264
3265 return []
3266
3267
Vaclav Brozekd5de76a2018-03-17 07:57:503268def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133269 """Checks that all source files use SYSLOG properly."""
3270 syslog_files = []
3271 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563272 for line_number, line in f.ChangedContents():
3273 if 'SYSLOG' in line:
3274 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3275
pastarmovj89f7ee12016-09-20 14:58:133276 if syslog_files:
3277 return [output_api.PresubmitPromptWarning(
3278 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3279 ' calls.\nFiles to check:\n', items=syslog_files)]
3280 return []
3281
3282
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193283def _CheckCrbugLinksHaveHttps(input_api, output_api):
Miguel Casas68bdb652017-12-19 16:29:093284 """Checks that crbug(.com) links are correctly prefixed by https://,
3285 unless they come in the accepted form TODO(crbug.com/...)
3286 """
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493287 white_list = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193288 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS)
3289 sources = lambda f: input_api.FilterSourceFile(
3290 f, white_list=white_list, black_list=black_list)
3291
3292 pattern = input_api.re.compile(r'//.*(?<!:\/\/)crbug[.com]*')
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203293 accepted_pattern = input_api.re.compile(r'//.*TODO\(crbug[.com]*')
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193294 problems = []
3295 for f in input_api.AffectedSourceFiles(sources):
3296 for line_num, line in f.ChangedContents():
Miguel Casas68bdb652017-12-19 16:29:093297 if pattern.search(line) and not accepted_pattern.search(line):
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193298 problems.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3299
3300 if problems:
3301 return [output_api.PresubmitPromptWarning(
3302 'Found unprefixed crbug.com URL(s), consider prepending https://\n'+
3303 '\n'.join(problems))]
3304 return []
3305
3306
[email protected]1f7b4172010-01-28 01:17:343307def CheckChangeOnUpload(input_api, output_api):
3308 results = []
3309 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473310 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283311 results.extend(
jam93a6ee792017-02-08 23:59:223312 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193313 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223314 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133315 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163316 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193317 results.extend(_CheckCrbugLinksHaveHttps(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:533318 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193319 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543320 return results
[email protected]ca8d1982009-02-19 16:33:123321
3322
[email protected]1bfb8322014-04-23 01:02:413323def GetTryServerMasterForBot(bot):
3324 """Returns the Try Server master for the given bot.
3325
[email protected]0bb112362014-07-26 04:38:323326 It tries to guess the master from the bot name, but may still fail
3327 and return None. There is no longer a default master.
3328 """
3329 # Potentially ambiguous bot names are listed explicitly.
3330 master_map = {
tandriie5587792016-07-14 00:34:503331 'chromium_presubmit': 'master.tryserver.chromium.linux',
3332 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413333 }
[email protected]0bb112362014-07-26 04:38:323334 master = master_map.get(bot)
3335 if not master:
wnwen4fbaab82016-05-25 12:54:363336 if 'android' in bot:
tandriie5587792016-07-14 00:34:503337 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363338 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503339 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323340 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503341 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323342 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503343 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323344 return master
[email protected]1bfb8322014-04-23 01:02:413345
3346
[email protected]ca8d1982009-02-19 16:33:123347def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543348 results = []
[email protected]1f7b4172010-01-28 01:17:343349 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543350 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273351 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343352 input_api,
3353 output_api,
[email protected]2fdd1f362013-01-16 03:56:033354 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273355
jam93a6ee792017-02-08 23:59:223356 results.extend(
3357 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543358 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3359 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413360 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3361 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543362 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143363
3364
3365def _CheckTranslationScreenshots(input_api, output_api):
3366 PART_FILE_TAG = "part"
3367 import os
3368 import sys
3369 from io import StringIO
3370
3371 try:
3372 old_sys_path = sys.path
3373 sys.path = sys.path + [input_api.os_path.join(
3374 input_api.PresubmitLocalPath(), 'tools', 'grit')]
3375 import grit.grd_reader
3376 import grit.node.message
3377 import grit.util
3378 finally:
3379 sys.path = old_sys_path
3380
3381 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
3382 """Load the grd file and return a dict of message ids to messages.
3383
3384 Ignores any nested grdp files pointed by <part> tag.
3385 """
3386 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
3387 stop_after=None, first_ids_file=None,
3388 debug=False, defines=None,
3389 tags_to_ignore=set([PART_FILE_TAG]))
3390 return {
3391 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
3392 grit.node.message.MessageNode)
3393 }
3394
3395 def _GetGrdpMessagesFromString(grdp_string):
3396 """Parses the contents of a grdp file given in grdp_string.
3397
3398 grd_reader can't parse grdp files directly. Instead, this creates a
3399 temporary directory with a grd file pointing to the grdp file, and loads the
3400 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
3401 """
3402 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
3403 <grit latest_public_release="1" current_release="1">
3404 <release seq="1">
3405 <messages>
3406 <part file="sub.grdp" />
3407 </messages>
3408 </release>
3409 </grit>
3410 """
3411 with grit.util.TempDir({'main.grd': WRAPPER,
3412 'sub.grdp': grdp_string}) as temp_dir:
3413 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
3414
3415 new_or_added_paths = set(f.LocalPath()
3416 for f in input_api.AffectedFiles()
3417 if (f.Action() == 'A' or f.Action() == 'M'))
3418 removed_paths = set(f.LocalPath()
3419 for f in input_api.AffectedFiles(include_deletes=True)
3420 if f.Action() == 'D')
3421
3422 affected_grds = [f for f in input_api.AffectedFiles()
3423 if (f.LocalPath().endswith('.grd') or
3424 f.LocalPath().endswith('.grdp'))]
3425 affected_png_paths = [f.AbsoluteLocalPath()
3426 for f in input_api.AffectedFiles()
3427 if (f.LocalPath().endswith('.png'))]
3428
3429 # Check for screenshots. Developers can upload screenshots using
3430 # tools/translation/upload_screenshots.py which finds and uploads
3431 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
3432 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
3433 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
3434 #
3435 # The logic here is as follows:
3436 #
3437 # - If the CL has a .png file under the screenshots directory for a grd
3438 # file, warn the developer. Actual images should never be checked into the
3439 # Chrome repo.
3440 #
3441 # - If the CL contains modified or new messages in grd files and doesn't
3442 # contain the corresponding .sha1 files, warn the developer to add images
3443 # and upload them via tools/translation/upload_screenshots.py.
3444 #
3445 # - If the CL contains modified or new messages in grd files and the
3446 # corresponding .sha1 files, everything looks good.
3447 #
3448 # - If the CL contains removed messages in grd files but the corresponding
3449 # .sha1 files aren't removed, warn the developer to remove them.
3450 unnecessary_screenshots = []
3451 missing_sha1 = []
3452 unnecessary_sha1_files = []
3453
3454
3455 def _CheckScreenshotAdded(screenshots_dir, message_id):
3456 sha1_path = input_api.os_path.join(
3457 screenshots_dir, message_id + '.png.sha1')
3458 if sha1_path not in new_or_added_paths:
3459 missing_sha1.append(sha1_path)
3460
3461
3462 def _CheckScreenshotRemoved(screenshots_dir, message_id):
3463 sha1_path = input_api.os_path.join(
3464 screenshots_dir, message_id + '.png.sha1')
3465 if sha1_path not in removed_paths:
3466 unnecessary_sha1_files.append(sha1_path)
3467
3468
3469 for f in affected_grds:
3470 file_path = f.LocalPath()
3471 old_id_to_msg_map = {}
3472 new_id_to_msg_map = {}
3473 if file_path.endswith('.grdp'):
3474 if f.OldContents():
3475 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393476 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143477 if f.NewContents():
3478 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393479 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143480 else:
3481 if f.OldContents():
3482 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393483 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143484 if f.NewContents():
3485 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393486 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143487
3488 # Compute added, removed and modified message IDs.
3489 old_ids = set(old_id_to_msg_map)
3490 new_ids = set(new_id_to_msg_map)
3491 added_ids = new_ids - old_ids
3492 removed_ids = old_ids - new_ids
3493 modified_ids = set([])
3494 for key in old_ids.intersection(new_ids):
3495 if (old_id_to_msg_map[key].FormatXml()
3496 != new_id_to_msg_map[key].FormatXml()):
3497 modified_ids.add(key)
3498
3499 grd_name, ext = input_api.os_path.splitext(
3500 input_api.os_path.basename(file_path))
3501 screenshots_dir = input_api.os_path.join(
3502 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
3503
3504 # Check the screenshot directory for .png files. Warn if there is any.
3505 for png_path in affected_png_paths:
3506 if png_path.startswith(screenshots_dir):
3507 unnecessary_screenshots.append(png_path)
3508
3509 for added_id in added_ids:
3510 _CheckScreenshotAdded(screenshots_dir, added_id)
3511
3512 for modified_id in modified_ids:
3513 _CheckScreenshotAdded(screenshots_dir, modified_id)
3514
3515 for removed_id in removed_ids:
3516 _CheckScreenshotRemoved(screenshots_dir, removed_id)
3517
3518 results = []
3519 if unnecessary_screenshots:
3520 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393521 'Do not include actual screenshots in the changelist. Run '
3522 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143523 sorted(unnecessary_screenshots)))
3524
3525 if missing_sha1:
3526 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393527 'You are adding or modifying UI strings.\n'
3528 'To ensure the best translations, take screenshots of the relevant UI '
3529 '(https://g.co/chrome/translation) and add these files to your '
3530 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143531
3532 if unnecessary_sha1_files:
3533 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393534 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143535 sorted(unnecessary_sha1_files)))
3536
3537 return results