blob: 08292e0ed2bfcb9d9125ee0916468786b0622751 [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
Stephen Martinis97a394142018-06-07 23:06:05588_LONG_PATH_ERROR = (
589 'Some files included in this CL have file names that are too long (> 200'
590 ' characters). If committed, these files will cause issues on Windows. See'
591 ' https://crbug.com/612667 for more details.'
592)
593
Shenghua Zhangbfaa38b82017-11-16 21:58:02594_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
595 r".*[\\\/]BuildHooksAndroidImpl\.java",
James Wallace-Lee524eb682018-05-10 01:36:35596 r".*[\\\/]ClassRegisterImpl\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:02597 r".*[\\\/]LicenseContentProvider\.java",
James Wallace-Leef31ae6c2018-05-01 23:30:20598 r".*[\\\/]PlatformServiceBridgeImpl.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:02599]
[email protected]127f18ec2012-06-16 05:05:59600
Sean Kau46e29bc2017-08-28 16:31:16601# These paths contain test data and other known invalid JSON files.
602_KNOWN_INVALID_JSON_FILE_PATTERNS = [
603 r'test[\\\/]data[\\\/]',
604 r'^components[\\\/]policy[\\\/]resources[\\\/]policy_templates\.json$',
605 r'^third_party[\\\/]protobuf[\\\/]',
Raphael Kubo da Costa211f3b472017-11-16 00:27:16606 r'^third_party[\\\/]WebKit[\\\/]LayoutTests[\\\/]external[\\\/]wpt[\\\/]',
Alexey Kozyatinskiya42a629f2018-04-17 17:49:38607 r'^third_party[\\\/]blink[\\\/]renderer[\\\/]devtools[\\\/]protocol\.json$',
Sean Kau46e29bc2017-08-28 16:31:16608]
609
610
[email protected]b00342e7f2013-03-26 16:21:54611_VALID_OS_MACROS = (
612 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08613 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54614 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:12615 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:54616 'OS_BSD',
617 'OS_CAT', # For testing.
618 'OS_CHROMEOS',
619 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37620 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54621 'OS_IOS',
622 'OS_LINUX',
623 'OS_MACOSX',
624 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21625 'OS_NACL_NONSFI',
626 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12627 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54628 'OS_OPENBSD',
629 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37630 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54631 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54632 'OS_WIN',
633)
634
635
agrievef32bcc72016-04-04 14:57:40636_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grievea7f1ee902018-05-18 16:17:22637 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:40638 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04639 'build/android/test_wrapper/logdog_wrapper.pydeps',
jbudorick276cc562017-04-29 01:34:58640 'build/secondary/third_party/android_platform/'
641 'development/scripts/stack.pydeps',
agrieve732db3a2016-04-26 19:18:19642 'net/tools/testserver/testserver.pydeps',
agrievef32bcc72016-04-04 14:57:40643]
644
wnwenbdc444e2016-05-25 13:44:15645
agrievef32bcc72016-04-04 14:57:40646_GENERIC_PYDEPS_FILES = [
John Chencde89192018-01-27 21:18:40647 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22648 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:40649]
650
wnwenbdc444e2016-05-25 13:44:15651
agrievef32bcc72016-04-04 14:57:40652_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
653
654
Eric Boren6fd2b932018-01-25 15:05:08655# Bypass the AUTHORS check for these accounts.
656_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:29657 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
658 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:08659 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
660 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:59661 ) | set('%[email protected]' % s for s in ('findit-for-me',)
662 ) | set('%[email protected]' % s
Sergiy Byelozyorovf78077a92018-06-14 08:07:11663 for s in ('v8-ci-autoroll-builder',))
Eric Boren6fd2b932018-01-25 15:05:08664
665
[email protected]55459852011-08-10 15:17:19666def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
667 """Attempts to prevent use of functions intended only for testing in
668 non-testing code. For now this is just a best-effort implementation
669 that ignores header files and may have some false positives. A
670 better implementation would probably need a proper C++ parser.
671 """
672 # We only scan .cc files and the like, as the declaration of
673 # for-testing functions in header files are hard to distinguish from
674 # calls to such functions without a proper C++ parser.
[email protected]06e6d0ff2012-12-11 01:36:44675 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
[email protected]55459852011-08-10 15:17:19676
jochenc0d4808c2015-07-27 09:25:42677 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19678 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09679 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19680 exclusion_pattern = input_api.re.compile(
681 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
682 base_function_pattern, base_function_pattern))
683
684 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44685 black_list = (_EXCLUDED_PATHS +
686 _TEST_CODE_EXCLUDED_PATHS +
687 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19688 return input_api.FilterSourceFile(
689 affected_file,
690 white_list=(file_inclusion_pattern, ),
691 black_list=black_list)
692
693 problems = []
694 for f in input_api.AffectedSourceFiles(FilterFile):
695 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24696 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03697 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46698 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03699 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19700 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03701 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19702
703 if problems:
[email protected]f7051d52013-04-02 18:31:42704 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03705 else:
706 return []
[email protected]55459852011-08-10 15:17:19707
708
Vaclav Brozek7dbc28c2018-03-27 08:35:23709def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
710 """This is a simplified version of
711 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
712 """
713 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
714 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
715 name_pattern = r'ForTest(s|ing)?'
716 # Describes an occurrence of "ForTest*" inside a // comment.
717 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
718 # Catch calls.
719 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
720 # Ignore definitions. (Comments are ignored separately.)
721 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
722
723 problems = []
724 sources = lambda x: input_api.FilterSourceFile(
725 x,
726 black_list=(('(?i).*test', r'.*\/junit\/')
727 + input_api.DEFAULT_BLACK_LIST),
728 white_list=(r'.*\.java$',)
729 )
730 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
731 local_path = f.LocalPath()
732 is_inside_javadoc = False
733 for line_number, line in f.ChangedContents():
734 if is_inside_javadoc and javadoc_end_re.search(line):
735 is_inside_javadoc = False
736 if not is_inside_javadoc and javadoc_start_re.search(line):
737 is_inside_javadoc = True
738 if is_inside_javadoc:
739 continue
740 if (inclusion_re.search(line) and
741 not comment_re.search(line) and
742 not exclusion_re.search(line)):
743 problems.append(
744 '%s:%d\n %s' % (local_path, line_number, line.strip()))
745
746 if problems:
747 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
748 else:
749 return []
750
751
[email protected]10689ca2011-09-02 02:31:54752def _CheckNoIOStreamInHeaders(input_api, output_api):
753 """Checks to make sure no .h files include <iostream>."""
754 files = []
755 pattern = input_api.re.compile(r'^#include\s*<iostream>',
756 input_api.re.MULTILINE)
757 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
758 if not f.LocalPath().endswith('.h'):
759 continue
760 contents = input_api.ReadFile(f)
761 if pattern.search(contents):
762 files.append(f)
763
764 if len(files):
yolandyandaabc6d2016-04-18 18:29:39765 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06766 'Do not #include <iostream> in header files, since it inserts static '
767 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54768 '#include <ostream>. See http://crbug.com/94794',
769 files) ]
770 return []
771
772
[email protected]72df4e782012-06-21 16:28:18773def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52774 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18775 problems = []
776 for f in input_api.AffectedFiles():
777 if (not f.LocalPath().endswith(('.cc', '.mm'))):
778 continue
779
780 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04781 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18782 problems.append(' %s:%d' % (f.LocalPath(), line_num))
783
784 if not problems:
785 return []
786 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
787 '\n'.join(problems))]
788
789
danakj61c1aa22015-10-26 19:55:52790def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:57791 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:52792 errors = []
793 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
794 input_api.re.MULTILINE)
795 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
796 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
797 continue
798 for lnum, line in f.ChangedContents():
799 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:17800 errors.append(output_api.PresubmitError(
801 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:57802 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:17803 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:52804 return errors
805
806
mcasasb7440c282015-02-04 14:52:19807def _FindHistogramNameInLine(histogram_name, line):
808 """Tries to find a histogram name or prefix in a line."""
809 if not "affected-histogram" in line:
810 return histogram_name in line
811 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
812 # the histogram_name.
813 if not '"' in line:
814 return False
815 histogram_prefix = line.split('\"')[1]
816 return histogram_prefix in histogram_name
817
818
819def _CheckUmaHistogramChanges(input_api, output_api):
820 """Check that UMA histogram names in touched lines can still be found in other
821 lines of the patch or in histograms.xml. Note that this check would not catch
822 the reverse: changes in histograms.xml not matched in the code itself."""
823 touched_histograms = []
824 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:47825 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
826 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
827 name_pattern = r'"(.*?)"'
828 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
829 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
830 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
831 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
832 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:17833 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:19834 for f in input_api.AffectedFiles():
835 # If histograms.xml itself is modified, keep the modified lines for later.
836 if f.LocalPath().endswith(('histograms.xml')):
837 histograms_xml_modifications = f.ChangedContents()
838 continue
Vaclav Brozekbdac817c2018-03-24 06:30:47839 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
840 single_line_re = single_line_c_re
841 split_line_prefix_re = split_line_c_prefix_re
842 elif f.LocalPath().endswith(('java')):
843 single_line_re = single_line_java_re
844 split_line_prefix_re = split_line_java_prefix_re
845 else:
mcasasb7440c282015-02-04 14:52:19846 continue
847 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:17848 if last_line_matched_prefix:
849 suffix_found = split_line_suffix_re.search(line)
850 if suffix_found :
851 touched_histograms.append([suffix_found.group(1), f, line_num])
852 last_line_matched_prefix = False
853 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:06854 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:19855 if found:
856 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:17857 continue
858 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:19859
860 # Search for the touched histogram names in the local modifications to
861 # histograms.xml, and, if not found, on the base histograms.xml file.
862 unmatched_histograms = []
863 for histogram_info in touched_histograms:
864 histogram_name_found = False
865 for line_num, line in histograms_xml_modifications:
866 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
867 if histogram_name_found:
868 break
869 if not histogram_name_found:
870 unmatched_histograms.append(histogram_info)
871
eromanb90c82e7e32015-04-01 15:13:49872 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:19873 problems = []
874 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:49875 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:19876 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:45877 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:19878 histogram_name_found = False
879 for line in histograms_xml:
880 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
881 if histogram_name_found:
882 break
883 if not histogram_name_found:
884 problems.append(' [%s:%d] %s' %
885 (f.LocalPath(), line_num, histogram_name))
886
887 if not problems:
888 return []
889 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
890 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:49891 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:19892
wnwenbdc444e2016-05-25 13:44:15893
yolandyandaabc6d2016-04-18 18:29:39894def _CheckFlakyTestUsage(input_api, output_api):
895 """Check that FlakyTest annotation is our own instead of the android one"""
896 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
897 files = []
898 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
899 if f.LocalPath().endswith('Test.java'):
900 if pattern.search(input_api.ReadFile(f)):
901 files.append(f)
902 if len(files):
903 return [output_api.PresubmitError(
904 'Use org.chromium.base.test.util.FlakyTest instead of '
905 'android.test.FlakyTest',
906 files)]
907 return []
mcasasb7440c282015-02-04 14:52:19908
wnwenbdc444e2016-05-25 13:44:15909
[email protected]8ea5d4b2011-09-13 21:49:22910def _CheckNoNewWStrings(input_api, output_api):
911 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:27912 problems = []
[email protected]8ea5d4b2011-09-13 21:49:22913 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:20914 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:57915 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:34916 '/win/' in f.LocalPath() or
917 'chrome_elf' in f.LocalPath() or
918 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:20919 continue
[email protected]8ea5d4b2011-09-13 21:49:22920
[email protected]a11dbe9b2012-08-07 01:32:58921 allowWString = False
[email protected]b5c24292011-11-28 14:38:20922 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:58923 if 'presubmit: allow wstring' in line:
924 allowWString = True
925 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:27926 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:58927 allowWString = False
928 else:
929 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:22930
[email protected]55463aa62011-10-12 00:48:27931 if not problems:
932 return []
933 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:58934 ' If you are calling a cross-platform API that accepts a wstring, '
935 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:27936 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:22937
938
[email protected]2a8ac9c2011-10-19 17:20:44939def _CheckNoDEPSGIT(input_api, output_api):
940 """Make sure .DEPS.git is never modified manually."""
941 if any(f.LocalPath().endswith('.DEPS.git') for f in
942 input_api.AffectedFiles()):
943 return [output_api.PresubmitError(
944 'Never commit changes to .DEPS.git. This file is maintained by an\n'
945 'automated system based on what\'s in DEPS and your changes will be\n'
946 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50947 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
948 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:44949 'for more information')]
950 return []
951
952
tandriief664692014-09-23 14:51:47953def _CheckValidHostsInDEPS(input_api, output_api):
954 """Checks that DEPS file deps are from allowed_hosts."""
955 # Run only if DEPS file has been modified to annoy fewer bystanders.
956 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
957 return []
958 # Outsource work to gclient verify
959 try:
960 input_api.subprocess.check_output(['gclient', 'verify'])
961 return []
962 except input_api.subprocess.CalledProcessError, error:
963 return [output_api.PresubmitError(
964 'DEPS file must have only git dependencies.',
965 long_text=error.output)]
966
967
[email protected]127f18ec2012-06-16 05:05:59968def _CheckNoBannedFunctions(input_api, output_api):
969 """Make sure that banned functions are not used."""
970 warnings = []
971 errors = []
972
wnwenbdc444e2016-05-25 13:44:15973 def IsBlacklisted(affected_file, blacklist):
974 local_path = affected_file.LocalPath()
975 for item in blacklist:
976 if input_api.re.match(item, local_path):
977 return True
978 return False
979
Sylvain Defresnea8b73d252018-02-28 15:45:54980 def IsIosObcjFile(affected_file):
981 local_path = affected_file.LocalPath()
982 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
983 return False
984 basename = input_api.os_path.basename(local_path)
985 if 'ios' in basename.split('_'):
986 return True
987 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
988 if sep and 'ios' in local_path.split(sep):
989 return True
990 return False
991
wnwenbdc444e2016-05-25 13:44:15992 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
993 matched = False
994 if func_name[0:1] == '/':
995 regex = func_name[1:]
996 if input_api.re.search(regex, line):
997 matched = True
998 elif func_name in line:
dchenge07de812016-06-20 19:27:17999 matched = True
wnwenbdc444e2016-05-25 13:44:151000 if matched:
dchenge07de812016-06-20 19:27:171001 problems = warnings
wnwenbdc444e2016-05-25 13:44:151002 if error:
dchenge07de812016-06-20 19:27:171003 problems = errors
wnwenbdc444e2016-05-25 13:44:151004 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1005 for message_line in message:
1006 problems.append(' %s' % message_line)
1007
Eric Stevensona9a980972017-09-23 00:04:411008 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1009 for f in input_api.AffectedFiles(file_filter=file_filter):
1010 for line_num, line in f.ChangedContents():
1011 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1012 CheckForMatch(f, line_num, line, func_name, message, error)
1013
[email protected]127f18ec2012-06-16 05:05:591014 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1015 for f in input_api.AffectedFiles(file_filter=file_filter):
1016 for line_num, line in f.ChangedContents():
1017 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151018 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591019
Sylvain Defresnea8b73d252018-02-28 15:45:541020 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1021 for line_num, line in f.ChangedContents():
1022 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1023 CheckForMatch(f, line_num, line, func_name, message, error)
1024
[email protected]127f18ec2012-06-16 05:05:591025 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1026 for f in input_api.AffectedFiles(file_filter=file_filter):
1027 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491028 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491029 if IsBlacklisted(f, excluded_paths):
1030 continue
wnwenbdc444e2016-05-25 13:44:151031 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591032
1033 result = []
1034 if (warnings):
1035 result.append(output_api.PresubmitPromptWarning(
1036 'Banned functions were used.\n' + '\n'.join(warnings)))
1037 if (errors):
1038 result.append(output_api.PresubmitError(
1039 'Banned functions were used.\n' + '\n'.join(errors)))
1040 return result
1041
1042
[email protected]6c063c62012-07-11 19:11:061043def _CheckNoPragmaOnce(input_api, output_api):
1044 """Make sure that banned functions are not used."""
1045 files = []
1046 pattern = input_api.re.compile(r'^#pragma\s+once',
1047 input_api.re.MULTILINE)
1048 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1049 if not f.LocalPath().endswith('.h'):
1050 continue
1051 contents = input_api.ReadFile(f)
1052 if pattern.search(contents):
1053 files.append(f)
1054
1055 if files:
1056 return [output_api.PresubmitError(
1057 'Do not use #pragma once in header files.\n'
1058 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1059 files)]
1060 return []
1061
[email protected]127f18ec2012-06-16 05:05:591062
[email protected]e7479052012-09-19 00:26:121063def _CheckNoTrinaryTrueFalse(input_api, output_api):
1064 """Checks to make sure we don't introduce use of foo ? true : false."""
1065 problems = []
1066 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1067 for f in input_api.AffectedFiles():
1068 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1069 continue
1070
1071 for line_num, line in f.ChangedContents():
1072 if pattern.match(line):
1073 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1074
1075 if not problems:
1076 return []
1077 return [output_api.PresubmitPromptWarning(
1078 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1079 '\n'.join(problems))]
1080
1081
[email protected]55f9f382012-07-31 11:02:181082def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281083 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181084 change. Breaking - rules is an error, breaking ! rules is a
1085 warning.
1086 """
mohan.reddyf21db962014-10-16 12:26:471087 import sys
[email protected]55f9f382012-07-31 11:02:181088 # We need to wait until we have an input_api object and use this
1089 # roundabout construct to import checkdeps because this file is
1090 # eval-ed and thus doesn't have __file__.
1091 original_sys_path = sys.path
1092 try:
1093 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471094 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181095 import checkdeps
1096 from cpp_checker import CppChecker
Jinsuk Kim5a092672017-10-24 22:42:241097 from java_checker import JavaChecker
rhalavati08acd232017-04-03 07:23:281098 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:181099 from rules import Rule
1100 finally:
1101 # Restore sys.path to what it was before.
1102 sys.path = original_sys_path
1103
1104 added_includes = []
rhalavati08acd232017-04-03 07:23:281105 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241106 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181107 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:281108 if CppChecker.IsCppFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501109 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081110 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
rhalavati08acd232017-04-03 07:23:281111 elif ProtoChecker.IsProtoFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501112 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081113 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241114 elif JavaChecker.IsJavaFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501115 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081116 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181117
[email protected]26385172013-05-09 23:11:351118 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181119
1120 error_descriptions = []
1121 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281122 error_subjects = set()
1123 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181124 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1125 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081126 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181127 description_with_path = '%s\n %s' % (path, rule_description)
1128 if rule_type == Rule.DISALLOW:
1129 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281130 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181131 else:
1132 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281133 warning_subjects.add("#includes")
1134
1135 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1136 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081137 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281138 description_with_path = '%s\n %s' % (path, rule_description)
1139 if rule_type == Rule.DISALLOW:
1140 error_descriptions.append(description_with_path)
1141 error_subjects.add("imports")
1142 else:
1143 warning_descriptions.append(description_with_path)
1144 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181145
Jinsuk Kim5a092672017-10-24 22:42:241146 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021147 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081148 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241149 description_with_path = '%s\n %s' % (path, rule_description)
1150 if rule_type == Rule.DISALLOW:
1151 error_descriptions.append(description_with_path)
1152 error_subjects.add("imports")
1153 else:
1154 warning_descriptions.append(description_with_path)
1155 warning_subjects.add("imports")
1156
[email protected]55f9f382012-07-31 11:02:181157 results = []
1158 if error_descriptions:
1159 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281160 'You added one or more %s that violate checkdeps rules.'
1161 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181162 error_descriptions))
1163 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421164 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281165 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181166 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281167 '%s? See relevant DEPS file(s) for details and contacts.' %
1168 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181169 warning_descriptions))
1170 return results
1171
1172
[email protected]fbcafe5a2012-08-08 15:31:221173def _CheckFilePermissions(input_api, output_api):
1174 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151175 if input_api.platform == 'win32':
1176 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291177 checkperms_tool = input_api.os_path.join(
1178 input_api.PresubmitLocalPath(),
1179 'tools', 'checkperms', 'checkperms.py')
1180 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471181 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391182 with input_api.CreateTemporaryFile() as file_list:
1183 for f in input_api.AffectedFiles():
1184 # checkperms.py file/directory arguments must be relative to the
1185 # repository.
1186 file_list.write(f.LocalPath() + '\n')
1187 file_list.close()
1188 args += ['--file-list', file_list.name]
1189 try:
1190 input_api.subprocess.check_output(args)
1191 return []
1192 except input_api.subprocess.CalledProcessError as error:
1193 return [output_api.PresubmitError(
1194 'checkperms.py failed:',
1195 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221196
1197
robertocn832f5992017-01-04 19:01:301198def _CheckTeamTags(input_api, output_api):
1199 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1200 checkteamtags_tool = input_api.os_path.join(
1201 input_api.PresubmitLocalPath(),
1202 'tools', 'checkteamtags', 'checkteamtags.py')
1203 args = [input_api.python_executable, checkteamtags_tool,
1204 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221205 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301206 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1207 'OWNERS']
1208 try:
1209 if files:
1210 input_api.subprocess.check_output(args + files)
1211 return []
1212 except input_api.subprocess.CalledProcessError as error:
1213 return [output_api.PresubmitError(
1214 'checkteamtags.py failed:',
1215 long_text=error.output)]
1216
1217
[email protected]c8278b32012-10-30 20:35:491218def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1219 """Makes sure we don't include ui/aura/window_property.h
1220 in header files.
1221 """
1222 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1223 errors = []
1224 for f in input_api.AffectedFiles():
1225 if not f.LocalPath().endswith('.h'):
1226 continue
1227 for line_num, line in f.ChangedContents():
1228 if pattern.match(line):
1229 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1230
1231 results = []
1232 if errors:
1233 results.append(output_api.PresubmitError(
1234 'Header files should not include ui/aura/window_property.h', errors))
1235 return results
1236
1237
[email protected]70ca77752012-11-20 03:45:031238def _CheckForVersionControlConflictsInFile(input_api, f):
1239 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1240 errors = []
1241 for line_num, line in f.ChangedContents():
dbeam95c35a2f2015-06-02 01:40:231242 if f.LocalPath().endswith('.md'):
1243 # First-level headers in markdown look a lot like version control
1244 # conflict markers. http://daringfireball.net/projects/markdown/basics
1245 continue
[email protected]70ca77752012-11-20 03:45:031246 if pattern.match(line):
1247 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1248 return errors
1249
1250
1251def _CheckForVersionControlConflicts(input_api, output_api):
1252 """Usually this is not intentional and will cause a compile failure."""
1253 errors = []
1254 for f in input_api.AffectedFiles():
1255 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1256
1257 results = []
1258 if errors:
1259 results.append(output_api.PresubmitError(
1260 'Version control conflict markers found, please resolve.', errors))
1261 return results
1262
estadee17314a02017-01-12 16:22:161263def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1264 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1265 errors = []
1266 for f in input_api.AffectedFiles():
1267 for line_num, line in f.ChangedContents():
1268 if pattern.search(line):
1269 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1270
1271 results = []
1272 if errors:
1273 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501274 'Found Google support URL addressed by answer number. Please replace '
1275 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161276 return results
1277
[email protected]70ca77752012-11-20 03:45:031278
[email protected]06e6d0ff2012-12-11 01:36:441279def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1280 def FilterFile(affected_file):
1281 """Filter function for use with input_api.AffectedSourceFiles,
1282 below. This filters out everything except non-test files from
1283 top-level directories that generally speaking should not hard-code
1284 service URLs (e.g. src/android_webview/, src/content/ and others).
1285 """
1286 return input_api.FilterSourceFile(
1287 affected_file,
[email protected]78bb39d62012-12-11 15:11:561288 white_list=(r'^(android_webview|base|content|net)[\\\/].*', ),
[email protected]06e6d0ff2012-12-11 01:36:441289 black_list=(_EXCLUDED_PATHS +
1290 _TEST_CODE_EXCLUDED_PATHS +
1291 input_api.DEFAULT_BLACK_LIST))
1292
reillyi38965732015-11-16 18:27:331293 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1294 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461295 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1296 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441297 problems = [] # items are (filename, line_number, line)
1298 for f in input_api.AffectedSourceFiles(FilterFile):
1299 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461300 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441301 problems.append((f.LocalPath(), line_num, line))
1302
1303 if problems:
[email protected]f7051d52013-04-02 18:31:421304 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441305 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581306 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441307 [' %s:%d: %s' % (
1308 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031309 else:
1310 return []
[email protected]06e6d0ff2012-12-11 01:36:441311
1312
[email protected]d2530012013-01-25 16:39:271313def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1314 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311315 The native_client_sdk directory is excluded because it has auto-generated PNG
1316 files for documentation.
[email protected]d2530012013-01-25 16:39:271317 """
[email protected]d2530012013-01-25 16:39:271318 errors = []
binji0dcdf342014-12-12 18:32:311319 white_list = (r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$',)
1320 black_list = (r'^native_client_sdk[\\\/]',)
1321 file_filter = lambda f: input_api.FilterSourceFile(
1322 f, white_list=white_list, black_list=black_list)
1323 for f in input_api.AffectedFiles(include_deletes=False,
1324 file_filter=file_filter):
1325 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271326
1327 results = []
1328 if errors:
1329 results.append(output_api.PresubmitError(
1330 'The name of PNG files should not have abbreviations. \n'
1331 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1332 'Contact [email protected] if you have questions.', errors))
1333 return results
1334
1335
Daniel Cheng4dcdb6b2017-04-13 08:30:171336def _ExtractAddRulesFromParsedDeps(parsed_deps):
1337 """Extract the rules that add dependencies from a parsed DEPS file.
1338
1339 Args:
1340 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1341 add_rules = set()
1342 add_rules.update([
1343 rule[1:] for rule in parsed_deps.get('include_rules', [])
1344 if rule.startswith('+') or rule.startswith('!')
1345 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501346 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171347 {}).iteritems():
1348 add_rules.update([
1349 rule[1:] for rule in rules
1350 if rule.startswith('+') or rule.startswith('!')
1351 ])
1352 return add_rules
1353
1354
1355def _ParseDeps(contents):
1356 """Simple helper for parsing DEPS files."""
1357 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171358 class _VarImpl:
1359
1360 def __init__(self, local_scope):
1361 self._local_scope = local_scope
1362
1363 def Lookup(self, var_name):
1364 """Implements the Var syntax."""
1365 try:
1366 return self._local_scope['vars'][var_name]
1367 except KeyError:
1368 raise Exception('Var is not defined: %s' % var_name)
1369
1370 local_scope = {}
1371 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171372 'Var': _VarImpl(local_scope).Lookup,
1373 }
1374 exec contents in global_scope, local_scope
1375 return local_scope
1376
1377
1378def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081379 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411380 a set of DEPS entries that we should look up.
1381
1382 For a directory (rather than a specific filename) we fake a path to
1383 a specific filename by adding /DEPS. This is chosen as a file that
1384 will seldom or never be subject to per-file include_rules.
1385 """
[email protected]2b438d62013-11-14 17:54:141386 # We ignore deps entries on auto-generated directories.
1387 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081388
Daniel Cheng4dcdb6b2017-04-13 08:30:171389 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1390 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1391
1392 added_deps = new_deps.difference(old_deps)
1393
[email protected]2b438d62013-11-14 17:54:141394 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171395 for added_dep in added_deps:
1396 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1397 continue
1398 # Assume that a rule that ends in .h is a rule for a specific file.
1399 if added_dep.endswith('.h'):
1400 results.add(added_dep)
1401 else:
1402 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081403 return results
1404
1405
[email protected]e871964c2013-05-13 14:14:551406def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1407 """When a dependency prefixed with + is added to a DEPS file, we
1408 want to make sure that the change is reviewed by an OWNER of the
1409 target file or directory, to avoid layering violations from being
1410 introduced. This check verifies that this happens.
1411 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171412 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241413
1414 file_filter = lambda f: not input_api.re.match(
Kent Tamurae9b3a9ec2017-08-31 02:20:191415 r"^third_party[\\\/](WebKit|blink)[\\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241416 for f in input_api.AffectedFiles(include_deletes=False,
1417 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551418 filename = input_api.os_path.basename(f.LocalPath())
1419 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171420 virtual_depended_on_files.update(_CalculateAddedDeps(
1421 input_api.os_path,
1422 '\n'.join(f.OldContents()),
1423 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551424
[email protected]e871964c2013-05-13 14:14:551425 if not virtual_depended_on_files:
1426 return []
1427
1428 if input_api.is_committing:
1429 if input_api.tbr:
1430 return [output_api.PresubmitNotifyResult(
1431 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271432 if input_api.dry_run:
1433 return [output_api.PresubmitNotifyResult(
1434 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551435 if not input_api.change.issue:
1436 return [output_api.PresubmitError(
1437 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401438 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551439 output = output_api.PresubmitError
1440 else:
1441 output = output_api.PresubmitNotifyResult
1442
1443 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501444 owner_email, reviewers = (
1445 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1446 input_api,
1447 owners_db.email_regexp,
1448 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551449
1450 owner_email = owner_email or input_api.change.author_email
1451
[email protected]de4f7d22013-05-23 14:27:461452 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511453 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461454 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551455 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1456 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411457
1458 # We strip the /DEPS part that was added by
1459 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1460 # directory.
1461 def StripDeps(path):
1462 start_deps = path.rfind('/DEPS')
1463 if start_deps != -1:
1464 return path[:start_deps]
1465 else:
1466 return path
1467 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551468 for path in missing_files]
1469
1470 if unapproved_dependencies:
1471 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151472 output('You need LGTM from owners of depends-on paths in DEPS that were '
1473 'modified in this CL:\n %s' %
1474 '\n '.join(sorted(unapproved_dependencies)))]
1475 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1476 output_list.append(output(
1477 'Suggested missing target path OWNERS:\n %s' %
1478 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551479 return output_list
1480
1481 return []
1482
1483
[email protected]85218562013-11-22 07:41:401484def _CheckSpamLogging(input_api, output_api):
1485 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1486 black_list = (_EXCLUDED_PATHS +
1487 _TEST_CODE_EXCLUDED_PATHS +
1488 input_api.DEFAULT_BLACK_LIST +
[email protected]6f742dd02013-11-26 23:19:501489 (r"^base[\\\/]logging\.h$",
[email protected]80f360a2014-01-23 01:36:191490 r"^base[\\\/]logging\.cc$",
[email protected]8dc338c2013-12-09 16:28:481491 r"^chrome[\\\/]app[\\\/]chrome_main_delegate\.cc$",
[email protected]6e268db2013-12-04 01:41:461492 r"^chrome[\\\/]browser[\\\/]chrome_browser_main\.cc$",
[email protected]4de75262013-12-18 23:16:121493 r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
1494 r"startup_browser_creator\.cc$",
[email protected]fe0e6e12013-12-04 05:52:581495 r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
[email protected]8cf6f842014-08-08 21:33:161496 r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031497 r"diagnostics_writer\.cc$",
[email protected]9f13b602014-08-07 02:59:151498 r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
1499 r"^chromecast[\\\/]",
1500 r"^cloud_print[\\\/]",
manzagop85e629e2017-05-09 22:11:481501 r"^components[\\\/]browser_watcher[\\\/]"
1502 r"dump_stability_report_main_win.cc$",
jochen34415e52015-07-10 08:34:311503 r"^components[\\\/]html_viewer[\\\/]"
1504 r"web_test_delegate_impl\.cc$",
Samuel Huang577ef6c2018-03-13 18:19:341505 r"^components[\\\/]zucchini[\\\/].*",
peter80739bb2015-10-20 11:17:461506 # TODO(peter): Remove this exception. https://crbug.com/534537
1507 r"^content[\\\/]browser[\\\/]notifications[\\\/]"
1508 r"notification_event_dispatcher_impl\.cc$",
[email protected]9056e732014-01-08 06:25:251509 r"^content[\\\/]common[\\\/]gpu[\\\/]client[\\\/]"
1510 r"gl_helper_benchmark\.cc$",
altimin979ea2e12016-05-18 16:16:241511 r"^courgette[\\\/]courgette_minimal_tool\.cc$",
thestigc9e38a22014-09-13 01:02:111512 r"^courgette[\\\/]courgette_tool\.cc$",
[email protected]9f13b602014-08-07 02:59:151513 r"^extensions[\\\/]renderer[\\\/]logging_native_handler\.cc$",
prashant.nb0252f62014-11-08 05:02:111514 r"^ipc[\\\/]ipc_logging\.cc$",
[email protected]9c36d922014-03-24 16:47:521515 r"^native_client_sdk[\\\/]",
[email protected]cdbdced2013-11-27 21:35:501516 r"^remoting[\\\/]base[\\\/]logging\.h$",
[email protected]67c96ab2013-12-17 02:05:361517 r"^remoting[\\\/]host[\\\/].*",
[email protected]8232f8fd2013-12-14 00:52:311518 r"^sandbox[\\\/]linux[\\\/].*",
[email protected]0b7a21e2014-02-11 18:38:131519 r"^tools[\\\/]",
asvitkine8a40fe5f02017-02-18 15:35:001520 r"^ui[\\\/]base[\\\/]resource[\\\/]data_pack.cc$",
thestig22dfc4012014-09-05 08:29:441521 r"^ui[\\\/]aura[\\\/]bench[\\\/]bench_main\.cc$",
halliwellf7fc61c62016-01-28 17:18:451522 r"^ui[\\\/]ozone[\\\/]platform[\\\/]cast[\\\/]",
vchigrin14251492015-01-12 08:09:021523 r"^storage[\\\/]browser[\\\/]fileapi[\\\/]" +
skyostil87681be82016-12-19 12:46:351524 r"dump_file_system.cc$",
1525 r"^headless[\\\/]app[\\\/]headless_shell\.cc$"))
[email protected]85218562013-11-22 07:41:401526 source_file_filter = lambda x: input_api.FilterSourceFile(
1527 x, white_list=(file_inclusion_pattern,), black_list=black_list)
1528
thomasanderson625d3932017-03-29 07:16:581529 log_info = set([])
1530 printf = set([])
[email protected]85218562013-11-22 07:41:401531
1532 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581533 for _, line in f.ChangedContents():
1534 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1535 log_info.add(f.LocalPath())
1536 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1537 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371538
thomasanderson625d3932017-03-29 07:16:581539 if input_api.re.search(r"\bprintf\(", line):
1540 printf.add(f.LocalPath())
1541 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1542 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401543
1544 if log_info:
1545 return [output_api.PresubmitError(
1546 'These files spam the console log with LOG(INFO):',
1547 items=log_info)]
1548 if printf:
1549 return [output_api.PresubmitError(
1550 'These files spam the console log with printf/fprintf:',
1551 items=printf)]
1552 return []
1553
1554
[email protected]49aa76a2013-12-04 06:59:161555def _CheckForAnonymousVariables(input_api, output_api):
1556 """These types are all expected to hold locks while in scope and
1557 so should never be anonymous (which causes them to be immediately
1558 destroyed)."""
1559 they_who_must_be_named = [
1560 'base::AutoLock',
1561 'base::AutoReset',
1562 'base::AutoUnlock',
1563 'SkAutoAlphaRestore',
1564 'SkAutoBitmapShaderInstall',
1565 'SkAutoBlitterChoose',
1566 'SkAutoBounderCommit',
1567 'SkAutoCallProc',
1568 'SkAutoCanvasRestore',
1569 'SkAutoCommentBlock',
1570 'SkAutoDescriptor',
1571 'SkAutoDisableDirectionCheck',
1572 'SkAutoDisableOvalCheck',
1573 'SkAutoFree',
1574 'SkAutoGlyphCache',
1575 'SkAutoHDC',
1576 'SkAutoLockColors',
1577 'SkAutoLockPixels',
1578 'SkAutoMalloc',
1579 'SkAutoMaskFreeImage',
1580 'SkAutoMutexAcquire',
1581 'SkAutoPathBoundsUpdate',
1582 'SkAutoPDFRelease',
1583 'SkAutoRasterClipValidate',
1584 'SkAutoRef',
1585 'SkAutoTime',
1586 'SkAutoTrace',
1587 'SkAutoUnref',
1588 ]
1589 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1590 # bad: base::AutoLock(lock.get());
1591 # not bad: base::AutoLock lock(lock.get());
1592 bad_pattern = input_api.re.compile(anonymous)
1593 # good: new base::AutoLock(lock.get())
1594 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1595 errors = []
1596
1597 for f in input_api.AffectedFiles():
1598 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1599 continue
1600 for linenum, line in f.ChangedContents():
1601 if bad_pattern.search(line) and not good_pattern.search(line):
1602 errors.append('%s:%d' % (f.LocalPath(), linenum))
1603
1604 if errors:
1605 return [output_api.PresubmitError(
1606 'These lines create anonymous variables that need to be named:',
1607 items=errors)]
1608 return []
1609
1610
Peter Kasting4844e46e2018-02-23 07:27:101611def _CheckUniquePtr(input_api, output_api):
1612 file_inclusion_pattern = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
1613 sources = lambda affected_file: input_api.FilterSourceFile(
1614 affected_file,
1615 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1616 input_api.DEFAULT_BLACK_LIST),
1617 white_list=(file_inclusion_pattern,))
Vaclav Brozeka54c528b2018-04-06 19:23:551618
1619 # Pattern to capture a single "<...>" block of template arguments. It can
1620 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
1621 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
1622 # latter would likely require counting that < and > match, which is not
1623 # expressible in regular languages. Should the need arise, one can introduce
1624 # limited counting (matching up to a total number of nesting depth), which
1625 # should cover all practical cases for already a low nesting limit.
1626 template_arg_pattern = (
1627 r'<[^>]*' # Opening block of <.
1628 r'>([^<]*>)?') # Closing block of >.
1629 # Prefix expressing that whatever follows is not already inside a <...>
1630 # block.
1631 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:101632 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:551633 not_inside_template_arg_pattern
1634 + r'\bstd::unique_ptr'
1635 + template_arg_pattern
1636 + r'\(\)')
1637
1638 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
1639 template_arg_no_array_pattern = (
1640 r'<[^>]*[^]]' # Opening block of <.
1641 r'>([^(<]*[^]]>)?') # Closing block of >.
1642 # Prefix saying that what follows is the start of an expression.
1643 start_of_expr_pattern = r'(=|\breturn|^)\s*'
1644 # Suffix saying that what follows are call parentheses with a non-empty list
1645 # of arguments.
1646 nonempty_arg_list_pattern = r'\(([^)]|$)'
1647 return_construct_pattern = input_api.re.compile(
1648 start_of_expr_pattern
1649 + r'std::unique_ptr'
1650 + template_arg_no_array_pattern
1651 + nonempty_arg_list_pattern)
1652
Vaclav Brozek851d9602018-04-04 16:13:051653 problems_constructor = []
1654 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:101655 for f in input_api.AffectedSourceFiles(sources):
1656 for line_number, line in f.ChangedContents():
1657 # Disallow:
1658 # return std::unique_ptr<T>(foo);
1659 # bar = std::unique_ptr<T>(foo);
1660 # But allow:
1661 # return std::unique_ptr<T[]>(foo);
1662 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozek851d9602018-04-04 16:13:051663 local_path = f.LocalPath()
Peter Kasting4844e46e2018-02-23 07:27:101664 if return_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051665 problems_constructor.append(
1666 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:101667 # Disallow:
1668 # std::unique_ptr<T>()
1669 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051670 problems_nullptr.append(
1671 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1672
1673 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:161674 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:051675 errors.append(output_api.PresubmitError(
1676 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161677 problems_nullptr))
1678 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:051679 errors.append(output_api.PresubmitError(
1680 'The following files use explicit std::unique_ptr constructor.'
1681 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161682 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:101683 return errors
1684
1685
[email protected]999261d2014-03-03 20:08:081686def _CheckUserActionUpdate(input_api, output_api):
1687 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521688 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081689 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521690 # If actions.xml is already included in the changelist, the PRESUBMIT
1691 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081692 return []
1693
[email protected]999261d2014-03-03 20:08:081694 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1695 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521696 current_actions = None
[email protected]999261d2014-03-03 20:08:081697 for f in input_api.AffectedFiles(file_filter=file_filter):
1698 for line_num, line in f.ChangedContents():
1699 match = input_api.re.search(action_re, line)
1700 if match:
[email protected]2f92dec2014-03-07 19:21:521701 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1702 # loaded only once.
1703 if not current_actions:
1704 with open('tools/metrics/actions/actions.xml') as actions_f:
1705 current_actions = actions_f.read()
1706 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:081707 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:521708 action = 'name="{0}"'.format(action_name)
1709 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:081710 return [output_api.PresubmitPromptWarning(
1711 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:521712 'tools/metrics/actions/actions.xml. Please run '
1713 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:081714 % (f.LocalPath(), line_num, action_name))]
1715 return []
1716
1717
Daniel Cheng13ca61a882017-08-25 15:11:251718def _ImportJSONCommentEater(input_api):
1719 import sys
1720 sys.path = sys.path + [input_api.os_path.join(
1721 input_api.PresubmitLocalPath(),
1722 'tools', 'json_comment_eater')]
1723 import json_comment_eater
1724 return json_comment_eater
1725
1726
[email protected]99171a92014-06-03 08:44:471727def _GetJSONParseError(input_api, filename, eat_comments=True):
1728 try:
1729 contents = input_api.ReadFile(filename)
1730 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:251731 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:131732 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:471733
1734 input_api.json.loads(contents)
1735 except ValueError as e:
1736 return e
1737 return None
1738
1739
1740def _GetIDLParseError(input_api, filename):
1741 try:
1742 contents = input_api.ReadFile(filename)
1743 idl_schema = input_api.os_path.join(
1744 input_api.PresubmitLocalPath(),
1745 'tools', 'json_schema_compiler', 'idl_schema.py')
1746 process = input_api.subprocess.Popen(
1747 [input_api.python_executable, idl_schema],
1748 stdin=input_api.subprocess.PIPE,
1749 stdout=input_api.subprocess.PIPE,
1750 stderr=input_api.subprocess.PIPE,
1751 universal_newlines=True)
1752 (_, error) = process.communicate(input=contents)
1753 return error or None
1754 except ValueError as e:
1755 return e
1756
1757
1758def _CheckParseErrors(input_api, output_api):
1759 """Check that IDL and JSON files do not contain syntax errors."""
1760 actions = {
1761 '.idl': _GetIDLParseError,
1762 '.json': _GetJSONParseError,
1763 }
[email protected]99171a92014-06-03 08:44:471764 # Most JSON files are preprocessed and support comments, but these do not.
1765 json_no_comments_patterns = [
joaodasilva718f87672014-08-30 09:25:491766 r'^testing[\\\/]',
[email protected]99171a92014-06-03 08:44:471767 ]
1768 # Only run IDL checker on files in these directories.
1769 idl_included_patterns = [
joaodasilva718f87672014-08-30 09:25:491770 r'^chrome[\\\/]common[\\\/]extensions[\\\/]api[\\\/]',
1771 r'^extensions[\\\/]common[\\\/]api[\\\/]',
[email protected]99171a92014-06-03 08:44:471772 ]
1773
1774 def get_action(affected_file):
1775 filename = affected_file.LocalPath()
1776 return actions.get(input_api.os_path.splitext(filename)[1])
1777
[email protected]99171a92014-06-03 08:44:471778 def FilterFile(affected_file):
1779 action = get_action(affected_file)
1780 if not action:
1781 return False
1782 path = affected_file.LocalPath()
1783
Sean Kau46e29bc2017-08-28 16:31:161784 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:471785 return False
1786
1787 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:161788 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:471789 return False
1790 return True
1791
1792 results = []
1793 for affected_file in input_api.AffectedFiles(
1794 file_filter=FilterFile, include_deletes=False):
1795 action = get_action(affected_file)
1796 kwargs = {}
1797 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:161798 _MatchesFile(input_api, json_no_comments_patterns,
1799 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:471800 kwargs['eat_comments'] = False
1801 parse_error = action(input_api,
1802 affected_file.AbsoluteLocalPath(),
1803 **kwargs)
1804 if parse_error:
1805 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
1806 (affected_file.LocalPath(), parse_error)))
1807 return results
1808
1809
[email protected]760deea2013-12-10 19:33:491810def _CheckJavaStyle(input_api, output_api):
1811 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:471812 import sys
[email protected]760deea2013-12-10 19:33:491813 original_sys_path = sys.path
1814 try:
1815 sys.path = sys.path + [input_api.os_path.join(
1816 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
1817 import checkstyle
1818 finally:
1819 # Restore sys.path to what it was before.
1820 sys.path = original_sys_path
1821
1822 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:091823 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:511824 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:491825
1826
Sean Kau46e29bc2017-08-28 16:31:161827def _MatchesFile(input_api, patterns, path):
1828 for pattern in patterns:
1829 if input_api.re.search(pattern, path):
1830 return True
1831 return False
1832
1833
Daniel Cheng7052cdf2017-11-21 19:23:291834def _GetOwnersFilesToCheckForIpcOwners(input_api):
1835 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:171836
Daniel Cheng7052cdf2017-11-21 19:23:291837 Returns:
1838 A dictionary mapping an OWNER file to the list of OWNERS rules it must
1839 contain to cover IPC-related files with noparent reviewer rules.
1840 """
1841 # Whether or not a file affects IPC is (mostly) determined by a simple list
1842 # of filename patterns.
dchenge07de812016-06-20 19:27:171843 file_patterns = [
palmerb19a0932017-01-24 04:00:311844 # Legacy IPC:
dchenge07de812016-06-20 19:27:171845 '*_messages.cc',
1846 '*_messages*.h',
1847 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:311848 # Mojo IPC:
dchenge07de812016-06-20 19:27:171849 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:471850 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:171851 '*_struct_traits*.*',
1852 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:311853 '*.typemap',
1854 # Android native IPC:
1855 '*.aidl',
1856 # Blink uses a different file naming convention:
1857 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:471858 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:171859 '*StructTraits*.*',
1860 '*TypeConverter*.*',
1861 ]
1862
scottmg7a6ed5ba2016-11-04 18:22:041863 # These third_party directories do not contain IPCs, but contain files
1864 # matching the above patterns, which trigger false positives.
1865 exclude_paths = [
1866 'third_party/crashpad/*',
Daniel Chengebe635e2018-07-13 12:36:061867 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:291868 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:041869 ]
1870
dchenge07de812016-06-20 19:27:171871 # Dictionary mapping an OWNERS file path to Patterns.
1872 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
1873 # rules ) to a PatternEntry.
1874 # PatternEntry is a dictionary with two keys:
1875 # - 'files': the files that are matched by this pattern
1876 # - 'rules': the per-file rules needed for this pattern
1877 # For example, if we expect OWNERS file to contain rules for *.mojom and
1878 # *_struct_traits*.*, Patterns might look like this:
1879 # {
1880 # '*.mojom': {
1881 # 'files': ...,
1882 # 'rules': [
1883 # 'per-file *.mojom=set noparent',
1884 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
1885 # ],
1886 # },
1887 # '*_struct_traits*.*': {
1888 # 'files': ...,
1889 # 'rules': [
1890 # 'per-file *_struct_traits*.*=set noparent',
1891 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
1892 # ],
1893 # },
1894 # }
1895 to_check = {}
1896
Daniel Cheng13ca61a882017-08-25 15:11:251897 def AddPatternToCheck(input_file, pattern):
1898 owners_file = input_api.os_path.join(
1899 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
1900 if owners_file not in to_check:
1901 to_check[owners_file] = {}
1902 if pattern not in to_check[owners_file]:
1903 to_check[owners_file][pattern] = {
1904 'files': [],
1905 'rules': [
1906 'per-file %s=set noparent' % pattern,
1907 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
1908 ]
1909 }
Vaclav Brozekd5de76a2018-03-17 07:57:501910 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:251911
dchenge07de812016-06-20 19:27:171912 # Iterate through the affected files to see what we actually need to check
1913 # for. We should only nag patch authors about per-file rules if a file in that
1914 # directory would match that pattern. If a directory only contains *.mojom
1915 # files and no *_messages*.h files, we should only nag about rules for
1916 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:251917 for f in input_api.AffectedFiles(include_deletes=False):
1918 # Manifest files don't have a strong naming convention. Instead, scan
1919 # affected files for .json files and see if they look like a manifest.
Sean Kau46e29bc2017-08-28 16:31:161920 if (f.LocalPath().endswith('.json') and
1921 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
1922 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:251923 json_comment_eater = _ImportJSONCommentEater(input_api)
1924 mostly_json_lines = '\n'.join(f.NewContents())
1925 # Comments aren't allowed in strict JSON, so filter them out.
1926 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:431927 try:
1928 json_content = input_api.json.loads(json_lines)
1929 except:
1930 # There's another PRESUBMIT check that already verifies that JSON files
1931 # are not invalid, so no need to emit another warning here.
1932 continue
Daniel Cheng13ca61a882017-08-25 15:11:251933 if 'interface_provider_specs' in json_content:
1934 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:171935 for pattern in file_patterns:
1936 if input_api.fnmatch.fnmatch(
1937 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:041938 skip = False
1939 for exclude in exclude_paths:
1940 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
1941 skip = True
1942 break
1943 if skip:
1944 continue
Daniel Cheng13ca61a882017-08-25 15:11:251945 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:171946 break
1947
Daniel Cheng7052cdf2017-11-21 19:23:291948 return to_check
1949
1950
1951def _CheckIpcOwners(input_api, output_api):
1952 """Checks that affected files involving IPC have an IPC OWNERS rule."""
1953 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
1954
1955 if to_check:
1956 # If there are any OWNERS files to check, there are IPC-related changes in
1957 # this CL. Auto-CC the review list.
1958 output_api.AppendCC('[email protected]')
1959
1960 # Go through the OWNERS files to check, filtering out rules that are already
1961 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:171962 for owners_file, patterns in to_check.iteritems():
1963 try:
1964 with file(owners_file) as f:
1965 lines = set(f.read().splitlines())
1966 for entry in patterns.itervalues():
1967 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
1968 ]
1969 except IOError:
1970 # No OWNERS file, so all the rules are definitely missing.
1971 continue
1972
1973 # All the remaining lines weren't found in OWNERS files, so emit an error.
1974 errors = []
1975 for owners_file, patterns in to_check.iteritems():
1976 missing_lines = []
1977 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:501978 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:171979 missing_lines.extend(entry['rules'])
1980 files.extend([' %s' % f.LocalPath() for f in entry['files']])
1981 if missing_lines:
1982 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:051983 'Because of the presence of files:\n%s\n\n'
1984 '%s needs the following %d lines added:\n\n%s' %
1985 ('\n'.join(files), owners_file, len(missing_lines),
1986 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:171987
1988 results = []
1989 if errors:
vabrf5ce3bf92016-07-11 14:52:411990 if input_api.is_committing:
1991 output = output_api.PresubmitError
1992 else:
1993 output = output_api.PresubmitPromptWarning
1994 results.append(output(
Daniel Cheng52111692017-06-14 08:00:591995 'Found OWNERS files that need to be updated for IPC security ' +
1996 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:171997 long_text='\n\n'.join(errors)))
1998
1999 return results
2000
2001
jbriance9e12f162016-11-25 07:57:502002def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312003 """Checks that added or removed lines in non third party affected
2004 header files do not lead to new useless class or struct forward
2005 declaration.
jbriance9e12f162016-11-25 07:57:502006 """
2007 results = []
2008 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2009 input_api.re.MULTILINE)
2010 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2011 input_api.re.MULTILINE)
2012 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312013 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192014 not f.LocalPath().startswith('third_party/blink') and
2015 not f.LocalPath().startswith('third_party\\blink') and
jbriance2c51e821a2016-12-12 08:24:312016 not f.LocalPath().startswith('third_party/WebKit') and
2017 not f.LocalPath().startswith('third_party\\WebKit')):
2018 continue
2019
jbriance9e12f162016-11-25 07:57:502020 if not f.LocalPath().endswith('.h'):
2021 continue
2022
2023 contents = input_api.ReadFile(f)
2024 fwd_decls = input_api.re.findall(class_pattern, contents)
2025 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2026
2027 useless_fwd_decls = []
2028 for decl in fwd_decls:
2029 count = sum(1 for _ in input_api.re.finditer(
2030 r'\b%s\b' % input_api.re.escape(decl), contents))
2031 if count == 1:
2032 useless_fwd_decls.append(decl)
2033
2034 if not useless_fwd_decls:
2035 continue
2036
2037 for line in f.GenerateScmDiff().splitlines():
2038 if (line.startswith('-') and not line.startswith('--') or
2039 line.startswith('+') and not line.startswith('++')):
2040 for decl in useless_fwd_decls:
2041 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2042 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242043 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502044 (f.LocalPath(), decl)))
2045 useless_fwd_decls.remove(decl)
2046
2047 return results
2048
2049
dskiba88634f4e2015-08-14 23:03:292050def _CheckAndroidToastUsage(input_api, output_api):
2051 """Checks that code uses org.chromium.ui.widget.Toast instead of
2052 android.widget.Toast (Chromium Toast doesn't force hardware
2053 acceleration on low-end devices, saving memory).
2054 """
2055 toast_import_pattern = input_api.re.compile(
2056 r'^import android\.widget\.Toast;$')
2057
2058 errors = []
2059
2060 sources = lambda affected_file: input_api.FilterSourceFile(
2061 affected_file,
2062 black_list=(_EXCLUDED_PATHS +
2063 _TEST_CODE_EXCLUDED_PATHS +
2064 input_api.DEFAULT_BLACK_LIST +
2065 (r'^chromecast[\\\/].*',
2066 r'^remoting[\\\/].*')),
2067 white_list=(r'.*\.java$',))
2068
2069 for f in input_api.AffectedSourceFiles(sources):
2070 for line_num, line in f.ChangedContents():
2071 if toast_import_pattern.search(line):
2072 errors.append("%s:%d" % (f.LocalPath(), line_num))
2073
2074 results = []
2075
2076 if errors:
2077 results.append(output_api.PresubmitError(
2078 'android.widget.Toast usage is detected. Android toasts use hardware'
2079 ' acceleration, and can be\ncostly on low-end devices. Please use'
2080 ' org.chromium.ui.widget.Toast instead.\n'
2081 'Contact [email protected] if you have any questions.',
2082 errors))
2083
2084 return results
2085
2086
dgnaa68d5e2015-06-10 10:08:222087def _CheckAndroidCrLogUsage(input_api, output_api):
2088 """Checks that new logs using org.chromium.base.Log:
2089 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512090 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222091 """
pkotwicza1dd0b002016-05-16 14:41:042092
torne89540622017-03-24 19:41:302093 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042094 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302095 # //chrome/android/webapk cannot depend on //base
pkotwicza1dd0b002016-05-16 14:41:042096 r"^chrome[\\\/]android[\\\/]webapk[\\\/].*",
torne89540622017-03-24 19:41:302097 # WebView license viewer code cannot depend on //base; used in stub APK.
2098 r"^android_webview[\\\/]glue[\\\/]java[\\\/]src[\\\/]com[\\\/]android[\\\/]"
2099 r"webview[\\\/]chromium[\\\/]License.*",
pkotwicza1dd0b002016-05-16 14:41:042100 ]
2101
dgnaa68d5e2015-06-10 10:08:222102 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122103 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2104 class_in_base_pattern = input_api.re.compile(
2105 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2106 has_some_log_import_pattern = input_api.re.compile(
2107 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222108 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122109 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222110 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512111 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222112 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222113
Vincent Scheib16d7b272015-09-15 18:09:072114 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222115 'or contact [email protected] for more info.')
pkotwicza1dd0b002016-05-16 14:41:042116 sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',),
2117 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122118
dgnaa68d5e2015-06-10 10:08:222119 tag_decl_errors = []
2120 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122121 tag_errors = []
dgn38736db2015-09-18 19:20:512122 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122123 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222124
2125 for f in input_api.AffectedSourceFiles(sources):
2126 file_content = input_api.ReadFile(f)
2127 has_modified_logs = False
2128
2129 # Per line checks
dgn87d9fb62015-06-12 09:15:122130 if (cr_log_import_pattern.search(file_content) or
2131 (class_in_base_pattern.search(file_content) and
2132 not has_some_log_import_pattern.search(file_content))):
2133 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222134 for line_num, line in f.ChangedContents():
2135
2136 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122137 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222138 if match:
2139 has_modified_logs = True
2140
2141 # Make sure it uses "TAG"
2142 if not match.group('tag') == 'TAG':
2143 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122144 else:
2145 # Report non cr Log function calls in changed lines
2146 for line_num, line in f.ChangedContents():
2147 if log_call_pattern.search(line):
2148 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222149
2150 # Per file checks
2151 if has_modified_logs:
2152 # Make sure the tag is using the "cr" prefix and is not too long
2153 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512154 tag_name = match.group('name') if match else None
2155 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222156 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512157 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222158 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512159 elif '.' in tag_name:
2160 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222161
2162 results = []
2163 if tag_decl_errors:
2164 results.append(output_api.PresubmitPromptWarning(
2165 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512166 '"private static final String TAG = "<package tag>".\n'
2167 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222168 tag_decl_errors))
2169
2170 if tag_length_errors:
2171 results.append(output_api.PresubmitError(
2172 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512173 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222174 tag_length_errors))
2175
2176 if tag_errors:
2177 results.append(output_api.PresubmitPromptWarning(
2178 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2179 tag_errors))
2180
dgn87d9fb62015-06-12 09:15:122181 if util_log_errors:
dgn4401aa52015-04-29 16:26:172182 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122183 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2184 util_log_errors))
2185
dgn38736db2015-09-18 19:20:512186 if tag_with_dot_errors:
2187 results.append(output_api.PresubmitPromptWarning(
2188 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2189 tag_with_dot_errors))
2190
dgn4401aa52015-04-29 16:26:172191 return results
2192
2193
Yoland Yanb92fa522017-08-28 17:37:062194def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2195 """Checks that junit.framework.* is no longer used."""
2196 deprecated_junit_framework_pattern = input_api.re.compile(
2197 r'^import junit\.framework\..*;',
2198 input_api.re.MULTILINE)
2199 sources = lambda x: input_api.FilterSourceFile(
2200 x, white_list=(r'.*\.java$',), black_list=None)
2201 errors = []
2202 for f in input_api.AffectedFiles(sources):
2203 for line_num, line in f.ChangedContents():
2204 if deprecated_junit_framework_pattern.search(line):
2205 errors.append("%s:%d" % (f.LocalPath(), line_num))
2206
2207 results = []
2208 if errors:
2209 results.append(output_api.PresubmitError(
2210 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2211 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2212 ' if you have any question.', errors))
2213 return results
2214
2215
2216def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2217 """Checks that if new Java test classes have inheritance.
2218 Either the new test class is JUnit3 test or it is a JUnit4 test class
2219 with a base class, either case is undesirable.
2220 """
2221 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2222
2223 sources = lambda x: input_api.FilterSourceFile(
2224 x, white_list=(r'.*Test\.java$',), black_list=None)
2225 errors = []
2226 for f in input_api.AffectedFiles(sources):
2227 if not f.OldContents():
2228 class_declaration_start_flag = False
2229 for line_num, line in f.ChangedContents():
2230 if class_declaration_pattern.search(line):
2231 class_declaration_start_flag = True
2232 if class_declaration_start_flag and ' extends ' in line:
2233 errors.append('%s:%d' % (f.LocalPath(), line_num))
2234 if '{' in line:
2235 class_declaration_start_flag = False
2236
2237 results = []
2238 if errors:
2239 results.append(output_api.PresubmitPromptWarning(
2240 'The newly created files include Test classes that inherits from base'
2241 ' class. Please do not use inheritance in JUnit4 tests or add new'
2242 ' JUnit3 tests. Contact [email protected] if you have any'
2243 ' questions.', errors))
2244 return results
2245
yolandyan45001472016-12-21 21:12:422246def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2247 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2248 deprecated_annotation_import_pattern = input_api.re.compile(
2249 r'^import android\.test\.suitebuilder\.annotation\..*;',
2250 input_api.re.MULTILINE)
2251 sources = lambda x: input_api.FilterSourceFile(
2252 x, white_list=(r'.*\.java$',), black_list=None)
2253 errors = []
2254 for f in input_api.AffectedFiles(sources):
2255 for line_num, line in f.ChangedContents():
2256 if deprecated_annotation_import_pattern.search(line):
2257 errors.append("%s:%d" % (f.LocalPath(), line_num))
2258
2259 results = []
2260 if errors:
2261 results.append(output_api.PresubmitError(
2262 'Annotations in android.test.suitebuilder.annotation have been'
2263 ' deprecated since API level 24. Please use android.support.test.filters'
2264 ' from //third_party/android_support_test_runner:runner_java instead.'
2265 ' Contact [email protected] if you have any questions.', errors))
2266 return results
2267
2268
agrieve7b6479d82015-10-07 14:24:222269def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2270 """Checks if MDPI assets are placed in a correct directory."""
2271 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2272 ('/res/drawable/' in f.LocalPath() or
2273 '/res/drawable-ldrtl/' in f.LocalPath()))
2274 errors = []
2275 for f in input_api.AffectedFiles(include_deletes=False,
2276 file_filter=file_filter):
2277 errors.append(' %s' % f.LocalPath())
2278
2279 results = []
2280 if errors:
2281 results.append(output_api.PresubmitError(
2282 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2283 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2284 '/res/drawable-ldrtl/.\n'
2285 'Contact [email protected] if you have questions.', errors))
2286 return results
2287
2288
Nate Fischer535972b2017-09-16 01:06:182289def _CheckAndroidWebkitImports(input_api, output_api):
2290 """Checks that code uses org.chromium.base.Callback instead of
2291 android.widget.ValueCallback except in the WebView glue layer.
2292 """
2293 valuecallback_import_pattern = input_api.re.compile(
2294 r'^import android\.webkit\.ValueCallback;$')
2295
2296 errors = []
2297
2298 sources = lambda affected_file: input_api.FilterSourceFile(
2299 affected_file,
2300 black_list=(_EXCLUDED_PATHS +
2301 _TEST_CODE_EXCLUDED_PATHS +
2302 input_api.DEFAULT_BLACK_LIST +
2303 (r'^android_webview[\\\/]glue[\\\/].*',)),
2304 white_list=(r'.*\.java$',))
2305
2306 for f in input_api.AffectedSourceFiles(sources):
2307 for line_num, line in f.ChangedContents():
2308 if valuecallback_import_pattern.search(line):
2309 errors.append("%s:%d" % (f.LocalPath(), line_num))
2310
2311 results = []
2312
2313 if errors:
2314 results.append(output_api.PresubmitError(
2315 'android.webkit.ValueCallback usage is detected outside of the glue'
2316 ' layer. To stay compatible with the support library, android.webkit.*'
2317 ' classes should only be used inside the glue layer and'
2318 ' org.chromium.base.Callback should be used instead.',
2319 errors))
2320
2321 return results
2322
2323
agrievef32bcc72016-04-04 14:57:402324class PydepsChecker(object):
2325 def __init__(self, input_api, pydeps_files):
2326 self._file_cache = {}
2327 self._input_api = input_api
2328 self._pydeps_files = pydeps_files
2329
2330 def _LoadFile(self, path):
2331 """Returns the list of paths within a .pydeps file relative to //."""
2332 if path not in self._file_cache:
2333 with open(path) as f:
2334 self._file_cache[path] = f.read()
2335 return self._file_cache[path]
2336
2337 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2338 """Returns an interable of paths within the .pydep, relativized to //."""
2339 os_path = self._input_api.os_path
2340 pydeps_dir = os_path.dirname(pydeps_path)
2341 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2342 if not l.startswith('*'))
2343 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2344
2345 def _CreateFilesToPydepsMap(self):
2346 """Returns a map of local_path -> list_of_pydeps."""
2347 ret = {}
2348 for pydep_local_path in self._pydeps_files:
2349 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2350 ret.setdefault(path, []).append(pydep_local_path)
2351 return ret
2352
2353 def ComputeAffectedPydeps(self):
2354 """Returns an iterable of .pydeps files that might need regenerating."""
2355 affected_pydeps = set()
2356 file_to_pydeps_map = None
2357 for f in self._input_api.AffectedFiles(include_deletes=True):
2358 local_path = f.LocalPath()
2359 if local_path == 'DEPS':
2360 return self._pydeps_files
2361 elif local_path.endswith('.pydeps'):
2362 if local_path in self._pydeps_files:
2363 affected_pydeps.add(local_path)
2364 elif local_path.endswith('.py'):
2365 if file_to_pydeps_map is None:
2366 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2367 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2368 return affected_pydeps
2369
2370 def DetermineIfStale(self, pydeps_path):
2371 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412372 import difflib
John Budorick47ca3fe2018-02-10 00:53:102373 import os
2374
agrievef32bcc72016-04-04 14:57:402375 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2376 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102377 env = dict(os.environ)
2378 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402379 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102380 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412381 old_contents = old_pydeps_data[2:]
2382 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402383 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412384 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402385
2386
2387def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2388 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402389 # This check is for Python dependency lists (.pydeps files), and involves
2390 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2391 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282392 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002393 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022394 # TODO(agrieve): Update when there's a better way to detect
2395 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402396 is_android = input_api.os_path.exists('third_party/android_tools')
2397 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2398 results = []
2399 # First, check for new / deleted .pydeps.
2400 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032401 # Check whether we are running the presubmit check for a file in src.
2402 # f.LocalPath is relative to repo (src, or internal repo).
2403 # os_path.exists is relative to src repo.
2404 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2405 # to src and we can conclude that the pydeps is in src.
2406 if input_api.os_path.exists(f.LocalPath()):
2407 if f.LocalPath().endswith('.pydeps'):
2408 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2409 results.append(output_api.PresubmitError(
2410 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2411 'remove %s' % f.LocalPath()))
2412 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2413 results.append(output_api.PresubmitError(
2414 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2415 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402416
2417 if results:
2418 return results
2419
2420 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2421
2422 for pydep_path in checker.ComputeAffectedPydeps():
2423 try:
phajdan.jr0d9878552016-11-04 10:49:412424 result = checker.DetermineIfStale(pydep_path)
2425 if result:
2426 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402427 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412428 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2429 'To regenerate, run:\n\n %s' %
2430 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402431 except input_api.subprocess.CalledProcessError as error:
2432 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2433 long_text=error.output)]
2434
2435 return results
2436
2437
glidere61efad2015-02-18 17:39:432438def _CheckSingletonInHeaders(input_api, output_api):
2439 """Checks to make sure no header files have |Singleton<|."""
2440 def FileFilter(affected_file):
2441 # It's ok for base/memory/singleton.h to have |Singleton<|.
2442 black_list = (_EXCLUDED_PATHS +
2443 input_api.DEFAULT_BLACK_LIST +
Michael Warrese4451492018-03-07 04:42:472444 (r"^base[\\\/]memory[\\\/]singleton\.h$",
2445 r"^net[\\\/]quic[\\\/]platform[\\\/]impl[\\\/]"
2446 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432447 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2448
sergeyu34d21222015-09-16 00:11:442449 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432450 files = []
2451 for f in input_api.AffectedSourceFiles(FileFilter):
2452 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2453 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2454 contents = input_api.ReadFile(f)
2455 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242456 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432457 pattern.search(line)):
2458 files.append(f)
2459 break
2460
2461 if files:
yolandyandaabc6d2016-04-18 18:29:392462 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442463 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432464 'Please move them to an appropriate source file so that the ' +
2465 'template gets instantiated in a single compilation unit.',
2466 files) ]
2467 return []
2468
2469
[email protected]fd20b902014-05-09 02:14:532470_DEPRECATED_CSS = [
2471 # Values
2472 ( "-webkit-box", "flex" ),
2473 ( "-webkit-inline-box", "inline-flex" ),
2474 ( "-webkit-flex", "flex" ),
2475 ( "-webkit-inline-flex", "inline-flex" ),
2476 ( "-webkit-min-content", "min-content" ),
2477 ( "-webkit-max-content", "max-content" ),
2478
2479 # Properties
2480 ( "-webkit-background-clip", "background-clip" ),
2481 ( "-webkit-background-origin", "background-origin" ),
2482 ( "-webkit-background-size", "background-size" ),
2483 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442484 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532485
2486 # Functions
2487 ( "-webkit-gradient", "gradient" ),
2488 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2489 ( "-webkit-linear-gradient", "linear-gradient" ),
2490 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2491 ( "-webkit-radial-gradient", "radial-gradient" ),
2492 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2493]
2494
dbeam1ec68ac2016-12-15 05:22:242495def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532496 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252497 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342498 documentation and iOS CSS for dom distiller
2499 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252500 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532501 results = []
dbeam070cfe62014-10-22 06:44:022502 file_inclusion_pattern = (r".+\.css$",)
[email protected]9a48e3f82014-05-22 00:06:252503 black_list = (_EXCLUDED_PATHS +
2504 _TEST_CODE_EXCLUDED_PATHS +
2505 input_api.DEFAULT_BLACK_LIST +
2506 (r"^chrome/common/extensions/docs",
2507 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342508 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442509 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252510 r"^native_client_sdk"))
2511 file_filter = lambda f: input_api.FilterSourceFile(
2512 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532513 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2514 for line_num, line in fpath.ChangedContents():
2515 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022516 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532517 results.append(output_api.PresubmitError(
2518 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2519 (fpath.LocalPath(), line_num, deprecated_value, value)))
2520 return results
2521
mohan.reddyf21db962014-10-16 12:26:472522
dbeam070cfe62014-10-22 06:44:022523_DEPRECATED_JS = [
2524 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2525 ( "__defineGetter__", "Object.defineProperty" ),
2526 ( "__defineSetter__", "Object.defineProperty" ),
2527]
2528
dbeam1ec68ac2016-12-15 05:22:242529def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022530 """Make sure that we don't use deprecated JS in Chrome code."""
2531 results = []
2532 file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html?
2533 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2534 input_api.DEFAULT_BLACK_LIST)
2535 file_filter = lambda f: input_api.FilterSourceFile(
2536 f, white_list=file_inclusion_pattern, black_list=black_list)
2537 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2538 for lnum, line in fpath.ChangedContents():
2539 for (deprecated, replacement) in _DEPRECATED_JS:
2540 if deprecated in line:
2541 results.append(output_api.PresubmitError(
2542 "%s:%d: Use of deprecated JS %s, use %s instead" %
2543 (fpath.LocalPath(), lnum, deprecated, replacement)))
2544 return results
2545
dpapadd651231d82017-07-21 02:44:472546def _CheckForRiskyJsArrowFunction(line_number, line):
2547 if ' => ' in line:
2548 return "line %d, is using an => (arrow) function\n %s\n" % (
2549 line_number, line)
2550 return ''
2551
2552def _CheckForRiskyJsConstLet(input_api, line_number, line):
2553 if input_api.re.match('^\s*(const|let)\s', line):
2554 return "line %d, is using const/let keyword\n %s\n" % (
2555 line_number, line)
2556 return ''
dbeam070cfe62014-10-22 06:44:022557
dbeam1ec68ac2016-12-15 05:22:242558def _CheckForRiskyJsFeatures(input_api, output_api):
2559 maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", )
Steven Bennetts90545f3cb2017-08-14 18:11:002560 # 'ui/webui/resources/cr_components are not allowed on ios'
2561 not_ios_filter = (r".*ui\/webui\/resources\/cr_components.*", )
Steven Bennetts9c7e3c22017-08-02 19:10:572562 file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js,
Steven Bennetts90545f3cb2017-08-14 18:11:002563 black_list=not_ios_filter)
dpapadd651231d82017-07-21 02:44:472564 results = []
dbeam1ec68ac2016-12-15 05:22:242565 for f in input_api.AffectedFiles(file_filter=file_filter):
dpapadd651231d82017-07-21 02:44:472566 arrow_error_lines = []
2567 const_let_error_lines = []
dbeam1ec68ac2016-12-15 05:22:242568 for lnum, line in f.ChangedContents():
dpapadd651231d82017-07-21 02:44:472569 arrow_error_lines += filter(None, [
2570 _CheckForRiskyJsArrowFunction(lnum, line),
2571 ])
dbeam1ec68ac2016-12-15 05:22:242572
dpapadd651231d82017-07-21 02:44:472573 const_let_error_lines += filter(None, [
2574 _CheckForRiskyJsConstLet(input_api, lnum, line),
2575 ])
dbeam1ec68ac2016-12-15 05:22:242576
dpapadd651231d82017-07-21 02:44:472577 if arrow_error_lines:
2578 arrow_error_lines = map(
2579 lambda e: "%s:%s" % (f.LocalPath(), e), arrow_error_lines)
2580 results.append(
2581 output_api.PresubmitPromptWarning('\n'.join(arrow_error_lines + [
2582"""
2583Use of => (arrow) operator detected in:
dbeam1ec68ac2016-12-15 05:22:242584%s
2585Please ensure your code does not run on iOS9 (=> (arrow) does not work there).
2586https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions
dpapadd651231d82017-07-21 02:44:472587""" % f.LocalPath()
2588 ])))
dbeam1ec68ac2016-12-15 05:22:242589
dpapadd651231d82017-07-21 02:44:472590 if const_let_error_lines:
2591 const_let_error_lines = map(
2592 lambda e: "%s:%s" % (f.LocalPath(), e), const_let_error_lines)
2593 results.append(
2594 output_api.PresubmitPromptWarning('\n'.join(const_let_error_lines + [
2595"""
2596Use of const/let keywords detected in:
2597%s
2598Please ensure your code does not run on iOS9 because const/let is not fully
2599supported.
2600https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#let-Block_Scoped-Variables
2601https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#const-Block_Scoped-Constants
2602""" % f.LocalPath()
2603 ])))
2604
2605 return results
dbeam1ec68ac2016-12-15 05:22:242606
rlanday6802cf632017-05-30 17:48:362607def _CheckForRelativeIncludes(input_api, output_api):
2608 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2609 import sys
2610 original_sys_path = sys.path
2611 try:
2612 sys.path = sys.path + [input_api.os_path.join(
2613 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2614 from cpp_checker import CppChecker
2615 finally:
2616 # Restore sys.path to what it was before.
2617 sys.path = original_sys_path
2618
2619 bad_files = {}
2620 for f in input_api.AffectedFiles(include_deletes=False):
2621 if (f.LocalPath().startswith('third_party') and
2622 not f.LocalPath().startswith('third_party/WebKit') and
2623 not f.LocalPath().startswith('third_party\\WebKit')):
2624 continue
2625
2626 if not CppChecker.IsCppFile(f.LocalPath()):
2627 continue
2628
Vaclav Brozekd5de76a2018-03-17 07:57:502629 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362630 if "#include" in line and "../" in line]
2631 if not relative_includes:
2632 continue
2633 bad_files[f.LocalPath()] = relative_includes
2634
2635 if not bad_files:
2636 return []
2637
2638 error_descriptions = []
2639 for file_path, bad_lines in bad_files.iteritems():
2640 error_description = file_path
2641 for line in bad_lines:
2642 error_description += '\n ' + line
2643 error_descriptions.append(error_description)
2644
2645 results = []
2646 results.append(output_api.PresubmitError(
2647 'You added one or more relative #include paths (including "../").\n'
2648 'These shouldn\'t be used because they can be used to include headers\n'
2649 'from code that\'s not correctly specified as a dependency in the\n'
2650 'relevant BUILD.gn file(s).',
2651 error_descriptions))
2652
2653 return results
2654
Takeshi Yoshinoe387aa32017-08-02 13:16:132655
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202656def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2657 if not isinstance(key, ast.Str):
2658 return 'Key at line %d must be a string literal' % key.lineno
2659 if not isinstance(value, ast.Dict):
2660 return 'Value at line %d must be a dict' % value.lineno
2661 if len(value.keys) != 1:
2662 return 'Dict at line %d must have single entry' % value.lineno
2663 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2664 return (
2665 'Entry at line %d must have a string literal \'filepath\' as key' %
2666 value.lineno)
2667 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132668
Takeshi Yoshinoe387aa32017-08-02 13:16:132669
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202670def _CheckWatchlistsEntrySyntax(key, value, ast):
2671 if not isinstance(key, ast.Str):
2672 return 'Key at line %d must be a string literal' % key.lineno
2673 if not isinstance(value, ast.List):
2674 return 'Value at line %d must be a list' % value.lineno
2675 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132676
Takeshi Yoshinoe387aa32017-08-02 13:16:132677
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202678def _CheckWATCHLISTSEntries(wd_dict, w_dict, ast):
2679 mismatch_template = (
2680 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2681 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132682
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202683 i = 0
2684 last_key = ''
2685 while True:
2686 if i >= len(wd_dict.keys):
2687 if i >= len(w_dict.keys):
2688 return None
2689 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2690 elif i >= len(w_dict.keys):
2691 return (
2692 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132693
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202694 wd_key = wd_dict.keys[i]
2695 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132696
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202697 result = _CheckWatchlistDefinitionsEntrySyntax(
2698 wd_key, wd_dict.values[i], ast)
2699 if result is not None:
2700 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132701
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202702 result = _CheckWatchlistsEntrySyntax(w_key, w_dict.values[i], ast)
2703 if result is not None:
2704 return 'Bad entry in WATCHLISTS dict: %s' % result
2705
2706 if wd_key.s != w_key.s:
2707 return mismatch_template % (
2708 '%s at line %d' % (wd_key.s, wd_key.lineno),
2709 '%s at line %d' % (w_key.s, w_key.lineno))
2710
2711 if wd_key.s < last_key:
2712 return (
2713 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
2714 (wd_key.lineno, w_key.lineno))
2715 last_key = wd_key.s
2716
2717 i = i + 1
2718
2719
2720def _CheckWATCHLISTSSyntax(expression, ast):
2721 if not isinstance(expression, ast.Expression):
2722 return 'WATCHLISTS file must contain a valid expression'
2723 dictionary = expression.body
2724 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
2725 return 'WATCHLISTS file must have single dict with exactly two entries'
2726
2727 first_key = dictionary.keys[0]
2728 first_value = dictionary.values[0]
2729 second_key = dictionary.keys[1]
2730 second_value = dictionary.values[1]
2731
2732 if (not isinstance(first_key, ast.Str) or
2733 first_key.s != 'WATCHLIST_DEFINITIONS' or
2734 not isinstance(first_value, ast.Dict)):
2735 return (
2736 'The first entry of the dict in WATCHLISTS file must be '
2737 'WATCHLIST_DEFINITIONS dict')
2738
2739 if (not isinstance(second_key, ast.Str) or
2740 second_key.s != 'WATCHLISTS' or
2741 not isinstance(second_value, ast.Dict)):
2742 return (
2743 'The second entry of the dict in WATCHLISTS file must be '
2744 'WATCHLISTS dict')
2745
2746 return _CheckWATCHLISTSEntries(first_value, second_value, ast)
Takeshi Yoshinoe387aa32017-08-02 13:16:132747
2748
2749def _CheckWATCHLISTS(input_api, output_api):
2750 for f in input_api.AffectedFiles(include_deletes=False):
2751 if f.LocalPath() == 'WATCHLISTS':
2752 contents = input_api.ReadFile(f, 'r')
2753
2754 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202755 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:132756 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202757 # Get an AST tree for it and scan the tree for detailed style checking.
2758 expression = input_api.ast.parse(
2759 contents, filename='WATCHLISTS', mode='eval')
2760 except ValueError as e:
2761 return [output_api.PresubmitError(
2762 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2763 except SyntaxError as e:
2764 return [output_api.PresubmitError(
2765 'Cannot parse WATCHLISTS file', long_text=repr(e))]
2766 except TypeError as e:
2767 return [output_api.PresubmitError(
2768 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:132769
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202770 result = _CheckWATCHLISTSSyntax(expression, input_api.ast)
2771 if result is not None:
2772 return [output_api.PresubmitError(result)]
2773 break
Takeshi Yoshinoe387aa32017-08-02 13:16:132774
2775 return []
2776
2777
dgnaa68d5e2015-06-10 10:08:222778def _AndroidSpecificOnUploadChecks(input_api, output_api):
2779 """Groups checks that target android code."""
2780 results = []
dgnaa68d5e2015-06-10 10:08:222781 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:222782 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:292783 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:062784 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
2785 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:422786 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:182787 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:222788 return results
2789
2790
[email protected]22c9bd72011-03-27 16:47:392791def _CommonChecks(input_api, output_api):
2792 """Checks common to both upload and commit."""
2793 results = []
2794 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:382795 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:542796 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:082797
2798 author = input_api.change.author_email
2799 if author and author not in _KNOWN_ROBOTS:
2800 results.extend(
2801 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
2802
[email protected]55459852011-08-10 15:17:192803 results.extend(
[email protected]760deea2013-12-10 19:33:492804 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:232805 results.extend(
2806 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:542807 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:182808 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
danakj61c1aa22015-10-26 19:55:522809 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:222810 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:442811 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:592812 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:062813 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:122814 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:182815 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:222816 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:302817 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:492818 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:032819 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:492820 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:442821 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:272822 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:072823 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:542824 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:442825 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:392826 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:552827 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:042828 results.extend(
2829 input_api.canned_checks.CheckChangeHasNoTabs(
2830 input_api,
2831 output_api,
2832 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:402833 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:162834 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:082835 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242836 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
2837 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:472838 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:042839 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:052840 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:142841 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:232842 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:432843 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:402844 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:152845 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:172846 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:502847 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:242848 results.extend(_CheckForRiskyJsFeatures(input_api, output_api))
rlanday6802cf632017-05-30 17:48:362849 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:132850 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:432851 results.extend(input_api.RunTests(
2852 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:242853
Vaclav Brozekcdc7defb2018-03-20 09:54:352854 for f in input_api.AffectedFiles():
2855 path, name = input_api.os_path.split(f.LocalPath())
2856 if name == 'PRESUBMIT.py':
2857 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:002858 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
2859 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:072860 # The PRESUBMIT.py file (and the directory containing it) might
2861 # have been affected by being moved or removed, so only try to
2862 # run the tests if they still exist.
2863 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
2864 input_api, output_api, full_path,
2865 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:392866 return results
[email protected]1f7b4172010-01-28 01:17:342867
[email protected]b337cb5b2011-01-23 21:24:052868
[email protected]b8079ae4a2012-12-05 19:56:492869def _CheckPatchFiles(input_api, output_api):
2870 problems = [f.LocalPath() for f in input_api.AffectedFiles()
2871 if f.LocalPath().endswith(('.orig', '.rej'))]
2872 if problems:
2873 return [output_api.PresubmitError(
2874 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:032875 else:
2876 return []
[email protected]b8079ae4a2012-12-05 19:56:492877
2878
Kent Tamura5a8755d2017-06-29 23:37:072879def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:212880 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
2881 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
2882 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:072883 include_re = input_api.re.compile(
2884 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
2885 extension_re = input_api.re.compile(r'\.[a-z]+$')
2886 errors = []
2887 for f in input_api.AffectedFiles():
2888 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
2889 continue
2890 found_line_number = None
2891 found_macro = None
2892 for line_num, line in f.ChangedContents():
2893 match = macro_re.search(line)
2894 if match:
2895 found_line_number = line_num
2896 found_macro = match.group(2)
2897 break
2898 if not found_line_number:
2899 continue
2900
2901 found_include = False
2902 for line in f.NewContents():
2903 if include_re.search(line):
2904 found_include = True
2905 break
2906 if found_include:
2907 continue
2908
2909 if not f.LocalPath().endswith('.h'):
2910 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
2911 try:
2912 content = input_api.ReadFile(primary_header_path, 'r')
2913 if include_re.search(content):
2914 continue
2915 except IOError:
2916 pass
2917 errors.append('%s:%d %s macro is used without including build/'
2918 'build_config.h.'
2919 % (f.LocalPath(), found_line_number, found_macro))
2920 if errors:
2921 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
2922 return []
2923
2924
[email protected]b00342e7f2013-03-26 16:21:542925def _DidYouMeanOSMacro(bad_macro):
2926 try:
2927 return {'A': 'OS_ANDROID',
2928 'B': 'OS_BSD',
2929 'C': 'OS_CHROMEOS',
2930 'F': 'OS_FREEBSD',
2931 'L': 'OS_LINUX',
2932 'M': 'OS_MACOSX',
2933 'N': 'OS_NACL',
2934 'O': 'OS_OPENBSD',
2935 'P': 'OS_POSIX',
2936 'S': 'OS_SOLARIS',
2937 'W': 'OS_WIN'}[bad_macro[3].upper()]
2938 except KeyError:
2939 return ''
2940
2941
2942def _CheckForInvalidOSMacrosInFile(input_api, f):
2943 """Check for sensible looking, totally invalid OS macros."""
2944 preprocessor_statement = input_api.re.compile(r'^\s*#')
2945 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
2946 results = []
2947 for lnum, line in f.ChangedContents():
2948 if preprocessor_statement.search(line):
2949 for match in os_macro.finditer(line):
2950 if not match.group(1) in _VALID_OS_MACROS:
2951 good = _DidYouMeanOSMacro(match.group(1))
2952 did_you_mean = ' (did you mean %s?)' % good if good else ''
2953 results.append(' %s:%d %s%s' % (f.LocalPath(),
2954 lnum,
2955 match.group(1),
2956 did_you_mean))
2957 return results
2958
2959
2960def _CheckForInvalidOSMacros(input_api, output_api):
2961 """Check all affected files for invalid OS macros."""
2962 bad_macros = []
2963 for f in input_api.AffectedFiles():
ellyjones47654342016-05-06 15:50:472964 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:542965 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
2966
2967 if not bad_macros:
2968 return []
2969
2970 return [output_api.PresubmitError(
2971 'Possibly invalid OS macro[s] found. Please fix your code\n'
2972 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
2973
lliabraa35bab3932014-10-01 12:16:442974
2975def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
2976 """Check all affected files for invalid "if defined" macros."""
2977 ALWAYS_DEFINED_MACROS = (
2978 "TARGET_CPU_PPC",
2979 "TARGET_CPU_PPC64",
2980 "TARGET_CPU_68K",
2981 "TARGET_CPU_X86",
2982 "TARGET_CPU_ARM",
2983 "TARGET_CPU_MIPS",
2984 "TARGET_CPU_SPARC",
2985 "TARGET_CPU_ALPHA",
2986 "TARGET_IPHONE_SIMULATOR",
2987 "TARGET_OS_EMBEDDED",
2988 "TARGET_OS_IPHONE",
2989 "TARGET_OS_MAC",
2990 "TARGET_OS_UNIX",
2991 "TARGET_OS_WIN32",
2992 )
2993 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
2994 results = []
2995 for lnum, line in f.ChangedContents():
2996 for match in ifdef_macro.finditer(line):
2997 if match.group(1) in ALWAYS_DEFINED_MACROS:
2998 always_defined = ' %s is always defined. ' % match.group(1)
2999 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
3000 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
3001 lnum,
3002 always_defined,
3003 did_you_mean))
3004 return results
3005
3006
3007def _CheckForInvalidIfDefinedMacros(input_api, output_api):
3008 """Check all affected files for invalid "if defined" macros."""
3009 bad_macros = []
3010 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:213011 if f.LocalPath().startswith('third_party/sqlite/'):
3012 continue
lliabraa35bab3932014-10-01 12:16:443013 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3014 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3015
3016 if not bad_macros:
3017 return []
3018
3019 return [output_api.PresubmitError(
3020 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3021 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3022 bad_macros)]
3023
3024
mlamouria82272622014-09-16 18:45:043025def _CheckForIPCRules(input_api, output_api):
3026 """Check for same IPC rules described in
3027 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3028 """
3029 base_pattern = r'IPC_ENUM_TRAITS\('
3030 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3031 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3032
3033 problems = []
3034 for f in input_api.AffectedSourceFiles(None):
3035 local_path = f.LocalPath()
3036 if not local_path.endswith('.h'):
3037 continue
3038 for line_number, line in f.ChangedContents():
3039 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3040 problems.append(
3041 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3042
3043 if problems:
3044 return [output_api.PresubmitPromptWarning(
3045 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
3046 else:
3047 return []
3048
[email protected]b00342e7f2013-03-26 16:21:543049
Stephen Martinis97a394142018-06-07 23:06:053050def _CheckForLongPathnames(input_api, output_api):
3051 """Check to make sure no files being submitted have long paths.
3052 This causes issues on Windows.
3053 """
3054 problems = []
3055 for f in input_api.AffectedSourceFiles(None):
3056 local_path = f.LocalPath()
3057 # Windows has a path limit of 260 characters. Limit path length to 200 so
3058 # that we have some extra for the prefix on dev machines and the bots.
3059 if len(local_path) > 200:
3060 problems.append(local_path)
3061
3062 if problems:
3063 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
3064 else:
3065 return []
3066
3067
Daniel Bratell8ba52722018-03-02 16:06:143068def _CheckForIncludeGuards(input_api, output_api):
3069 """Check that header files have proper guards against multiple inclusion.
3070 If a file should not have such guards (and it probably should) then it
3071 should include the string "no-include-guard-because-multiply-included".
3072 """
Daniel Bratell6a75baef62018-06-04 10:04:453073 def is_chromium_header_file(f):
3074 # We only check header files under the control of the Chromium
3075 # project. That is, those outside third_party apart from
3076 # third_party/blink.
3077 file_with_path = input_api.os_path.normpath(f.LocalPath())
3078 return (file_with_path.endswith('.h') and
3079 (not file_with_path.startswith('third_party') or
3080 file_with_path.startswith(
3081 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:143082
3083 def replace_special_with_underscore(string):
3084 return input_api.re.sub(r'[\\/.-]', '_', string)
3085
3086 errors = []
3087
Daniel Bratell6a75baef62018-06-04 10:04:453088 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:143089 guard_name = None
3090 guard_line_number = None
3091 seen_guard_end = False
3092
3093 file_with_path = input_api.os_path.normpath(f.LocalPath())
3094 base_file_name = input_api.os_path.splitext(
3095 input_api.os_path.basename(file_with_path))[0]
3096 upper_base_file_name = base_file_name.upper()
3097
3098 expected_guard = replace_special_with_underscore(
3099 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:143100
3101 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:573102 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
3103 # are too many (1000+) files with slight deviations from the
3104 # coding style. The most important part is that the include guard
3105 # is there, and that it's unique, not the name so this check is
3106 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:143107 #
3108 # As code becomes more uniform, this could be made stricter.
3109
3110 guard_name_pattern_list = [
3111 # Anything with the right suffix (maybe with an extra _).
3112 r'\w+_H__?',
3113
Daniel Bratell39b5b062018-05-16 18:09:573114 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:143115 r'\w+_h',
3116
3117 # Anything including the uppercase name of the file.
3118 r'\w*' + input_api.re.escape(replace_special_with_underscore(
3119 upper_base_file_name)) + r'\w*',
3120 ]
3121 guard_name_pattern = '|'.join(guard_name_pattern_list)
3122 guard_pattern = input_api.re.compile(
3123 r'#ifndef\s+(' + guard_name_pattern + ')')
3124
3125 for line_number, line in enumerate(f.NewContents()):
3126 if 'no-include-guard-because-multiply-included' in line:
3127 guard_name = 'DUMMY' # To not trigger check outside the loop.
3128 break
3129
3130 if guard_name is None:
3131 match = guard_pattern.match(line)
3132 if match:
3133 guard_name = match.group(1)
3134 guard_line_number = line_number
3135
Daniel Bratell39b5b062018-05-16 18:09:573136 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:453137 # don't match the chromium style guide, but new files should
3138 # get it right.
3139 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:573140 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:143141 errors.append(output_api.PresubmitPromptWarning(
3142 'Header using the wrong include guard name %s' % guard_name,
3143 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:573144 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:143145 else:
3146 # The line after #ifndef should have a #define of the same name.
3147 if line_number == guard_line_number + 1:
3148 expected_line = '#define %s' % guard_name
3149 if line != expected_line:
3150 errors.append(output_api.PresubmitPromptWarning(
3151 'Missing "%s" for include guard' % expected_line,
3152 ['%s:%d' % (f.LocalPath(), line_number + 1)],
3153 'Expected: %r\nGot: %r' % (expected_line, line)))
3154
3155 if not seen_guard_end and line == '#endif // %s' % guard_name:
3156 seen_guard_end = True
3157 elif seen_guard_end:
3158 if line.strip() != '':
3159 errors.append(output_api.PresubmitPromptWarning(
3160 'Include guard %s not covering the whole file' % (
3161 guard_name), [f.LocalPath()]))
3162 break # Nothing else to check and enough to warn once.
3163
3164 if guard_name is None:
3165 errors.append(output_api.PresubmitPromptWarning(
3166 'Missing include guard %s' % expected_guard,
3167 [f.LocalPath()],
3168 'Missing include guard in %s\n'
3169 'Recommended name: %s\n'
3170 'This check can be disabled by having the string\n'
3171 'no-include-guard-because-multiply-included in the header.' %
3172 (f.LocalPath(), expected_guard)))
3173
3174 return errors
3175
3176
mostynbb639aca52015-01-07 20:31:233177def _CheckForWindowsLineEndings(input_api, output_api):
3178 """Check source code and known ascii text files for Windows style line
3179 endings.
3180 """
earthdok1b5e0ee2015-03-10 15:19:103181 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233182
3183 file_inclusion_pattern = (
3184 known_text_files,
3185 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3186 )
3187
mostynbb639aca52015-01-07 20:31:233188 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533189 source_file_filter = lambda f: input_api.FilterSourceFile(
3190 f, white_list=file_inclusion_pattern, black_list=None)
3191 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503192 include_file = False
3193 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233194 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503195 include_file = True
3196 if include_file:
3197 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233198
3199 if problems:
3200 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3201 'these files to contain Windows style line endings?\n' +
3202 '\n'.join(problems))]
3203
3204 return []
3205
3206
Vaclav Brozekd5de76a2018-03-17 07:57:503207def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133208 """Checks that all source files use SYSLOG properly."""
3209 syslog_files = []
3210 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563211 for line_number, line in f.ChangedContents():
3212 if 'SYSLOG' in line:
3213 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3214
pastarmovj89f7ee12016-09-20 14:58:133215 if syslog_files:
3216 return [output_api.PresubmitPromptWarning(
3217 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3218 ' calls.\nFiles to check:\n', items=syslog_files)]
3219 return []
3220
3221
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193222def _CheckCrbugLinksHaveHttps(input_api, output_api):
Miguel Casas68bdb652017-12-19 16:29:093223 """Checks that crbug(.com) links are correctly prefixed by https://,
3224 unless they come in the accepted form TODO(crbug.com/...)
3225 """
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193226 white_list = r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3227 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS)
3228 sources = lambda f: input_api.FilterSourceFile(
3229 f, white_list=white_list, black_list=black_list)
3230
3231 pattern = input_api.re.compile(r'//.*(?<!:\/\/)crbug[.com]*')
Miguel Casas68bdb652017-12-19 16:29:093232 accepted_pattern = input_api.re.compile(r'//.*TODO\(crbug[.com]*');
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193233 problems = []
3234 for f in input_api.AffectedSourceFiles(sources):
3235 for line_num, line in f.ChangedContents():
Miguel Casas68bdb652017-12-19 16:29:093236 if pattern.search(line) and not accepted_pattern.search(line):
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193237 problems.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
3238
3239 if problems:
3240 return [output_api.PresubmitPromptWarning(
3241 'Found unprefixed crbug.com URL(s), consider prepending https://\n'+
3242 '\n'.join(problems))]
3243 return []
3244
3245
[email protected]1f7b4172010-01-28 01:17:343246def CheckChangeOnUpload(input_api, output_api):
3247 results = []
3248 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473249 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283250 results.extend(
jam93a6ee792017-02-08 23:59:223251 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193252 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223253 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133254 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163255 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Miguel Casas-Sancheze0d46d42017-12-14 15:52:193256 results.extend(_CheckCrbugLinksHaveHttps(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:533257 results.extend(_CheckUniquePtr(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543258 return results
[email protected]ca8d1982009-02-19 16:33:123259
3260
[email protected]1bfb8322014-04-23 01:02:413261def GetTryServerMasterForBot(bot):
3262 """Returns the Try Server master for the given bot.
3263
[email protected]0bb112362014-07-26 04:38:323264 It tries to guess the master from the bot name, but may still fail
3265 and return None. There is no longer a default master.
3266 """
3267 # Potentially ambiguous bot names are listed explicitly.
3268 master_map = {
tandriie5587792016-07-14 00:34:503269 'chromium_presubmit': 'master.tryserver.chromium.linux',
3270 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413271 }
[email protected]0bb112362014-07-26 04:38:323272 master = master_map.get(bot)
3273 if not master:
wnwen4fbaab82016-05-25 12:54:363274 if 'android' in bot:
tandriie5587792016-07-14 00:34:503275 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363276 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503277 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323278 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503279 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323280 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503281 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323282 return master
[email protected]1bfb8322014-04-23 01:02:413283
3284
[email protected]ca8d1982009-02-19 16:33:123285def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543286 results = []
[email protected]1f7b4172010-01-28 01:17:343287 results.extend(_CommonChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543288 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273289 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343290 input_api,
3291 output_api,
[email protected]2fdd1f362013-01-16 03:56:033292 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273293
jam93a6ee792017-02-08 23:59:223294 results.extend(
3295 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543296 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3297 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413298 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3299 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543300 return results