blob: 9481e9a8387b58a2f17acc3b5d5fc2cc7a0c71a5 [file] [log] [blame]
[email protected]a18130a2012-01-03 17:52:081# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ca8d1982009-02-19 16:33:122# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Top-level presubmit script for Chromium.
6
[email protected]f1293792009-07-31 18:09:567See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
tfarina78bb92f42015-01-31 00:20:488for more details about the presubmit API built into depot_tools.
[email protected]ca8d1982009-02-19 16:33:129"""
10
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0413 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
14 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
15 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
16 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
17 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4918 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0419 r"^third_party[\\/]breakpad[\\/].*",
20 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5421 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5322 r".+_autogen\.h$",
Egor Paskoce145c42018-09-28 19:31:0423 r".+[\\/]pnacl_shim\.c$",
24 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
25 r"^chrome[\\/]browser[\\/]resources[\\/]pdf[\\/]index.js",
26 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1427 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0428 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5429 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0430 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4031)
[email protected]ca8d1982009-02-19 16:33:1232
wnwenbdc444e2016-05-25 13:44:1533
[email protected]06e6d0ff2012-12-11 01:36:4434# Fragment of a regular expression that matches C++ and Objective-C++
35# implementation files.
36_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
37
wnwenbdc444e2016-05-25 13:44:1538
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1939# Fragment of a regular expression that matches C++ and Objective-C++
40# header files.
41_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
42
43
[email protected]06e6d0ff2012-12-11 01:36:4444# Regular expression that matches code only used for test binaries
45# (best effort).
46_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0447 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4448 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4449 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1250 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1851 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4452 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0453 r'.*[\\/](test|tool(s)?)[\\/].*',
[email protected]ef070cc2013-05-03 11:53:0554 # content_shell is used for running layout tests.
Egor Paskoce145c42018-09-28 19:31:0455 r'content[\\/]shell[\\/].*',
[email protected]7b054982013-11-27 00:44:4756 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0457 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0858 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0459 r'testing[\\/]iossim[\\/]iossim\.mm$',
[email protected]06e6d0ff2012-12-11 01:36:4460)
[email protected]ca8d1982009-02-19 16:33:1261
Daniel Bratell609102be2019-03-27 20:53:2162_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1563
[email protected]eea609a2011-11-18 13:10:1264_TEST_ONLY_WARNING = (
65 'You might be calling functions intended only for testing from\n'
66 'production code. It is OK to ignore this warning if you know what\n'
67 'you are doing, as the heuristics used to detect the situation are\n'
[email protected]b0149772014-03-27 16:47:5868 'not perfect. The commit queue will not block on this warning.')
[email protected]eea609a2011-11-18 13:10:1269
70
[email protected]cf9b78f2012-11-14 11:40:2871_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4072 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2173 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
74 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2875
wnwenbdc444e2016-05-25 13:44:1576
Daniel Bratell609102be2019-03-27 20:53:2177# Format: Sequence of tuples containing:
78# * String pattern or, if starting with a slash, a regular expression.
79# * Sequence of strings to show when the pattern matches.
80# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:4181_BANNED_JAVA_FUNCTIONS = (
82 (
83 'StrictMode.allowThreadDiskReads()',
84 (
85 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
86 'directly.',
87 ),
88 False,
89 ),
90 (
91 'StrictMode.allowThreadDiskWrites()',
92 (
93 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
94 'directly.',
95 ),
96 False,
97 ),
98)
99
Daniel Bratell609102be2019-03-27 20:53:21100# Format: Sequence of tuples containing:
101# * String pattern or, if starting with a slash, a regular expression.
102# * Sequence of strings to show when the pattern matches.
103# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59104_BANNED_OBJC_FUNCTIONS = (
105 (
106 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20107 (
108 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59109 'prohibited. Please use CrTrackingArea instead.',
110 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
111 ),
112 False,
113 ),
114 (
[email protected]eaae1972014-04-16 04:17:26115 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20116 (
117 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59118 'instead.',
119 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
120 ),
121 False,
122 ),
123 (
124 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20125 (
126 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59127 'Please use |convertPoint:(point) fromView:nil| instead.',
128 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
129 ),
130 True,
131 ),
132 (
133 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20134 (
135 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59136 'Please use |convertPoint:(point) toView:nil| instead.',
137 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
138 ),
139 True,
140 ),
141 (
142 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20143 (
144 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59145 'Please use |convertRect:(point) fromView:nil| instead.',
146 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
147 ),
148 True,
149 ),
150 (
151 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20152 (
153 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59154 'Please use |convertRect:(point) toView:nil| instead.',
155 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
156 ),
157 True,
158 ),
159 (
160 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20161 (
162 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59163 'Please use |convertSize:(point) fromView:nil| instead.',
164 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
165 ),
166 True,
167 ),
168 (
169 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20170 (
171 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59172 'Please use |convertSize:(point) toView:nil| instead.',
173 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
174 ),
175 True,
176 ),
jif65398702016-10-27 10:19:48177 (
178 r"/\s+UTF8String\s*]",
179 (
180 'The use of -[NSString UTF8String] is dangerous as it can return null',
181 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
182 'Please use |SysNSStringToUTF8| instead.',
183 ),
184 True,
185 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34186 (
187 r'__unsafe_unretained',
188 (
189 'The use of __unsafe_unretained is almost certainly wrong, unless',
190 'when interacting with NSFastEnumeration or NSInvocation.',
191 'Please use __weak in files build with ARC, nothing otherwise.',
192 ),
193 False,
194 ),
[email protected]127f18ec2012-06-16 05:05:59195)
196
Daniel Bratell609102be2019-03-27 20:53:21197# Format: Sequence of tuples containing:
198# * String pattern or, if starting with a slash, a regular expression.
199# * Sequence of strings to show when the pattern matches.
200# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54201_BANNED_IOS_OBJC_FUNCTIONS = (
202 (
203 r'/\bTEST[(]',
204 (
205 'TEST() macro should not be used in Objective-C++ code as it does not ',
206 'drain the autorelease pool at the end of the test. Use TEST_F() ',
207 'macro instead with a fixture inheriting from PlatformTest (or a ',
208 'typedef).'
209 ),
210 True,
211 ),
212 (
213 r'/\btesting::Test\b',
214 (
215 'testing::Test should not be used in Objective-C++ code as it does ',
216 'not drain the autorelease pool at the end of the test. Use ',
217 'PlatformTest instead.'
218 ),
219 True,
220 ),
221)
222
[email protected]127f18ec2012-06-16 05:05:59223
Daniel Bratell609102be2019-03-27 20:53:21224# Format: Sequence of tuples containing:
225# * String pattern or, if starting with a slash, a regular expression.
226# * Sequence of strings to show when the pattern matches.
227# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
228# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59229_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20230 (
thomasandersone7caaa9b2017-03-29 19:22:53231 r'\bNULL\b',
232 (
233 'New code should not use NULL. Use nullptr instead.',
234 ),
235 True,
236 (),
237 ),
Antonio Gomes07300d02019-03-13 20:59:57238 # Make sure that gtest's FRIEND_TEST() macro is not used; the
239 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
240 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53241 (
[email protected]23e6cbc2012-06-16 18:51:20242 'FRIEND_TEST(',
243 (
[email protected]e3c945502012-06-26 20:01:49244 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20245 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
246 ),
247 False,
[email protected]7345da02012-11-27 14:31:49248 (),
[email protected]23e6cbc2012-06-16 18:51:20249 ),
250 (
thomasanderson4b569052016-09-14 20:15:53251 r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK',
252 (
253 'Chrome clients wishing to select events on X windows should use',
254 'ui::XScopedEventSelector. It is safe to ignore this warning only if',
255 'you are selecting events from the GPU process, or if you are using',
256 'an XDisplay other than gfx::GetXDisplay().',
257 ),
258 True,
259 (
Egor Paskoce145c42018-09-28 19:31:04260 r"^ui[\\/]gl[\\/].*\.cc$",
261 r"^media[\\/]gpu[\\/].*\.cc$",
262 r"^gpu[\\/].*\.cc$",
thomasanderson4b569052016-09-14 20:15:53263 ),
264 ),
265 (
thomasandersone043e3ce2017-06-08 00:43:20266 r'XInternAtom|xcb_intern_atom',
267 (
thomasanderson11aa41d2017-06-08 22:22:38268 'Use gfx::GetAtom() instead of interning atoms directly.',
thomasandersone043e3ce2017-06-08 00:43:20269 ),
270 True,
271 (
Egor Paskoce145c42018-09-28 19:31:04272 r"^gpu[\\/]ipc[\\/]service[\\/]gpu_watchdog_thread\.cc$",
273 r"^remoting[\\/]host[\\/]linux[\\/]x_server_clipboard\.cc$",
274 r"^ui[\\/]gfx[\\/]x[\\/]x11_atom_cache\.cc$",
thomasandersone043e3ce2017-06-08 00:43:20275 ),
276 ),
277 (
tomhudsone2c14d552016-05-26 17:07:46278 'setMatrixClip',
279 (
280 'Overriding setMatrixClip() is prohibited; ',
281 'the base function is deprecated. ',
282 ),
283 True,
284 (),
285 ),
286 (
[email protected]52657f62013-05-20 05:30:31287 'SkRefPtr',
288 (
289 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22290 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31291 ),
292 True,
293 (),
294 ),
295 (
296 'SkAutoRef',
297 (
298 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22299 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31300 ),
301 True,
302 (),
303 ),
304 (
305 'SkAutoTUnref',
306 (
307 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22308 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31309 ),
310 True,
311 (),
312 ),
313 (
314 'SkAutoUnref',
315 (
316 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
317 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22318 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31319 ),
320 True,
321 (),
322 ),
[email protected]d89eec82013-12-03 14:10:59323 (
324 r'/HANDLE_EINTR\(.*close',
325 (
326 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
327 'descriptor will be closed, and it is incorrect to retry the close.',
328 'Either call close directly and ignore its return value, or wrap close',
329 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
330 ),
331 True,
332 (),
333 ),
334 (
335 r'/IGNORE_EINTR\((?!.*close)',
336 (
337 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
338 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
339 ),
340 True,
341 (
342 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04343 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
344 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59345 ),
346 ),
[email protected]ec5b3f02014-04-04 18:43:43347 (
348 r'/v8::Extension\(',
349 (
350 'Do not introduce new v8::Extensions into the code base, use',
351 'gin::Wrappable instead. See http://crbug.com/334679',
352 ),
353 True,
[email protected]f55c90ee62014-04-12 00:50:03354 (
Egor Paskoce145c42018-09-28 19:31:04355 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03356 ),
[email protected]ec5b3f02014-04-04 18:43:43357 ),
skyostilf9469f72015-04-20 10:38:52358 (
jame2d1a952016-04-02 00:27:10359 '#pragma comment(lib,',
360 (
361 'Specify libraries to link with in build files and not in the source.',
362 ),
363 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41364 (
tzik3f295992018-12-04 20:32:23365 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04366 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41367 ),
jame2d1a952016-04-02 00:27:10368 ),
fdorayc4ac18d2017-05-01 21:39:59369 (
Gabriel Charette7cc6c432018-04-25 20:52:02370 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59371 (
372 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
373 ),
374 False,
375 (),
376 ),
377 (
Gabriel Charette7cc6c432018-04-25 20:52:02378 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59379 (
380 'Consider using THREAD_CHECKER macros instead of the class directly.',
381 ),
382 False,
383 (),
384 ),
dbeamb6f4fde2017-06-15 04:03:06385 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06386 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
387 (
388 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
389 'deprecated (http://crbug.com/634507). Please avoid converting away',
390 'from the Time types in Chromium code, especially if any math is',
391 'being done on time values. For interfacing with platform/library',
392 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
393 'type converter methods instead. For faking TimeXXX values (for unit',
394 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
395 'other use cases, please contact base/time/OWNERS.',
396 ),
397 False,
398 (),
399 ),
400 (
dbeamb6f4fde2017-06-15 04:03:06401 'CallJavascriptFunctionUnsafe',
402 (
403 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
404 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
405 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
406 ),
407 False,
408 (
Egor Paskoce145c42018-09-28 19:31:04409 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
410 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
411 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06412 ),
413 ),
dskiba1474c2bfd62017-07-20 02:19:24414 (
415 'leveldb::DB::Open',
416 (
417 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
418 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
419 "Chrome's tracing, making their memory usage visible.",
420 ),
421 True,
422 (
423 r'^third_party/leveldatabase/.*\.(cc|h)$',
424 ),
Gabriel Charette0592c3a2017-07-26 12:02:04425 ),
426 (
Chris Mumfordc38afb62017-10-09 17:55:08427 'leveldb::NewMemEnv',
428 (
429 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58430 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
431 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08432 ),
433 True,
434 (
435 r'^third_party/leveldatabase/.*\.(cc|h)$',
436 ),
437 ),
438 (
Gabriel Charetted9839bc2017-07-29 14:17:47439 'RunLoop::QuitCurrent',
440 (
Robert Liao64b7ab22017-08-04 23:03:43441 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
442 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47443 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41444 False,
Gabriel Charetted9839bc2017-07-29 14:17:47445 (),
Gabriel Charettea44975052017-08-21 23:14:04446 ),
447 (
448 'base::ScopedMockTimeMessageLoopTaskRunner',
449 (
Gabriel Charette87cc1af2018-04-25 20:52:51450 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
451 'ScopedTaskEnvironment::MainThreadType::MOCK_TIME. There are still a',
452 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
453 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
454 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04455 ),
Gabriel Charette87cc1af2018-04-25 20:52:51456 False,
Gabriel Charettea44975052017-08-21 23:14:04457 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57458 ),
459 (
460 r'std::regex',
461 (
462 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02463 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57464 ),
465 True,
466 (),
Francois Doray43670e32017-09-27 12:40:38467 ),
468 (
Daniel Bratell69334cc2019-03-26 11:07:45469 r'/\bstd::to_string\b',
470 (
471 'std::to_string is locale dependent and slower than alternatives.',
472 'For locale-independent strings, e.g. writing numbers to and from',
473 'disk profiles, use base::NumberToString().',
474 'For user-visible strings, use base::FormatNumber() and',
475 'the related functions in base/i18n/number_formatting.h.',
476 ),
477 False, # Only a warning for now since it is already used,
Daniel Bratell609102be2019-03-27 20:53:21478 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45479 ),
480 (
481 r'/\bstd::shared_ptr\b',
482 (
483 'std::shared_ptr should not be used. Use scoped_refptr instead.',
484 ),
485 True,
Daniel Bratell609102be2019-03-27 20:53:21486 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
487 ),
488 (
489 r'/\blong long\b',
490 (
491 'long long is banned. Use stdint.h if you need a 64 bit number.',
492 ),
493 False, # Only a warning since it is already used.
494 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
495 ),
496 (
497 r'/\bstd::bind\b',
498 (
499 'std::bind is banned because of lifetime risks.',
500 'Use base::BindOnce or base::BindRepeating instead.',
501 ),
502 True,
503 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
504 ),
505 (
506 r'/\b#include <chrono>\b',
507 (
508 '<chrono> overlaps with Time APIs in base. Keep using',
509 'base classes.',
510 ),
511 True,
512 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
513 ),
514 (
515 r'/\b#include <exception>\b',
516 (
517 'Exceptions are banned and disabled in Chromium.',
518 ),
519 True,
520 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
521 ),
522 (
523 r'/\bstd::function\b',
524 (
525 'std::function is banned. Instead use base::Callback which directly',
526 'supports Chromium\'s weak pointers, ref counting and more.',
527 ),
528 False, # Only a warning since there are dozens of uses already.
529 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
530 ),
531 (
532 r'/\b#include <random>\b',
533 (
534 'Do not use any random number engines from <random>. Instead',
535 'use base::RandomBitGenerator.',
536 ),
537 True,
538 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
539 ),
540 (
541 r'/\bstd::ratio\b',
542 (
543 'std::ratio is banned by the Google Style Guide.',
544 ),
545 True,
546 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45547 ),
548 (
Francois Doray43670e32017-09-27 12:40:38549 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
550 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
551 (
552 'Use the new API in base/threading/thread_restrictions.h.',
553 ),
Gabriel Charette04b138f2018-08-06 00:03:22554 False,
Francois Doray43670e32017-09-27 12:40:38555 (),
556 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38557 (
558 r'/\bbase::Bind\(',
559 (
Gabriel Charette147335ea2018-03-22 15:59:19560 'Please consider using base::Bind{Once,Repeating} instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02561 'of base::Bind. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38562 ),
563 False,
564 (),
565 ),
566 (
567 r'/\bbase::Callback<',
568 (
Gabriel Charette147335ea2018-03-22 15:59:19569 'Please consider using base::{Once,Repeating}Callback instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02570 'of base::Callback. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38571 ),
572 False,
573 (),
574 ),
575 (
576 r'/\bbase::Closure\b',
577 (
Gabriel Charette147335ea2018-03-22 15:59:19578 'Please consider using base::{Once,Repeating}Closure instead',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02579 'of base::Closure. (crbug.com/714018)',
Luis Hector Chavez9bbaed532017-11-30 18:25:38580 ),
581 False,
582 (),
583 ),
Victor Costan3653df62018-02-08 21:38:16584 (
Alex Ilin5929abe32019-04-03 17:09:34585 r'/base::SharedMemory(|Handle)',
Alex Ilin63058f62019-03-28 19:29:45586 (
587 'base::SharedMemory is deprecated. Please use',
588 '{Writable,ReadOnly}SharedMemoryRegion instead.',
589 ),
590 False,
591 (),
592 ),
593 (
Michael Giuffrida7f93d6922019-04-19 14:39:58594 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19595 (
596 'RunMessageLoop is deprecated, use RunLoop instead.',
597 ),
598 False,
599 (),
600 ),
601 (
602 r'RunThisRunLoop',
603 (
604 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
605 ),
606 False,
607 (),
608 ),
609 (
610 r'RunAllPendingInMessageLoop()',
611 (
612 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
613 "if you're convinced you need this.",
614 ),
615 False,
616 (),
617 ),
618 (
619 r'RunAllPendingInMessageLoop(BrowserThread',
620 (
621 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
622 'BrowserThread::UI, TestBrowserThreadBundle::RunIOThreadUntilIdle',
623 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
624 'async events instead of flushing threads.',
625 ),
626 False,
627 (),
628 ),
629 (
630 r'MessageLoopRunner',
631 (
632 'MessageLoopRunner is deprecated, use RunLoop instead.',
633 ),
634 False,
635 (),
636 ),
637 (
638 r'GetDeferredQuitTaskForRunLoop',
639 (
640 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
641 "gab@ if you found a use case where this is the only solution.",
642 ),
643 False,
644 (),
645 ),
646 (
Victor Costane48a2e82019-03-15 22:02:34647 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16648 (
Victor Costane48a2e82019-03-15 22:02:34649 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16650 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
651 ),
652 True,
653 (
654 r'^sql/initialization\.(cc|h)$',
655 r'^third_party/sqlite/.*\.(c|cc|h)$',
656 ),
657 ),
Matt Menke7f520a82018-03-28 21:38:37658 (
659 'net::URLFetcher',
660 (
661 'net::URLFetcher should no longer be used in content embedders. ',
662 'Instead, use network::SimpleURLLoader instead, which supports ',
663 'an out-of-process network stack. ',
664 'net::URLFetcher may still be used in binaries that do not embed',
665 'content.',
666 ),
Matt Menke59716d02018-04-05 12:45:53667 False,
Matt Menke7f520a82018-03-28 21:38:37668 (
Egor Paskoce145c42018-09-28 19:31:04669 r'^ios[\\/].*\.(cc|h)$',
670 r'.*[\\/]ios[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:37671 r'.*_ios\.(cc|h)$',
Egor Paskoce145c42018-09-28 19:31:04672 r'^net[\\/].*\.(cc|h)$',
673 r'.*[\\/]tools[\\/].*\.(cc|h)$',
Matt Menke7f520a82018-03-28 21:38:37674 ),
675 ),
jdoerried7d10ab2018-04-27 10:46:13676 (
tzik5de2157f2018-05-08 03:42:47677 r'std::random_shuffle',
678 (
679 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
680 'base::RandomShuffle instead.'
681 ),
682 True,
683 (),
684 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24685 (
686 'ios/web/public/test/http_server',
687 (
688 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
689 ),
690 False,
691 (),
692 ),
Robert Liao764c9492019-01-24 18:46:28693 (
694 'GetAddressOf',
695 (
696 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
697 'implicated in a few leaks. Use operator& instead.'
698 ),
699 True,
700 (),
701 ),
Antonio Gomes07300d02019-03-13 20:59:57702 (
703 'DEFINE_TYPE_CASTS',
704 (
705 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
706 '//third_party/blink/renderer/platform/casting.h.'
707 ),
708 True,
709 (
710 r'^third_party/blink/renderer/.*\.(cc|h)$',
711 ),
712 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38713 (
Kinuko Yasuda376c2ce12019-04-16 01:20:37714 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:38715 (
716 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
717 ),
718 True,
719 (),
720 ),
Ben Lewisa9514602019-04-29 17:53:05721 (
722 'SHFileOperation',
723 (
724 'SHFileOperation was deprecated in Windows Vista, and there are less ',
725 'complex functions to achieve the same goals. Use IFileOperation for ',
726 'any esoteric actions instead.'
727 ),
728 True,
729 (),
730 ),
[email protected]127f18ec2012-06-16 05:05:59731)
732
wnwenbdc444e2016-05-25 13:44:15733
mlamouria82272622014-09-16 18:45:04734_IPC_ENUM_TRAITS_DEPRECATED = (
735 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50736 'See http://www.chromium.org/Home/chromium-security/education/'
737 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:04738
Stephen Martinis97a394142018-06-07 23:06:05739_LONG_PATH_ERROR = (
740 'Some files included in this CL have file names that are too long (> 200'
741 ' characters). If committed, these files will cause issues on Windows. See'
742 ' https://crbug.com/612667 for more details.'
743)
744
Shenghua Zhangbfaa38b82017-11-16 21:58:02745_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:04746 r".*[\\/]BuildHooksAndroidImpl\.java",
747 r".*[\\/]LicenseContentProvider\.java",
748 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:28749 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:02750]
[email protected]127f18ec2012-06-16 05:05:59751
Sean Kau46e29bc2017-08-28 16:31:16752# These paths contain test data and other known invalid JSON files.
753_KNOWN_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:04754 r'test[\\/]data[\\/]',
755 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
756 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:04757 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:43758 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:16759]
760
761
[email protected]b00342e7f2013-03-26 16:21:54762_VALID_OS_MACROS = (
763 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08764 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54765 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:12766 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:54767 'OS_BSD',
768 'OS_CAT', # For testing.
769 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:04770 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:54771 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37772 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54773 'OS_IOS',
774 'OS_LINUX',
775 'OS_MACOSX',
776 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21777 'OS_NACL_NONSFI',
778 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12779 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54780 'OS_OPENBSD',
781 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37782 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54783 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54784 'OS_WIN',
785)
786
787
agrievef32bcc72016-04-04 14:57:40788_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:39789 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36790 'base/android/jni_generator/jni_generator.pydeps',
791 'base/android/jni_generator/jni_registration_generator.pydeps',
Egor Pasko56273b52019-03-14 14:45:22792 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36793 'build/android/gyp/aar.pydeps',
794 'build/android/gyp/aidl.pydeps',
795 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:38796 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36797 'build/android/gyp/bytecode_processor.pydeps',
798 'build/android/gyp/compile_resources.pydeps',
Andrew Grievef89e926c2019-02-07 18:36:57799 'build/android/gyp/create_app_bundle_minimal_apks.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36800 'build/android/gyp/create_bundle_wrapper_script.pydeps',
801 'build/android/gyp/copy_ex.pydeps',
802 'build/android/gyp/create_app_bundle.pydeps',
803 'build/android/gyp/create_apk_operations_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36804 'build/android/gyp/create_java_binary_script.pydeps',
Andrew Grieveb838d832019-02-11 16:55:22805 'build/android/gyp/create_size_info_files.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36806 'build/android/gyp/create_stack_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36807 'build/android/gyp/create_tool_wrapper.pydeps',
808 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:59809 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36810 'build/android/gyp/dex.pydeps',
811 'build/android/gyp/dist_aar.pydeps',
812 'build/android/gyp/emma_instr.pydeps',
813 'build/android/gyp/filter_zip.pydeps',
814 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:36815 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36816 'build/android/gyp/ijar.pydeps',
817 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:26818 'build/android/gyp/java_cpp_strings.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36819 'build/android/gyp/javac.pydeps',
820 'build/android/gyp/jinja_template.pydeps',
821 'build/android/gyp/lint.pydeps',
822 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36823 'build/android/gyp/merge_manifest.pydeps',
824 'build/android/gyp/prepare_resources.pydeps',
825 'build/android/gyp/proguard.pydeps',
826 'build/android/gyp/write_build_config.pydeps',
827 'build/android/gyp/write_ordered_libraries.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:56828 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36829 'build/android/incremental_install/generate_android_manifest.pydeps',
830 'build/android/incremental_install/write_installer_json.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22831 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:40832 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04833 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36834 'build/protoc_java.pydeps',
Peter Wene410bd792019-04-29 18:05:41835 'chrome/android/features/create_stripped_java_factory.pydeps',
agrieve732db3a2016-04-26 19:18:19836 'net/tools/testserver/testserver.pydeps',
Peter Wen22bc3ec2019-03-28 22:18:02837 'third_party/android_platform/development/scripts/stack.pydeps',
agrievef32bcc72016-04-04 14:57:40838]
839
wnwenbdc444e2016-05-25 13:44:15840
agrievef32bcc72016-04-04 14:57:40841_GENERIC_PYDEPS_FILES = [
John Chencde89192018-01-27 21:18:40842 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Cole Winstanley7045a1b2018-08-27 23:37:29843 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
John Budorickbc3571aa2019-04-25 02:20:06844 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22845 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:40846]
847
wnwenbdc444e2016-05-25 13:44:15848
agrievef32bcc72016-04-04 14:57:40849_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
850
851
Eric Boren6fd2b932018-01-25 15:05:08852# Bypass the AUTHORS check for these accounts.
853_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:29854 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
855 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:08856 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
Eric Boren57cc805b2018-08-20 17:28:32857 'spirv', 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:59858 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:45859 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:59860 ) | set('%[email protected]' % s
Robert Ma7f024172018-11-01 20:59:22861 for s in ('v8-ci-autoroll-builder', 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:04862 ) | set('%[email protected]' % s
863 for s in ('chromium-autoroll',)
864 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:30865 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:08866
867
Daniel Bratell65b033262019-04-23 08:17:06868def _IsCPlusPlusFile(input_api, file_path):
869 """Returns True if this file contains C++-like code (and not Python,
870 Go, Java, MarkDown, ...)"""
871
872 ext = input_api.os_path.splitext(file_path)[1]
873 # This list is compatible with CppChecker.IsCppFile but we should
874 # consider adding ".c" to it. If we do that we can use this function
875 # at more places in the code.
876 return ext in (
877 '.h',
878 '.cc',
879 '.cpp',
880 '.m',
881 '.mm',
882 )
883
884def _IsCPlusPlusHeaderFile(input_api, file_path):
885 return input_api.os_path.splitext(file_path)[1] == ".h"
886
887
888def _IsJavaFile(input_api, file_path):
889 return input_api.os_path.splitext(file_path)[1] == ".java"
890
891
892def _IsProtoFile(input_api, file_path):
893 return input_api.os_path.splitext(file_path)[1] == ".proto"
894
[email protected]55459852011-08-10 15:17:19895def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
896 """Attempts to prevent use of functions intended only for testing in
897 non-testing code. For now this is just a best-effort implementation
898 that ignores header files and may have some false positives. A
899 better implementation would probably need a proper C++ parser.
900 """
901 # We only scan .cc files and the like, as the declaration of
902 # for-testing functions in header files are hard to distinguish from
903 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49904 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:19905
jochenc0d4808c2015-07-27 09:25:42906 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19907 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09908 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19909 exclusion_pattern = input_api.re.compile(
910 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
911 base_function_pattern, base_function_pattern))
912
913 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44914 black_list = (_EXCLUDED_PATHS +
915 _TEST_CODE_EXCLUDED_PATHS +
916 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19917 return input_api.FilterSourceFile(
918 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49919 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:19920 black_list=black_list)
921
922 problems = []
923 for f in input_api.AffectedSourceFiles(FilterFile):
924 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24925 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03926 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46927 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03928 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19929 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03930 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19931
932 if problems:
[email protected]f7051d52013-04-02 18:31:42933 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03934 else:
935 return []
[email protected]55459852011-08-10 15:17:19936
937
Vaclav Brozek7dbc28c2018-03-27 08:35:23938def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
939 """This is a simplified version of
940 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
941 """
942 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
943 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
944 name_pattern = r'ForTest(s|ing)?'
945 # Describes an occurrence of "ForTest*" inside a // comment.
946 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
947 # Catch calls.
948 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
949 # Ignore definitions. (Comments are ignored separately.)
950 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
951
952 problems = []
953 sources = lambda x: input_api.FilterSourceFile(
954 x,
955 black_list=(('(?i).*test', r'.*\/junit\/')
956 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49957 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:23958 )
959 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
960 local_path = f.LocalPath()
961 is_inside_javadoc = False
962 for line_number, line in f.ChangedContents():
963 if is_inside_javadoc and javadoc_end_re.search(line):
964 is_inside_javadoc = False
965 if not is_inside_javadoc and javadoc_start_re.search(line):
966 is_inside_javadoc = True
967 if is_inside_javadoc:
968 continue
969 if (inclusion_re.search(line) and
970 not comment_re.search(line) and
971 not exclusion_re.search(line)):
972 problems.append(
973 '%s:%d\n %s' % (local_path, line_number, line.strip()))
974
975 if problems:
976 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
977 else:
978 return []
979
980
[email protected]10689ca2011-09-02 02:31:54981def _CheckNoIOStreamInHeaders(input_api, output_api):
982 """Checks to make sure no .h files include <iostream>."""
983 files = []
984 pattern = input_api.re.compile(r'^#include\s*<iostream>',
985 input_api.re.MULTILINE)
986 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
987 if not f.LocalPath().endswith('.h'):
988 continue
989 contents = input_api.ReadFile(f)
990 if pattern.search(contents):
991 files.append(f)
992
993 if len(files):
yolandyandaabc6d2016-04-18 18:29:39994 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06995 'Do not #include <iostream> in header files, since it inserts static '
996 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54997 '#include <ostream>. See http://crbug.com/94794',
998 files) ]
999 return []
1000
Danil Chapovalov3518f362018-08-11 16:13:431001def _CheckNoStrCatRedefines(input_api, output_api):
1002 """Checks no windows headers with StrCat redefined are included directly."""
1003 files = []
1004 pattern_deny = input_api.re.compile(
1005 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1006 input_api.re.MULTILINE)
1007 pattern_allow = input_api.re.compile(
1008 r'^#include\s"base/win/windows_defines.inc"',
1009 input_api.re.MULTILINE)
1010 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1011 contents = input_api.ReadFile(f)
1012 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1013 files.append(f.LocalPath())
1014
1015 if len(files):
1016 return [output_api.PresubmitError(
1017 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1018 'directly since they pollute code with StrCat macro. Instead, '
1019 'include matching header from base/win. See http://crbug.com/856536',
1020 files) ]
1021 return []
1022
[email protected]10689ca2011-09-02 02:31:541023
[email protected]72df4e782012-06-21 16:28:181024def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521025 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181026 problems = []
1027 for f in input_api.AffectedFiles():
1028 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1029 continue
1030
1031 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041032 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181033 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1034
1035 if not problems:
1036 return []
1037 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1038 '\n'.join(problems))]
1039
Dominic Battre033531052018-09-24 15:45:341040def _CheckNoDISABLETypoInTests(input_api, output_api):
1041 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1042
1043 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1044 instead of DISABLED_. To filter false positives, reports are only generated
1045 if a corresponding MAYBE_ line exists.
1046 """
1047 problems = []
1048
1049 # The following two patterns are looked for in tandem - is a test labeled
1050 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1051 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1052 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1053
1054 # This is for the case that a test is disabled on all platforms.
1055 full_disable_pattern = input_api.re.compile(
1056 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1057 input_api.re.MULTILINE)
1058
Katie Df13948e2018-09-25 07:33:441059 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341060 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1061 continue
1062
1063 # Search for MABYE_, DISABLE_ pairs.
1064 disable_lines = {} # Maps of test name to line number.
1065 maybe_lines = {}
1066 for line_num, line in f.ChangedContents():
1067 disable_match = disable_pattern.search(line)
1068 if disable_match:
1069 disable_lines[disable_match.group(1)] = line_num
1070 maybe_match = maybe_pattern.search(line)
1071 if maybe_match:
1072 maybe_lines[maybe_match.group(1)] = line_num
1073
1074 # Search for DISABLE_ occurrences within a TEST() macro.
1075 disable_tests = set(disable_lines.keys())
1076 maybe_tests = set(maybe_lines.keys())
1077 for test in disable_tests.intersection(maybe_tests):
1078 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1079
1080 contents = input_api.ReadFile(f)
1081 full_disable_match = full_disable_pattern.search(contents)
1082 if full_disable_match:
1083 problems.append(' %s' % f.LocalPath())
1084
1085 if not problems:
1086 return []
1087 return [
1088 output_api.PresubmitPromptWarning(
1089 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1090 '\n'.join(problems))
1091 ]
1092
[email protected]72df4e782012-06-21 16:28:181093
danakj61c1aa22015-10-26 19:55:521094def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571095 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521096 errors = []
1097 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
1098 input_api.re.MULTILINE)
1099 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1100 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1101 continue
1102 for lnum, line in f.ChangedContents():
1103 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171104 errors.append(output_api.PresubmitError(
1105 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571106 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171107 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521108 return errors
1109
1110
mcasasb7440c282015-02-04 14:52:191111def _FindHistogramNameInLine(histogram_name, line):
1112 """Tries to find a histogram name or prefix in a line."""
1113 if not "affected-histogram" in line:
1114 return histogram_name in line
1115 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1116 # the histogram_name.
1117 if not '"' in line:
1118 return False
1119 histogram_prefix = line.split('\"')[1]
1120 return histogram_prefix in histogram_name
1121
1122
1123def _CheckUmaHistogramChanges(input_api, output_api):
1124 """Check that UMA histogram names in touched lines can still be found in other
1125 lines of the patch or in histograms.xml. Note that this check would not catch
1126 the reverse: changes in histograms.xml not matched in the code itself."""
1127 touched_histograms = []
1128 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471129 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1130 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1131 name_pattern = r'"(.*?)"'
1132 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1133 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1134 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1135 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1136 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171137 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191138 for f in input_api.AffectedFiles():
1139 # If histograms.xml itself is modified, keep the modified lines for later.
1140 if f.LocalPath().endswith(('histograms.xml')):
1141 histograms_xml_modifications = f.ChangedContents()
1142 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471143 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1144 single_line_re = single_line_c_re
1145 split_line_prefix_re = split_line_c_prefix_re
1146 elif f.LocalPath().endswith(('java')):
1147 single_line_re = single_line_java_re
1148 split_line_prefix_re = split_line_java_prefix_re
1149 else:
mcasasb7440c282015-02-04 14:52:191150 continue
1151 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171152 if last_line_matched_prefix:
1153 suffix_found = split_line_suffix_re.search(line)
1154 if suffix_found :
1155 touched_histograms.append([suffix_found.group(1), f, line_num])
1156 last_line_matched_prefix = False
1157 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061158 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191159 if found:
1160 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171161 continue
1162 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191163
1164 # Search for the touched histogram names in the local modifications to
1165 # histograms.xml, and, if not found, on the base histograms.xml file.
1166 unmatched_histograms = []
1167 for histogram_info in touched_histograms:
1168 histogram_name_found = False
1169 for line_num, line in histograms_xml_modifications:
1170 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
1171 if histogram_name_found:
1172 break
1173 if not histogram_name_found:
1174 unmatched_histograms.append(histogram_info)
1175
eromanb90c82e7e32015-04-01 15:13:491176 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191177 problems = []
1178 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491179 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191180 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451181 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191182 histogram_name_found = False
1183 for line in histograms_xml:
1184 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
1185 if histogram_name_found:
1186 break
1187 if not histogram_name_found:
1188 problems.append(' [%s:%d] %s' %
1189 (f.LocalPath(), line_num, histogram_name))
1190
1191 if not problems:
1192 return []
1193 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1194 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491195 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191196
wnwenbdc444e2016-05-25 13:44:151197
yolandyandaabc6d2016-04-18 18:29:391198def _CheckFlakyTestUsage(input_api, output_api):
1199 """Check that FlakyTest annotation is our own instead of the android one"""
1200 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1201 files = []
1202 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1203 if f.LocalPath().endswith('Test.java'):
1204 if pattern.search(input_api.ReadFile(f)):
1205 files.append(f)
1206 if len(files):
1207 return [output_api.PresubmitError(
1208 'Use org.chromium.base.test.util.FlakyTest instead of '
1209 'android.test.FlakyTest',
1210 files)]
1211 return []
mcasasb7440c282015-02-04 14:52:191212
wnwenbdc444e2016-05-25 13:44:151213
[email protected]8ea5d4b2011-09-13 21:49:221214def _CheckNoNewWStrings(input_api, output_api):
1215 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271216 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221217 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201218 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571219 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341220 '/win/' in f.LocalPath() or
1221 'chrome_elf' in f.LocalPath() or
1222 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201223 continue
[email protected]8ea5d4b2011-09-13 21:49:221224
[email protected]a11dbe9b2012-08-07 01:32:581225 allowWString = False
[email protected]b5c24292011-11-28 14:38:201226 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581227 if 'presubmit: allow wstring' in line:
1228 allowWString = True
1229 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271230 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581231 allowWString = False
1232 else:
1233 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221234
[email protected]55463aa62011-10-12 00:48:271235 if not problems:
1236 return []
1237 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581238 ' If you are calling a cross-platform API that accepts a wstring, '
1239 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271240 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221241
1242
[email protected]2a8ac9c2011-10-19 17:20:441243def _CheckNoDEPSGIT(input_api, output_api):
1244 """Make sure .DEPS.git is never modified manually."""
1245 if any(f.LocalPath().endswith('.DEPS.git') for f in
1246 input_api.AffectedFiles()):
1247 return [output_api.PresubmitError(
1248 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1249 'automated system based on what\'s in DEPS and your changes will be\n'
1250 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501251 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1252 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441253 'for more information')]
1254 return []
1255
1256
tandriief664692014-09-23 14:51:471257def _CheckValidHostsInDEPS(input_api, output_api):
1258 """Checks that DEPS file deps are from allowed_hosts."""
1259 # Run only if DEPS file has been modified to annoy fewer bystanders.
1260 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1261 return []
1262 # Outsource work to gclient verify
1263 try:
John Budorickf20c0042019-04-25 23:23:401264 gclient_path = input_api.os_path.join(
1265 input_api.PresubmitLocalPath(),
1266 'third_party', 'depot_tools', 'gclient.py')
1267 input_api.subprocess.check_output(
1268 [input_api.python_executable, gclient_path, 'verify'],
1269 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471270 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201271 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471272 return [output_api.PresubmitError(
1273 'DEPS file must have only git dependencies.',
1274 long_text=error.output)]
1275
1276
[email protected]127f18ec2012-06-16 05:05:591277def _CheckNoBannedFunctions(input_api, output_api):
1278 """Make sure that banned functions are not used."""
1279 warnings = []
1280 errors = []
1281
wnwenbdc444e2016-05-25 13:44:151282 def IsBlacklisted(affected_file, blacklist):
1283 local_path = affected_file.LocalPath()
1284 for item in blacklist:
1285 if input_api.re.match(item, local_path):
1286 return True
1287 return False
1288
Sylvain Defresnea8b73d252018-02-28 15:45:541289 def IsIosObcjFile(affected_file):
1290 local_path = affected_file.LocalPath()
1291 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1292 return False
1293 basename = input_api.os_path.basename(local_path)
1294 if 'ios' in basename.split('_'):
1295 return True
1296 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1297 if sep and 'ios' in local_path.split(sep):
1298 return True
1299 return False
1300
wnwenbdc444e2016-05-25 13:44:151301 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
1302 matched = False
1303 if func_name[0:1] == '/':
1304 regex = func_name[1:]
1305 if input_api.re.search(regex, line):
1306 matched = True
1307 elif func_name in line:
dchenge07de812016-06-20 19:27:171308 matched = True
wnwenbdc444e2016-05-25 13:44:151309 if matched:
dchenge07de812016-06-20 19:27:171310 problems = warnings
wnwenbdc444e2016-05-25 13:44:151311 if error:
dchenge07de812016-06-20 19:27:171312 problems = errors
wnwenbdc444e2016-05-25 13:44:151313 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1314 for message_line in message:
1315 problems.append(' %s' % message_line)
1316
Eric Stevensona9a980972017-09-23 00:04:411317 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1318 for f in input_api.AffectedFiles(file_filter=file_filter):
1319 for line_num, line in f.ChangedContents():
1320 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1321 CheckForMatch(f, line_num, line, func_name, message, error)
1322
[email protected]127f18ec2012-06-16 05:05:591323 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1324 for f in input_api.AffectedFiles(file_filter=file_filter):
1325 for line_num, line in f.ChangedContents():
1326 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151327 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591328
Sylvain Defresnea8b73d252018-02-28 15:45:541329 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1330 for line_num, line in f.ChangedContents():
1331 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1332 CheckForMatch(f, line_num, line, func_name, message, error)
1333
[email protected]127f18ec2012-06-16 05:05:591334 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1335 for f in input_api.AffectedFiles(file_filter=file_filter):
1336 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491337 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491338 if IsBlacklisted(f, excluded_paths):
1339 continue
wnwenbdc444e2016-05-25 13:44:151340 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591341
1342 result = []
1343 if (warnings):
1344 result.append(output_api.PresubmitPromptWarning(
1345 'Banned functions were used.\n' + '\n'.join(warnings)))
1346 if (errors):
1347 result.append(output_api.PresubmitError(
1348 'Banned functions were used.\n' + '\n'.join(errors)))
1349 return result
1350
1351
[email protected]6c063c62012-07-11 19:11:061352def _CheckNoPragmaOnce(input_api, output_api):
1353 """Make sure that banned functions are not used."""
1354 files = []
1355 pattern = input_api.re.compile(r'^#pragma\s+once',
1356 input_api.re.MULTILINE)
1357 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1358 if not f.LocalPath().endswith('.h'):
1359 continue
1360 contents = input_api.ReadFile(f)
1361 if pattern.search(contents):
1362 files.append(f)
1363
1364 if files:
1365 return [output_api.PresubmitError(
1366 'Do not use #pragma once in header files.\n'
1367 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1368 files)]
1369 return []
1370
[email protected]127f18ec2012-06-16 05:05:591371
[email protected]e7479052012-09-19 00:26:121372def _CheckNoTrinaryTrueFalse(input_api, output_api):
1373 """Checks to make sure we don't introduce use of foo ? true : false."""
1374 problems = []
1375 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1376 for f in input_api.AffectedFiles():
1377 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1378 continue
1379
1380 for line_num, line in f.ChangedContents():
1381 if pattern.match(line):
1382 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1383
1384 if not problems:
1385 return []
1386 return [output_api.PresubmitPromptWarning(
1387 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1388 '\n'.join(problems))]
1389
1390
[email protected]55f9f382012-07-31 11:02:181391def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281392 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181393 change. Breaking - rules is an error, breaking ! rules is a
1394 warning.
1395 """
mohan.reddyf21db962014-10-16 12:26:471396 import sys
[email protected]55f9f382012-07-31 11:02:181397 # We need to wait until we have an input_api object and use this
1398 # roundabout construct to import checkdeps because this file is
1399 # eval-ed and thus doesn't have __file__.
1400 original_sys_path = sys.path
1401 try:
1402 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471403 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181404 import checkdeps
[email protected]55f9f382012-07-31 11:02:181405 from rules import Rule
1406 finally:
1407 # Restore sys.path to what it was before.
1408 sys.path = original_sys_path
1409
1410 added_includes = []
rhalavati08acd232017-04-03 07:23:281411 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241412 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181413 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:061414 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501415 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081416 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061417 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501418 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081419 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:061420 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501421 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081422 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181423
[email protected]26385172013-05-09 23:11:351424 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181425
1426 error_descriptions = []
1427 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281428 error_subjects = set()
1429 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181430 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1431 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081432 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181433 description_with_path = '%s\n %s' % (path, rule_description)
1434 if rule_type == Rule.DISALLOW:
1435 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281436 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181437 else:
1438 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281439 warning_subjects.add("#includes")
1440
1441 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1442 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081443 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281444 description_with_path = '%s\n %s' % (path, rule_description)
1445 if rule_type == Rule.DISALLOW:
1446 error_descriptions.append(description_with_path)
1447 error_subjects.add("imports")
1448 else:
1449 warning_descriptions.append(description_with_path)
1450 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181451
Jinsuk Kim5a092672017-10-24 22:42:241452 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021453 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081454 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241455 description_with_path = '%s\n %s' % (path, rule_description)
1456 if rule_type == Rule.DISALLOW:
1457 error_descriptions.append(description_with_path)
1458 error_subjects.add("imports")
1459 else:
1460 warning_descriptions.append(description_with_path)
1461 warning_subjects.add("imports")
1462
[email protected]55f9f382012-07-31 11:02:181463 results = []
1464 if error_descriptions:
1465 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281466 'You added one or more %s that violate checkdeps rules.'
1467 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181468 error_descriptions))
1469 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421470 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281471 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181472 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281473 '%s? See relevant DEPS file(s) for details and contacts.' %
1474 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181475 warning_descriptions))
1476 return results
1477
1478
[email protected]fbcafe5a2012-08-08 15:31:221479def _CheckFilePermissions(input_api, output_api):
1480 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151481 if input_api.platform == 'win32':
1482 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291483 checkperms_tool = input_api.os_path.join(
1484 input_api.PresubmitLocalPath(),
1485 'tools', 'checkperms', 'checkperms.py')
1486 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471487 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391488 with input_api.CreateTemporaryFile() as file_list:
1489 for f in input_api.AffectedFiles():
1490 # checkperms.py file/directory arguments must be relative to the
1491 # repository.
1492 file_list.write(f.LocalPath() + '\n')
1493 file_list.close()
1494 args += ['--file-list', file_list.name]
1495 try:
1496 input_api.subprocess.check_output(args)
1497 return []
1498 except input_api.subprocess.CalledProcessError as error:
1499 return [output_api.PresubmitError(
1500 'checkperms.py failed:',
1501 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221502
1503
robertocn832f5992017-01-04 19:01:301504def _CheckTeamTags(input_api, output_api):
1505 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1506 checkteamtags_tool = input_api.os_path.join(
1507 input_api.PresubmitLocalPath(),
1508 'tools', 'checkteamtags', 'checkteamtags.py')
1509 args = [input_api.python_executable, checkteamtags_tool,
1510 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221511 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301512 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1513 'OWNERS']
1514 try:
1515 if files:
1516 input_api.subprocess.check_output(args + files)
1517 return []
1518 except input_api.subprocess.CalledProcessError as error:
1519 return [output_api.PresubmitError(
1520 'checkteamtags.py failed:',
1521 long_text=error.output)]
1522
1523
[email protected]c8278b32012-10-30 20:35:491524def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1525 """Makes sure we don't include ui/aura/window_property.h
1526 in header files.
1527 """
1528 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1529 errors = []
1530 for f in input_api.AffectedFiles():
1531 if not f.LocalPath().endswith('.h'):
1532 continue
1533 for line_num, line in f.ChangedContents():
1534 if pattern.match(line):
1535 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1536
1537 results = []
1538 if errors:
1539 results.append(output_api.PresubmitError(
1540 'Header files should not include ui/aura/window_property.h', errors))
1541 return results
1542
1543
[email protected]70ca77752012-11-20 03:45:031544def _CheckForVersionControlConflictsInFile(input_api, f):
1545 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1546 errors = []
1547 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:161548 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:231549 # First-level headers in markdown look a lot like version control
1550 # conflict markers. http://daringfireball.net/projects/markdown/basics
1551 continue
[email protected]70ca77752012-11-20 03:45:031552 if pattern.match(line):
1553 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1554 return errors
1555
1556
1557def _CheckForVersionControlConflicts(input_api, output_api):
1558 """Usually this is not intentional and will cause a compile failure."""
1559 errors = []
1560 for f in input_api.AffectedFiles():
1561 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1562
1563 results = []
1564 if errors:
1565 results.append(output_api.PresubmitError(
1566 'Version control conflict markers found, please resolve.', errors))
1567 return results
1568
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201569
estadee17314a02017-01-12 16:22:161570def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1571 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1572 errors = []
1573 for f in input_api.AffectedFiles():
1574 for line_num, line in f.ChangedContents():
1575 if pattern.search(line):
1576 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1577
1578 results = []
1579 if errors:
1580 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501581 'Found Google support URL addressed by answer number. Please replace '
1582 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161583 return results
1584
[email protected]70ca77752012-11-20 03:45:031585
[email protected]06e6d0ff2012-12-11 01:36:441586def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1587 def FilterFile(affected_file):
1588 """Filter function for use with input_api.AffectedSourceFiles,
1589 below. This filters out everything except non-test files from
1590 top-level directories that generally speaking should not hard-code
1591 service URLs (e.g. src/android_webview/, src/content/ and others).
1592 """
1593 return input_api.FilterSourceFile(
1594 affected_file,
Egor Paskoce145c42018-09-28 19:31:041595 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:441596 black_list=(_EXCLUDED_PATHS +
1597 _TEST_CODE_EXCLUDED_PATHS +
1598 input_api.DEFAULT_BLACK_LIST))
1599
reillyi38965732015-11-16 18:27:331600 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1601 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461602 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1603 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441604 problems = [] # items are (filename, line_number, line)
1605 for f in input_api.AffectedSourceFiles(FilterFile):
1606 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461607 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441608 problems.append((f.LocalPath(), line_num, line))
1609
1610 if problems:
[email protected]f7051d52013-04-02 18:31:421611 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441612 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581613 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441614 [' %s:%d: %s' % (
1615 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031616 else:
1617 return []
[email protected]06e6d0ff2012-12-11 01:36:441618
1619
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491620# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:271621def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1622 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311623 The native_client_sdk directory is excluded because it has auto-generated PNG
1624 files for documentation.
[email protected]d2530012013-01-25 16:39:271625 """
[email protected]d2530012013-01-25 16:39:271626 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491627 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:041628 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:311629 file_filter = lambda f: input_api.FilterSourceFile(
1630 f, white_list=white_list, black_list=black_list)
1631 for f in input_api.AffectedFiles(include_deletes=False,
1632 file_filter=file_filter):
1633 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271634
1635 results = []
1636 if errors:
1637 results.append(output_api.PresubmitError(
1638 'The name of PNG files should not have abbreviations. \n'
1639 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1640 'Contact [email protected] if you have questions.', errors))
1641 return results
1642
1643
Daniel Cheng4dcdb6b2017-04-13 08:30:171644def _ExtractAddRulesFromParsedDeps(parsed_deps):
1645 """Extract the rules that add dependencies from a parsed DEPS file.
1646
1647 Args:
1648 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1649 add_rules = set()
1650 add_rules.update([
1651 rule[1:] for rule in parsed_deps.get('include_rules', [])
1652 if rule.startswith('+') or rule.startswith('!')
1653 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501654 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171655 {}).iteritems():
1656 add_rules.update([
1657 rule[1:] for rule in rules
1658 if rule.startswith('+') or rule.startswith('!')
1659 ])
1660 return add_rules
1661
1662
1663def _ParseDeps(contents):
1664 """Simple helper for parsing DEPS files."""
1665 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171666 class _VarImpl:
1667
1668 def __init__(self, local_scope):
1669 self._local_scope = local_scope
1670
1671 def Lookup(self, var_name):
1672 """Implements the Var syntax."""
1673 try:
1674 return self._local_scope['vars'][var_name]
1675 except KeyError:
1676 raise Exception('Var is not defined: %s' % var_name)
1677
1678 local_scope = {}
1679 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171680 'Var': _VarImpl(local_scope).Lookup,
1681 }
1682 exec contents in global_scope, local_scope
1683 return local_scope
1684
1685
1686def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081687 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411688 a set of DEPS entries that we should look up.
1689
1690 For a directory (rather than a specific filename) we fake a path to
1691 a specific filename by adding /DEPS. This is chosen as a file that
1692 will seldom or never be subject to per-file include_rules.
1693 """
[email protected]2b438d62013-11-14 17:54:141694 # We ignore deps entries on auto-generated directories.
1695 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081696
Daniel Cheng4dcdb6b2017-04-13 08:30:171697 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1698 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1699
1700 added_deps = new_deps.difference(old_deps)
1701
[email protected]2b438d62013-11-14 17:54:141702 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171703 for added_dep in added_deps:
1704 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1705 continue
1706 # Assume that a rule that ends in .h is a rule for a specific file.
1707 if added_dep.endswith('.h'):
1708 results.add(added_dep)
1709 else:
1710 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081711 return results
1712
1713
[email protected]e871964c2013-05-13 14:14:551714def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1715 """When a dependency prefixed with + is added to a DEPS file, we
1716 want to make sure that the change is reviewed by an OWNER of the
1717 target file or directory, to avoid layering violations from being
1718 introduced. This check verifies that this happens.
1719 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171720 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241721
1722 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:491723 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241724 for f in input_api.AffectedFiles(include_deletes=False,
1725 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551726 filename = input_api.os_path.basename(f.LocalPath())
1727 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171728 virtual_depended_on_files.update(_CalculateAddedDeps(
1729 input_api.os_path,
1730 '\n'.join(f.OldContents()),
1731 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551732
[email protected]e871964c2013-05-13 14:14:551733 if not virtual_depended_on_files:
1734 return []
1735
1736 if input_api.is_committing:
1737 if input_api.tbr:
1738 return [output_api.PresubmitNotifyResult(
1739 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271740 if input_api.dry_run:
1741 return [output_api.PresubmitNotifyResult(
1742 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551743 if not input_api.change.issue:
1744 return [output_api.PresubmitError(
1745 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401746 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551747 output = output_api.PresubmitError
1748 else:
1749 output = output_api.PresubmitNotifyResult
1750
1751 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501752 owner_email, reviewers = (
1753 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1754 input_api,
1755 owners_db.email_regexp,
1756 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551757
1758 owner_email = owner_email or input_api.change.author_email
1759
[email protected]de4f7d22013-05-23 14:27:461760 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511761 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461762 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551763 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1764 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411765
1766 # We strip the /DEPS part that was added by
1767 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1768 # directory.
1769 def StripDeps(path):
1770 start_deps = path.rfind('/DEPS')
1771 if start_deps != -1:
1772 return path[:start_deps]
1773 else:
1774 return path
1775 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551776 for path in missing_files]
1777
1778 if unapproved_dependencies:
1779 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151780 output('You need LGTM from owners of depends-on paths in DEPS that were '
1781 'modified in this CL:\n %s' %
1782 '\n '.join(sorted(unapproved_dependencies)))]
1783 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1784 output_list.append(output(
1785 'Suggested missing target path OWNERS:\n %s' %
1786 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551787 return output_list
1788
1789 return []
1790
1791
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491792# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:401793def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491794 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:401795 black_list = (_EXCLUDED_PATHS +
1796 _TEST_CODE_EXCLUDED_PATHS +
1797 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:041798 (r"^base[\\/]logging\.h$",
1799 r"^base[\\/]logging\.cc$",
1800 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
1801 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
1802 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:121803 r"startup_browser_creator\.cc$",
Nicolas Ouellet-Payeur16730ab2019-04-09 15:39:181804 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
Egor Paskoce145c42018-09-28 19:31:041805 r"^chrome[\\/]installer[\\/]setup[\\/].*",
1806 r"^chrome[\\/]chrome_cleaner[\\/].*",
1807 r"chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031808 r"diagnostics_writer\.cc$",
Egor Paskoce145c42018-09-28 19:31:041809 r"^chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
1810 r"^chromecast[\\/]",
1811 r"^cloud_print[\\/]",
1812 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:481813 r"dump_stability_report_main_win.cc$",
Egor Paskoce145c42018-09-28 19:31:041814 r"^components[\\/]html_viewer[\\/]"
jochen34415e52015-07-10 08:34:311815 r"web_test_delegate_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041816 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:461817 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:041818 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:461819 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041820 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:251821 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:041822 r"^courgette[\\/]courgette_minimal_tool\.cc$",
1823 r"^courgette[\\/]courgette_tool\.cc$",
1824 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:271825 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331826 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:041827 r"^ipc[\\/]ipc_logging\.cc$",
1828 r"^native_client_sdk[\\/]",
1829 r"^remoting[\\/]base[\\/]logging\.h$",
1830 r"^remoting[\\/]host[\\/].*",
1831 r"^sandbox[\\/]linux[\\/].*",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331832 r"^storage[\\/]browser[\\/]fileapi[\\/]" +
1833 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:041834 r"^tools[\\/]",
1835 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
1836 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331837 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]"))
[email protected]85218562013-11-22 07:41:401838 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491839 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:401840
thomasanderson625d3932017-03-29 07:16:581841 log_info = set([])
1842 printf = set([])
[email protected]85218562013-11-22 07:41:401843
1844 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581845 for _, line in f.ChangedContents():
1846 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1847 log_info.add(f.LocalPath())
1848 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1849 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371850
thomasanderson625d3932017-03-29 07:16:581851 if input_api.re.search(r"\bprintf\(", line):
1852 printf.add(f.LocalPath())
1853 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1854 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401855
1856 if log_info:
1857 return [output_api.PresubmitError(
1858 'These files spam the console log with LOG(INFO):',
1859 items=log_info)]
1860 if printf:
1861 return [output_api.PresubmitError(
1862 'These files spam the console log with printf/fprintf:',
1863 items=printf)]
1864 return []
1865
1866
[email protected]49aa76a2013-12-04 06:59:161867def _CheckForAnonymousVariables(input_api, output_api):
1868 """These types are all expected to hold locks while in scope and
1869 so should never be anonymous (which causes them to be immediately
1870 destroyed)."""
1871 they_who_must_be_named = [
1872 'base::AutoLock',
1873 'base::AutoReset',
1874 'base::AutoUnlock',
1875 'SkAutoAlphaRestore',
1876 'SkAutoBitmapShaderInstall',
1877 'SkAutoBlitterChoose',
1878 'SkAutoBounderCommit',
1879 'SkAutoCallProc',
1880 'SkAutoCanvasRestore',
1881 'SkAutoCommentBlock',
1882 'SkAutoDescriptor',
1883 'SkAutoDisableDirectionCheck',
1884 'SkAutoDisableOvalCheck',
1885 'SkAutoFree',
1886 'SkAutoGlyphCache',
1887 'SkAutoHDC',
1888 'SkAutoLockColors',
1889 'SkAutoLockPixels',
1890 'SkAutoMalloc',
1891 'SkAutoMaskFreeImage',
1892 'SkAutoMutexAcquire',
1893 'SkAutoPathBoundsUpdate',
1894 'SkAutoPDFRelease',
1895 'SkAutoRasterClipValidate',
1896 'SkAutoRef',
1897 'SkAutoTime',
1898 'SkAutoTrace',
1899 'SkAutoUnref',
1900 ]
1901 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1902 # bad: base::AutoLock(lock.get());
1903 # not bad: base::AutoLock lock(lock.get());
1904 bad_pattern = input_api.re.compile(anonymous)
1905 # good: new base::AutoLock(lock.get())
1906 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1907 errors = []
1908
1909 for f in input_api.AffectedFiles():
1910 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1911 continue
1912 for linenum, line in f.ChangedContents():
1913 if bad_pattern.search(line) and not good_pattern.search(line):
1914 errors.append('%s:%d' % (f.LocalPath(), linenum))
1915
1916 if errors:
1917 return [output_api.PresubmitError(
1918 'These lines create anonymous variables that need to be named:',
1919 items=errors)]
1920 return []
1921
1922
Peter Kasting4844e46e2018-02-23 07:27:101923def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:531924 # Returns whether |template_str| is of the form <T, U...> for some types T
1925 # and U. Assumes that |template_str| is already in the form <...>.
1926 def HasMoreThanOneArg(template_str):
1927 # Level of <...> nesting.
1928 nesting = 0
1929 for c in template_str:
1930 if c == '<':
1931 nesting += 1
1932 elif c == '>':
1933 nesting -= 1
1934 elif c == ',' and nesting == 1:
1935 return True
1936 return False
1937
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491938 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:101939 sources = lambda affected_file: input_api.FilterSourceFile(
1940 affected_file,
1941 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1942 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491943 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:551944
1945 # Pattern to capture a single "<...>" block of template arguments. It can
1946 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
1947 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
1948 # latter would likely require counting that < and > match, which is not
1949 # expressible in regular languages. Should the need arise, one can introduce
1950 # limited counting (matching up to a total number of nesting depth), which
1951 # should cover all practical cases for already a low nesting limit.
1952 template_arg_pattern = (
1953 r'<[^>]*' # Opening block of <.
1954 r'>([^<]*>)?') # Closing block of >.
1955 # Prefix expressing that whatever follows is not already inside a <...>
1956 # block.
1957 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:101958 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:551959 not_inside_template_arg_pattern
1960 + r'\bstd::unique_ptr'
1961 + template_arg_pattern
1962 + r'\(\)')
1963
1964 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
1965 template_arg_no_array_pattern = (
1966 r'<[^>]*[^]]' # Opening block of <.
1967 r'>([^(<]*[^]]>)?') # Closing block of >.
1968 # Prefix saying that what follows is the start of an expression.
1969 start_of_expr_pattern = r'(=|\breturn|^)\s*'
1970 # Suffix saying that what follows are call parentheses with a non-empty list
1971 # of arguments.
1972 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:531973 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:551974 return_construct_pattern = input_api.re.compile(
1975 start_of_expr_pattern
1976 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:531977 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:551978 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:531979 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:551980 + nonempty_arg_list_pattern)
1981
Vaclav Brozek851d9602018-04-04 16:13:051982 problems_constructor = []
1983 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:101984 for f in input_api.AffectedSourceFiles(sources):
1985 for line_number, line in f.ChangedContents():
1986 # Disallow:
1987 # return std::unique_ptr<T>(foo);
1988 # bar = std::unique_ptr<T>(foo);
1989 # But allow:
1990 # return std::unique_ptr<T[]>(foo);
1991 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:531992 # And also allow cases when the second template argument is present. Those
1993 # cases cannot be handled by std::make_unique:
1994 # return std::unique_ptr<T, U>(foo);
1995 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:051996 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:531997 return_construct_result = return_construct_pattern.search(line)
1998 if return_construct_result and not HasMoreThanOneArg(
1999 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052000 problems_constructor.append(
2001 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102002 # Disallow:
2003 # std::unique_ptr<T>()
2004 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052005 problems_nullptr.append(
2006 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2007
2008 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162009 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052010 errors.append(output_api.PresubmitError(
2011 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162012 problems_nullptr))
2013 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052014 errors.append(output_api.PresubmitError(
2015 'The following files use explicit std::unique_ptr constructor.'
2016 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162017 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102018 return errors
2019
2020
[email protected]999261d2014-03-03 20:08:082021def _CheckUserActionUpdate(input_api, output_api):
2022 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522023 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082024 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522025 # If actions.xml is already included in the changelist, the PRESUBMIT
2026 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082027 return []
2028
[email protected]999261d2014-03-03 20:08:082029 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2030 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522031 current_actions = None
[email protected]999261d2014-03-03 20:08:082032 for f in input_api.AffectedFiles(file_filter=file_filter):
2033 for line_num, line in f.ChangedContents():
2034 match = input_api.re.search(action_re, line)
2035 if match:
[email protected]2f92dec2014-03-07 19:21:522036 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2037 # loaded only once.
2038 if not current_actions:
2039 with open('tools/metrics/actions/actions.xml') as actions_f:
2040 current_actions = actions_f.read()
2041 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082042 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522043 action = 'name="{0}"'.format(action_name)
2044 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082045 return [output_api.PresubmitPromptWarning(
2046 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522047 'tools/metrics/actions/actions.xml. Please run '
2048 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082049 % (f.LocalPath(), line_num, action_name))]
2050 return []
2051
2052
Daniel Cheng13ca61a882017-08-25 15:11:252053def _ImportJSONCommentEater(input_api):
2054 import sys
2055 sys.path = sys.path + [input_api.os_path.join(
2056 input_api.PresubmitLocalPath(),
2057 'tools', 'json_comment_eater')]
2058 import json_comment_eater
2059 return json_comment_eater
2060
2061
[email protected]99171a92014-06-03 08:44:472062def _GetJSONParseError(input_api, filename, eat_comments=True):
2063 try:
2064 contents = input_api.ReadFile(filename)
2065 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252066 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132067 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472068
2069 input_api.json.loads(contents)
2070 except ValueError as e:
2071 return e
2072 return None
2073
2074
2075def _GetIDLParseError(input_api, filename):
2076 try:
2077 contents = input_api.ReadFile(filename)
2078 idl_schema = input_api.os_path.join(
2079 input_api.PresubmitLocalPath(),
2080 'tools', 'json_schema_compiler', 'idl_schema.py')
2081 process = input_api.subprocess.Popen(
2082 [input_api.python_executable, idl_schema],
2083 stdin=input_api.subprocess.PIPE,
2084 stdout=input_api.subprocess.PIPE,
2085 stderr=input_api.subprocess.PIPE,
2086 universal_newlines=True)
2087 (_, error) = process.communicate(input=contents)
2088 return error or None
2089 except ValueError as e:
2090 return e
2091
2092
2093def _CheckParseErrors(input_api, output_api):
2094 """Check that IDL and JSON files do not contain syntax errors."""
2095 actions = {
2096 '.idl': _GetIDLParseError,
2097 '.json': _GetJSONParseError,
2098 }
[email protected]99171a92014-06-03 08:44:472099 # Most JSON files are preprocessed and support comments, but these do not.
2100 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042101 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472102 ]
2103 # Only run IDL checker on files in these directories.
2104 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042105 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2106 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472107 ]
2108
2109 def get_action(affected_file):
2110 filename = affected_file.LocalPath()
2111 return actions.get(input_api.os_path.splitext(filename)[1])
2112
[email protected]99171a92014-06-03 08:44:472113 def FilterFile(affected_file):
2114 action = get_action(affected_file)
2115 if not action:
2116 return False
2117 path = affected_file.LocalPath()
2118
Sean Kau46e29bc2017-08-28 16:31:162119 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:472120 return False
2121
2122 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162123 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472124 return False
2125 return True
2126
2127 results = []
2128 for affected_file in input_api.AffectedFiles(
2129 file_filter=FilterFile, include_deletes=False):
2130 action = get_action(affected_file)
2131 kwargs = {}
2132 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162133 _MatchesFile(input_api, json_no_comments_patterns,
2134 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472135 kwargs['eat_comments'] = False
2136 parse_error = action(input_api,
2137 affected_file.AbsoluteLocalPath(),
2138 **kwargs)
2139 if parse_error:
2140 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2141 (affected_file.LocalPath(), parse_error)))
2142 return results
2143
2144
[email protected]760deea2013-12-10 19:33:492145def _CheckJavaStyle(input_api, output_api):
2146 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472147 import sys
[email protected]760deea2013-12-10 19:33:492148 original_sys_path = sys.path
2149 try:
2150 sys.path = sys.path + [input_api.os_path.join(
2151 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2152 import checkstyle
2153 finally:
2154 # Restore sys.path to what it was before.
2155 sys.path = original_sys_path
2156
2157 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092158 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:512159 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:492160
2161
Sean Kau46e29bc2017-08-28 16:31:162162def _MatchesFile(input_api, patterns, path):
2163 for pattern in patterns:
2164 if input_api.re.search(pattern, path):
2165 return True
2166 return False
2167
2168
Daniel Cheng7052cdf2017-11-21 19:23:292169def _GetOwnersFilesToCheckForIpcOwners(input_api):
2170 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172171
Daniel Cheng7052cdf2017-11-21 19:23:292172 Returns:
2173 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2174 contain to cover IPC-related files with noparent reviewer rules.
2175 """
2176 # Whether or not a file affects IPC is (mostly) determined by a simple list
2177 # of filename patterns.
dchenge07de812016-06-20 19:27:172178 file_patterns = [
palmerb19a0932017-01-24 04:00:312179 # Legacy IPC:
dchenge07de812016-06-20 19:27:172180 '*_messages.cc',
2181 '*_messages*.h',
2182 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312183 # Mojo IPC:
dchenge07de812016-06-20 19:27:172184 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472185 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172186 '*_struct_traits*.*',
2187 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312188 '*.typemap',
2189 # Android native IPC:
2190 '*.aidl',
2191 # Blink uses a different file naming convention:
2192 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472193 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172194 '*StructTraits*.*',
2195 '*TypeConverter*.*',
2196 ]
2197
scottmg7a6ed5ba2016-11-04 18:22:042198 # These third_party directories do not contain IPCs, but contain files
2199 # matching the above patterns, which trigger false positives.
2200 exclude_paths = [
2201 'third_party/crashpad/*',
Andres Medinae684cf42018-08-27 18:48:232202 'third_party/protobuf/benchmarks/python/*',
Daniel Chengebe635e2018-07-13 12:36:062203 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:292204 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:042205 ]
2206
dchenge07de812016-06-20 19:27:172207 # Dictionary mapping an OWNERS file path to Patterns.
2208 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2209 # rules ) to a PatternEntry.
2210 # PatternEntry is a dictionary with two keys:
2211 # - 'files': the files that are matched by this pattern
2212 # - 'rules': the per-file rules needed for this pattern
2213 # For example, if we expect OWNERS file to contain rules for *.mojom and
2214 # *_struct_traits*.*, Patterns might look like this:
2215 # {
2216 # '*.mojom': {
2217 # 'files': ...,
2218 # 'rules': [
2219 # 'per-file *.mojom=set noparent',
2220 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2221 # ],
2222 # },
2223 # '*_struct_traits*.*': {
2224 # 'files': ...,
2225 # 'rules': [
2226 # 'per-file *_struct_traits*.*=set noparent',
2227 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2228 # ],
2229 # },
2230 # }
2231 to_check = {}
2232
Daniel Cheng13ca61a882017-08-25 15:11:252233 def AddPatternToCheck(input_file, pattern):
2234 owners_file = input_api.os_path.join(
2235 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2236 if owners_file not in to_check:
2237 to_check[owners_file] = {}
2238 if pattern not in to_check[owners_file]:
2239 to_check[owners_file][pattern] = {
2240 'files': [],
2241 'rules': [
2242 'per-file %s=set noparent' % pattern,
2243 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2244 ]
2245 }
Vaclav Brozekd5de76a2018-03-17 07:57:502246 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252247
dchenge07de812016-06-20 19:27:172248 # Iterate through the affected files to see what we actually need to check
2249 # for. We should only nag patch authors about per-file rules if a file in that
2250 # directory would match that pattern. If a directory only contains *.mojom
2251 # files and no *_messages*.h files, we should only nag about rules for
2252 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252253 for f in input_api.AffectedFiles(include_deletes=False):
2254 # Manifest files don't have a strong naming convention. Instead, scan
Ken Rockot9f668262018-12-21 18:56:362255 # affected files for .json, .cc, and .h files which look like they contain
2256 # a manifest definition.
Sean Kau46e29bc2017-08-28 16:31:162257 if (f.LocalPath().endswith('.json') and
2258 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
2259 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:252260 json_comment_eater = _ImportJSONCommentEater(input_api)
2261 mostly_json_lines = '\n'.join(f.NewContents())
2262 # Comments aren't allowed in strict JSON, so filter them out.
2263 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:432264 try:
2265 json_content = input_api.json.loads(json_lines)
2266 except:
2267 # There's another PRESUBMIT check that already verifies that JSON files
2268 # are not invalid, so no need to emit another warning here.
2269 continue
Daniel Cheng13ca61a882017-08-25 15:11:252270 if 'interface_provider_specs' in json_content:
2271 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
Ken Rockot9f668262018-12-21 18:56:362272 else:
2273 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2274 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2275 if (manifest_pattern.search(f.LocalPath()) and not
2276 test_manifest_pattern.search(f.LocalPath())):
2277 # We expect all actual service manifest files to contain at least one
2278 # qualified reference to service_manager::Manifest.
2279 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2280 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172281 for pattern in file_patterns:
2282 if input_api.fnmatch.fnmatch(
2283 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042284 skip = False
2285 for exclude in exclude_paths:
2286 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2287 skip = True
2288 break
2289 if skip:
2290 continue
Daniel Cheng13ca61a882017-08-25 15:11:252291 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172292 break
2293
Daniel Cheng7052cdf2017-11-21 19:23:292294 return to_check
2295
2296
2297def _CheckIpcOwners(input_api, output_api):
2298 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2299 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2300
2301 if to_check:
2302 # If there are any OWNERS files to check, there are IPC-related changes in
2303 # this CL. Auto-CC the review list.
2304 output_api.AppendCC('[email protected]')
2305
2306 # Go through the OWNERS files to check, filtering out rules that are already
2307 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172308 for owners_file, patterns in to_check.iteritems():
2309 try:
2310 with file(owners_file) as f:
2311 lines = set(f.read().splitlines())
2312 for entry in patterns.itervalues():
2313 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2314 ]
2315 except IOError:
2316 # No OWNERS file, so all the rules are definitely missing.
2317 continue
2318
2319 # All the remaining lines weren't found in OWNERS files, so emit an error.
2320 errors = []
2321 for owners_file, patterns in to_check.iteritems():
2322 missing_lines = []
2323 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502324 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172325 missing_lines.extend(entry['rules'])
2326 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2327 if missing_lines:
2328 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052329 'Because of the presence of files:\n%s\n\n'
2330 '%s needs the following %d lines added:\n\n%s' %
2331 ('\n'.join(files), owners_file, len(missing_lines),
2332 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172333
2334 results = []
2335 if errors:
vabrf5ce3bf92016-07-11 14:52:412336 if input_api.is_committing:
2337 output = output_api.PresubmitError
2338 else:
2339 output = output_api.PresubmitPromptWarning
2340 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592341 'Found OWNERS files that need to be updated for IPC security ' +
2342 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172343 long_text='\n\n'.join(errors)))
2344
2345 return results
2346
2347
jbriance9e12f162016-11-25 07:57:502348def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312349 """Checks that added or removed lines in non third party affected
2350 header files do not lead to new useless class or struct forward
2351 declaration.
jbriance9e12f162016-11-25 07:57:502352 """
2353 results = []
2354 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2355 input_api.re.MULTILINE)
2356 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2357 input_api.re.MULTILINE)
2358 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312359 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192360 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:492361 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:312362 continue
2363
jbriance9e12f162016-11-25 07:57:502364 if not f.LocalPath().endswith('.h'):
2365 continue
2366
2367 contents = input_api.ReadFile(f)
2368 fwd_decls = input_api.re.findall(class_pattern, contents)
2369 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2370
2371 useless_fwd_decls = []
2372 for decl in fwd_decls:
2373 count = sum(1 for _ in input_api.re.finditer(
2374 r'\b%s\b' % input_api.re.escape(decl), contents))
2375 if count == 1:
2376 useless_fwd_decls.append(decl)
2377
2378 if not useless_fwd_decls:
2379 continue
2380
2381 for line in f.GenerateScmDiff().splitlines():
2382 if (line.startswith('-') and not line.startswith('--') or
2383 line.startswith('+') and not line.startswith('++')):
2384 for decl in useless_fwd_decls:
2385 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2386 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242387 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502388 (f.LocalPath(), decl)))
2389 useless_fwd_decls.remove(decl)
2390
2391 return results
2392
Jinsong Fan91ebbbd2019-04-16 14:57:172393def _CheckAndroidDebuggableBuild(input_api, output_api):
2394 """Checks that code uses BuildInfo.isDebugAndroid() instead of
2395 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
2396 this is a debuggable build of Android.
2397 """
2398 build_type_check_pattern = input_api.re.compile(
2399 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
2400
2401 errors = []
2402
2403 sources = lambda affected_file: input_api.FilterSourceFile(
2404 affected_file,
2405 black_list=(_EXCLUDED_PATHS +
2406 _TEST_CODE_EXCLUDED_PATHS +
2407 input_api.DEFAULT_BLACK_LIST +
2408 (r"^android_webview[\\/]support_library[\\/]"
2409 "boundary_interfaces[\\/]",
2410 r"^chrome[\\/]android[\\/]webapk[\\/].*",
2411 r'^third_party[\\/].*',
2412 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
2413 r"webview[\\/]chromium[\\/]License.*",)),
2414 white_list=[r'.*\.java$'])
2415
2416 for f in input_api.AffectedSourceFiles(sources):
2417 for line_num, line in f.ChangedContents():
2418 if build_type_check_pattern.search(line):
2419 errors.append("%s:%d" % (f.LocalPath(), line_num))
2420
2421 results = []
2422
2423 if errors:
2424 results.append(output_api.PresubmitPromptWarning(
2425 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
2426 ' Please use BuildInfo.isDebugAndroid() instead.',
2427 errors))
2428
2429 return results
jbriance9e12f162016-11-25 07:57:502430
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492431# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:292432def _CheckAndroidToastUsage(input_api, output_api):
2433 """Checks that code uses org.chromium.ui.widget.Toast instead of
2434 android.widget.Toast (Chromium Toast doesn't force hardware
2435 acceleration on low-end devices, saving memory).
2436 """
2437 toast_import_pattern = input_api.re.compile(
2438 r'^import android\.widget\.Toast;$')
2439
2440 errors = []
2441
2442 sources = lambda affected_file: input_api.FilterSourceFile(
2443 affected_file,
2444 black_list=(_EXCLUDED_PATHS +
2445 _TEST_CODE_EXCLUDED_PATHS +
2446 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042447 (r'^chromecast[\\/].*',
2448 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492449 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:292450
2451 for f in input_api.AffectedSourceFiles(sources):
2452 for line_num, line in f.ChangedContents():
2453 if toast_import_pattern.search(line):
2454 errors.append("%s:%d" % (f.LocalPath(), line_num))
2455
2456 results = []
2457
2458 if errors:
2459 results.append(output_api.PresubmitError(
2460 'android.widget.Toast usage is detected. Android toasts use hardware'
2461 ' acceleration, and can be\ncostly on low-end devices. Please use'
2462 ' org.chromium.ui.widget.Toast instead.\n'
2463 'Contact [email protected] if you have any questions.',
2464 errors))
2465
2466 return results
2467
2468
dgnaa68d5e2015-06-10 10:08:222469def _CheckAndroidCrLogUsage(input_api, output_api):
2470 """Checks that new logs using org.chromium.base.Log:
2471 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512472 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222473 """
pkotwicza1dd0b002016-05-16 14:41:042474
torne89540622017-03-24 19:41:302475 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042476 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302477 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:042478 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:302479 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:042480 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
2481 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:092482 # The customtabs_benchmark is a small app that does not depend on Chromium
2483 # java pieces.
Egor Paskoce145c42018-09-28 19:31:042484 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:042485 ]
2486
dgnaa68d5e2015-06-10 10:08:222487 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122488 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2489 class_in_base_pattern = input_api.re.compile(
2490 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2491 has_some_log_import_pattern = input_api.re.compile(
2492 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222493 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122494 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222495 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512496 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222497 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222498
Vincent Scheib16d7b272015-09-15 18:09:072499 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222500 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492501 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:042502 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122503
dgnaa68d5e2015-06-10 10:08:222504 tag_decl_errors = []
2505 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122506 tag_errors = []
dgn38736db2015-09-18 19:20:512507 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122508 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222509
2510 for f in input_api.AffectedSourceFiles(sources):
2511 file_content = input_api.ReadFile(f)
2512 has_modified_logs = False
2513
2514 # Per line checks
dgn87d9fb62015-06-12 09:15:122515 if (cr_log_import_pattern.search(file_content) or
2516 (class_in_base_pattern.search(file_content) and
2517 not has_some_log_import_pattern.search(file_content))):
2518 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222519 for line_num, line in f.ChangedContents():
2520
2521 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122522 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222523 if match:
2524 has_modified_logs = True
2525
2526 # Make sure it uses "TAG"
2527 if not match.group('tag') == 'TAG':
2528 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122529 else:
2530 # Report non cr Log function calls in changed lines
2531 for line_num, line in f.ChangedContents():
2532 if log_call_pattern.search(line):
2533 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222534
2535 # Per file checks
2536 if has_modified_logs:
2537 # Make sure the tag is using the "cr" prefix and is not too long
2538 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512539 tag_name = match.group('name') if match else None
2540 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222541 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512542 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222543 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512544 elif '.' in tag_name:
2545 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222546
2547 results = []
2548 if tag_decl_errors:
2549 results.append(output_api.PresubmitPromptWarning(
2550 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512551 '"private static final String TAG = "<package tag>".\n'
2552 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222553 tag_decl_errors))
2554
2555 if tag_length_errors:
2556 results.append(output_api.PresubmitError(
2557 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512558 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222559 tag_length_errors))
2560
2561 if tag_errors:
2562 results.append(output_api.PresubmitPromptWarning(
2563 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2564 tag_errors))
2565
dgn87d9fb62015-06-12 09:15:122566 if util_log_errors:
dgn4401aa52015-04-29 16:26:172567 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122568 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2569 util_log_errors))
2570
dgn38736db2015-09-18 19:20:512571 if tag_with_dot_errors:
2572 results.append(output_api.PresubmitPromptWarning(
2573 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2574 tag_with_dot_errors))
2575
dgn4401aa52015-04-29 16:26:172576 return results
2577
2578
Yoland Yanb92fa522017-08-28 17:37:062579def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2580 """Checks that junit.framework.* is no longer used."""
2581 deprecated_junit_framework_pattern = input_api.re.compile(
2582 r'^import junit\.framework\..*;',
2583 input_api.re.MULTILINE)
2584 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492585 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062586 errors = []
2587 for f in input_api.AffectedFiles(sources):
2588 for line_num, line in f.ChangedContents():
2589 if deprecated_junit_framework_pattern.search(line):
2590 errors.append("%s:%d" % (f.LocalPath(), line_num))
2591
2592 results = []
2593 if errors:
2594 results.append(output_api.PresubmitError(
2595 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2596 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2597 ' if you have any question.', errors))
2598 return results
2599
2600
2601def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2602 """Checks that if new Java test classes have inheritance.
2603 Either the new test class is JUnit3 test or it is a JUnit4 test class
2604 with a base class, either case is undesirable.
2605 """
2606 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2607
2608 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492609 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062610 errors = []
2611 for f in input_api.AffectedFiles(sources):
2612 if not f.OldContents():
2613 class_declaration_start_flag = False
2614 for line_num, line in f.ChangedContents():
2615 if class_declaration_pattern.search(line):
2616 class_declaration_start_flag = True
2617 if class_declaration_start_flag and ' extends ' in line:
2618 errors.append('%s:%d' % (f.LocalPath(), line_num))
2619 if '{' in line:
2620 class_declaration_start_flag = False
2621
2622 results = []
2623 if errors:
2624 results.append(output_api.PresubmitPromptWarning(
2625 'The newly created files include Test classes that inherits from base'
2626 ' class. Please do not use inheritance in JUnit4 tests or add new'
2627 ' JUnit3 tests. Contact [email protected] if you have any'
2628 ' questions.', errors))
2629 return results
2630
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202631
yolandyan45001472016-12-21 21:12:422632def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2633 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2634 deprecated_annotation_import_pattern = input_api.re.compile(
2635 r'^import android\.test\.suitebuilder\.annotation\..*;',
2636 input_api.re.MULTILINE)
2637 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492638 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:422639 errors = []
2640 for f in input_api.AffectedFiles(sources):
2641 for line_num, line in f.ChangedContents():
2642 if deprecated_annotation_import_pattern.search(line):
2643 errors.append("%s:%d" % (f.LocalPath(), line_num))
2644
2645 results = []
2646 if errors:
2647 results.append(output_api.PresubmitError(
2648 'Annotations in android.test.suitebuilder.annotation have been'
2649 ' deprecated since API level 24. Please use android.support.test.filters'
2650 ' from //third_party/android_support_test_runner:runner_java instead.'
2651 ' Contact [email protected] if you have any questions.', errors))
2652 return results
2653
2654
agrieve7b6479d82015-10-07 14:24:222655def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2656 """Checks if MDPI assets are placed in a correct directory."""
2657 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2658 ('/res/drawable/' in f.LocalPath() or
2659 '/res/drawable-ldrtl/' in f.LocalPath()))
2660 errors = []
2661 for f in input_api.AffectedFiles(include_deletes=False,
2662 file_filter=file_filter):
2663 errors.append(' %s' % f.LocalPath())
2664
2665 results = []
2666 if errors:
2667 results.append(output_api.PresubmitError(
2668 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2669 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2670 '/res/drawable-ldrtl/.\n'
2671 'Contact [email protected] if you have questions.', errors))
2672 return results
2673
2674
Nate Fischer535972b2017-09-16 01:06:182675def _CheckAndroidWebkitImports(input_api, output_api):
2676 """Checks that code uses org.chromium.base.Callback instead of
2677 android.widget.ValueCallback except in the WebView glue layer.
2678 """
2679 valuecallback_import_pattern = input_api.re.compile(
2680 r'^import android\.webkit\.ValueCallback;$')
2681
2682 errors = []
2683
2684 sources = lambda affected_file: input_api.FilterSourceFile(
2685 affected_file,
2686 black_list=(_EXCLUDED_PATHS +
2687 _TEST_CODE_EXCLUDED_PATHS +
2688 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042689 (r'^android_webview[\\/]glue[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492690 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:182691
2692 for f in input_api.AffectedSourceFiles(sources):
2693 for line_num, line in f.ChangedContents():
2694 if valuecallback_import_pattern.search(line):
2695 errors.append("%s:%d" % (f.LocalPath(), line_num))
2696
2697 results = []
2698
2699 if errors:
2700 results.append(output_api.PresubmitError(
2701 'android.webkit.ValueCallback usage is detected outside of the glue'
2702 ' layer. To stay compatible with the support library, android.webkit.*'
2703 ' classes should only be used inside the glue layer and'
2704 ' org.chromium.base.Callback should be used instead.',
2705 errors))
2706
2707 return results
2708
2709
Becky Zhou7c69b50992018-12-10 19:37:572710def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
2711 """Checks Android XML styles """
2712 import sys
2713 original_sys_path = sys.path
2714 try:
2715 sys.path = sys.path + [input_api.os_path.join(
2716 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
2717 import checkxmlstyle
2718 finally:
2719 # Restore sys.path to what it was before.
2720 sys.path = original_sys_path
2721
2722 if is_check_on_upload:
2723 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
2724 else:
2725 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
2726
2727
agrievef32bcc72016-04-04 14:57:402728class PydepsChecker(object):
2729 def __init__(self, input_api, pydeps_files):
2730 self._file_cache = {}
2731 self._input_api = input_api
2732 self._pydeps_files = pydeps_files
2733
2734 def _LoadFile(self, path):
2735 """Returns the list of paths within a .pydeps file relative to //."""
2736 if path not in self._file_cache:
2737 with open(path) as f:
2738 self._file_cache[path] = f.read()
2739 return self._file_cache[path]
2740
2741 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2742 """Returns an interable of paths within the .pydep, relativized to //."""
2743 os_path = self._input_api.os_path
2744 pydeps_dir = os_path.dirname(pydeps_path)
2745 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2746 if not l.startswith('*'))
2747 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2748
2749 def _CreateFilesToPydepsMap(self):
2750 """Returns a map of local_path -> list_of_pydeps."""
2751 ret = {}
2752 for pydep_local_path in self._pydeps_files:
2753 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2754 ret.setdefault(path, []).append(pydep_local_path)
2755 return ret
2756
2757 def ComputeAffectedPydeps(self):
2758 """Returns an iterable of .pydeps files that might need regenerating."""
2759 affected_pydeps = set()
2760 file_to_pydeps_map = None
2761 for f in self._input_api.AffectedFiles(include_deletes=True):
2762 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:462763 # Changes to DEPS can lead to .pydeps changes if any .py files are in
2764 # subrepositories. We can't figure out which files change, so re-check
2765 # all files.
2766 # Changes to print_python_deps.py affect all .pydeps.
2767 if local_path == 'DEPS' or local_path.endswith('print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:402768 return self._pydeps_files
2769 elif local_path.endswith('.pydeps'):
2770 if local_path in self._pydeps_files:
2771 affected_pydeps.add(local_path)
2772 elif local_path.endswith('.py'):
2773 if file_to_pydeps_map is None:
2774 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2775 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2776 return affected_pydeps
2777
2778 def DetermineIfStale(self, pydeps_path):
2779 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412780 import difflib
John Budorick47ca3fe2018-02-10 00:53:102781 import os
2782
agrievef32bcc72016-04-04 14:57:402783 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2784 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102785 env = dict(os.environ)
2786 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402787 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102788 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412789 old_contents = old_pydeps_data[2:]
2790 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402791 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412792 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402793
2794
2795def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2796 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402797 # This check is for Python dependency lists (.pydeps files), and involves
2798 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2799 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282800 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002801 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022802 # TODO(agrieve): Update when there's a better way to detect
2803 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402804 is_android = input_api.os_path.exists('third_party/android_tools')
2805 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2806 results = []
2807 # First, check for new / deleted .pydeps.
2808 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032809 # Check whether we are running the presubmit check for a file in src.
2810 # f.LocalPath is relative to repo (src, or internal repo).
2811 # os_path.exists is relative to src repo.
2812 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2813 # to src and we can conclude that the pydeps is in src.
2814 if input_api.os_path.exists(f.LocalPath()):
2815 if f.LocalPath().endswith('.pydeps'):
2816 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2817 results.append(output_api.PresubmitError(
2818 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2819 'remove %s' % f.LocalPath()))
2820 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2821 results.append(output_api.PresubmitError(
2822 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2823 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402824
2825 if results:
2826 return results
2827
2828 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2829
2830 for pydep_path in checker.ComputeAffectedPydeps():
2831 try:
phajdan.jr0d9878552016-11-04 10:49:412832 result = checker.DetermineIfStale(pydep_path)
2833 if result:
2834 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402835 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412836 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2837 'To regenerate, run:\n\n %s' %
2838 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402839 except input_api.subprocess.CalledProcessError as error:
2840 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2841 long_text=error.output)]
2842
2843 return results
2844
2845
glidere61efad2015-02-18 17:39:432846def _CheckSingletonInHeaders(input_api, output_api):
2847 """Checks to make sure no header files have |Singleton<|."""
2848 def FileFilter(affected_file):
2849 # It's ok for base/memory/singleton.h to have |Singleton<|.
2850 black_list = (_EXCLUDED_PATHS +
2851 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042852 (r"^base[\\/]memory[\\/]singleton\.h$",
2853 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:472854 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432855 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2856
sergeyu34d21222015-09-16 00:11:442857 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432858 files = []
2859 for f in input_api.AffectedSourceFiles(FileFilter):
2860 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2861 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2862 contents = input_api.ReadFile(f)
2863 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242864 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432865 pattern.search(line)):
2866 files.append(f)
2867 break
2868
2869 if files:
yolandyandaabc6d2016-04-18 18:29:392870 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442871 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432872 'Please move them to an appropriate source file so that the ' +
2873 'template gets instantiated in a single compilation unit.',
2874 files) ]
2875 return []
2876
2877
[email protected]fd20b902014-05-09 02:14:532878_DEPRECATED_CSS = [
2879 # Values
2880 ( "-webkit-box", "flex" ),
2881 ( "-webkit-inline-box", "inline-flex" ),
2882 ( "-webkit-flex", "flex" ),
2883 ( "-webkit-inline-flex", "inline-flex" ),
2884 ( "-webkit-min-content", "min-content" ),
2885 ( "-webkit-max-content", "max-content" ),
2886
2887 # Properties
2888 ( "-webkit-background-clip", "background-clip" ),
2889 ( "-webkit-background-origin", "background-origin" ),
2890 ( "-webkit-background-size", "background-size" ),
2891 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442892 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532893
2894 # Functions
2895 ( "-webkit-gradient", "gradient" ),
2896 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2897 ( "-webkit-linear-gradient", "linear-gradient" ),
2898 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2899 ( "-webkit-radial-gradient", "radial-gradient" ),
2900 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2901]
2902
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202903
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492904# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242905def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532906 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252907 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342908 documentation and iOS CSS for dom distiller
2909 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252910 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532911 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492912 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:252913 black_list = (_EXCLUDED_PATHS +
2914 _TEST_CODE_EXCLUDED_PATHS +
2915 input_api.DEFAULT_BLACK_LIST +
2916 (r"^chrome/common/extensions/docs",
2917 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342918 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442919 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252920 r"^native_client_sdk"))
2921 file_filter = lambda f: input_api.FilterSourceFile(
2922 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532923 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2924 for line_num, line in fpath.ChangedContents():
2925 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022926 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532927 results.append(output_api.PresubmitError(
2928 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2929 (fpath.LocalPath(), line_num, deprecated_value, value)))
2930 return results
2931
mohan.reddyf21db962014-10-16 12:26:472932
dbeam070cfe62014-10-22 06:44:022933_DEPRECATED_JS = [
2934 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2935 ( "__defineGetter__", "Object.defineProperty" ),
2936 ( "__defineSetter__", "Object.defineProperty" ),
2937]
2938
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202939
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492940# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242941def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022942 """Make sure that we don't use deprecated JS in Chrome code."""
2943 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492944 file_inclusion_pattern = [r".+\.js$"] # TODO(dbeam): .html?
dbeam070cfe62014-10-22 06:44:022945 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2946 input_api.DEFAULT_BLACK_LIST)
2947 file_filter = lambda f: input_api.FilterSourceFile(
2948 f, white_list=file_inclusion_pattern, black_list=black_list)
2949 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2950 for lnum, line in fpath.ChangedContents():
2951 for (deprecated, replacement) in _DEPRECATED_JS:
2952 if deprecated in line:
2953 results.append(output_api.PresubmitError(
2954 "%s:%d: Use of deprecated JS %s, use %s instead" %
2955 (fpath.LocalPath(), lnum, deprecated, replacement)))
2956 return results
2957
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202958
rlanday6802cf632017-05-30 17:48:362959def _CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:362960 bad_files = {}
2961 for f in input_api.AffectedFiles(include_deletes=False):
2962 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:492963 not f.LocalPath().startswith('third_party/blink') and
2964 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:362965 continue
2966
Daniel Bratell65b033262019-04-23 08:17:062967 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:362968 continue
2969
Vaclav Brozekd5de76a2018-03-17 07:57:502970 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362971 if "#include" in line and "../" in line]
2972 if not relative_includes:
2973 continue
2974 bad_files[f.LocalPath()] = relative_includes
2975
2976 if not bad_files:
2977 return []
2978
2979 error_descriptions = []
2980 for file_path, bad_lines in bad_files.iteritems():
2981 error_description = file_path
2982 for line in bad_lines:
2983 error_description += '\n ' + line
2984 error_descriptions.append(error_description)
2985
2986 results = []
2987 results.append(output_api.PresubmitError(
2988 'You added one or more relative #include paths (including "../").\n'
2989 'These shouldn\'t be used because they can be used to include headers\n'
2990 'from code that\'s not correctly specified as a dependency in the\n'
2991 'relevant BUILD.gn file(s).',
2992 error_descriptions))
2993
2994 return results
2995
Takeshi Yoshinoe387aa32017-08-02 13:16:132996
Daniel Bratell65b033262019-04-23 08:17:062997def _CheckForCcIncludes(input_api, output_api):
2998 """Check that nobody tries to include a cc file. It's a relatively
2999 common error which results in duplicate symbols in object
3000 files. This may not always break the build until someone later gets
3001 very confusing linking errors."""
3002 results = []
3003 for f in input_api.AffectedFiles(include_deletes=False):
3004 # We let third_party code do whatever it wants
3005 if (f.LocalPath().startswith('third_party') and
3006 not f.LocalPath().startswith('third_party/blink') and
3007 not f.LocalPath().startswith('third_party\\blink')):
3008 continue
3009
3010 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3011 continue
3012
3013 for _, line in f.ChangedContents():
3014 if line.startswith('#include "'):
3015 included_file = line.split('"')[1]
3016 if _IsCPlusPlusFile(input_api, included_file):
3017 # The most common naming for external files with C++ code,
3018 # apart from standard headers, is to call them foo.inc, but
3019 # Chromium sometimes uses foo-inc.cc so allow that as well.
3020 if not included_file.endswith(('.h', '-inc.cc')):
3021 results.append(output_api.PresubmitError(
3022 'Only header files or .inc files should be included in other\n'
3023 'C++ files. Compiling the contents of a cc file more than once\n'
3024 'will cause duplicate information in the build which may later\n'
3025 'result in strange link_errors.\n' +
3026 f.LocalPath() + ':\n ' +
3027 line))
3028
3029 return results
3030
3031
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203032def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3033 if not isinstance(key, ast.Str):
3034 return 'Key at line %d must be a string literal' % key.lineno
3035 if not isinstance(value, ast.Dict):
3036 return 'Value at line %d must be a dict' % value.lineno
3037 if len(value.keys) != 1:
3038 return 'Dict at line %d must have single entry' % value.lineno
3039 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3040 return (
3041 'Entry at line %d must have a string literal \'filepath\' as key' %
3042 value.lineno)
3043 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133044
Takeshi Yoshinoe387aa32017-08-02 13:16:133045
Sergey Ulanov4af16052018-11-08 02:41:463046def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203047 if not isinstance(key, ast.Str):
3048 return 'Key at line %d must be a string literal' % key.lineno
3049 if not isinstance(value, ast.List):
3050 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463051 for element in value.elts:
3052 if not isinstance(element, ast.Str):
3053 return 'Watchlist elements on line %d is not a string' % key.lineno
3054 if not email_regex.match(element.s):
3055 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3056 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203057 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133058
Takeshi Yoshinoe387aa32017-08-02 13:16:133059
Sergey Ulanov4af16052018-11-08 02:41:463060def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203061 mismatch_template = (
3062 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3063 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133064
Sergey Ulanov4af16052018-11-08 02:41:463065 email_regex = input_api.re.compile(
3066 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3067
3068 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203069 i = 0
3070 last_key = ''
3071 while True:
3072 if i >= len(wd_dict.keys):
3073 if i >= len(w_dict.keys):
3074 return None
3075 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3076 elif i >= len(w_dict.keys):
3077 return (
3078 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133079
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203080 wd_key = wd_dict.keys[i]
3081 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133082
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203083 result = _CheckWatchlistDefinitionsEntrySyntax(
3084 wd_key, wd_dict.values[i], ast)
3085 if result is not None:
3086 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133087
Sergey Ulanov4af16052018-11-08 02:41:463088 result = _CheckWatchlistsEntrySyntax(
3089 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203090 if result is not None:
3091 return 'Bad entry in WATCHLISTS dict: %s' % result
3092
3093 if wd_key.s != w_key.s:
3094 return mismatch_template % (
3095 '%s at line %d' % (wd_key.s, wd_key.lineno),
3096 '%s at line %d' % (w_key.s, w_key.lineno))
3097
3098 if wd_key.s < last_key:
3099 return (
3100 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3101 (wd_key.lineno, w_key.lineno))
3102 last_key = wd_key.s
3103
3104 i = i + 1
3105
3106
Sergey Ulanov4af16052018-11-08 02:41:463107def _CheckWATCHLISTSSyntax(expression, input_api):
3108 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203109 if not isinstance(expression, ast.Expression):
3110 return 'WATCHLISTS file must contain a valid expression'
3111 dictionary = expression.body
3112 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3113 return 'WATCHLISTS file must have single dict with exactly two entries'
3114
3115 first_key = dictionary.keys[0]
3116 first_value = dictionary.values[0]
3117 second_key = dictionary.keys[1]
3118 second_value = dictionary.values[1]
3119
3120 if (not isinstance(first_key, ast.Str) or
3121 first_key.s != 'WATCHLIST_DEFINITIONS' or
3122 not isinstance(first_value, ast.Dict)):
3123 return (
3124 'The first entry of the dict in WATCHLISTS file must be '
3125 'WATCHLIST_DEFINITIONS dict')
3126
3127 if (not isinstance(second_key, ast.Str) or
3128 second_key.s != 'WATCHLISTS' or
3129 not isinstance(second_value, ast.Dict)):
3130 return (
3131 'The second entry of the dict in WATCHLISTS file must be '
3132 'WATCHLISTS dict')
3133
Sergey Ulanov4af16052018-11-08 02:41:463134 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133135
3136
3137def _CheckWATCHLISTS(input_api, output_api):
3138 for f in input_api.AffectedFiles(include_deletes=False):
3139 if f.LocalPath() == 'WATCHLISTS':
3140 contents = input_api.ReadFile(f, 'r')
3141
3142 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203143 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133144 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203145 # Get an AST tree for it and scan the tree for detailed style checking.
3146 expression = input_api.ast.parse(
3147 contents, filename='WATCHLISTS', mode='eval')
3148 except ValueError as e:
3149 return [output_api.PresubmitError(
3150 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3151 except SyntaxError as e:
3152 return [output_api.PresubmitError(
3153 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3154 except TypeError as e:
3155 return [output_api.PresubmitError(
3156 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133157
Sergey Ulanov4af16052018-11-08 02:41:463158 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203159 if result is not None:
3160 return [output_api.PresubmitError(result)]
3161 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133162
3163 return []
3164
3165
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193166def _CheckNewHeaderWithoutGnChange(input_api, output_api):
3167 """Checks that newly added header files have corresponding GN changes.
3168 Note that this is only a heuristic. To be precise, run script:
3169 build/check_gn_headers.py.
3170 """
3171
3172 def headers(f):
3173 return input_api.FilterSourceFile(
3174 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
3175
3176 new_headers = []
3177 for f in input_api.AffectedSourceFiles(headers):
3178 if f.Action() != 'A':
3179 continue
3180 new_headers.append(f.LocalPath())
3181
3182 def gn_files(f):
3183 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
3184
3185 all_gn_changed_contents = ''
3186 for f in input_api.AffectedSourceFiles(gn_files):
3187 for _, line in f.ChangedContents():
3188 all_gn_changed_contents += line
3189
3190 problems = []
3191 for header in new_headers:
3192 basename = input_api.os_path.basename(header)
3193 if basename not in all_gn_changed_contents:
3194 problems.append(header)
3195
3196 if problems:
3197 return [output_api.PresubmitPromptWarning(
3198 'Missing GN changes for new header files', items=sorted(problems),
3199 long_text='Please double check whether newly added header files need '
3200 'corresponding changes in gn or gni files.\nThis checking is only a '
3201 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3202 'Read https://crbug.com/661774 for more info.')]
3203 return []
3204
3205
Michael Giuffridad3bc8672018-10-25 22:48:023206def _CheckCorrectProductNameInMessages(input_api, output_api):
3207 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
3208
3209 This assumes we won't intentionally reference one product from the other
3210 product.
3211 """
3212 all_problems = []
3213 test_cases = [{
3214 "filename_postfix": "google_chrome_strings.grd",
3215 "correct_name": "Chrome",
3216 "incorrect_name": "Chromium",
3217 }, {
3218 "filename_postfix": "chromium_strings.grd",
3219 "correct_name": "Chromium",
3220 "incorrect_name": "Chrome",
3221 }]
3222
3223 for test_case in test_cases:
3224 problems = []
3225 filename_filter = lambda x: x.LocalPath().endswith(
3226 test_case["filename_postfix"])
3227
3228 # Check each new line. Can yield false positives in multiline comments, but
3229 # easier than trying to parse the XML because messages can have nested
3230 # children, and associating message elements with affected lines is hard.
3231 for f in input_api.AffectedSourceFiles(filename_filter):
3232 for line_num, line in f.ChangedContents():
3233 if "<message" in line or "<!--" in line or "-->" in line:
3234 continue
3235 if test_case["incorrect_name"] in line:
3236 problems.append(
3237 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
3238
3239 if problems:
3240 message = (
3241 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
3242 % (test_case["correct_name"], test_case["correct_name"],
3243 test_case["incorrect_name"]))
3244 all_problems.append(
3245 output_api.PresubmitPromptWarning(message, items=problems))
3246
3247 return all_problems
3248
3249
Dirk Pranke3c18a382019-03-15 01:07:513250def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
3251 # TODO(crbug.com/941824): We need to make sure the entries in
3252 # //buildtools/DEPS are kept in sync with the entries in //DEPS
3253 # so that users of //buildtools in other projects get the same tooling
3254 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
3255 # support to gclient, we can eliminate the duplication and delete
3256 # this presubmit check.
3257
3258 # Update this regexp if new revisions are added to the files.
3259 rev_regexp = input_api.re.compile(
Dirk Pranke6d095b42019-03-15 23:44:013260 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:513261
3262 # If a user is changing one revision, they need to change the same
3263 # line in both files. This means that any given change should contain
3264 # exactly the same list of changed lines that match the regexps. The
3265 # replace(' ', '') call allows us to ignore whitespace changes to the
3266 # lines. The 'long_text' parameter to the error will contain the
3267 # list of changed lines in both files, which should make it easy enough
3268 # to spot the error without going overboard in this implementation.
3269 revs_changes = {
3270 'DEPS': {},
3271 'buildtools/DEPS': {},
3272 }
3273 long_text = ''
3274
3275 for f in input_api.AffectedFiles(
3276 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
3277 for line_num, line in f.ChangedContents():
3278 if rev_regexp.search(line):
3279 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
3280 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
3281
3282 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
3283 return [output_api.PresubmitError(
3284 'Change buildtools revisions in sync in both //DEPS and '
3285 '//buildtools/DEPS.', long_text=long_text + '\n')]
3286 else:
3287 return []
3288
3289
dgnaa68d5e2015-06-10 10:08:223290def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:573291 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:223292 results = []
dgnaa68d5e2015-06-10 10:08:223293 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:173294 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:223295 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:293296 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:063297 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
3298 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:423299 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:183300 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573301 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
3302 return results
3303
3304def _AndroidSpecificOnCommitChecks(input_api, output_api):
3305 """Groups commit checks that target android code."""
3306 results = []
3307 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:223308 return results
3309
3310
[email protected]22c9bd72011-03-27 16:47:393311def _CommonChecks(input_api, output_api):
3312 """Checks common to both upload and commit."""
3313 results = []
3314 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:383315 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:543316 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:083317
3318 author = input_api.change.author_email
3319 if author and author not in _KNOWN_ROBOTS:
3320 results.extend(
3321 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
3322
[email protected]55459852011-08-10 15:17:193323 results.extend(
[email protected]760deea2013-12-10 19:33:493324 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:233325 results.extend(
3326 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:543327 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:183328 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:343329 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:523330 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:223331 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:443332 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:593333 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:063334 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:123335 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:183336 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:223337 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:303338 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:493339 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:033340 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:493341 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:443342 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:273343 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:073344 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:543345 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:443346 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:393347 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:553348 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:043349 results.extend(
3350 input_api.canned_checks.CheckChangeHasNoTabs(
3351 input_api,
3352 output_api,
3353 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:403354 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:163355 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:083356 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:243357 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
3358 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:473359 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:043360 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:053361 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:143362 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:233363 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:433364 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:403365 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:153366 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:173367 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:503368 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:363369 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Daniel Bratell65b033262019-04-23 08:17:063370 results.extend(_CheckForCcIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:133371 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:433372 results.extend(input_api.RunTests(
3373 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143374 results.extend(_CheckTranslationScreenshots(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:023375 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:513376 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:243377
Vaclav Brozekcdc7defb2018-03-20 09:54:353378 for f in input_api.AffectedFiles():
3379 path, name = input_api.os_path.split(f.LocalPath())
3380 if name == 'PRESUBMIT.py':
3381 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:003382 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
3383 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:073384 # The PRESUBMIT.py file (and the directory containing it) might
3385 # have been affected by being moved or removed, so only try to
3386 # run the tests if they still exist.
3387 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
3388 input_api, output_api, full_path,
3389 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:393390 return results
[email protected]1f7b4172010-01-28 01:17:343391
[email protected]b337cb5b2011-01-23 21:24:053392
[email protected]b8079ae4a2012-12-05 19:56:493393def _CheckPatchFiles(input_api, output_api):
3394 problems = [f.LocalPath() for f in input_api.AffectedFiles()
3395 if f.LocalPath().endswith(('.orig', '.rej'))]
3396 if problems:
3397 return [output_api.PresubmitError(
3398 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:033399 else:
3400 return []
[email protected]b8079ae4a2012-12-05 19:56:493401
3402
Kent Tamura5a8755d2017-06-29 23:37:073403def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:213404 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
3405 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
3406 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:073407 include_re = input_api.re.compile(
3408 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
3409 extension_re = input_api.re.compile(r'\.[a-z]+$')
3410 errors = []
3411 for f in input_api.AffectedFiles():
3412 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
3413 continue
3414 found_line_number = None
3415 found_macro = None
3416 for line_num, line in f.ChangedContents():
3417 match = macro_re.search(line)
3418 if match:
3419 found_line_number = line_num
3420 found_macro = match.group(2)
3421 break
3422 if not found_line_number:
3423 continue
3424
3425 found_include = False
3426 for line in f.NewContents():
3427 if include_re.search(line):
3428 found_include = True
3429 break
3430 if found_include:
3431 continue
3432
3433 if not f.LocalPath().endswith('.h'):
3434 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
3435 try:
3436 content = input_api.ReadFile(primary_header_path, 'r')
3437 if include_re.search(content):
3438 continue
3439 except IOError:
3440 pass
3441 errors.append('%s:%d %s macro is used without including build/'
3442 'build_config.h.'
3443 % (f.LocalPath(), found_line_number, found_macro))
3444 if errors:
3445 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
3446 return []
3447
3448
[email protected]b00342e7f2013-03-26 16:21:543449def _DidYouMeanOSMacro(bad_macro):
3450 try:
3451 return {'A': 'OS_ANDROID',
3452 'B': 'OS_BSD',
3453 'C': 'OS_CHROMEOS',
3454 'F': 'OS_FREEBSD',
3455 'L': 'OS_LINUX',
3456 'M': 'OS_MACOSX',
3457 'N': 'OS_NACL',
3458 'O': 'OS_OPENBSD',
3459 'P': 'OS_POSIX',
3460 'S': 'OS_SOLARIS',
3461 'W': 'OS_WIN'}[bad_macro[3].upper()]
3462 except KeyError:
3463 return ''
3464
3465
3466def _CheckForInvalidOSMacrosInFile(input_api, f):
3467 """Check for sensible looking, totally invalid OS macros."""
3468 preprocessor_statement = input_api.re.compile(r'^\s*#')
3469 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
3470 results = []
3471 for lnum, line in f.ChangedContents():
3472 if preprocessor_statement.search(line):
3473 for match in os_macro.finditer(line):
3474 if not match.group(1) in _VALID_OS_MACROS:
3475 good = _DidYouMeanOSMacro(match.group(1))
3476 did_you_mean = ' (did you mean %s?)' % good if good else ''
3477 results.append(' %s:%d %s%s' % (f.LocalPath(),
3478 lnum,
3479 match.group(1),
3480 did_you_mean))
3481 return results
3482
3483
3484def _CheckForInvalidOSMacros(input_api, output_api):
3485 """Check all affected files for invalid OS macros."""
3486 bad_macros = []
tzik3f295992018-12-04 20:32:233487 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:473488 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:543489 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
3490
3491 if not bad_macros:
3492 return []
3493
3494 return [output_api.PresubmitError(
3495 'Possibly invalid OS macro[s] found. Please fix your code\n'
3496 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
3497
lliabraa35bab3932014-10-01 12:16:443498
3499def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
3500 """Check all affected files for invalid "if defined" macros."""
3501 ALWAYS_DEFINED_MACROS = (
3502 "TARGET_CPU_PPC",
3503 "TARGET_CPU_PPC64",
3504 "TARGET_CPU_68K",
3505 "TARGET_CPU_X86",
3506 "TARGET_CPU_ARM",
3507 "TARGET_CPU_MIPS",
3508 "TARGET_CPU_SPARC",
3509 "TARGET_CPU_ALPHA",
3510 "TARGET_IPHONE_SIMULATOR",
3511 "TARGET_OS_EMBEDDED",
3512 "TARGET_OS_IPHONE",
3513 "TARGET_OS_MAC",
3514 "TARGET_OS_UNIX",
3515 "TARGET_OS_WIN32",
3516 )
3517 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
3518 results = []
3519 for lnum, line in f.ChangedContents():
3520 for match in ifdef_macro.finditer(line):
3521 if match.group(1) in ALWAYS_DEFINED_MACROS:
3522 always_defined = ' %s is always defined. ' % match.group(1)
3523 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
3524 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
3525 lnum,
3526 always_defined,
3527 did_you_mean))
3528 return results
3529
3530
3531def _CheckForInvalidIfDefinedMacros(input_api, output_api):
3532 """Check all affected files for invalid "if defined" macros."""
3533 bad_macros = []
3534 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:213535 if f.LocalPath().startswith('third_party/sqlite/'):
3536 continue
lliabraa35bab3932014-10-01 12:16:443537 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3538 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3539
3540 if not bad_macros:
3541 return []
3542
3543 return [output_api.PresubmitError(
3544 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3545 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3546 bad_macros)]
3547
3548
mlamouria82272622014-09-16 18:45:043549def _CheckForIPCRules(input_api, output_api):
3550 """Check for same IPC rules described in
3551 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3552 """
3553 base_pattern = r'IPC_ENUM_TRAITS\('
3554 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3555 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3556
3557 problems = []
3558 for f in input_api.AffectedSourceFiles(None):
3559 local_path = f.LocalPath()
3560 if not local_path.endswith('.h'):
3561 continue
3562 for line_number, line in f.ChangedContents():
3563 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3564 problems.append(
3565 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3566
3567 if problems:
3568 return [output_api.PresubmitPromptWarning(
3569 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
3570 else:
3571 return []
3572
[email protected]b00342e7f2013-03-26 16:21:543573
Stephen Martinis97a394142018-06-07 23:06:053574def _CheckForLongPathnames(input_api, output_api):
3575 """Check to make sure no files being submitted have long paths.
3576 This causes issues on Windows.
3577 """
3578 problems = []
3579 for f in input_api.AffectedSourceFiles(None):
3580 local_path = f.LocalPath()
3581 # Windows has a path limit of 260 characters. Limit path length to 200 so
3582 # that we have some extra for the prefix on dev machines and the bots.
3583 if len(local_path) > 200:
3584 problems.append(local_path)
3585
3586 if problems:
3587 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
3588 else:
3589 return []
3590
3591
Daniel Bratell8ba52722018-03-02 16:06:143592def _CheckForIncludeGuards(input_api, output_api):
3593 """Check that header files have proper guards against multiple inclusion.
3594 If a file should not have such guards (and it probably should) then it
3595 should include the string "no-include-guard-because-multiply-included".
3596 """
Daniel Bratell6a75baef62018-06-04 10:04:453597 def is_chromium_header_file(f):
3598 # We only check header files under the control of the Chromium
3599 # project. That is, those outside third_party apart from
3600 # third_party/blink.
3601 file_with_path = input_api.os_path.normpath(f.LocalPath())
3602 return (file_with_path.endswith('.h') and
3603 (not file_with_path.startswith('third_party') or
3604 file_with_path.startswith(
3605 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:143606
3607 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:343608 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:143609
3610 errors = []
3611
Daniel Bratell6a75baef62018-06-04 10:04:453612 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:143613 guard_name = None
3614 guard_line_number = None
3615 seen_guard_end = False
3616
3617 file_with_path = input_api.os_path.normpath(f.LocalPath())
3618 base_file_name = input_api.os_path.splitext(
3619 input_api.os_path.basename(file_with_path))[0]
3620 upper_base_file_name = base_file_name.upper()
3621
3622 expected_guard = replace_special_with_underscore(
3623 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:143624
3625 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:573626 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
3627 # are too many (1000+) files with slight deviations from the
3628 # coding style. The most important part is that the include guard
3629 # is there, and that it's unique, not the name so this check is
3630 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:143631 #
3632 # As code becomes more uniform, this could be made stricter.
3633
3634 guard_name_pattern_list = [
3635 # Anything with the right suffix (maybe with an extra _).
3636 r'\w+_H__?',
3637
Daniel Bratell39b5b062018-05-16 18:09:573638 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:143639 r'\w+_h',
3640
3641 # Anything including the uppercase name of the file.
3642 r'\w*' + input_api.re.escape(replace_special_with_underscore(
3643 upper_base_file_name)) + r'\w*',
3644 ]
3645 guard_name_pattern = '|'.join(guard_name_pattern_list)
3646 guard_pattern = input_api.re.compile(
3647 r'#ifndef\s+(' + guard_name_pattern + ')')
3648
3649 for line_number, line in enumerate(f.NewContents()):
3650 if 'no-include-guard-because-multiply-included' in line:
3651 guard_name = 'DUMMY' # To not trigger check outside the loop.
3652 break
3653
3654 if guard_name is None:
3655 match = guard_pattern.match(line)
3656 if match:
3657 guard_name = match.group(1)
3658 guard_line_number = line_number
3659
Daniel Bratell39b5b062018-05-16 18:09:573660 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:453661 # don't match the chromium style guide, but new files should
3662 # get it right.
3663 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:573664 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:143665 errors.append(output_api.PresubmitPromptWarning(
3666 'Header using the wrong include guard name %s' % guard_name,
3667 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:573668 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:143669 else:
3670 # The line after #ifndef should have a #define of the same name.
3671 if line_number == guard_line_number + 1:
3672 expected_line = '#define %s' % guard_name
3673 if line != expected_line:
3674 errors.append(output_api.PresubmitPromptWarning(
3675 'Missing "%s" for include guard' % expected_line,
3676 ['%s:%d' % (f.LocalPath(), line_number + 1)],
3677 'Expected: %r\nGot: %r' % (expected_line, line)))
3678
3679 if not seen_guard_end and line == '#endif // %s' % guard_name:
3680 seen_guard_end = True
3681 elif seen_guard_end:
3682 if line.strip() != '':
3683 errors.append(output_api.PresubmitPromptWarning(
3684 'Include guard %s not covering the whole file' % (
3685 guard_name), [f.LocalPath()]))
3686 break # Nothing else to check and enough to warn once.
3687
3688 if guard_name is None:
3689 errors.append(output_api.PresubmitPromptWarning(
3690 'Missing include guard %s' % expected_guard,
3691 [f.LocalPath()],
3692 'Missing include guard in %s\n'
3693 'Recommended name: %s\n'
3694 'This check can be disabled by having the string\n'
3695 'no-include-guard-because-multiply-included in the header.' %
3696 (f.LocalPath(), expected_guard)))
3697
3698 return errors
3699
3700
mostynbb639aca52015-01-07 20:31:233701def _CheckForWindowsLineEndings(input_api, output_api):
3702 """Check source code and known ascii text files for Windows style line
3703 endings.
3704 """
earthdok1b5e0ee2015-03-10 15:19:103705 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233706
3707 file_inclusion_pattern = (
3708 known_text_files,
3709 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3710 )
3711
mostynbb639aca52015-01-07 20:31:233712 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533713 source_file_filter = lambda f: input_api.FilterSourceFile(
3714 f, white_list=file_inclusion_pattern, black_list=None)
3715 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503716 include_file = False
3717 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233718 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503719 include_file = True
3720 if include_file:
3721 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233722
3723 if problems:
3724 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3725 'these files to contain Windows style line endings?\n' +
3726 '\n'.join(problems))]
3727
3728 return []
3729
3730
Vaclav Brozekd5de76a2018-03-17 07:57:503731def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133732 """Checks that all source files use SYSLOG properly."""
3733 syslog_files = []
3734 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563735 for line_number, line in f.ChangedContents():
3736 if 'SYSLOG' in line:
3737 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3738
pastarmovj89f7ee12016-09-20 14:58:133739 if syslog_files:
3740 return [output_api.PresubmitPromptWarning(
3741 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3742 ' calls.\nFiles to check:\n', items=syslog_files)]
3743 return []
3744
3745
[email protected]1f7b4172010-01-28 01:17:343746def CheckChangeOnUpload(input_api, output_api):
3747 results = []
3748 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473749 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283750 results.extend(
jam93a6ee792017-02-08 23:59:223751 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193752 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223753 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133754 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163755 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:533756 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193757 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543758 return results
[email protected]ca8d1982009-02-19 16:33:123759
3760
[email protected]1bfb8322014-04-23 01:02:413761def GetTryServerMasterForBot(bot):
3762 """Returns the Try Server master for the given bot.
3763
[email protected]0bb112362014-07-26 04:38:323764 It tries to guess the master from the bot name, but may still fail
3765 and return None. There is no longer a default master.
3766 """
3767 # Potentially ambiguous bot names are listed explicitly.
3768 master_map = {
tandriie5587792016-07-14 00:34:503769 'chromium_presubmit': 'master.tryserver.chromium.linux',
3770 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413771 }
[email protected]0bb112362014-07-26 04:38:323772 master = master_map.get(bot)
3773 if not master:
wnwen4fbaab82016-05-25 12:54:363774 if 'android' in bot:
tandriie5587792016-07-14 00:34:503775 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363776 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503777 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323778 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503779 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323780 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503781 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323782 return master
[email protected]1bfb8322014-04-23 01:02:413783
3784
[email protected]ca8d1982009-02-19 16:33:123785def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543786 results = []
[email protected]1f7b4172010-01-28 01:17:343787 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573788 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543789 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273790 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343791 input_api,
3792 output_api,
[email protected]2fdd1f362013-01-16 03:56:033793 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273794
jam93a6ee792017-02-08 23:59:223795 results.extend(
3796 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543797 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3798 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413799 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3800 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543801 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143802
3803
3804def _CheckTranslationScreenshots(input_api, output_api):
3805 PART_FILE_TAG = "part"
3806 import os
3807 import sys
3808 from io import StringIO
3809
3810 try:
3811 old_sys_path = sys.path
3812 sys.path = sys.path + [input_api.os_path.join(
3813 input_api.PresubmitLocalPath(), 'tools', 'grit')]
3814 import grit.grd_reader
3815 import grit.node.message
3816 import grit.util
3817 finally:
3818 sys.path = old_sys_path
3819
3820 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
3821 """Load the grd file and return a dict of message ids to messages.
3822
3823 Ignores any nested grdp files pointed by <part> tag.
3824 """
3825 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
3826 stop_after=None, first_ids_file=None,
3827 debug=False, defines=None,
3828 tags_to_ignore=set([PART_FILE_TAG]))
3829 return {
3830 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
3831 grit.node.message.MessageNode)
3832 }
3833
3834 def _GetGrdpMessagesFromString(grdp_string):
3835 """Parses the contents of a grdp file given in grdp_string.
3836
3837 grd_reader can't parse grdp files directly. Instead, this creates a
3838 temporary directory with a grd file pointing to the grdp file, and loads the
3839 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
3840 """
3841 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
3842 <grit latest_public_release="1" current_release="1">
3843 <release seq="1">
3844 <messages>
3845 <part file="sub.grdp" />
3846 </messages>
3847 </release>
3848 </grit>
3849 """
3850 with grit.util.TempDir({'main.grd': WRAPPER,
3851 'sub.grdp': grdp_string}) as temp_dir:
3852 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
3853
3854 new_or_added_paths = set(f.LocalPath()
3855 for f in input_api.AffectedFiles()
3856 if (f.Action() == 'A' or f.Action() == 'M'))
3857 removed_paths = set(f.LocalPath()
3858 for f in input_api.AffectedFiles(include_deletes=True)
3859 if f.Action() == 'D')
3860
3861 affected_grds = [f for f in input_api.AffectedFiles()
3862 if (f.LocalPath().endswith('.grd') or
3863 f.LocalPath().endswith('.grdp'))]
3864 affected_png_paths = [f.AbsoluteLocalPath()
3865 for f in input_api.AffectedFiles()
3866 if (f.LocalPath().endswith('.png'))]
3867
3868 # Check for screenshots. Developers can upload screenshots using
3869 # tools/translation/upload_screenshots.py which finds and uploads
3870 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
3871 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
3872 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
3873 #
3874 # The logic here is as follows:
3875 #
3876 # - If the CL has a .png file under the screenshots directory for a grd
3877 # file, warn the developer. Actual images should never be checked into the
3878 # Chrome repo.
3879 #
3880 # - If the CL contains modified or new messages in grd files and doesn't
3881 # contain the corresponding .sha1 files, warn the developer to add images
3882 # and upload them via tools/translation/upload_screenshots.py.
3883 #
3884 # - If the CL contains modified or new messages in grd files and the
3885 # corresponding .sha1 files, everything looks good.
3886 #
3887 # - If the CL contains removed messages in grd files but the corresponding
3888 # .sha1 files aren't removed, warn the developer to remove them.
3889 unnecessary_screenshots = []
3890 missing_sha1 = []
3891 unnecessary_sha1_files = []
3892
3893
3894 def _CheckScreenshotAdded(screenshots_dir, message_id):
3895 sha1_path = input_api.os_path.join(
3896 screenshots_dir, message_id + '.png.sha1')
3897 if sha1_path not in new_or_added_paths:
3898 missing_sha1.append(sha1_path)
3899
3900
3901 def _CheckScreenshotRemoved(screenshots_dir, message_id):
3902 sha1_path = input_api.os_path.join(
3903 screenshots_dir, message_id + '.png.sha1')
3904 if sha1_path not in removed_paths:
3905 unnecessary_sha1_files.append(sha1_path)
3906
3907
3908 for f in affected_grds:
3909 file_path = f.LocalPath()
3910 old_id_to_msg_map = {}
3911 new_id_to_msg_map = {}
3912 if file_path.endswith('.grdp'):
3913 if f.OldContents():
3914 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393915 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143916 if f.NewContents():
3917 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393918 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143919 else:
3920 if f.OldContents():
3921 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393922 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143923 if f.NewContents():
3924 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393925 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143926
3927 # Compute added, removed and modified message IDs.
3928 old_ids = set(old_id_to_msg_map)
3929 new_ids = set(new_id_to_msg_map)
3930 added_ids = new_ids - old_ids
3931 removed_ids = old_ids - new_ids
3932 modified_ids = set([])
3933 for key in old_ids.intersection(new_ids):
3934 if (old_id_to_msg_map[key].FormatXml()
3935 != new_id_to_msg_map[key].FormatXml()):
3936 modified_ids.add(key)
3937
3938 grd_name, ext = input_api.os_path.splitext(
3939 input_api.os_path.basename(file_path))
3940 screenshots_dir = input_api.os_path.join(
3941 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
3942
3943 # Check the screenshot directory for .png files. Warn if there is any.
3944 for png_path in affected_png_paths:
3945 if png_path.startswith(screenshots_dir):
3946 unnecessary_screenshots.append(png_path)
3947
3948 for added_id in added_ids:
3949 _CheckScreenshotAdded(screenshots_dir, added_id)
3950
3951 for modified_id in modified_ids:
3952 _CheckScreenshotAdded(screenshots_dir, modified_id)
3953
3954 for removed_id in removed_ids:
3955 _CheckScreenshotRemoved(screenshots_dir, removed_id)
3956
3957 results = []
3958 if unnecessary_screenshots:
3959 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393960 'Do not include actual screenshots in the changelist. Run '
3961 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143962 sorted(unnecessary_screenshots)))
3963
3964 if missing_sha1:
3965 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393966 'You are adding or modifying UI strings.\n'
3967 'To ensure the best translations, take screenshots of the relevant UI '
3968 '(https://g.co/chrome/translation) and add these files to your '
3969 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143970
3971 if unnecessary_sha1_files:
3972 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393973 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143974 sorted(unnecessary_sha1_files)))
3975
3976 return results