blob: 0a40f6ea53c535ec879674c05128f65780b18c90 [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
[email protected]06e6d0ff2012-12-11 01:36:4439# Regular expression that matches code only used for test binaries
40# (best effort).
41_TEST_CODE_EXCLUDED_PATHS = (
joaodasilva718f87672014-08-30 09:25:4942 r'.*[\\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4443 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4444 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1245 _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4446 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
joaodasilva718f87672014-08-30 09:25:4947 r'.*[\\\/](test|tool(s)?)[\\\/].*',
[email protected]ef070cc2013-05-03 11:53:0548 # content_shell is used for running layout tests.
joaodasilva718f87672014-08-30 09:25:4949 r'content[\\\/]shell[\\\/].*',
[email protected]7b054982013-11-27 00:44:4750 # Non-production example code.
joaodasilva718f87672014-08-30 09:25:4951 r'mojo[\\\/]examples[\\\/].*',
[email protected]8176de12014-06-20 19:07:0852 # Launcher for running iOS tests on the simulator.
joaodasilva718f87672014-08-30 09:25:4953 r'testing[\\\/]iossim[\\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4454)
[email protected]ca8d1982009-02-19 16:33:1255
wnwenbdc444e2016-05-25 13:44:1556
[email protected]eea609a2011-11-18 13:10:1257_TEST_ONLY_WARNING = (
58 'You might be calling functions intended only for testing from\n'
59 'production code. It is OK to ignore this warning if you know what\n'
60 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5861 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1262
63
[email protected]cf9b78f2012-11-14 11:40:2864_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4065 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2166 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
67 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2868
wnwenbdc444e2016-05-25 13:44:1569
Eric Stevensona9a980972017-09-23 00:04:4170_BANNED_JAVA_FUNCTIONS = (
71 (
72 'StrictMode.allowThreadDiskReads()',
73 (
74 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
75 'directly.',
76 ),
77 False,
78 ),
79 (
80 'StrictMode.allowThreadDiskWrites()',
81 (
82 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
83 'directly.',
84 ),
85 False,
86 ),
87)
88
[email protected]127f18ec2012-06-16 05:05:5989_BANNED_OBJC_FUNCTIONS = (
90 (
91 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:2092 (
93 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:5994 'prohibited. Please use CrTrackingArea instead.',
95 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
96 ),
97 False,
98 ),
99 (
[email protected]eaae1972014-04-16 04:17:26100 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20101 (
102 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59103 'instead.',
104 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
105 ),
106 False,
107 ),
108 (
109 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20110 (
111 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59112 'Please use |convertPoint:(point) fromView:nil| instead.',
113 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
114 ),
115 True,
116 ),
117 (
118 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20119 (
120 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59121 'Please use |convertPoint:(point) toView:nil| instead.',
122 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
123 ),
124 True,
125 ),
126 (
127 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20128 (
129 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59130 'Please use |convertRect:(point) fromView:nil| instead.',
131 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
132 ),
133 True,
134 ),
135 (
136 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20137 (
138 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59139 'Please use |convertRect:(point) toView:nil| instead.',
140 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
141 ),
142 True,
143 ),
144 (
145 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20146 (
147 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59148 'Please use |convertSize:(point) fromView:nil| instead.',
149 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
150 ),
151 True,
152 ),
153 (
154 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20155 (
156 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59157 'Please use |convertSize:(point) toView:nil| instead.',
158 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
159 ),
160 True,
161 ),
jif65398702016-10-27 10:19:48162 (
163 r"/\s+UTF8String\s*]",
164 (
165 'The use of -[NSString UTF8String] is dangerous as it can return null',
166 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
167 'Please use |SysNSStringToUTF8| instead.',
168 ),
169 True,
170 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34171 (
172 r'__unsafe_unretained',
173 (
174 'The use of __unsafe_unretained is almost certainly wrong, unless',
175 'when interacting with NSFastEnumeration or NSInvocation.',
176 'Please use __weak in files build with ARC, nothing otherwise.',
177 ),
178 False,
179 ),
[email protected]127f18ec2012-06-16 05:05:59180)
181
Sylvain Defresnea8b73d252018-02-28 15:45:54182_BANNED_IOS_OBJC_FUNCTIONS = (
183 (
184 r'/\bTEST[(]',
185 (
186 'TEST() macro should not be used in Objective-C++ code as it does not ',
187 'drain the autorelease pool at the end of the test. Use TEST_F() ',
188 'macro instead with a fixture inheriting from PlatformTest (or a ',
189 'typedef).'
190 ),
191 True,
192 ),
193 (
194 r'/\btesting::Test\b',
195 (
196 'testing::Test should not be used in Objective-C++ code as it does ',
197 'not drain the autorelease pool at the end of the test. Use ',
198 'PlatformTest instead.'
199 ),
200 True,
201 ),
202)
203
[email protected]127f18ec2012-06-16 05:05:59204
205_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20206 # Make sure that gtest's FRIEND_TEST() macro is not used; the
207 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
[email protected]e00ccc92012-11-01 17:32:30208 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
[email protected]23e6cbc2012-06-16 18:51:20209 (
thomasandersone7caaa9b2017-03-29 19:22:53210 r'\bNULL\b',
211 (
212 'New code should not use NULL. Use nullptr instead.',
213 ),
214 True,
215 (),
216 ),
217 (
[email protected]23e6cbc2012-06-16 18:51:20218 'FRIEND_TEST(',
219 (
[email protected]e3c945502012-06-26 20:01:49220 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20221 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
222 ),
223 False,
[email protected]7345da02012-11-27 14:31:49224 (),
[email protected]23e6cbc2012-06-16 18:51:20225 ),
226 (
thomasanderson4b569052016-09-14 20:15:53227 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
228 (
229 'Chrome clients wishing to select events on X windows should use',
230 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
231 'you are selecting events from the GPU process, or if you are using',
232 'an XDisplay other than gfx::GetXDisplay().',
233 ),
234 True,
235 (
236 r"^ui[\\\/]gl[\\\/].*\.cc$",
237 r"^media[\\\/]gpu[\\\/].*\.cc$",
238 r"^gpu[\\\/].*\.cc$",
239 ),
240 ),
241 (
thomasandersone043e3ce2017-06-08 00:43:20242 r'XInternAtom|xcb_intern_atom',
243 (
thomasanderson11aa41d2017-06-08 22:22:38244 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20245 ),
246 True,
247 (
thomasanderson11aa41d2017-06-08 22:22:38248 r"^gpu[\\\/]ipc[\\\/]service[\\\/]gpu_watchdog_thread\.cc$",
249 r"^remoting[\\\/]host[\\\/]linux[\\\/]x_server_clipboard\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20250 r"^ui[\\\/]gfx[\\\/]x[\\\/]x11_atom_cache\.cc$",
251 ),
252 ),
253 (
tomhudsone2c14d552016-05-26 17:07:46254 'setMatrixClip',
255 (
256 'Overriding setMatrixClip() is prohibited; ',
257 'the base function is deprecated. ',
258 ),
259 True,
260 (),
261 ),
262 (
[email protected]52657f62013-05-20 05:30:31263 'SkRefPtr',
264 (
265 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22266 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31267 ),
268 True,
269 (),
270 ),
271 (
272 'SkAutoRef',
273 (
274 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22275 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31276 ),
277 True,
278 (),
279 ),
280 (
281 'SkAutoTUnref',
282 (
283 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22284 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31285 ),
286 True,
287 (),
288 ),
289 (
290 'SkAutoUnref',
291 (
292 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
293 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22294 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31295 ),
296 True,
297 (),
298 ),
[email protected]d89eec82013-12-03 14:10:59299 (
300 r'/HANDLE_EINTR\(.*close',
301 (
302 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
303 'descriptor will be closed, and it is incorrect to retry the close.',
304 'Either call close directly and ignore its return value, or wrap close',
305 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
306 ),
307 True,
308 (),
309 ),
310 (
311 r'/IGNORE_EINTR\((?!.*close)',
312 (
313 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
314 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
315 ),
316 True,
317 (
318 # Files that #define IGNORE_EINTR.
319 r'^base[\\\/]posix[\\\/]eintr_wrapper\.h$',
320 r'^ppapi[\\\/]tests[\\\/]test_broker\.cc$',
321 ),
322 ),
[email protected]ec5b3f02014-04-04 18:43:43323 (
324 r'/v8::Extension\(',
325 (
326 'Do not introduce new v8::Extensions into the code base, use',
327 'gin::Wrappable instead. See http://crbug.com/334679',
328 ),
329 True,
[email protected]f55c90ee62014-04-12 00:50:03330 (
joaodasilva718f87672014-08-30 09:25:49331 r'extensions[\\\/]renderer[\\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03332 ),
[email protected]ec5b3f02014-04-04 18:43:43333 ),
skyostilf9469f72015-04-20 10:38:52334 (
jame2d1a952016-04-02 00:27:10335 '#pragma comment(lib,',
336 (
337 'Specify libraries to link with in build files and not in the source.',
338 ),
339 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41340 (
341 r'^third_party[\\\/]abseil-cpp[\\\/].*',
342 ),
jame2d1a952016-04-02 00:27:10343 ),
fdorayc4ac18d2017-05-01 21:39:59344 (
Gabriel Charette7cc6c432018-04-25 20:52:02345 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59346 (
347 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
348 ),
349 False,
350 (),
351 ),
352 (
Gabriel Charette7cc6c432018-04-25 20:52:02353 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59354 (
355 'Consider using THREAD_CHECKER macros instead of the class directly.',
356 ),
357 False,
358 (),
359 ),
dbeamb6f4fde2017-06-15 04:03:06360 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06361 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
362 (
363 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
364 'deprecated (http://crbug.com/634507). Please avoid converting away',
365 'from the Time types in Chromium code, especially if any math is',
366 'being done on time values. For interfacing with platform/library',
367 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
368 'type converter methods instead. For faking TimeXXX values (for unit',
369 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
370 'other use cases, please contact base/time/OWNERS.',
371 ),
372 False,
373 (),
374 ),
375 (
dbeamb6f4fde2017-06-15 04:03:06376 'CallJavascriptFunctionUnsafe',
377 (
378 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
379 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
380 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
381 ),
382 False,
383 (
384 r'^content[\\\/]browser[\\\/]webui[\\\/]web_ui_impl\.(cc|h)$',
385 r'^content[\\\/]public[\\\/]browser[\\\/]web_ui\.h$',
386 r'^content[\\\/]public[\\\/]test[\\\/]test_web_ui\.(cc|h)$',
387 ),
388 ),
dskiba1474c2bfd62017-07-20 02:19:24389 (
390 'leveldb::DB::Open',
391 (
392 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
393 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
394 "Chrome's tracing, making their memory usage visible.",
395 ),
396 True,
397 (
398 r'^third_party/leveldatabase/.*\.(cc|h)$',
399 ),
Gabriel Charette0592c3a2017-07-26 12:02:04400 ),
401 (
Chris Mumfordc38afb62017-10-09 17:55:08402 'leveldb::NewMemEnv',
403 (
404 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58405 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
406 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08407 ),
408 True,
409 (
410 r'^third_party/leveldatabase/.*\.(cc|h)$',
411 ),
412 ),
413 (
Gabriel Charetted9839bc2017-07-29 14:17:47414 'RunLoop::QuitCurrent',
415 (
Robert Liao64b7ab22017-08-04 23:03:43416 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
417 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47418 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41419 False,
Gabriel Charetted9839bc2017-07-29 14:17:47420 (),
Gabriel Charettea44975052017-08-21 23:14:04421 ),
422 (
423 'base::ScopedMockTimeMessageLoopTaskRunner',
424 (
Gabriel Charette87cc1af2018-04-25 20:52:51425 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
426 'ScopedTaskEnvironment::MainThreadType::MOCK_TIME. There are still a',
427 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
428 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
429 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04430 ),
Gabriel Charette87cc1af2018-04-25 20:52:51431 False,
Gabriel Charettea44975052017-08-21 23:14:04432 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57433 ),
434 (
435 r'std::regex',
436 (
437 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02438 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57439 ),
440 True,
441 (),
Francois Doray43670e32017-09-27 12:40:38442 ),
443 (
444 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
445 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
446 (
447 'Use the new API in base/threading/thread_restrictions.h.',
448 ),
449 True,
450 (),
451 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38452 (
453 r'/\bbase::Bind\(',
454 (
Gabriel Charette147335ea2018-03-22 15:59:19455 'Please consider using base::Bind{Once,Repeating} instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02456 'of base::Bind. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38457 ),
458 False,
459 (),
460 ),
461 (
462 r'/\bbase::Callback<',
463 (
Gabriel Charette147335ea2018-03-22 15:59:19464 'Please consider using base::{Once,Repeating}Callback instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02465 'of base::Callback. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38466 ),
467 False,
468 (),
469 ),
470 (
471 r'/\bbase::Closure\b',
472 (
Gabriel Charette147335ea2018-03-22 15:59:19473 'Please consider using base::{Once,Repeating}Closure instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02474 'of base::Closure. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38475 ),
476 False,
477 (),
478 ),
Victor Costan3653df62018-02-08 21:38:16479 (
Gabriel Charette147335ea2018-03-22 15:59:19480 r'RunMessageLoop',
481 (
482 'RunMessageLoop is deprecated, use RunLoop instead.',
483 ),
484 False,
485 (),
486 ),
487 (
488 r'RunThisRunLoop',
489 (
490 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
491 ),
492 False,
493 (),
494 ),
495 (
496 r'RunAllPendingInMessageLoop()',
497 (
498 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
499 "if you're convinced you need this.",
500 ),
501 False,
502 (),
503 ),
504 (
505 r'RunAllPendingInMessageLoop(BrowserThread',
506 (
507 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
508 'BrowserThread::UI, TestBrowserThreadBundle::RunIOThreadUntilIdle',
509 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
510 'async events instead of flushing threads.',
511 ),
512 False,
513 (),
514 ),
515 (
516 r'MessageLoopRunner',
517 (
518 'MessageLoopRunner is deprecated, use RunLoop instead.',
519 ),
520 False,
521 (),
522 ),
523 (
524 r'GetDeferredQuitTaskForRunLoop',
525 (
526 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
527 "gab@ if you found a use case where this is the only solution.",
528 ),
529 False,
530 (),
531 ),
532 (
Victor Costan3653df62018-02-08 21:38:16533 'sqlite3_initialize',
534 (
535 'Instead of sqlite3_initialize, depend on //sql, ',
536 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
537 ),
538 True,
539 (
540 r'^sql/initialization\.(cc|h)$',
541 r'^third_party/sqlite/.*\.(c|cc|h)$',
542 ),
543 ),
Matt Menke7f520a82018-03-28 21:38:37544 (
545 'net::URLFetcher',
546 (
547 'net::URLFetcher should no longer be used in content embedders. ',
548 'Instead, use network::SimpleURLLoader instead, which supports ',
549 'an out-of-process network stack. ',
550 'net::URLFetcher may still be used in binaries that do not embed',
551 'content.',
552 ),
Matt Menke59716d02018-04-05 12:45:53553 False,
Matt Menke7f520a82018-03-28 21:38:37554 (
555 r'^ios[\\\/].*\.(cc|h)$',
556 r'.*[\\\/]ios[\\\/].*\.(cc|h)$',
557 r'.*_ios\.(cc|h)$',
558 r'^net[\\\/].*\.(cc|h)$',
559 r'.*[\\\/]tools[\\\/].*\.(cc|h)$',
560 ),
561 ),
jdoerried7d10ab2018-04-27 10:46:13562 (
563 r'/\barraysize\b',
564 (
565 "arraysize is deprecated, please use base::size(array) instead ",
566 "(https://crbug.com/837308). ",
567 ),
568 False,
569 (),
570 ),
tzik5de2157f2018-05-08 03:42:47571 (
572 r'std::random_shuffle',
573 (
574 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
575 'base::RandomShuffle instead.'
576 ),
577 True,
578 (),
579 ),
[email protected]127f18ec2012-06-16 05:05:59580)
581
wnwenbdc444e2016-05-25 13:44:15582
mlamouria82272622014-09-16 18:45:04583_IPC_ENUM_TRAITS_DEPRECATED = (
584 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50585 'See http://www.chromium.org/Home/chromium-security/education/'
586 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:04587
Shenghua Zhangbfaa38b82017-11-16 21:58:02588_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
589 r".*[\\\/]BuildHooksAndroidImpl\.java",
James Wallace-Lee524eb682018-05-10 01:36:35590 r".*[\\\/]ClassRegisterImpl\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:02591 r".*[\\\/]LicenseContentProvider\.java",
James Wallace-Leef31ae6c2018-05-01 23:30:20592 r".*[\\\/]PlatformServiceBridgeImpl.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:02593]
[email protected]127f18ec2012-06-16 05:05:59594
Sean Kau46e29bc2017-08-28 16:31:16595# These paths contain test data and other known invalid JSON files.
596_KNOWN_INVALID_JSON_FILE_PATTERNS = [
597 r'test[\\\/]data[\\\/]',
598 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
599 r'^third_party[\\\/]protobuf[\\\/]',
Raphael Kubo da Costa211f3b472017-11-16 00:27:16600 r'^third_party[\\\/]WebKit[\\\/]LayoutTests[\\\/]external[\\\/]wpt[\\\/]',
Alexey Kozyatinskiya42a629f2018-04-17 17:49:38601 r'^third_party[\\\/]blink[\\\/]renderer[\\\/]devtools[\\\/]protocol\.json$',
Sean Kau46e29bc2017-08-28 16:31:16602]
603
604
[email protected]b00342e7f2013-03-26 16:21:54605_VALID_OS_MACROS = (
606 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08607 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54608 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:12609 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:54610 'OS_BSD',
611 'OS_CAT', # For testing.
612 'OS_CHROMEOS',
613 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37614 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54615 'OS_IOS',
616 'OS_LINUX',
617 'OS_MACOSX',
618 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21619 'OS_NACL_NONSFI',
620 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12621 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54622 'OS_OPENBSD',
623 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37624 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54625 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54626 'OS_WIN',
627)
628
629
agrievef32bcc72016-04-04 14:57:40630_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grievea7f1ee902018-05-18 16:17:22631 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:40632 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04633 'build/android/test_wrapper/logdog_wrapper.pydeps',
jbudorick276cc562017-04-29 01:34:58634 'build/secondary/third_party/android_platform/'
635 'development/scripts/stack.pydeps',
agrieve732db3a2016-04-26 19:18:19636 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40637]
638
wnwenbdc444e2016-05-25 13:44:15639
agrievef32bcc72016-04-04 14:57:40640_GENERIC_PYDEPS_FILES = [
John Chencde89192018-01-27 21:18:40641 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22642 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:40643]
644
wnwenbdc444e2016-05-25 13:44:15645
agrievef32bcc72016-04-04 14:57:40646_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
647
648
Eric Boren6fd2b932018-01-25 15:05:08649# Bypass the AUTHORS check for these accounts.
650_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:29651 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
652 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
653 'fuchsia-sdk', 'nacl', 'pdfium', 'skia', 'src-internal', 'webrtc')
654 ) | set('%[email protected]' % s for s in ('findit-for-me',))
Eric Boren6fd2b932018-01-25 15:05:08655
656
[email protected]55459852011-08-10 15:17:19657def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
658 """Attempts to prevent use of functions intended only for testing in
659 non-testing code. For now this is just a best-effort implementation
660 that ignores header files and may have some false positives. A
661 better implementation would probably need a proper C++ parser.
662 """
663 # We only scan .cc files and the like, as the declaration of
664 # for-testing functions in header files are hard to distinguish from
665 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44666 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19667
jochenc0d4808c2015-07-27 09:25:42668 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19669 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09670 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19671 exclusion_pattern = input_api.re.compile(
672 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
673 base_function_pattern, base_function_pattern))
674
675 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44676 black_list = (_EXCLUDED_PATHS +
677 _TEST_CODE_EXCLUDED_PATHS +
678 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19679 return input_api.FilterSourceFile(
680 affected_file,
681 white_list=(file_inclusion_pattern, ),
682 black_list=black_list)
683
684 problems = []
685 for f in input_api.AffectedSourceFiles(FilterFile):
686 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24687 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03688 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46689 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03690 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19691 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03692 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19693
694 if problems:
[email protected]f7051d52013-04-02 18:31:42695 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03696 else:
697 return []
[email protected]55459852011-08-10 15:17:19698
699
Vaclav Brozek7dbc28c2018-03-27 08:35:23700def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
701 """This is a simplified version of
702 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
703 """
704 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
705 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
706 name_pattern = r'ForTest(s|ing)?'
707 # Describes an occurrence of "ForTest*" inside a // comment.
708 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
709 # Catch calls.
710 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
711 # Ignore definitions. (Comments are ignored separately.)
712 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
713
714 problems = []
715 sources = lambda x: input_api.FilterSourceFile(
716 x,
717 black_list=(('(?i).*test', r'.*\/junit\/')
718 + input_api.DEFAULT_BLACK_LIST),
719 white_list=(r'.*\.java$',)
720 )
721 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
722 local_path = f.LocalPath()
723 is_inside_javadoc = False
724 for line_number, line in f.ChangedContents():
725 if is_inside_javadoc and javadoc_end_re.search(line):
726 is_inside_javadoc = False
727 if not is_inside_javadoc and javadoc_start_re.search(line):
728 is_inside_javadoc = True
729 if is_inside_javadoc:
730 continue
731 if (inclusion_re.search(line) and
732 not comment_re.search(line) and
733 not exclusion_re.search(line)):
734 problems.append(
735 '%s:%d\n %s' % (local_path, line_number, line.strip()))
736
737 if problems:
738 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
739 else:
740 return []
741
742
[email protected]10689ca2011-09-02 02:31:54743def _CheckNoIOStreamInHeaders(input_api, output_api):
744 """Checks to make sure no .h files include <iostream>."""
745 files = []
746 pattern = input_api.re.compile(r'^#include\s*<iostream>',
747 input_api.re.MULTILINE)
748 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
749 if not f.LocalPath().endswith('.h'):
750 continue
751 contents = input_api.ReadFile(f)
752 if pattern.search(contents):
753 files.append(f)
754
755 if len(files):
yolandyandaabc6d2016-04-18 18:29:39756 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06757 'Do not #include <iostream> in header files, since it inserts static '
758 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54759 '#include <ostream>. See http://crbug.com/94794',
760 files) ]
761 return []
762
763
[email protected]72df4e782012-06-21 16:28:18764def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52765 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18766 problems = []
767 for f in input_api.AffectedFiles():
768 if (not f.LocalPath().endswith(('.cc', '.mm'))):
769 continue
770
771 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04772 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18773 problems.append(' %s:%d' % (f.LocalPath(), line_num))
774
775 if not problems:
776 return []
777 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
778 '\n'.join(problems))]
779
780
danakj61c1aa22015-10-26 19:55:52781def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57782 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52783 errors = []
784 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
785 input_api.re.MULTILINE)
786 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
787 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
788 continue
789 for lnum, line in f.ChangedContents():
790 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17791 errors.append(output_api.PresubmitError(
792 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57793 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17794 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52795 return errors
796
797
mcasasb7440c282015-02-04 14:52:19798def _FindHistogramNameInLine(histogram_name, line):
799 """Tries to find a histogram name or prefix in a line."""
800 if not "affected-histogram" in line:
801 return histogram_name in line
802 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
803 # the histogram_name.
804 if not '"' in line:
805 return False
806 histogram_prefix = line.split('\"')[1]
807 return histogram_prefix in histogram_name
808
809
810def _CheckUmaHistogramChanges(input_api, output_api):
811 """Check that UMA histogram names in touched lines can still be found in other
812 lines of the patch or in histograms.xml. Note that this check would not catch
813 the reverse: changes in histograms.xml not matched in the code itself."""
814 touched_histograms = []
815 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:47816 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
817 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
818 name_pattern = r'"(.*?)"'
819 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
820 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
821 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
822 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
823 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:17824 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:19825 for f in input_api.AffectedFiles():
826 # If histograms.xml itself is modified, keep the modified lines for later.
827 if f.LocalPath().endswith(('histograms.xml')):
828 histograms_xml_modifications = f.ChangedContents()
829 continue
Vaclav Brozekbdac817c2018-03-24 06:30:47830 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
831 single_line_re = single_line_c_re
832 split_line_prefix_re = split_line_c_prefix_re
833 elif f.LocalPath().endswith(('java')):
834 single_line_re = single_line_java_re
835 split_line_prefix_re = split_line_java_prefix_re
836 else:
mcasasb7440c282015-02-04 14:52:19837 continue
838 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:17839 if last_line_matched_prefix:
840 suffix_found = split_line_suffix_re.search(line)
841 if suffix_found :
842 touched_histograms.append([suffix_found.group(1), f, line_num])
843 last_line_matched_prefix = False
844 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:06845 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:19846 if found:
847 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:17848 continue
849 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:19850
851 # Search for the touched histogram names in the local modifications to
852 # histograms.xml, and, if not found, on the base histograms.xml file.
853 unmatched_histograms = []
854 for histogram_info in touched_histograms:
855 histogram_name_found = False
856 for line_num, line in histograms_xml_modifications:
857 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
858 if histogram_name_found:
859 break
860 if not histogram_name_found:
861 unmatched_histograms.append(histogram_info)
862
eromanb90c82e7e32015-04-01 15:13:49863 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19864 problems = []
865 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49866 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19867 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45868 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19869 histogram_name_found = False
870 for line in histograms_xml:
871 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
872 if histogram_name_found:
873 break
874 if not histogram_name_found:
875 problems.append(' [%s:%d] %s' %
876 (f.LocalPath(), line_num, histogram_name))
877
878 if not problems:
879 return []
880 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
881 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49882 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19883
wnwenbdc444e2016-05-25 13:44:15884
yolandyandaabc6d2016-04-18 18:29:39885def _CheckFlakyTestUsage(input_api, output_api):
886 """Check that FlakyTest annotation is our own instead of the android one"""
887 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
888 files = []
889 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
890 if f.LocalPath().endswith('Test.java'):
891 if pattern.search(input_api.ReadFile(f)):
892 files.append(f)
893 if len(files):
894 return [output_api.PresubmitError(
895 'Use org.chromium.base.test.util.FlakyTest instead of '
896 'android.test.FlakyTest',
897 files)]
898 return []
mcasasb7440c282015-02-04 14:52:19899
wnwenbdc444e2016-05-25 13:44:15900
[email protected]8ea5d4b2011-09-13 21:49:22901def _CheckNoNewWStrings(input_api, output_api):
902 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27903 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22904 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20905 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57906 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34907 '/win/' in f.LocalPath() or
908 'chrome_elf' in f.LocalPath() or
909 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20910 continue
[email protected]8ea5d4b2011-09-13 21:49:22911
[email protected]a11dbe9b2012-08-07 01:32:58912 allowWString = False
[email protected]b5c24292011-11-28 14:38:20913 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58914 if 'presubmit: allow wstring' in line:
915 allowWString = True
916 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27917 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58918 allowWString = False
919 else:
920 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22921
[email protected]55463aa62011-10-12 00:48:27922 if not problems:
923 return []
924 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58925 ' If you are calling a cross-platform API that accepts a wstring, '
926 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27927 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22928
929
[email protected]2a8ac9c2011-10-19 17:20:44930def _CheckNoDEPSGIT(input_api, output_api):
931 """Make sure .DEPS.git is never modified manually."""
932 if any(f.LocalPath().endswith('.DEPS.git') for f in
933 input_api.AffectedFiles()):
934 return [output_api.PresubmitError(
935 'Never commit changes to .DEPS.git. This file is maintained by an\n'
936 'automated system based on what\'s in DEPS and your changes will be\n'
937 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50938 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
939 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:44940 'for more information')]
941 return []
942
943
tandriief664692014-09-23 14:51:47944def _CheckValidHostsInDEPS(input_api, output_api):
945 """Checks that DEPS file deps are from allowed_hosts."""
946 # Run only if DEPS file has been modified to annoy fewer bystanders.
947 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
948 return []
949 # Outsource work to gclient verify
950 try:
951 input_api.subprocess.check_output(['gclient', 'verify'])
952 return []
953 except input_api.subprocess.CalledProcessError, error:
954 return [output_api.PresubmitError(
955 'DEPS file must have only git dependencies.',
956 long_text=error.output)]
957
958
[email protected]127f18ec2012-06-16 05:05:59959def _CheckNoBannedFunctions(input_api, output_api):
960 """Make sure that banned functions are not used."""
961 warnings = []
962 errors = []
963
wnwenbdc444e2016-05-25 13:44:15964 def IsBlacklisted(affected_file, blacklist):
965 local_path = affected_file.LocalPath()
966 for item in blacklist:
967 if input_api.re.match(item, local_path):
968 return True
969 return False
970
Sylvain Defresnea8b73d252018-02-28 15:45:54971 def IsIosObcjFile(affected_file):
972 local_path = affected_file.LocalPath()
973 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
974 return False
975 basename = input_api.os_path.basename(local_path)
976 if 'ios' in basename.split('_'):
977 return True
978 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
979 if sep and 'ios' in local_path.split(sep):
980 return True
981 return False
982
wnwenbdc444e2016-05-25 13:44:15983 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
984 matched = False
985 if func_name[0:1] == '/':
986 regex = func_name[1:]
987 if input_api.re.search(regex, line):
988 matched = True
989 elif func_name in line:
dchenge07de812016-06-20 19:27:17990 matched = True
wnwenbdc444e2016-05-25 13:44:15991 if matched:
dchenge07de812016-06-20 19:27:17992 problems = warnings
wnwenbdc444e2016-05-25 13:44:15993 if error:
dchenge07de812016-06-20 19:27:17994 problems = errors
wnwenbdc444e2016-05-25 13:44:15995 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
996 for message_line in message:
997 problems.append(' %s' % message_line)
998
Eric Stevensona9a980972017-09-23 00:04:41999 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1000 for f in input_api.AffectedFiles(file_filter=file_filter):
1001 for line_num, line in f.ChangedContents():
1002 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1003 CheckForMatch(f, line_num, line, func_name, message, error)
1004
[email protected]127f18ec2012-06-16 05:05:591005 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1006 for f in input_api.AffectedFiles(file_filter=file_filter):
1007 for line_num, line in f.ChangedContents():
1008 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151009 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591010
Sylvain Defresnea8b73d252018-02-28 15:45:541011 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1012 for line_num, line in f.ChangedContents():
1013 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1014 CheckForMatch(f, line_num, line, func_name, message, error)
1015
[email protected]127f18ec2012-06-16 05:05:591016 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1017 for f in input_api.AffectedFiles(file_filter=file_filter):
1018 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491019 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491020 if IsBlacklisted(f, excluded_paths):
1021 continue
wnwenbdc444e2016-05-25 13:44:151022 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591023
1024 result = []
1025 if (warnings):
1026 result.append(output_api.PresubmitPromptWarning(
1027 'Banned functions were used.\n' + '\n'.join(warnings)))
1028 if (errors):
1029 result.append(output_api.PresubmitError(
1030 'Banned functions were used.\n' + '\n'.join(errors)))
1031 return result
1032
1033
[email protected]6c063c62012-07-11 19:11:061034def _CheckNoPragmaOnce(input_api, output_api):
1035 """Make sure that banned functions are not used."""
1036 files = []
1037 pattern = input_api.re.compile(r'^#pragma\s+once',
1038 input_api.re.MULTILINE)
1039 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1040 if not f.LocalPath().endswith('.h'):
1041 continue
1042 contents = input_api.ReadFile(f)
1043 if pattern.search(contents):
1044 files.append(f)
1045
1046 if files:
1047 return [output_api.PresubmitError(
1048 'Do not use #pragma once in header files.\n'
1049 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1050 files)]
1051 return []
1052
[email protected]127f18ec2012-06-16 05:05:591053
[email protected]e7479052012-09-19 00:26:121054def _CheckNoTrinaryTrueFalse(input_api, output_api):
1055 """Checks to make sure we don't introduce use of foo ? true : false."""
1056 problems = []
1057 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1058 for f in input_api.AffectedFiles():
1059 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1060 continue
1061
1062 for line_num, line in f.ChangedContents():
1063 if pattern.match(line):
1064 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1065
1066 if not problems:
1067 return []
1068 return [output_api.PresubmitPromptWarning(
1069 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1070 '\n'.join(problems))]
1071
1072
[email protected]55f9f382012-07-31 11:02:181073def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281074 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181075 change. Breaking - rules is an error, breaking ! rules is a
1076 warning.
1077 """
mohan.reddyf21db962014-10-16 12:26:471078 import sys
[email protected]55f9f382012-07-31 11:02:181079 # We need to wait until we have an input_api object and use this
1080 # roundabout construct to import checkdeps because this file is
1081 # eval-ed and thus doesn't have __file__.
1082 original_sys_path = sys.path
1083 try:
1084 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471085 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181086 import checkdeps
1087 from cpp_checker import CppChecker
Jinsuk Kim5a092672017-10-24 22:42:241088 from java_checker import JavaChecker
rhalavati08acd232017-04-03 07:23:281089 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:181090 from rules import Rule
1091 finally:
1092 # Restore sys.path to what it was before.
1093 sys.path = original_sys_path
1094
1095 added_includes = []
rhalavati08acd232017-04-03 07:23:281096 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241097 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181098 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:281099 if CppChecker.IsCppFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501100 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081101 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
rhalavati08acd232017-04-03 07:23:281102 elif ProtoChecker.IsProtoFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501103 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081104 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241105 elif JavaChecker.IsJavaFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501106 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081107 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181108
[email protected]26385172013-05-09 23:11:351109 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181110
1111 error_descriptions = []
1112 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281113 error_subjects = set()
1114 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181115 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1116 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081117 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181118 description_with_path = '%s\n %s' % (path, rule_description)
1119 if rule_type == Rule.DISALLOW:
1120 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281121 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181122 else:
1123 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281124 warning_subjects.add("#includes")
1125
1126 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1127 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081128 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281129 description_with_path = '%s\n %s' % (path, rule_description)
1130 if rule_type == Rule.DISALLOW:
1131 error_descriptions.append(description_with_path)
1132 error_subjects.add("imports")
1133 else:
1134 warning_descriptions.append(description_with_path)
1135 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181136
Jinsuk Kim5a092672017-10-24 22:42:241137 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021138 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081139 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241140 description_with_path = '%s\n %s' % (path, rule_description)
1141 if rule_type == Rule.DISALLOW:
1142 error_descriptions.append(description_with_path)
1143 error_subjects.add("imports")
1144 else:
1145 warning_descriptions.append(description_with_path)
1146 warning_subjects.add("imports")
1147
[email protected]55f9f382012-07-31 11:02:181148 results = []
1149 if error_descriptions:
1150 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281151 'You added one or more %s that violate checkdeps rules.'
1152 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181153 error_descriptions))
1154 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421155 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281156 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181157 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281158 '%s? See relevant DEPS file(s) for details and contacts.' %
1159 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181160 warning_descriptions))
1161 return results
1162
1163
[email protected]fbcafe5a2012-08-08 15:31:221164def _CheckFilePermissions(input_api, output_api):
1165 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151166 if input_api.platform == 'win32':
1167 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291168 checkperms_tool = input_api.os_path.join(
1169 input_api.PresubmitLocalPath(),
1170 'tools', 'checkperms', 'checkperms.py')
1171 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471172 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391173 with input_api.CreateTemporaryFile() as file_list:
1174 for f in input_api.AffectedFiles():
1175 # checkperms.py file/directory arguments must be relative to the
1176 # repository.
1177 file_list.write(f.LocalPath() + '\n')
1178 file_list.close()
1179 args += ['--file-list', file_list.name]
1180 try:
1181 input_api.subprocess.check_output(args)
1182 return []
1183 except input_api.subprocess.CalledProcessError as error:
1184 return [output_api.PresubmitError(
1185 'checkperms.py failed:',
1186 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221187
1188
robertocn832f5992017-01-04 19:01:301189def _CheckTeamTags(input_api, output_api):
1190 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1191 checkteamtags_tool = input_api.os_path.join(
1192 input_api.PresubmitLocalPath(),
1193 'tools', 'checkteamtags', 'checkteamtags.py')
1194 args = [input_api.python_executable, checkteamtags_tool,
1195 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221196 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301197 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1198 'OWNERS']
1199 try:
1200 if files:
1201 input_api.subprocess.check_output(args + files)
1202 return []
1203 except input_api.subprocess.CalledProcessError as error:
1204 return [output_api.PresubmitError(
1205 'checkteamtags.py failed:',
1206 long_text=error.output)]
1207
1208
[email protected]c8278b32012-10-30 20:35:491209def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1210 """Makes sure we don't include ui/aura/window_property.h
1211 in header files.
1212 """
1213 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1214 errors = []
1215 for f in input_api.AffectedFiles():
1216 if not f.LocalPath().endswith('.h'):
1217 continue
1218 for line_num, line in f.ChangedContents():
1219 if pattern.match(line):
1220 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1221
1222 results = []
1223 if errors:
1224 results.append(output_api.PresubmitError(
1225 'Header files should not include ui/aura/window_property.h', errors))
1226 return results
1227
1228
[email protected]70ca77752012-11-20 03:45:031229def _CheckForVersionControlConflictsInFile(input_api, f):
1230 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1231 errors = []
1232 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:231233 if f.LocalPath().endswith('.md'):
1234 # First-level headers in markdown look a lot like version control
1235 # conflict markers. http://daringfireball.net/projects/markdown/basics
1236 continue
[email protected]70ca77752012-11-20 03:45:031237 if pattern.match(line):
1238 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1239 return errors
1240
1241
1242def _CheckForVersionControlConflicts(input_api, output_api):
1243 """Usually this is not intentional and will cause a compile failure."""
1244 errors = []
1245 for f in input_api.AffectedFiles():
1246 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1247
1248 results = []
1249 if errors:
1250 results.append(output_api.PresubmitError(
1251 'Version control conflict markers found, please resolve.', errors))
1252 return results
1253
estadee17314a02017-01-12 16:22:161254def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1255 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1256 errors = []
1257 for f in input_api.AffectedFiles():
1258 for line_num, line in f.ChangedContents():
1259 if pattern.search(line):
1260 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1261
1262 results = []
1263 if errors:
1264 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501265 'Found Google support URL addressed by answer number. Please replace '
1266 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161267 return results
1268
[email protected]70ca77752012-11-20 03:45:031269
[email protected]06e6d0ff2012-12-11 01:36:441270def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1271 def FilterFile(affected_file):
1272 """Filter function for use with input_api.AffectedSourceFiles,
1273 below. This filters out everything except non-test files from
1274 top-level directories that generally speaking should not hard-code
1275 service URLs (e.g. src/android_webview/, src/content/ and others).
1276 """
1277 return input_api.FilterSourceFile(
1278 affected_file,
[email protected]78bb39d62012-12-11 15:11:561279 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:441280 black_list=(_EXCLUDED_PATHS +
1281 _TEST_CODE_EXCLUDED_PATHS +
1282 input_api.DEFAULT_BLACK_LIST))
1283
reillyi38965732015-11-16 18:27:331284 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1285 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461286 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1287 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441288 problems = [] # items are (filename, line_number, line)
1289 for f in input_api.AffectedSourceFiles(FilterFile):
1290 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461291 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441292 problems.append((f.LocalPath(), line_num, line))
1293
1294 if problems:
[email protected]f7051d52013-04-02 18:31:421295 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441296 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581297 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441298 [' %s:%d: %s' % (
1299 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031300 else:
1301 return []
[email protected]06e6d0ff2012-12-11 01:36:441302
1303
[email protected]d2530012013-01-25 16:39:271304def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1305 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311306 The native_client_sdk directory is excluded because it has auto-generated PNG
1307 files for documentation.
[email protected]d2530012013-01-25 16:39:271308 """
[email protected]d2530012013-01-25 16:39:271309 errors = []
binji0dcdf342014-12-12 18:32:311310 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
1311 black_list = (r'^native_client_sdk[\\\/]',)
1312 file_filter = lambda f: input_api.FilterSourceFile(
1313 f, white_list=white_list, black_list=black_list)
1314 for f in input_api.AffectedFiles(include_deletes=False,
1315 file_filter=file_filter):
1316 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271317
1318 results = []
1319 if errors:
1320 results.append(output_api.PresubmitError(
1321 'The name of PNG files should not have abbreviations. \n'
1322 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1323 'Contact [email protected] if you have questions.', errors))
1324 return results
1325
1326
Daniel Cheng4dcdb6b2017-04-13 08:30:171327def _ExtractAddRulesFromParsedDeps(parsed_deps):
1328 """Extract the rules that add dependencies from a parsed DEPS file.
1329
1330 Args:
1331 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1332 add_rules = set()
1333 add_rules.update([
1334 rule[1:] for rule in parsed_deps.get('include_rules', [])
1335 if rule.startswith('+') or rule.startswith('!')
1336 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501337 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171338 {}).iteritems():
1339 add_rules.update([
1340 rule[1:] for rule in rules
1341 if rule.startswith('+') or rule.startswith('!')
1342 ])
1343 return add_rules
1344
1345
1346def _ParseDeps(contents):
1347 """Simple helper for parsing DEPS files."""
1348 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171349 class _VarImpl:
1350
1351 def __init__(self, local_scope):
1352 self._local_scope = local_scope
1353
1354 def Lookup(self, var_name):
1355 """Implements the Var syntax."""
1356 try:
1357 return self._local_scope['vars'][var_name]
1358 except KeyError:
1359 raise Exception('Var is not defined: %s' % var_name)
1360
1361 local_scope = {}
1362 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171363 'Var': _VarImpl(local_scope).Lookup,
1364 }
1365 exec contents in global_scope, local_scope
1366 return local_scope
1367
1368
1369def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081370 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411371 a set of DEPS entries that we should look up.
1372
1373 For a directory (rather than a specific filename) we fake a path to
1374 a specific filename by adding /DEPS. This is chosen as a file that
1375 will seldom or never be subject to per-file include_rules.
1376 """
[email protected]2b438d62013-11-14 17:54:141377 # We ignore deps entries on auto-generated directories.
1378 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081379
Daniel Cheng4dcdb6b2017-04-13 08:30:171380 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1381 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1382
1383 added_deps = new_deps.difference(old_deps)
1384
[email protected]2b438d62013-11-14 17:54:141385 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171386 for added_dep in added_deps:
1387 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1388 continue
1389 # Assume that a rule that ends in .h is a rule for a specific file.
1390 if added_dep.endswith('.h'):
1391 results.add(added_dep)
1392 else:
1393 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081394 return results
1395
1396
[email protected]e871964c2013-05-13 14:14:551397def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1398 """When a dependency prefixed with + is added to a DEPS file, we
1399 want to make sure that the change is reviewed by an OWNER of the
1400 target file or directory, to avoid layering violations from being
1401 introduced. This check verifies that this happens.
1402 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171403 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241404
1405 file_filter = lambda f: not input_api.re.match(
Kent Tamurae9b3a9ec2017-08-31 02:20:191406 r"^third_party[\\\/](WebKit|blink)[\\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241407 for f in input_api.AffectedFiles(include_deletes=False,
1408 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551409 filename = input_api.os_path.basename(f.LocalPath())
1410 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171411 virtual_depended_on_files.update(_CalculateAddedDeps(
1412 input_api.os_path,
1413 '\n'.join(f.OldContents()),
1414 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551415
[email protected]e871964c2013-05-13 14:14:551416 if not virtual_depended_on_files:
1417 return []
1418
1419 if input_api.is_committing:
1420 if input_api.tbr:
1421 return [output_api.PresubmitNotifyResult(
1422 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271423 if input_api.dry_run:
1424 return [output_api.PresubmitNotifyResult(
1425 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551426 if not input_api.change.issue:
1427 return [output_api.PresubmitError(
1428 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401429 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551430 output = output_api.PresubmitError
1431 else:
1432 output = output_api.PresubmitNotifyResult
1433
1434 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501435 owner_email, reviewers = (
1436 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1437 input_api,
1438 owners_db.email_regexp,
1439 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551440
1441 owner_email = owner_email or input_api.change.author_email
1442
[email protected]de4f7d22013-05-23 14:27:461443 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511444 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461445 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551446 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1447 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411448
1449 # We strip the /DEPS part that was added by
1450 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1451 # directory.
1452 def StripDeps(path):
1453 start_deps = path.rfind('/DEPS')
1454 if start_deps != -1:
1455 return path[:start_deps]
1456 else:
1457 return path
1458 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551459 for path in missing_files]
1460
1461 if unapproved_dependencies:
1462 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151463 output('You need LGTM from owners of depends-on paths in DEPS that were '
1464 'modified in this CL:\n %s' %
1465 '\n '.join(sorted(unapproved_dependencies)))]
1466 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1467 output_list.append(output(
1468 'Suggested missing target path OWNERS:\n %s' %
1469 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551470 return output_list
1471
1472 return []
1473
1474
[email protected]85218562013-11-22 07:41:401475def _CheckSpamLogging(input_api, output_api):
1476 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1477 black_list = (_EXCLUDED_PATHS +
1478 _TEST_CODE_EXCLUDED_PATHS +
1479 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501480 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191481 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481482 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461483 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121484 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1485 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581486 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161487 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031488 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151489 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1490 r"^chromecast[\\\/]",
1491 r"^cloud_print[\\\/]",
manzagop85e629e2017-05-09 22:11:481492 r"^components[\\\/]browser_watcher[\\\/]"
1493 r"dump_stability_report_main_win.cc$",
jochen34415e52015-07-10 08:34:311494 r"^components[\\\/]html_viewer[\\\/]"
1495 r"web_test_delegate_impl\.cc$",
Samuel Huang577ef6c2018-03-13 18:19:341496 r"^components[\\\/]zucchini[\\\/].*",
peter80739bb2015-10-20 11:17:461497 # TODO(peter): Remove this exception. https://crbug.com/534537
1498 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1499 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251500 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1501 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241502 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111503 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151504 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111505 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521506 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501507 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361508 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311509 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131510 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001511 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441512 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451513 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021514 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351515 r"dump_file_system.cc$",
1516 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401517 source_file_filter = lambda x: input_api.FilterSourceFile(
1518 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1519
thomasanderson625d3932017-03-29 07:16:581520 log_info = set([])
1521 printf = set([])
[email protected]85218562013-11-22 07:41:401522
1523 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581524 for _, line in f.ChangedContents():
1525 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1526 log_info.add(f.LocalPath())
1527 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1528 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371529
thomasanderson625d3932017-03-29 07:16:581530 if input_api.re.search(r"\bprintf\(", line):
1531 printf.add(f.LocalPath())
1532 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1533 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401534
1535 if log_info:
1536 return [output_api.PresubmitError(
1537 'These files spam the console log with LOG(INFO):',
1538 items=log_info)]
1539 if printf:
1540 return [output_api.PresubmitError(
1541 'These files spam the console log with printf/fprintf:',
1542 items=printf)]
1543 return []
1544
1545
[email protected]49aa76a2013-12-04 06:59:161546def _CheckForAnonymousVariables(input_api, output_api):
1547 """These types are all expected to hold locks while in scope and
1548 so should never be anonymous (which causes them to be immediately
1549 destroyed)."""
1550 they_who_must_be_named = [
1551 'base::AutoLock',
1552 'base::AutoReset',
1553 'base::AutoUnlock',
1554 'SkAutoAlphaRestore',
1555 'SkAutoBitmapShaderInstall',
1556 'SkAutoBlitterChoose',
1557 'SkAutoBounderCommit',
1558 'SkAutoCallProc',
1559 'SkAutoCanvasRestore',
1560 'SkAutoCommentBlock',
1561 'SkAutoDescriptor',
1562 'SkAutoDisableDirectionCheck',
1563 'SkAutoDisableOvalCheck',
1564 'SkAutoFree',
1565 'SkAutoGlyphCache',
1566 'SkAutoHDC',
1567 'SkAutoLockColors',
1568 'SkAutoLockPixels',
1569 'SkAutoMalloc',
1570 'SkAutoMaskFreeImage',
1571 'SkAutoMutexAcquire',
1572 'SkAutoPathBoundsUpdate',
1573 'SkAutoPDFRelease',
1574 'SkAutoRasterClipValidate',
1575 'SkAutoRef',
1576 'SkAutoTime',
1577 'SkAutoTrace',
1578 'SkAutoUnref',
1579 ]
1580 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1581 # bad: base::AutoLock(lock.get());
1582 # not bad: base::AutoLock lock(lock.get());
1583 bad_pattern = input_api.re.compile(anonymous)
1584 # good: new base::AutoLock(lock.get())
1585 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1586 errors = []
1587
1588 for f in input_api.AffectedFiles():
1589 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1590 continue
1591 for linenum, line in f.ChangedContents():
1592 if bad_pattern.search(line) and not good_pattern.search(line):
1593 errors.append('%s:%d' % (f.LocalPath(), linenum))
1594
1595 if errors:
1596 return [output_api.PresubmitError(
1597 'These lines create anonymous variables that need to be named:',
1598 items=errors)]
1599 return []
1600
1601
Peter Kasting4844e46e2018-02-23 07:27:101602def _CheckUniquePtr(input_api, output_api):
1603 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1604 sources = lambda affected_file: input_api.FilterSourceFile(
1605 affected_file,
1606 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1607 input_api.DEFAULT_BLACK_LIST),
1608 white_list=(file_inclusion_pattern,))
Vaclav Brozeka54c528b2018-04-06 19:23:551609
1610 # Pattern to capture a single "<...>" block of template arguments. It can
1611 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
1612 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
1613 # latter would likely require counting that < and > match, which is not
1614 # expressible in regular languages. Should the need arise, one can introduce
1615 # limited counting (matching up to a total number of nesting depth), which
1616 # should cover all practical cases for already a low nesting limit.
1617 template_arg_pattern = (
1618 r'<[^>]*' # Opening block of <.
1619 r'>([^<]*>)?') # Closing block of >.
1620 # Prefix expressing that whatever follows is not already inside a <...>
1621 # block.
1622 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:101623 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:551624 not_inside_template_arg_pattern
1625 + r'\bstd::unique_ptr'
1626 + template_arg_pattern
1627 + r'\(\)')
1628
1629 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
1630 template_arg_no_array_pattern = (
1631 r'<[^>]*[^]]' # Opening block of <.
1632 r'>([^(<]*[^]]>)?') # Closing block of >.
1633 # Prefix saying that what follows is the start of an expression.
1634 start_of_expr_pattern = r'(=|\breturn|^)\s*'
1635 # Suffix saying that what follows are call parentheses with a non-empty list
1636 # of arguments.
1637 nonempty_arg_list_pattern = r'\(([^)]|$)'
1638 return_construct_pattern = input_api.re.compile(
1639 start_of_expr_pattern
1640 + r'std::unique_ptr'
1641 + template_arg_no_array_pattern
1642 + nonempty_arg_list_pattern)
1643
Vaclav Brozek851d9602018-04-04 16:13:051644 problems_constructor = []
1645 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:101646 for f in input_api.AffectedSourceFiles(sources):
1647 for line_number, line in f.ChangedContents():
1648 # Disallow:
1649 # return std::unique_ptr<T>(foo);
1650 # bar = std::unique_ptr<T>(foo);
1651 # But allow:
1652 # return std::unique_ptr<T[]>(foo);
1653 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozek851d9602018-04-04 16:13:051654 local_path = f.LocalPath()
Peter Kasting4844e46e2018-02-23 07:27:101655 if return_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051656 problems_constructor.append(
1657 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:101658 # Disallow:
1659 # std::unique_ptr<T>()
1660 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051661 problems_nullptr.append(
1662 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1663
1664 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:161665 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:051666 errors.append(output_api.PresubmitError(
1667 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161668 problems_nullptr))
1669 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:051670 errors.append(output_api.PresubmitError(
1671 'The following files use explicit std::unique_ptr constructor.'
1672 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161673 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:101674 return errors
1675
1676
[email protected]999261d2014-03-03 20:08:081677def _CheckUserActionUpdate(input_api, output_api):
1678 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521679 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081680 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521681 # If actions.xml is already included in the changelist, the PRESUBMIT
1682 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081683 return []
1684
[email protected]999261d2014-03-03 20:08:081685 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1686 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521687 current_actions = None
[email protected]999261d2014-03-03 20:08:081688 for f in input_api.AffectedFiles(file_filter=file_filter):
1689 for line_num, line in f.ChangedContents():
1690 match = input_api.re.search(action_re, line)
1691 if match:
[email protected]2f92dec2014-03-07 19:21:521692 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1693 # loaded only once.
1694 if not current_actions:
1695 with open('tools/metrics/actions/actions.xml') as actions_f:
1696 current_actions = actions_f.read()
1697 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081698 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521699 action = 'name="{0}"'.format(action_name)
1700 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081701 return [output_api.PresubmitPromptWarning(
1702 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521703 'tools/metrics/actions/actions.xml. Please run '
1704 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081705 % (f.LocalPath(), line_num, action_name))]
1706 return []
1707
1708
Daniel Cheng13ca61a882017-08-25 15:11:251709def _ImportJSONCommentEater(input_api):
1710 import sys
1711 sys.path = sys.path + [input_api.os_path.join(
1712 input_api.PresubmitLocalPath(),
1713 'tools', 'json_comment_eater')]
1714 import json_comment_eater
1715 return json_comment_eater
1716
1717
[email protected]99171a92014-06-03 08:44:471718def _GetJSONParseError(input_api, filename, eat_comments=True):
1719 try:
1720 contents = input_api.ReadFile(filename)
1721 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:251722 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:131723 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471724
1725 input_api.json.loads(contents)
1726 except ValueError as e:
1727 return e
1728 return None
1729
1730
1731def _GetIDLParseError(input_api, filename):
1732 try:
1733 contents = input_api.ReadFile(filename)
1734 idl_schema = input_api.os_path.join(
1735 input_api.PresubmitLocalPath(),
1736 'tools', 'json_schema_compiler', 'idl_schema.py')
1737 process = input_api.subprocess.Popen(
1738 [input_api.python_executable, idl_schema],
1739 stdin=input_api.subprocess.PIPE,
1740 stdout=input_api.subprocess.PIPE,
1741 stderr=input_api.subprocess.PIPE,
1742 universal_newlines=True)
1743 (_, error) = process.communicate(input=contents)
1744 return error or None
1745 except ValueError as e:
1746 return e
1747
1748
1749def _CheckParseErrors(input_api, output_api):
1750 """Check that IDL and JSON files do not contain syntax errors."""
1751 actions = {
1752 '.idl': _GetIDLParseError,
1753 '.json': _GetJSONParseError,
1754 }
[email protected]99171a92014-06-03 08:44:471755 # Most JSON files are preprocessed and support comments, but these do not.
1756 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491757 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471758 ]
1759 # Only run IDL checker on files in these directories.
1760 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491761 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1762 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471763 ]
1764
1765 def get_action(affected_file):
1766 filename = affected_file.LocalPath()
1767 return actions.get(input_api.os_path.splitext(filename)[1])
1768
[email protected]99171a92014-06-03 08:44:471769 def FilterFile(affected_file):
1770 action = get_action(affected_file)
1771 if not action:
1772 return False
1773 path = affected_file.LocalPath()
1774
Sean Kau46e29bc2017-08-28 16:31:161775 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:471776 return False
1777
1778 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:161779 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:471780 return False
1781 return True
1782
1783 results = []
1784 for affected_file in input_api.AffectedFiles(
1785 file_filter=FilterFile, include_deletes=False):
1786 action = get_action(affected_file)
1787 kwargs = {}
1788 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:161789 _MatchesFile(input_api, json_no_comments_patterns,
1790 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:471791 kwargs['eat_comments'] = False
1792 parse_error = action(input_api,
1793 affected_file.AbsoluteLocalPath(),
1794 **kwargs)
1795 if parse_error:
1796 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1797 (affected_file.LocalPath(), parse_error)))
1798 return results
1799
1800
[email protected]760deea2013-12-10 19:33:491801def _CheckJavaStyle(input_api, output_api):
1802 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471803 import sys
[email protected]760deea2013-12-10 19:33:491804 original_sys_path = sys.path
1805 try:
1806 sys.path = sys.path + [input_api.os_path.join(
1807 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1808 import checkstyle
1809 finally:
1810 # Restore sys.path to what it was before.
1811 sys.path = original_sys_path
1812
1813 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091814 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511815 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491816
1817
Sean Kau46e29bc2017-08-28 16:31:161818def _MatchesFile(input_api, patterns, path):
1819 for pattern in patterns:
1820 if input_api.re.search(pattern, path):
1821 return True
1822 return False
1823
1824
Daniel Cheng7052cdf2017-11-21 19:23:291825def _GetOwnersFilesToCheckForIpcOwners(input_api):
1826 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:171827
Daniel Cheng7052cdf2017-11-21 19:23:291828 Returns:
1829 A dictionary mapping an OWNER file to the list of OWNERS rules it must
1830 contain to cover IPC-related files with noparent reviewer rules.
1831 """
1832 # Whether or not a file affects IPC is (mostly) determined by a simple list
1833 # of filename patterns.
dchenge07de812016-06-20 19:27:171834 file_patterns = [
palmerb19a0932017-01-24 04:00:311835 # Legacy IPC:
dchenge07de812016-06-20 19:27:171836 '*_messages.cc',
1837 '*_messages*.h',
1838 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311839 # Mojo IPC:
dchenge07de812016-06-20 19:27:171840 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:471841 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:171842 '*_struct_traits*.*',
1843 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311844 '*.typemap',
1845 # Android native IPC:
1846 '*.aidl',
1847 # Blink uses a different file naming convention:
1848 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:471849 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:171850 '*StructTraits*.*',
1851 '*TypeConverter*.*',
1852 ]
1853
scottmg7a6ed5ba2016-11-04 18:22:041854 # These third_party directories do not contain IPCs, but contain files
1855 # matching the above patterns, which trigger false positives.
1856 exclude_paths = [
1857 'third_party/crashpad/*',
Nico Weberee3dc9b2017-08-31 17:09:291858 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:041859 ]
1860
dchenge07de812016-06-20 19:27:171861 # Dictionary mapping an OWNERS file path to Patterns.
1862 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1863 # rules ) to a PatternEntry.
1864 # PatternEntry is a dictionary with two keys:
1865 # - 'files': the files that are matched by this pattern
1866 # - 'rules': the per-file rules needed for this pattern
1867 # For example, if we expect OWNERS file to contain rules for *.mojom and
1868 # *_struct_traits*.*, Patterns might look like this:
1869 # {
1870 # '*.mojom': {
1871 # 'files': ...,
1872 # 'rules': [
1873 # 'per-file *.mojom=set noparent',
1874 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1875 # ],
1876 # },
1877 # '*_struct_traits*.*': {
1878 # 'files': ...,
1879 # 'rules': [
1880 # 'per-file *_struct_traits*.*=set noparent',
1881 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1882 # ],
1883 # },
1884 # }
1885 to_check = {}
1886
Daniel Cheng13ca61a882017-08-25 15:11:251887 def AddPatternToCheck(input_file, pattern):
1888 owners_file = input_api.os_path.join(
1889 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
1890 if owners_file not in to_check:
1891 to_check[owners_file] = {}
1892 if pattern not in to_check[owners_file]:
1893 to_check[owners_file][pattern] = {
1894 'files': [],
1895 'rules': [
1896 'per-file %s=set noparent' % pattern,
1897 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1898 ]
1899 }
Vaclav Brozekd5de76a2018-03-17 07:57:501900 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:251901
dchenge07de812016-06-20 19:27:171902 # Iterate through the affected files to see what we actually need to check
1903 # for. We should only nag patch authors about per-file rules if a file in that
1904 # directory would match that pattern. If a directory only contains *.mojom
1905 # files and no *_messages*.h files, we should only nag about rules for
1906 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:251907 for f in input_api.AffectedFiles(include_deletes=False):
1908 # Manifest files don't have a strong naming convention. Instead, scan
1909 # affected files for .json files and see if they look like a manifest.
Sean Kau46e29bc2017-08-28 16:31:161910 if (f.LocalPath().endswith('.json') and
1911 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
1912 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:251913 json_comment_eater = _ImportJSONCommentEater(input_api)
1914 mostly_json_lines = '\n'.join(f.NewContents())
1915 # Comments aren't allowed in strict JSON, so filter them out.
1916 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:431917 try:
1918 json_content = input_api.json.loads(json_lines)
1919 except:
1920 # There's another PRESUBMIT check that already verifies that JSON files
1921 # are not invalid, so no need to emit another warning here.
1922 continue
Daniel Cheng13ca61a882017-08-25 15:11:251923 if 'interface_provider_specs' in json_content:
1924 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:171925 for pattern in file_patterns:
1926 if input_api.fnmatch.fnmatch(
1927 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041928 skip = False
1929 for exclude in exclude_paths:
1930 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1931 skip = True
1932 break
1933 if skip:
1934 continue
Daniel Cheng13ca61a882017-08-25 15:11:251935 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:171936 break
1937
Daniel Cheng7052cdf2017-11-21 19:23:291938 return to_check
1939
1940
1941def _CheckIpcOwners(input_api, output_api):
1942 """Checks that affected files involving IPC have an IPC OWNERS rule."""
1943 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
1944
1945 if to_check:
1946 # If there are any OWNERS files to check, there are IPC-related changes in
1947 # this CL. Auto-CC the review list.
1948 output_api.AppendCC('[email protected]')
1949
1950 # Go through the OWNERS files to check, filtering out rules that are already
1951 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:171952 for owners_file, patterns in to_check.iteritems():
1953 try:
1954 with file(owners_file) as f:
1955 lines = set(f.read().splitlines())
1956 for entry in patterns.itervalues():
1957 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1958 ]
1959 except IOError:
1960 # No OWNERS file, so all the rules are definitely missing.
1961 continue
1962
1963 # All the remaining lines weren't found in OWNERS files, so emit an error.
1964 errors = []
1965 for owners_file, patterns in to_check.iteritems():
1966 missing_lines = []
1967 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:501968 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:171969 missing_lines.extend(entry['rules'])
1970 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1971 if missing_lines:
1972 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:051973 'Because of the presence of files:\n%s\n\n'
1974 '%s needs the following %d lines added:\n\n%s' %
1975 ('\n'.join(files), owners_file, len(missing_lines),
1976 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:171977
1978 results = []
1979 if errors:
vabrf5ce3bf92016-07-11 14:52:411980 if input_api.is_committing:
1981 output = output_api.PresubmitError
1982 else:
1983 output = output_api.PresubmitPromptWarning
1984 results.append(output(
Daniel Cheng52111692017-06-14 08:00:591985 'Found OWNERS files that need to be updated for IPC security ' +
1986 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:171987 long_text='\n\n'.join(errors)))
1988
1989 return results
1990
1991
jbriance9e12f162016-11-25 07:57:501992def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:311993 """Checks that added or removed lines in non third party affected
1994 header files do not lead to new useless class or struct forward
1995 declaration.
jbriance9e12f162016-11-25 07:57:501996 """
1997 results = []
1998 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
1999 input_api.re.MULTILINE)
2000 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2001 input_api.re.MULTILINE)
2002 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312003 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192004 not f.LocalPath().startswith('third_party/blink') and
2005 not f.LocalPath().startswith('third_party\\blink') and
jbriance2c51e821a2016-12-12 08:24:312006 not f.LocalPath().startswith('third_party/WebKit') and
2007 not f.LocalPath().startswith('third_party\\WebKit')):
2008 continue
2009
jbriance9e12f162016-11-25 07:57:502010 if not f.LocalPath().endswith('.h'):
2011 continue
2012
2013 contents = input_api.ReadFile(f)
2014 fwd_decls = input_api.re.findall(class_pattern, contents)
2015 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2016
2017 useless_fwd_decls = []
2018 for decl in fwd_decls:
2019 count = sum(1 for _ in input_api.re.finditer(
2020 r'\b%s\b' % input_api.re.escape(decl), contents))
2021 if count == 1:
2022 useless_fwd_decls.append(decl)
2023
2024 if not useless_fwd_decls:
2025 continue
2026
2027 for line in f.GenerateScmDiff().splitlines():
2028 if (line.startswith('-') and not line.startswith('--') or
2029 line.startswith('+') and not line.startswith('++')):
2030 for decl in useless_fwd_decls:
2031 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2032 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242033 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502034 (f.LocalPath(), decl)))
2035 useless_fwd_decls.remove(decl)
2036
2037 return results
2038
2039
dskiba88634f4e2015-08-14 23:03:292040def _CheckAndroidToastUsage(input_api, output_api):
2041 """Checks that code uses org.chromium.ui.widget.Toast instead of
2042 android.widget.Toast (Chromium Toast doesn't force hardware
2043 acceleration on low-end devices, saving memory).
2044 """
2045 toast_import_pattern = input_api.re.compile(
2046 r'^import android\.widget\.Toast;$')
2047
2048 errors = []
2049
2050 sources = lambda affected_file: input_api.FilterSourceFile(
2051 affected_file,
2052 black_list=(_EXCLUDED_PATHS +
2053 _TEST_CODE_EXCLUDED_PATHS +
2054 input_api.DEFAULT_BLACK_LIST +
2055 (r'^chromecast[\\\/].*',
2056 r'^remoting[\\\/].*')),
2057 white_list=(r'.*\.java$',))
2058
2059 for f in input_api.AffectedSourceFiles(sources):
2060 for line_num, line in f.ChangedContents():
2061 if toast_import_pattern.search(line):
2062 errors.append("%s:%d" % (f.LocalPath(), line_num))
2063
2064 results = []
2065
2066 if errors:
2067 results.append(output_api.PresubmitError(
2068 'android.widget.Toast usage is detected. Android toasts use hardware'
2069 ' acceleration, and can be\ncostly on low-end devices. Please use'
2070 ' org.chromium.ui.widget.Toast instead.\n'
2071 'Contact [email protected] if you have any questions.',
2072 errors))
2073
2074 return results
2075
2076
dgnaa68d5e2015-06-10 10:08:222077def _CheckAndroidCrLogUsage(input_api, output_api):
2078 """Checks that new logs using org.chromium.base.Log:
2079 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512080 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222081 """
pkotwicza1dd0b002016-05-16 14:41:042082
torne89540622017-03-24 19:41:302083 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042084 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302085 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:042086 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:302087 # WebView license viewer code cannot depend on //base; used in stub APK.
2088 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
2089 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:042090 ]
2091
dgnaa68d5e2015-06-10 10:08:222092 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122093 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2094 class_in_base_pattern = input_api.re.compile(
2095 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2096 has_some_log_import_pattern = input_api.re.compile(
2097 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222098 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122099 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222100 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512101 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222102 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222103
Vincent Scheib16d7b272015-09-15 18:09:072104 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222105 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:042106 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
2107 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122108
dgnaa68d5e2015-06-10 10:08:222109 tag_decl_errors = []
2110 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122111 tag_errors = []
dgn38736db2015-09-18 19:20:512112 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122113 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222114
2115 for f in input_api.AffectedSourceFiles(sources):
2116 file_content = input_api.ReadFile(f)
2117 has_modified_logs = False
2118
2119 # Per line checks
dgn87d9fb62015-06-12 09:15:122120 if (cr_log_import_pattern.search(file_content) or
2121 (class_in_base_pattern.search(file_content) and
2122 not has_some_log_import_pattern.search(file_content))):
2123 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222124 for line_num, line in f.ChangedContents():
2125
2126 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122127 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222128 if match:
2129 has_modified_logs = True
2130
2131 # Make sure it uses "TAG"
2132 if not match.group('tag') == 'TAG':
2133 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122134 else:
2135 # Report non cr Log function calls in changed lines
2136 for line_num, line in f.ChangedContents():
2137 if log_call_pattern.search(line):
2138 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222139
2140 # Per file checks
2141 if has_modified_logs:
2142 # Make sure the tag is using the "cr" prefix and is not too long
2143 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512144 tag_name = match.group('name') if match else None
2145 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222146 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512147 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222148 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512149 elif '.' in tag_name:
2150 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222151
2152 results = []
2153 if tag_decl_errors:
2154 results.append(output_api.PresubmitPromptWarning(
2155 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512156 '"private static final String TAG = "<package tag>".\n'
2157 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222158 tag_decl_errors))
2159
2160 if tag_length_errors:
2161 results.append(output_api.PresubmitError(
2162 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512163 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222164 tag_length_errors))
2165
2166 if tag_errors:
2167 results.append(output_api.PresubmitPromptWarning(
2168 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2169 tag_errors))
2170
dgn87d9fb62015-06-12 09:15:122171 if util_log_errors:
dgn4401aa52015-04-29 16:26:172172 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122173 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2174 util_log_errors))
2175
dgn38736db2015-09-18 19:20:512176 if tag_with_dot_errors:
2177 results.append(output_api.PresubmitPromptWarning(
2178 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2179 tag_with_dot_errors))
2180
dgn4401aa52015-04-29 16:26:172181 return results
2182
2183
Yoland Yanb92fa522017-08-28 17:37:062184def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2185 """Checks that junit.framework.* is no longer used."""
2186 deprecated_junit_framework_pattern = input_api.re.compile(
2187 r'^import junit\.framework\..*;',
2188 input_api.re.MULTILINE)
2189 sources = lambda x: input_api.FilterSourceFile(
2190 x, white_list=(r'.*\.java$',), black_list=None)
2191 errors = []
2192 for f in input_api.AffectedFiles(sources):
2193 for line_num, line in f.ChangedContents():
2194 if deprecated_junit_framework_pattern.search(line):
2195 errors.append("%s:%d" % (f.LocalPath(), line_num))
2196
2197 results = []
2198 if errors:
2199 results.append(output_api.PresubmitError(
2200 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2201 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2202 ' if you have any question.', errors))
2203 return results
2204
2205
2206def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2207 """Checks that if new Java test classes have inheritance.
2208 Either the new test class is JUnit3 test or it is a JUnit4 test class
2209 with a base class, either case is undesirable.
2210 """
2211 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2212
2213 sources = lambda x: input_api.FilterSourceFile(
2214 x, white_list=(r'.*Test\.java$',), black_list=None)
2215 errors = []
2216 for f in input_api.AffectedFiles(sources):
2217 if not f.OldContents():
2218 class_declaration_start_flag = False
2219 for line_num, line in f.ChangedContents():
2220 if class_declaration_pattern.search(line):
2221 class_declaration_start_flag = True
2222 if class_declaration_start_flag and ' extends ' in line:
2223 errors.append('%s:%d' % (f.LocalPath(), line_num))
2224 if '{' in line:
2225 class_declaration_start_flag = False
2226
2227 results = []
2228 if errors:
2229 results.append(output_api.PresubmitPromptWarning(
2230 'The newly created files include Test classes that inherits from base'
2231 ' class. Please do not use inheritance in JUnit4 tests or add new'
2232 ' JUnit3 tests. Contact [email protected] if you have any'
2233 ' questions.', errors))
2234 return results
2235
yolandyan45001472016-12-21 21:12:422236def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2237 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2238 deprecated_annotation_import_pattern = input_api.re.compile(
2239 r'^import android\.test\.suitebuilder\.annotation\..*;',
2240 input_api.re.MULTILINE)
2241 sources = lambda x: input_api.FilterSourceFile(
2242 x, white_list=(r'.*\.java$',), black_list=None)
2243 errors = []
2244 for f in input_api.AffectedFiles(sources):
2245 for line_num, line in f.ChangedContents():
2246 if deprecated_annotation_import_pattern.search(line):
2247 errors.append("%s:%d" % (f.LocalPath(), line_num))
2248
2249 results = []
2250 if errors:
2251 results.append(output_api.PresubmitError(
2252 'Annotations in android.test.suitebuilder.annotation have been'
2253 ' deprecated since API level 24. Please use android.support.test.filters'
2254 ' from //third_party/android_support_test_runner:runner_java instead.'
2255 ' Contact [email protected] if you have any questions.', errors))
2256 return results
2257
2258
agrieve7b6479d82015-10-07 14:24:222259def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2260 """Checks if MDPI assets are placed in a correct directory."""
2261 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2262 ('/res/drawable/' in f.LocalPath() or
2263 '/res/drawable-ldrtl/' in f.LocalPath()))
2264 errors = []
2265 for f in input_api.AffectedFiles(include_deletes=False,
2266 file_filter=file_filter):
2267 errors.append(' %s' % f.LocalPath())
2268
2269 results = []
2270 if errors:
2271 results.append(output_api.PresubmitError(
2272 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2273 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2274 '/res/drawable-ldrtl/.\n'
2275 'Contact [email protected] if you have questions.', errors))
2276 return results
2277
2278
Nate Fischer535972b2017-09-16 01:06:182279def _CheckAndroidWebkitImports(input_api, output_api):
2280 """Checks that code uses org.chromium.base.Callback instead of
2281 android.widget.ValueCallback except in the WebView glue layer.
2282 """
2283 valuecallback_import_pattern = input_api.re.compile(
2284 r'^import android\.webkit\.ValueCallback;$')
2285
2286 errors = []
2287
2288 sources = lambda affected_file: input_api.FilterSourceFile(
2289 affected_file,
2290 black_list=(_EXCLUDED_PATHS +
2291 _TEST_CODE_EXCLUDED_PATHS +
2292 input_api.DEFAULT_BLACK_LIST +
2293 (r'^android_webview[\\\/]glue[\\\/].*',)),
2294 white_list=(r'.*\.java$',))
2295
2296 for f in input_api.AffectedSourceFiles(sources):
2297 for line_num, line in f.ChangedContents():
2298 if valuecallback_import_pattern.search(line):
2299 errors.append("%s:%d" % (f.LocalPath(), line_num))
2300
2301 results = []
2302
2303 if errors:
2304 results.append(output_api.PresubmitError(
2305 'android.webkit.ValueCallback usage is detected outside of the glue'
2306 ' layer. To stay compatible with the support library, android.webkit.*'
2307 ' classes should only be used inside the glue layer and'
2308 ' org.chromium.base.Callback should be used instead.',
2309 errors))
2310
2311 return results
2312
2313
agrievef32bcc72016-04-04 14:57:402314class PydepsChecker(object):
2315 def __init__(self, input_api, pydeps_files):
2316 self._file_cache = {}
2317 self._input_api = input_api
2318 self._pydeps_files = pydeps_files
2319
2320 def _LoadFile(self, path):
2321 """Returns the list of paths within a .pydeps file relative to //."""
2322 if path not in self._file_cache:
2323 with open(path) as f:
2324 self._file_cache[path] = f.read()
2325 return self._file_cache[path]
2326
2327 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2328 """Returns an interable of paths within the .pydep, relativized to //."""
2329 os_path = self._input_api.os_path
2330 pydeps_dir = os_path.dirname(pydeps_path)
2331 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2332 if not l.startswith('*'))
2333 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2334
2335 def _CreateFilesToPydepsMap(self):
2336 """Returns a map of local_path -> list_of_pydeps."""
2337 ret = {}
2338 for pydep_local_path in self._pydeps_files:
2339 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2340 ret.setdefault(path, []).append(pydep_local_path)
2341 return ret
2342
2343 def ComputeAffectedPydeps(self):
2344 """Returns an iterable of .pydeps files that might need regenerating."""
2345 affected_pydeps = set()
2346 file_to_pydeps_map = None
2347 for f in self._input_api.AffectedFiles(include_deletes=True):
2348 local_path = f.LocalPath()
2349 if local_path == 'DEPS':
2350 return self._pydeps_files
2351 elif local_path.endswith('.pydeps'):
2352 if local_path in self._pydeps_files:
2353 affected_pydeps.add(local_path)
2354 elif local_path.endswith('.py'):
2355 if file_to_pydeps_map is None:
2356 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2357 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2358 return affected_pydeps
2359
2360 def DetermineIfStale(self, pydeps_path):
2361 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412362 import difflib
John Budorick47ca3fe2018-02-10 00:53:102363 import os
2364
agrievef32bcc72016-04-04 14:57:402365 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2366 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102367 env = dict(os.environ)
2368 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402369 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102370 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412371 old_contents = old_pydeps_data[2:]
2372 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402373 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412374 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402375
2376
2377def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2378 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402379 # This check is for Python dependency lists (.pydeps files), and involves
2380 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2381 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282382 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002383 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022384 # TODO(agrieve): Update when there's a better way to detect
2385 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402386 is_android = input_api.os_path.exists('third_party/android_tools')
2387 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2388 results = []
2389 # First, check for new / deleted .pydeps.
2390 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032391 # Check whether we are running the presubmit check for a file in src.
2392 # f.LocalPath is relative to repo (src, or internal repo).
2393 # os_path.exists is relative to src repo.
2394 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2395 # to src and we can conclude that the pydeps is in src.
2396 if input_api.os_path.exists(f.LocalPath()):
2397 if f.LocalPath().endswith('.pydeps'):
2398 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2399 results.append(output_api.PresubmitError(
2400 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2401 'remove %s' % f.LocalPath()))
2402 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2403 results.append(output_api.PresubmitError(
2404 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2405 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402406
2407 if results:
2408 return results
2409
2410 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2411
2412 for pydep_path in checker.ComputeAffectedPydeps():
2413 try:
phajdan.jr0d9878552016-11-04 10:49:412414 result = checker.DetermineIfStale(pydep_path)
2415 if result:
2416 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402417 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412418 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2419 'To regenerate, run:\n\n %s' %
2420 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402421 except input_api.subprocess.CalledProcessError as error:
2422 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2423 long_text=error.output)]
2424
2425 return results
2426
2427
glidere61efad2015-02-18 17:39:432428def _CheckSingletonInHeaders(input_api, output_api):
2429 """Checks to make sure no header files have |Singleton<|."""
2430 def FileFilter(affected_file):
2431 # It's ok for base/memory/singleton.h to have |Singleton<|.
2432 black_list = (_EXCLUDED_PATHS +
2433 input_api.DEFAULT_BLACK_LIST +
Michael Warrese4451492018-03-07 04:42:472434 (r"^base[\\\/]memory[\\\/]singleton\.h$",
2435 r"^net[\\\/]quic[\\\/]platform[\\\/]impl[\\\/]"
2436 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432437 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2438
sergeyu34d21222015-09-16 00:11:442439 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432440 files = []
2441 for f in input_api.AffectedSourceFiles(FileFilter):
2442 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2443 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2444 contents = input_api.ReadFile(f)
2445 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242446 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432447 pattern.search(line)):
2448 files.append(f)
2449 break
2450
2451 if files:
yolandyandaabc6d2016-04-18 18:29:392452 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442453 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432454 'Please move them to an appropriate source file so that the ' +
2455 'template gets instantiated in a single compilation unit.',
2456 files) ]
2457 return []
2458
2459
[email protected]fd20b902014-05-09 02:14:532460_DEPRECATED_CSS = [
2461 # Values
2462 ( "-webkit-box", "flex" ),
2463 ( "-webkit-inline-box", "inline-flex" ),
2464 ( "-webkit-flex", "flex" ),
2465 ( "-webkit-inline-flex", "inline-flex" ),
2466 ( "-webkit-min-content", "min-content" ),
2467 ( "-webkit-max-content", "max-content" ),
2468
2469 # Properties
2470 ( "-webkit-background-clip", "background-clip" ),
2471 ( "-webkit-background-origin", "background-origin" ),
2472 ( "-webkit-background-size", "background-size" ),
2473 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442474 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532475
2476 # Functions
2477 ( "-webkit-gradient", "gradient" ),
2478 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2479 ( "-webkit-linear-gradient", "linear-gradient" ),
2480 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2481 ( "-webkit-radial-gradient", "radial-gradient" ),
2482 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2483]
2484
dbeam1ec68ac2016-12-15 05:22:242485def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532486 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252487 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342488 documentation and iOS CSS for dom distiller
2489 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252490 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532491 results = []
dbeam070cfe62014-10-22 06:44:022492 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:252493 black_list = (_EXCLUDED_PATHS +
2494 _TEST_CODE_EXCLUDED_PATHS +
2495 input_api.DEFAULT_BLACK_LIST +
2496 (r"^chrome/common/extensions/docs",
2497 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342498 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442499 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252500 r"^native_client_sdk"))
2501 file_filter = lambda f: input_api.FilterSourceFile(
2502 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532503 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2504 for line_num, line in fpath.ChangedContents():
2505 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022506 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532507 results.append(output_api.PresubmitError(
2508 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2509 (fpath.LocalPath(), line_num, deprecated_value, value)))
2510 return results
2511
mohan.reddyf21db962014-10-16 12:26:472512
dbeam070cfe62014-10-22 06:44:022513_DEPRECATED_JS = [
2514 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2515 ( "__defineGetter__", "Object.defineProperty" ),
2516 ( "__defineSetter__", "Object.defineProperty" ),
2517]
2518
dbeam1ec68ac2016-12-15 05:22:242519def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022520 """Make sure that we don't use deprecated JS in Chrome code."""
2521 results = []
2522 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2523 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2524 input_api.DEFAULT_BLACK_LIST)
2525 file_filter = lambda f: input_api.FilterSourceFile(
2526 f, white_list=file_inclusion_pattern, black_list=black_list)
2527 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2528 for lnum, line in fpath.ChangedContents():
2529 for (deprecated, replacement) in _DEPRECATED_JS:
2530 if deprecated in line:
2531 results.append(output_api.PresubmitError(
2532 "%s:%d: Use of deprecated JS %s, use %s instead" %
2533 (fpath.LocalPath(), lnum, deprecated, replacement)))
2534 return results
2535
dpapadd651231d82017-07-21 02:44:472536def _CheckForRiskyJsArrowFunction(line_number, line):
2537 if ' => ' in line:
2538 return "line %d, is using an => (arrow) function\n %s\n" % (
2539 line_number, line)
2540 return ''
2541
2542def _CheckForRiskyJsConstLet(input_api, line_number, line):
2543 if input_api.re.match('^\s*(const|let)\s', line):
2544 return "line %d, is using const/let keyword\n %s\n" % (
2545 line_number, line)
2546 return ''
dbeam070cfe62014-10-22 06:44:022547
dbeam1ec68ac2016-12-15 05:22:242548def _CheckForRiskyJsFeatures(input_api, output_api):
2549 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
Steven Bennetts90545f3cb2017-08-14 18:11:002550 # 'ui/webui/resources/cr_components are not allowed on ios'
2551 not_ios_filter = (r".*ui\/webui\/resources\/cr_components.*", )
Steven Bennetts9c7e3c22017-08-02 19:10:572552 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js,
Steven Bennetts90545f3cb2017-08-14 18:11:002553 black_list=not_ios_filter)
dpapadd651231d82017-07-21 02:44:472554 results = []
dbeam1ec68ac2016-12-15 05:22:242555 for f in input_api.AffectedFiles(file_filter=file_filter):
dpapadd651231d82017-07-21 02:44:472556 arrow_error_lines = []
2557 const_let_error_lines = []
dbeam1ec68ac2016-12-15 05:22:242558 for lnum, line in f.ChangedContents():
dpapadd651231d82017-07-21 02:44:472559 arrow_error_lines += filter(None, [
2560 _CheckForRiskyJsArrowFunction(lnum, line),
2561 ])
dbeam1ec68ac2016-12-15 05:22:242562
dpapadd651231d82017-07-21 02:44:472563 const_let_error_lines += filter(None, [
2564 _CheckForRiskyJsConstLet(input_api, lnum, line),
2565 ])
dbeam1ec68ac2016-12-15 05:22:242566
dpapadd651231d82017-07-21 02:44:472567 if arrow_error_lines:
2568 arrow_error_lines = map(
2569 lambda e: "%s:%s" % (f.LocalPath(), e), arrow_error_lines)
2570 results.append(
2571 output_api.PresubmitPromptWarning('\n'.join(arrow_error_lines + [
2572"""
2573Use of => (arrow) operator detected in:
dbeam1ec68ac2016-12-15 05:22:242574%s
2575Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2576https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
dpapadd651231d82017-07-21 02:44:472577""" % f.LocalPath()
2578 ])))
dbeam1ec68ac2016-12-15 05:22:242579
dpapadd651231d82017-07-21 02:44:472580 if const_let_error_lines:
2581 const_let_error_lines = map(
2582 lambda e: "%s:%s" % (f.LocalPath(), e), const_let_error_lines)
2583 results.append(
2584 output_api.PresubmitPromptWarning('\n'.join(const_let_error_lines + [
2585"""
2586Use of const/let keywords detected in:
2587%s
2588Please ensure your code does not run on iOS9 because const/let is not fully
2589supported.
2590https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#let-Block_Scoped-Variables
2591https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#const-Block_Scoped-Constants
2592""" % f.LocalPath()
2593 ])))
2594
2595 return results
dbeam1ec68ac2016-12-15 05:22:242596
rlanday6802cf632017-05-30 17:48:362597def _CheckForRelativeIncludes(input_api, output_api):
2598 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2599 import sys
2600 original_sys_path = sys.path
2601 try:
2602 sys.path = sys.path + [input_api.os_path.join(
2603 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2604 from cpp_checker import CppChecker
2605 finally:
2606 # Restore sys.path to what it was before.
2607 sys.path = original_sys_path
2608
2609 bad_files = {}
2610 for f in input_api.AffectedFiles(include_deletes=False):
2611 if (f.LocalPath().startswith('third_party') and
2612 not f.LocalPath().startswith('third_party/WebKit') and
2613 not f.LocalPath().startswith('third_party\\WebKit')):
2614 continue
2615
2616 if not CppChecker.IsCppFile(f.LocalPath()):
2617 continue
2618
Vaclav Brozekd5de76a2018-03-17 07:57:502619 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362620 if "#include" in line and "../" in line]
2621 if not relative_includes:
2622 continue
2623 bad_files[f.LocalPath()] = relative_includes
2624
2625 if not bad_files:
2626 return []
2627
2628 error_descriptions = []
2629 for file_path, bad_lines in bad_files.iteritems():
2630 error_description = file_path
2631 for line in bad_lines:
2632 error_description += '\n ' + line
2633 error_descriptions.append(error_description)
2634
2635 results = []
2636 results.append(output_api.PresubmitError(
2637 'You added one or more relative #include paths (including "../").\n'
2638 'These shouldn\'t be used because they can be used to include headers\n'
2639 'from code that\'s not correctly specified as a dependency in the\n'
2640 'relevant BUILD.gn file(s).',
2641 error_descriptions))
2642
2643 return results
2644
Takeshi Yoshinoe387aa32017-08-02 13:16:132645
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202646def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2647 if not isinstance(key, ast.Str):
2648 return 'Key at line %d must be a string literal' % key.lineno
2649 if not isinstance(value, ast.Dict):
2650 return 'Value at line %d must be a dict' % value.lineno
2651 if len(value.keys) != 1:
2652 return 'Dict at line %d must have single entry' % value.lineno
2653 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2654 return (
2655 'Entry at line %d must have a string literal \'filepath\' as key' %
2656 value.lineno)
2657 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132658
Takeshi Yoshinoe387aa32017-08-02 13:16:132659
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202660def _CheckWatchlistsEntrySyntax(key, value, ast):
2661 if not isinstance(key, ast.Str):
2662 return 'Key at line %d must be a string literal' % key.lineno
2663 if not isinstance(value, ast.List):
2664 return 'Value at line %d must be a list' % value.lineno
2665 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132666
Takeshi Yoshinoe387aa32017-08-02 13:16:132667
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202668def _CheckWATCHLISTSEntries(wd_dict, w_dict, ast):
2669 mismatch_template = (
2670 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2671 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132672
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202673 i = 0
2674 last_key = ''
2675 while True:
2676 if i >= len(wd_dict.keys):
2677 if i >= len(w_dict.keys):
2678 return None
2679 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2680 elif i >= len(w_dict.keys):
2681 return (
2682 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132683
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202684 wd_key = wd_dict.keys[i]
2685 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132686
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202687 result = _CheckWatchlistDefinitionsEntrySyntax(
2688 wd_key, wd_dict.values[i], ast)
2689 if result is not None:
2690 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132691
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202692 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast)
2693 if result is not None:
2694 return 'Bad entry in WATCHLISTS dict: %s' % result
2695
2696 if wd_key.s != w_key.s:
2697 return mismatch_template % (
2698 '%s at line %d' % (wd_key.s, wd_key.lineno),
2699 '%s at line %d' % (w_key.s, w_key.lineno))
2700
2701 if wd_key.s < last_key:
2702 return (
2703 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2704 (wd_key.lineno, w_key.lineno))
2705 last_key = wd_key.s
2706
2707 i = i + 1
2708
2709
2710def _CheckWATCHLISTSSyntax(expression, ast):
2711 if not isinstance(expression, ast.Expression):
2712 return 'WATCHLISTS file must contain a valid expression'
2713 dictionary = expression.body
2714 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2715 return 'WATCHLISTS file must have single dict with exactly two entries'
2716
2717 first_key = dictionary.keys[0]
2718 first_value = dictionary.values[0]
2719 second_key = dictionary.keys[1]
2720 second_value = dictionary.values[1]
2721
2722 if (not isinstance(first_key, ast.Str) or
2723 first_key.s != 'WATCHLIST_DEFINITIONS' or
2724 not isinstance(first_value, ast.Dict)):
2725 return (
2726 'The first entry of the dict in WATCHLISTS file must be '
2727 'WATCHLIST_DEFINITIONS dict')
2728
2729 if (not isinstance(second_key, ast.Str) or
2730 second_key.s != 'WATCHLISTS' or
2731 not isinstance(second_value, ast.Dict)):
2732 return (
2733 'The second entry of the dict in WATCHLISTS file must be '
2734 'WATCHLISTS dict')
2735
2736 return _CheckWATCHLISTSEntries(first_value, second_value, ast)
Takeshi Yoshinoe387aa32017-08-02 13:16:132737
2738
2739def _CheckWATCHLISTS(input_api, output_api):
2740 for f in input_api.AffectedFiles(include_deletes=False):
2741 if f.LocalPath() == 'WATCHLISTS':
2742 contents = input_api.ReadFile(f, 'r')
2743
2744 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202745 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132746 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202747 # Get an AST tree for it and scan the tree for detailed style checking.
2748 expression = input_api.ast.parse(
2749 contents, filename='WATCHLISTS', mode='eval')
2750 except ValueError as e:
2751 return [output_api.PresubmitError(
2752 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2753 except SyntaxError as e:
2754 return [output_api.PresubmitError(
2755 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2756 except TypeError as e:
2757 return [output_api.PresubmitError(
2758 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132759
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202760 result = _CheckWATCHLISTSSyntax(expression, input_api.ast)
2761 if result is not None:
2762 return [output_api.PresubmitError(result)]
2763 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132764
2765 return []
2766
2767
dgnaa68d5e2015-06-10 10:08:222768def _AndroidSpecificOnUploadChecks(input_api, output_api):
2769 """Groups checks that target android code."""
2770 results = []
dgnaa68d5e2015-06-10 10:08:222771 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222772 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292773 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:062774 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
2775 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:422776 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:182777 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222778 return results
2779
2780
[email protected]22c9bd72011-03-27 16:47:392781def _CommonChecks(input_api, output_api):
2782 """Checks common to both upload and commit."""
2783 results = []
2784 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382785 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542786 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:082787
2788 author = input_api.change.author_email
2789 if author and author not in _KNOWN_ROBOTS:
2790 results.extend(
2791 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
2792
[email protected]55459852011-08-10 15:17:192793 results.extend(
[email protected]760deea2013-12-10 19:33:492794 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:232795 results.extend(
2796 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542797 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182798 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522799 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222800 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442801 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592802 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062803 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122804 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182805 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222806 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302807 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492808 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032809 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492810 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442811 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272812 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:072813 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542814 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442815 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392816 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552817 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042818 results.extend(
2819 input_api.canned_checks.CheckChangeHasNoTabs(
2820 input_api,
2821 output_api,
2822 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402823 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162824 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082825 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242826 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2827 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472828 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042829 results.extend(_CheckForIPCRules(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:142830 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232831 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432832 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402833 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152834 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172835 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502836 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242837 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:362838 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:132839 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:432840 results.extend(input_api.RunTests(
2841 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:242842
Vaclav Brozekcdc7defb2018-03-20 09:54:352843 for f in input_api.AffectedFiles():
2844 path, name = input_api.os_path.split(f.LocalPath())
2845 if name == 'PRESUBMIT.py':
2846 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:002847 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
2848 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:072849 # The PRESUBMIT.py file (and the directory containing it) might
2850 # have been affected by being moved or removed, so only try to
2851 # run the tests if they still exist.
2852 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2853 input_api, output_api, full_path,
2854 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392855 return results
[email protected]1f7b4172010-01-28 01:17:342856
[email protected]b337cb5b2011-01-23 21:24:052857
[email protected]b8079ae4a2012-12-05 19:56:492858def _CheckPatchFiles(input_api, output_api):
2859 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2860 if f.LocalPath().endswith(('.orig', '.rej'))]
2861 if problems:
2862 return [output_api.PresubmitError(
2863 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032864 else:
2865 return []
[email protected]b8079ae4a2012-12-05 19:56:492866
2867
Kent Tamura5a8755d2017-06-29 23:37:072868def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:212869 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
2870 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
2871 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:072872 include_re = input_api.re.compile(
2873 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
2874 extension_re = input_api.re.compile(r'\.[a-z]+$')
2875 errors = []
2876 for f in input_api.AffectedFiles():
2877 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
2878 continue
2879 found_line_number = None
2880 found_macro = None
2881 for line_num, line in f.ChangedContents():
2882 match = macro_re.search(line)
2883 if match:
2884 found_line_number = line_num
2885 found_macro = match.group(2)
2886 break
2887 if not found_line_number:
2888 continue
2889
2890 found_include = False
2891 for line in f.NewContents():
2892 if include_re.search(line):
2893 found_include = True
2894 break
2895 if found_include:
2896 continue
2897
2898 if not f.LocalPath().endswith('.h'):
2899 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
2900 try:
2901 content = input_api.ReadFile(primary_header_path, 'r')
2902 if include_re.search(content):
2903 continue
2904 except IOError:
2905 pass
2906 errors.append('%s:%d %s macro is used without including build/'
2907 'build_config.h.'
2908 % (f.LocalPath(), found_line_number, found_macro))
2909 if errors:
2910 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
2911 return []
2912
2913
[email protected]b00342e7f2013-03-26 16:21:542914def _DidYouMeanOSMacro(bad_macro):
2915 try:
2916 return {'A': 'OS_ANDROID',
2917 'B': 'OS_BSD',
2918 'C': 'OS_CHROMEOS',
2919 'F': 'OS_FREEBSD',
2920 'L': 'OS_LINUX',
2921 'M': 'OS_MACOSX',
2922 'N': 'OS_NACL',
2923 'O': 'OS_OPENBSD',
2924 'P': 'OS_POSIX',
2925 'S': 'OS_SOLARIS',
2926 'W': 'OS_WIN'}[bad_macro[3].upper()]
2927 except KeyError:
2928 return ''
2929
2930
2931def _CheckForInvalidOSMacrosInFile(input_api, f):
2932 """Check for sensible looking, totally invalid OS macros."""
2933 preprocessor_statement = input_api.re.compile(r'^\s*#')
2934 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2935 results = []
2936 for lnum, line in f.ChangedContents():
2937 if preprocessor_statement.search(line):
2938 for match in os_macro.finditer(line):
2939 if not match.group(1) in _VALID_OS_MACROS:
2940 good = _DidYouMeanOSMacro(match.group(1))
2941 did_you_mean = ' (did you mean %s?)' % good if good else ''
2942 results.append(' %s:%d %s%s' % (f.LocalPath(),
2943 lnum,
2944 match.group(1),
2945 did_you_mean))
2946 return results
2947
2948
2949def _CheckForInvalidOSMacros(input_api, output_api):
2950 """Check all affected files for invalid OS macros."""
2951 bad_macros = []
2952 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472953 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542954 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2955
2956 if not bad_macros:
2957 return []
2958
2959 return [output_api.PresubmitError(
2960 'Possibly invalid OS macro[s] found. Please fix your code\n'
2961 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2962
lliabraa35bab3932014-10-01 12:16:442963
2964def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2965 """Check all affected files for invalid "if defined" macros."""
2966 ALWAYS_DEFINED_MACROS = (
2967 "TARGET_CPU_PPC",
2968 "TARGET_CPU_PPC64",
2969 "TARGET_CPU_68K",
2970 "TARGET_CPU_X86",
2971 "TARGET_CPU_ARM",
2972 "TARGET_CPU_MIPS",
2973 "TARGET_CPU_SPARC",
2974 "TARGET_CPU_ALPHA",
2975 "TARGET_IPHONE_SIMULATOR",
2976 "TARGET_OS_EMBEDDED",
2977 "TARGET_OS_IPHONE",
2978 "TARGET_OS_MAC",
2979 "TARGET_OS_UNIX",
2980 "TARGET_OS_WIN32",
2981 )
2982 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2983 results = []
2984 for lnum, line in f.ChangedContents():
2985 for match in ifdef_macro.finditer(line):
2986 if match.group(1) in ALWAYS_DEFINED_MACROS:
2987 always_defined = ' %s is always defined. ' % match.group(1)
2988 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
2989 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
2990 lnum,
2991 always_defined,
2992 did_you_mean))
2993 return results
2994
2995
2996def _CheckForInvalidIfDefinedMacros(input_api, output_api):
2997 """Check all affected files for invalid "if defined" macros."""
2998 bad_macros = []
2999 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:213000 if f.LocalPath().startswith('third_party/sqlite/'):
3001 continue
lliabraa35bab3932014-10-01 12:16:443002 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3003 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3004
3005 if not bad_macros:
3006 return []
3007
3008 return [output_api.PresubmitError(
3009 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3010 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3011 bad_macros)]
3012
3013
mlamouria82272622014-09-16 18:45:043014def _CheckForIPCRules(input_api, output_api):
3015 """Check for same IPC rules described in
3016 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3017 """
3018 base_pattern = r'IPC_ENUM_TRAITS\('
3019 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3020 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3021
3022 problems = []
3023 for f in input_api.AffectedSourceFiles(None):
3024 local_path = f.LocalPath()
3025 if not local_path.endswith('.h'):
3026 continue
3027 for line_number, line in f.ChangedContents():
3028 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3029 problems.append(
3030 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3031
3032 if problems:
3033 return [output_api.PresubmitPromptWarning(
3034 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
3035 else:
3036 return []
3037
[email protected]b00342e7f2013-03-26 16:21:543038
Daniel Bratell8ba52722018-03-02 16:06:143039def _CheckForIncludeGuards(input_api, output_api):
3040 """Check that header files have proper guards against multiple inclusion.
3041 If a file should not have such guards (and it probably should) then it
3042 should include the string "no-include-guard-because-multiply-included".
3043 """
3044 def is_header_file(f):
3045 return f.LocalPath().endswith('.h')
3046
3047 def replace_special_with_underscore(string):
3048 return input_api.re.sub(r'[\\/.-]', '_', string)
3049
3050 errors = []
3051
3052 for f in input_api.AffectedSourceFiles(is_header_file):
3053 guard_name = None
3054 guard_line_number = None
3055 seen_guard_end = False
3056
3057 file_with_path = input_api.os_path.normpath(f.LocalPath())
3058 base_file_name = input_api.os_path.splitext(
3059 input_api.os_path.basename(file_with_path))[0]
3060 upper_base_file_name = base_file_name.upper()
3061
3062 expected_guard = replace_special_with_underscore(
3063 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:143064
3065 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:573066 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
3067 # are too many (1000+) files with slight deviations from the
3068 # coding style. The most important part is that the include guard
3069 # is there, and that it's unique, not the name so this check is
3070 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:143071 #
3072 # As code becomes more uniform, this could be made stricter.
3073
3074 guard_name_pattern_list = [
3075 # Anything with the right suffix (maybe with an extra _).
3076 r'\w+_H__?',
3077
Daniel Bratell39b5b062018-05-16 18:09:573078 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:143079 r'\w+_h',
3080
3081 # Anything including the uppercase name of the file.
3082 r'\w*' + input_api.re.escape(replace_special_with_underscore(
3083 upper_base_file_name)) + r'\w*',
3084 ]
3085 guard_name_pattern = '|'.join(guard_name_pattern_list)
3086 guard_pattern = input_api.re.compile(
3087 r'#ifndef\s+(' + guard_name_pattern + ')')
3088
3089 for line_number, line in enumerate(f.NewContents()):
3090 if 'no-include-guard-because-multiply-included' in line:
3091 guard_name = 'DUMMY' # To not trigger check outside the loop.
3092 break
3093
3094 if guard_name is None:
3095 match = guard_pattern.match(line)
3096 if match:
3097 guard_name = match.group(1)
3098 guard_line_number = line_number
3099
Daniel Bratell39b5b062018-05-16 18:09:573100 # We allow existing files to use include guards whose names
3101 # don't match the chromium style guide, but new files
3102 # (outside third_party) should get it right. The only part
3103 # of third_party we check is blink.
3104 should_check_strict_guard_name = (
3105 not f.OldContents() and
3106 (not file_with_path.startswith('third_party') or
3107 file_with_path.startswith(
3108 input_api.os_path.join('third_party', 'blink'))))
3109
3110 if should_check_strict_guard_name:
3111 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:143112 errors.append(output_api.PresubmitPromptWarning(
3113 'Header using the wrong include guard name %s' % guard_name,
3114 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:573115 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:143116 else:
3117 # The line after #ifndef should have a #define of the same name.
3118 if line_number == guard_line_number + 1:
3119 expected_line = '#define %s' % guard_name
3120 if line != expected_line:
3121 errors.append(output_api.PresubmitPromptWarning(
3122 'Missing "%s" for include guard' % expected_line,
3123 ['%s:%d' % (f.LocalPath(), line_number + 1)],
3124 'Expected: %r\nGot: %r' % (expected_line, line)))
3125
3126 if not seen_guard_end and line == '#endif // %s' % guard_name:
3127 seen_guard_end = True
3128 elif seen_guard_end:
3129 if line.strip() != '':
3130 errors.append(output_api.PresubmitPromptWarning(
3131 'Include guard %s not covering the whole file' % (
3132 guard_name), [f.LocalPath()]))
3133 break # Nothing else to check and enough to warn once.
3134
3135 if guard_name is None:
3136 errors.append(output_api.PresubmitPromptWarning(
3137 'Missing include guard %s' % expected_guard,
3138 [f.LocalPath()],
3139 'Missing include guard in %s\n'
3140 'Recommended name: %s\n'
3141 'This check can be disabled by having the string\n'
3142 'no-include-guard-because-multiply-included in the header.' %
3143 (f.LocalPath(), expected_guard)))
3144
3145 return errors
3146
3147
mostynbb639aca52015-01-07 20:31:233148def _CheckForWindowsLineEndings(input_api, output_api):
3149 """Check source code and known ascii text files for Windows style line
3150 endings.
3151 """
earthdok1b5e0ee2015-03-10 15:19:103152 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233153
3154 file_inclusion_pattern = (
3155 known_text_files,
3156 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3157 )
3158
mostynbb639aca52015-01-07 20:31:233159 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533160 source_file_filter = lambda f: input_api.FilterSourceFile(
3161 f, white_list=file_inclusion_pattern, black_list=None)
3162 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503163 include_file = False
3164 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233165 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503166 include_file = True
3167 if include_file:
3168 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233169
3170 if problems:
3171 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3172 'these files to contain Windows style line endings?\n' +
3173 '\n'.join(problems))]
3174
3175 return []
3176
3177
Vaclav Brozekd5de76a2018-03-17 07:57:503178def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133179 """Checks that all source files use SYSLOG properly."""
3180 syslog_files = []
3181 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563182 for line_number, line in f.ChangedContents():
3183 if 'SYSLOG' in line:
3184 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3185
pastarmovj89f7ee12016-09-20 14:58:133186 if syslog_files:
3187 return [output_api.PresubmitPromptWarning(
3188 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3189 ' calls.\nFiles to check:\n', items=syslog_files)]
3190 return []
3191
3192
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193193def _CheckCrbugLinksHaveHttps(input_api, output_api):
Miguel Casas68bdb652017-12-19 16:29:093194 """Checks that crbug(.com) links are correctly prefixed by https://,
3195 unless they come in the accepted form TODO(crbug.com/...)
3196 """
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193197 white_list = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3198 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS)
3199 sources = lambda f: input_api.FilterSourceFile(
3200 f, white_list=white_list, black_list=black_list)
3201
3202 pattern = input_api.re.compile(r'//.*(?<!:\/\/)crbug[.com]*')
Miguel Casas68bdb652017-12-19 16:29:093203 accepted_pattern = input_api.re.compile(r'//.*TODO\(crbug[.com]*');
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193204 problems = []
3205 for f in input_api.AffectedSourceFiles(sources):
3206 for line_num, line in f.ChangedContents():
Miguel Casas68bdb652017-12-19 16:29:093207 if pattern.search(line) and not accepted_pattern.search(line):
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193208 problems.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3209
3210 if problems:
3211 return [output_api.PresubmitPromptWarning(
3212 'Found unprefixed crbug.com URL(s), consider prepending https://\n'+
3213 '\n'.join(problems))]
3214 return []
3215
3216
[email protected]1f7b4172010-01-28 01:17:343217def CheckChangeOnUpload(input_api, output_api):
3218 results = []
3219 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473220 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283221 results.extend(
jam93a6ee792017-02-08 23:59:223222 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193223 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223224 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133225 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163226 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193227 results.extend(_CheckCrbugLinksHaveHttps(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:533228 results.extend(_CheckUniquePtr(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543229 return results
[email protected]ca8d1982009-02-19 16:33:123230
3231
[email protected]1bfb8322014-04-23 01:02:413232def GetTryServerMasterForBot(bot):
3233 """Returns the Try Server master for the given bot.
3234
[email protected]0bb112362014-07-26 04:38:323235 It tries to guess the master from the bot name, but may still fail
3236 and return None. There is no longer a default master.
3237 """
3238 # Potentially ambiguous bot names are listed explicitly.
3239 master_map = {
tandriie5587792016-07-14 00:34:503240 'chromium_presubmit': 'master.tryserver.chromium.linux',
3241 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413242 }
[email protected]0bb112362014-07-26 04:38:323243 master = master_map.get(bot)
3244 if not master:
wnwen4fbaab82016-05-25 12:54:363245 if 'android' in bot:
tandriie5587792016-07-14 00:34:503246 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363247 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503248 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323249 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503250 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323251 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503252 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323253 return master
[email protected]1bfb8322014-04-23 01:02:413254
3255
[email protected]ca8d1982009-02-19 16:33:123256def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543257 results = []
[email protected]1f7b4172010-01-28 01:17:343258 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543259 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273260 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343261 input_api,
3262 output_api,
[email protected]2fdd1f362013-01-16 03:56:033263 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273264
jam93a6ee792017-02-08 23:59:223265 results.extend(
3266 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543267 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3268 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413269 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3270 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543271 return results