blob: fd062ae6a930a8e9cf9c6cba179772ac04d85127 [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 (
Gabriel Charette147335ea2018-03-22 15:59:19594 r'RunMessageLoop',
595 (
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 (
714 'mojo::DataPipe',
715 (
716 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
717 ),
718 True,
719 (),
720 ),
[email protected]127f18ec2012-06-16 05:05:59721)
722
wnwenbdc444e2016-05-25 13:44:15723
mlamouria82272622014-09-16 18:45:04724_IPC_ENUM_TRAITS_DEPRECATED = (
725 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:50726 'See http://www.chromium.org/Home/chromium-security/education/'
727 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:04728
Stephen Martinis97a394142018-06-07 23:06:05729_LONG_PATH_ERROR = (
730 'Some files included in this CL have file names that are too long (> 200'
731 ' characters). If committed, these files will cause issues on Windows. See'
732 ' https://crbug.com/612667 for more details.'
733)
734
Shenghua Zhangbfaa38b82017-11-16 21:58:02735_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:04736 r".*[\\/]BuildHooksAndroidImpl\.java",
737 r".*[\\/]LicenseContentProvider\.java",
738 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:28739 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:02740]
[email protected]127f18ec2012-06-16 05:05:59741
Sean Kau46e29bc2017-08-28 16:31:16742# These paths contain test data and other known invalid JSON files.
743_KNOWN_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:04744 r'test[\\/]data[\\/]',
745 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
746 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:04747 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:43748 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:16749]
750
751
[email protected]b00342e7f2013-03-26 16:21:54752_VALID_OS_MACROS = (
753 # Please keep sorted.
rayb0088ee52017-04-26 22:35:08754 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:54755 'OS_ANDROID',
Henrique Nakashimaafff0502018-01-24 17:14:12756 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:54757 'OS_BSD',
758 'OS_CAT', # For testing.
759 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:04760 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:54761 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:37762 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:54763 'OS_IOS',
764 'OS_LINUX',
765 'OS_MACOSX',
766 'OS_NACL',
hidehikof7295f22014-10-28 11:57:21767 'OS_NACL_NONSFI',
768 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:12769 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:54770 'OS_OPENBSD',
771 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:37772 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:54773 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:54774 'OS_WIN',
775)
776
777
agrievef32bcc72016-04-04 14:57:40778_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Luob2e4b342018-09-20 19:32:39779 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36780 'base/android/jni_generator/jni_generator.pydeps',
781 'base/android/jni_generator/jni_registration_generator.pydeps',
Egor Pasko56273b52019-03-14 14:45:22782 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36783 'build/android/gyp/aar.pydeps',
784 'build/android/gyp/aidl.pydeps',
785 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:38786 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36787 'build/android/gyp/bytecode_processor.pydeps',
788 'build/android/gyp/compile_resources.pydeps',
Andrew Grievef89e926c2019-02-07 18:36:57789 'build/android/gyp/create_app_bundle_minimal_apks.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36790 'build/android/gyp/create_bundle_wrapper_script.pydeps',
791 'build/android/gyp/copy_ex.pydeps',
792 'build/android/gyp/create_app_bundle.pydeps',
793 'build/android/gyp/create_apk_operations_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36794 'build/android/gyp/create_java_binary_script.pydeps',
Andrew Grieveb838d832019-02-11 16:55:22795 'build/android/gyp/create_size_info_files.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36796 'build/android/gyp/create_stack_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36797 'build/android/gyp/create_tool_wrapper.pydeps',
798 'build/android/gyp/desugar.pydeps',
Sam Maier3599daa2018-11-26 18:02:59799 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36800 'build/android/gyp/dex.pydeps',
801 'build/android/gyp/dist_aar.pydeps',
802 'build/android/gyp/emma_instr.pydeps',
803 'build/android/gyp/filter_zip.pydeps',
804 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:36805 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36806 'build/android/gyp/ijar.pydeps',
807 'build/android/gyp/java_cpp_enum.pydeps',
Ian Vollickb99472e2019-03-07 21:35:26808 'build/android/gyp/java_cpp_strings.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36809 'build/android/gyp/javac.pydeps',
810 'build/android/gyp/jinja_template.pydeps',
811 'build/android/gyp/lint.pydeps',
812 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36813 'build/android/gyp/merge_manifest.pydeps',
814 'build/android/gyp/prepare_resources.pydeps',
815 'build/android/gyp/proguard.pydeps',
816 'build/android/gyp/write_build_config.pydeps',
817 'build/android/gyp/write_ordered_libraries.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:56818 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36819 'build/android/incremental_install/generate_android_manifest.pydeps',
820 'build/android/incremental_install/write_installer_json.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22821 'build/android/resource_sizes.pydeps',
agrievef32bcc72016-04-04 14:57:40822 'build/android/test_runner.pydeps',
hzl9b15df52017-03-23 23:43:04823 'build/android/test_wrapper/logdog_wrapper.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:36824 'build/protoc_java.pydeps',
agrieve732db3a2016-04-26 19:18:19825 'net/tools/testserver/testserver.pydeps',
Peter Wen22bc3ec2019-03-28 22:18:02826 'third_party/android_platform/development/scripts/stack.pydeps',
agrievef32bcc72016-04-04 14:57:40827]
828
wnwenbdc444e2016-05-25 13:44:15829
agrievef32bcc72016-04-04 14:57:40830_GENERIC_PYDEPS_FILES = [
John Chencde89192018-01-27 21:18:40831 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Cole Winstanley7045a1b2018-08-27 23:37:29832 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:22833 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:40834]
835
wnwenbdc444e2016-05-25 13:44:15836
agrievef32bcc72016-04-04 14:57:40837_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
838
839
Eric Boren6fd2b932018-01-25 15:05:08840# Bypass the AUTHORS check for these accounts.
841_KNOWN_ROBOTS = set(
Chan52654f52018-03-21 21:02:29842 '%s-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com' % s
843 for s in ('afdo', 'angle', 'catapult', 'chromite', 'depot-tools',
Eric Boren36af476a2018-06-08 16:21:08844 'fuchsia-sdk', 'nacl', 'pdfium', 'perfetto', 'skia',
Eric Boren57cc805b2018-08-20 17:28:32845 'spirv', 'src-internal', 'webrtc')
Sergiy Byelozyorov47158a52018-06-13 22:38:59846 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:45847 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:59848 ) | set('%[email protected]' % s
Robert Ma7f024172018-11-01 20:59:22849 for s in ('v8-ci-autoroll-builder', 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:04850 ) | set('%[email protected]' % s
851 for s in ('chromium-autoroll',)
852 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:30853 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:08854
855
[email protected]55459852011-08-10 15:17:19856def _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
857 """Attempts to prevent use of functions intended only for testing in
858 non-testing code. For now this is just a best-effort implementation
859 that ignores header files and may have some false positives. A
860 better implementation would probably need a proper C++ parser.
861 """
862 # We only scan .cc files and the like, as the declaration of
863 # for-testing functions in header files are hard to distinguish from
864 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49865 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:19866
jochenc0d4808c2015-07-27 09:25:42867 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:19868 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:09869 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
[email protected]55459852011-08-10 15:17:19870 exclusion_pattern = input_api.re.compile(
871 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
872 base_function_pattern, base_function_pattern))
873
874 def FilterFile(affected_file):
[email protected]06e6d0ff2012-12-11 01:36:44875 black_list = (_EXCLUDED_PATHS +
876 _TEST_CODE_EXCLUDED_PATHS +
877 input_api.DEFAULT_BLACK_LIST)
[email protected]55459852011-08-10 15:17:19878 return input_api.FilterSourceFile(
879 affected_file,
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49880 white_list=file_inclusion_pattern,
[email protected]55459852011-08-10 15:17:19881 black_list=black_list)
882
883 problems = []
884 for f in input_api.AffectedSourceFiles(FilterFile):
885 local_path = f.LocalPath()
[email protected]825d27182014-01-02 21:24:24886 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:03887 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:46888 not comment_pattern.search(line) and
[email protected]2fdd1f362013-01-16 03:56:03889 not exclusion_pattern.search(line)):
[email protected]55459852011-08-10 15:17:19890 problems.append(
[email protected]2fdd1f362013-01-16 03:56:03891 '%s:%d\n %s' % (local_path, line_number, line.strip()))
[email protected]55459852011-08-10 15:17:19892
893 if problems:
[email protected]f7051d52013-04-02 18:31:42894 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:03895 else:
896 return []
[email protected]55459852011-08-10 15:17:19897
898
Vaclav Brozek7dbc28c2018-03-27 08:35:23899def _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
900 """This is a simplified version of
901 _CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
902 """
903 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
904 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
905 name_pattern = r'ForTest(s|ing)?'
906 # Describes an occurrence of "ForTest*" inside a // comment.
907 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
908 # Catch calls.
909 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
910 # Ignore definitions. (Comments are ignored separately.)
911 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
912
913 problems = []
914 sources = lambda x: input_api.FilterSourceFile(
915 x,
916 black_list=(('(?i).*test', r'.*\/junit\/')
917 + input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:49918 white_list=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:23919 )
920 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
921 local_path = f.LocalPath()
922 is_inside_javadoc = False
923 for line_number, line in f.ChangedContents():
924 if is_inside_javadoc and javadoc_end_re.search(line):
925 is_inside_javadoc = False
926 if not is_inside_javadoc and javadoc_start_re.search(line):
927 is_inside_javadoc = True
928 if is_inside_javadoc:
929 continue
930 if (inclusion_re.search(line) and
931 not comment_re.search(line) and
932 not exclusion_re.search(line)):
933 problems.append(
934 '%s:%d\n %s' % (local_path, line_number, line.strip()))
935
936 if problems:
937 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
938 else:
939 return []
940
941
[email protected]10689ca2011-09-02 02:31:54942def _CheckNoIOStreamInHeaders(input_api, output_api):
943 """Checks to make sure no .h files include <iostream>."""
944 files = []
945 pattern = input_api.re.compile(r'^#include\s*<iostream>',
946 input_api.re.MULTILINE)
947 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
948 if not f.LocalPath().endswith('.h'):
949 continue
950 contents = input_api.ReadFile(f)
951 if pattern.search(contents):
952 files.append(f)
953
954 if len(files):
yolandyandaabc6d2016-04-18 18:29:39955 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:06956 'Do not #include <iostream> in header files, since it inserts static '
957 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:54958 '#include <ostream>. See http://crbug.com/94794',
959 files) ]
960 return []
961
Danil Chapovalov3518f362018-08-11 16:13:43962def _CheckNoStrCatRedefines(input_api, output_api):
963 """Checks no windows headers with StrCat redefined are included directly."""
964 files = []
965 pattern_deny = input_api.re.compile(
966 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
967 input_api.re.MULTILINE)
968 pattern_allow = input_api.re.compile(
969 r'^#include\s"base/win/windows_defines.inc"',
970 input_api.re.MULTILINE)
971 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
972 contents = input_api.ReadFile(f)
973 if pattern_deny.search(contents) and not pattern_allow.search(contents):
974 files.append(f.LocalPath())
975
976 if len(files):
977 return [output_api.PresubmitError(
978 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
979 'directly since they pollute code with StrCat macro. Instead, '
980 'include matching header from base/win. See http://crbug.com/856536',
981 files) ]
982 return []
983
[email protected]10689ca2011-09-02 02:31:54984
[email protected]72df4e782012-06-21 16:28:18985def _CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:52986 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:18987 problems = []
988 for f in input_api.AffectedFiles():
989 if (not f.LocalPath().endswith(('.cc', '.mm'))):
990 continue
991
992 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:04993 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:18994 problems.append(' %s:%d' % (f.LocalPath(), line_num))
995
996 if not problems:
997 return []
998 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
999 '\n'.join(problems))]
1000
Dominic Battre033531052018-09-24 15:45:341001def _CheckNoDISABLETypoInTests(input_api, output_api):
1002 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1003
1004 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1005 instead of DISABLED_. To filter false positives, reports are only generated
1006 if a corresponding MAYBE_ line exists.
1007 """
1008 problems = []
1009
1010 # The following two patterns are looked for in tandem - is a test labeled
1011 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1012 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1013 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1014
1015 # This is for the case that a test is disabled on all platforms.
1016 full_disable_pattern = input_api.re.compile(
1017 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1018 input_api.re.MULTILINE)
1019
Katie Df13948e2018-09-25 07:33:441020 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341021 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1022 continue
1023
1024 # Search for MABYE_, DISABLE_ pairs.
1025 disable_lines = {} # Maps of test name to line number.
1026 maybe_lines = {}
1027 for line_num, line in f.ChangedContents():
1028 disable_match = disable_pattern.search(line)
1029 if disable_match:
1030 disable_lines[disable_match.group(1)] = line_num
1031 maybe_match = maybe_pattern.search(line)
1032 if maybe_match:
1033 maybe_lines[maybe_match.group(1)] = line_num
1034
1035 # Search for DISABLE_ occurrences within a TEST() macro.
1036 disable_tests = set(disable_lines.keys())
1037 maybe_tests = set(maybe_lines.keys())
1038 for test in disable_tests.intersection(maybe_tests):
1039 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1040
1041 contents = input_api.ReadFile(f)
1042 full_disable_match = full_disable_pattern.search(contents)
1043 if full_disable_match:
1044 problems.append(' %s' % f.LocalPath())
1045
1046 if not problems:
1047 return []
1048 return [
1049 output_api.PresubmitPromptWarning(
1050 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1051 '\n'.join(problems))
1052 ]
1053
[email protected]72df4e782012-06-21 16:28:181054
danakj61c1aa22015-10-26 19:55:521055def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571056 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521057 errors = []
1058 pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
1059 input_api.re.MULTILINE)
1060 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1061 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1062 continue
1063 for lnum, line in f.ChangedContents():
1064 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171065 errors.append(output_api.PresubmitError(
1066 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571067 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171068 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521069 return errors
1070
1071
mcasasb7440c282015-02-04 14:52:191072def _FindHistogramNameInLine(histogram_name, line):
1073 """Tries to find a histogram name or prefix in a line."""
1074 if not "affected-histogram" in line:
1075 return histogram_name in line
1076 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1077 # the histogram_name.
1078 if not '"' in line:
1079 return False
1080 histogram_prefix = line.split('\"')[1]
1081 return histogram_prefix in histogram_name
1082
1083
1084def _CheckUmaHistogramChanges(input_api, output_api):
1085 """Check that UMA histogram names in touched lines can still be found in other
1086 lines of the patch or in histograms.xml. Note that this check would not catch
1087 the reverse: changes in histograms.xml not matched in the code itself."""
1088 touched_histograms = []
1089 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471090 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1091 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1092 name_pattern = r'"(.*?)"'
1093 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1094 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1095 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1096 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1097 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171098 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191099 for f in input_api.AffectedFiles():
1100 # If histograms.xml itself is modified, keep the modified lines for later.
1101 if f.LocalPath().endswith(('histograms.xml')):
1102 histograms_xml_modifications = f.ChangedContents()
1103 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471104 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1105 single_line_re = single_line_c_re
1106 split_line_prefix_re = split_line_c_prefix_re
1107 elif f.LocalPath().endswith(('java')):
1108 single_line_re = single_line_java_re
1109 split_line_prefix_re = split_line_java_prefix_re
1110 else:
mcasasb7440c282015-02-04 14:52:191111 continue
1112 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171113 if last_line_matched_prefix:
1114 suffix_found = split_line_suffix_re.search(line)
1115 if suffix_found :
1116 touched_histograms.append([suffix_found.group(1), f, line_num])
1117 last_line_matched_prefix = False
1118 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061119 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191120 if found:
1121 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171122 continue
1123 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191124
1125 # Search for the touched histogram names in the local modifications to
1126 # histograms.xml, and, if not found, on the base histograms.xml file.
1127 unmatched_histograms = []
1128 for histogram_info in touched_histograms:
1129 histogram_name_found = False
1130 for line_num, line in histograms_xml_modifications:
1131 histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
1132 if histogram_name_found:
1133 break
1134 if not histogram_name_found:
1135 unmatched_histograms.append(histogram_info)
1136
eromanb90c82e7e32015-04-01 15:13:491137 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191138 problems = []
1139 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491140 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191141 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451142 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191143 histogram_name_found = False
1144 for line in histograms_xml:
1145 histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
1146 if histogram_name_found:
1147 break
1148 if not histogram_name_found:
1149 problems.append(' [%s:%d] %s' %
1150 (f.LocalPath(), line_num, histogram_name))
1151
1152 if not problems:
1153 return []
1154 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1155 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491156 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191157
wnwenbdc444e2016-05-25 13:44:151158
yolandyandaabc6d2016-04-18 18:29:391159def _CheckFlakyTestUsage(input_api, output_api):
1160 """Check that FlakyTest annotation is our own instead of the android one"""
1161 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1162 files = []
1163 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1164 if f.LocalPath().endswith('Test.java'):
1165 if pattern.search(input_api.ReadFile(f)):
1166 files.append(f)
1167 if len(files):
1168 return [output_api.PresubmitError(
1169 'Use org.chromium.base.test.util.FlakyTest instead of '
1170 'android.test.FlakyTest',
1171 files)]
1172 return []
mcasasb7440c282015-02-04 14:52:191173
wnwenbdc444e2016-05-25 13:44:151174
[email protected]8ea5d4b2011-09-13 21:49:221175def _CheckNoNewWStrings(input_api, output_api):
1176 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271177 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221178 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201179 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571180 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341181 '/win/' in f.LocalPath() or
1182 'chrome_elf' in f.LocalPath() or
1183 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201184 continue
[email protected]8ea5d4b2011-09-13 21:49:221185
[email protected]a11dbe9b2012-08-07 01:32:581186 allowWString = False
[email protected]b5c24292011-11-28 14:38:201187 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581188 if 'presubmit: allow wstring' in line:
1189 allowWString = True
1190 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271191 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581192 allowWString = False
1193 else:
1194 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221195
[email protected]55463aa62011-10-12 00:48:271196 if not problems:
1197 return []
1198 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581199 ' If you are calling a cross-platform API that accepts a wstring, '
1200 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271201 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221202
1203
[email protected]2a8ac9c2011-10-19 17:20:441204def _CheckNoDEPSGIT(input_api, output_api):
1205 """Make sure .DEPS.git is never modified manually."""
1206 if any(f.LocalPath().endswith('.DEPS.git') for f in
1207 input_api.AffectedFiles()):
1208 return [output_api.PresubmitError(
1209 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1210 'automated system based on what\'s in DEPS and your changes will be\n'
1211 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501212 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1213 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441214 'for more information')]
1215 return []
1216
1217
tandriief664692014-09-23 14:51:471218def _CheckValidHostsInDEPS(input_api, output_api):
1219 """Checks that DEPS file deps are from allowed_hosts."""
1220 # Run only if DEPS file has been modified to annoy fewer bystanders.
1221 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1222 return []
1223 # Outsource work to gclient verify
1224 try:
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201225 input_api.subprocess.check_output(['gclient', 'verify'],
1226 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471227 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201228 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471229 return [output_api.PresubmitError(
1230 'DEPS file must have only git dependencies.',
1231 long_text=error.output)]
1232
1233
[email protected]127f18ec2012-06-16 05:05:591234def _CheckNoBannedFunctions(input_api, output_api):
1235 """Make sure that banned functions are not used."""
1236 warnings = []
1237 errors = []
1238
wnwenbdc444e2016-05-25 13:44:151239 def IsBlacklisted(affected_file, blacklist):
1240 local_path = affected_file.LocalPath()
1241 for item in blacklist:
1242 if input_api.re.match(item, local_path):
1243 return True
1244 return False
1245
Sylvain Defresnea8b73d252018-02-28 15:45:541246 def IsIosObcjFile(affected_file):
1247 local_path = affected_file.LocalPath()
1248 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1249 return False
1250 basename = input_api.os_path.basename(local_path)
1251 if 'ios' in basename.split('_'):
1252 return True
1253 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1254 if sep and 'ios' in local_path.split(sep):
1255 return True
1256 return False
1257
wnwenbdc444e2016-05-25 13:44:151258 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
1259 matched = False
1260 if func_name[0:1] == '/':
1261 regex = func_name[1:]
1262 if input_api.re.search(regex, line):
1263 matched = True
1264 elif func_name in line:
dchenge07de812016-06-20 19:27:171265 matched = True
wnwenbdc444e2016-05-25 13:44:151266 if matched:
dchenge07de812016-06-20 19:27:171267 problems = warnings
wnwenbdc444e2016-05-25 13:44:151268 if error:
dchenge07de812016-06-20 19:27:171269 problems = errors
wnwenbdc444e2016-05-25 13:44:151270 problems.append(' %s:%d:' % (affected_file.LocalPath(), line_num))
1271 for message_line in message:
1272 problems.append(' %s' % message_line)
1273
Eric Stevensona9a980972017-09-23 00:04:411274 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1275 for f in input_api.AffectedFiles(file_filter=file_filter):
1276 for line_num, line in f.ChangedContents():
1277 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1278 CheckForMatch(f, line_num, line, func_name, message, error)
1279
[email protected]127f18ec2012-06-16 05:05:591280 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1281 for f in input_api.AffectedFiles(file_filter=file_filter):
1282 for line_num, line in f.ChangedContents():
1283 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151284 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591285
Sylvain Defresnea8b73d252018-02-28 15:45:541286 for f in input_api.AffectedFiles(file_filter=IsIosObcjFile):
1287 for line_num, line in f.ChangedContents():
1288 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1289 CheckForMatch(f, line_num, line, func_name, message, error)
1290
[email protected]127f18ec2012-06-16 05:05:591291 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1292 for f in input_api.AffectedFiles(file_filter=file_filter):
1293 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491294 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
[email protected]7345da02012-11-27 14:31:491295 if IsBlacklisted(f, excluded_paths):
1296 continue
wnwenbdc444e2016-05-25 13:44:151297 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591298
1299 result = []
1300 if (warnings):
1301 result.append(output_api.PresubmitPromptWarning(
1302 'Banned functions were used.\n' + '\n'.join(warnings)))
1303 if (errors):
1304 result.append(output_api.PresubmitError(
1305 'Banned functions were used.\n' + '\n'.join(errors)))
1306 return result
1307
1308
[email protected]6c063c62012-07-11 19:11:061309def _CheckNoPragmaOnce(input_api, output_api):
1310 """Make sure that banned functions are not used."""
1311 files = []
1312 pattern = input_api.re.compile(r'^#pragma\s+once',
1313 input_api.re.MULTILINE)
1314 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1315 if not f.LocalPath().endswith('.h'):
1316 continue
1317 contents = input_api.ReadFile(f)
1318 if pattern.search(contents):
1319 files.append(f)
1320
1321 if files:
1322 return [output_api.PresubmitError(
1323 'Do not use #pragma once in header files.\n'
1324 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
1325 files)]
1326 return []
1327
[email protected]127f18ec2012-06-16 05:05:591328
[email protected]e7479052012-09-19 00:26:121329def _CheckNoTrinaryTrueFalse(input_api, output_api):
1330 """Checks to make sure we don't introduce use of foo ? true : false."""
1331 problems = []
1332 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
1333 for f in input_api.AffectedFiles():
1334 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1335 continue
1336
1337 for line_num, line in f.ChangedContents():
1338 if pattern.match(line):
1339 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1340
1341 if not problems:
1342 return []
1343 return [output_api.PresubmitPromptWarning(
1344 'Please consider avoiding the "? true : false" pattern if possible.\n' +
1345 '\n'.join(problems))]
1346
1347
[email protected]55f9f382012-07-31 11:02:181348def _CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:281349 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:181350 change. Breaking - rules is an error, breaking ! rules is a
1351 warning.
1352 """
mohan.reddyf21db962014-10-16 12:26:471353 import sys
[email protected]55f9f382012-07-31 11:02:181354 # We need to wait until we have an input_api object and use this
1355 # roundabout construct to import checkdeps because this file is
1356 # eval-ed and thus doesn't have __file__.
1357 original_sys_path = sys.path
1358 try:
1359 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:471360 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:181361 import checkdeps
1362 from cpp_checker import CppChecker
Jinsuk Kim5a092672017-10-24 22:42:241363 from java_checker import JavaChecker
rhalavati08acd232017-04-03 07:23:281364 from proto_checker import ProtoChecker
[email protected]55f9f382012-07-31 11:02:181365 from rules import Rule
1366 finally:
1367 # Restore sys.path to what it was before.
1368 sys.path = original_sys_path
1369
1370 added_includes = []
rhalavati08acd232017-04-03 07:23:281371 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:241372 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:181373 for f in input_api.AffectedFiles():
rhalavati08acd232017-04-03 07:23:281374 if CppChecker.IsCppFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501375 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081376 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
rhalavati08acd232017-04-03 07:23:281377 elif ProtoChecker.IsProtoFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501378 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081379 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Jinsuk Kim5a092672017-10-24 22:42:241380 elif JavaChecker.IsJavaFile(f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:501381 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:081382 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:181383
[email protected]26385172013-05-09 23:11:351384 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181385
1386 error_descriptions = []
1387 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:281388 error_subjects = set()
1389 warning_subjects = set()
[email protected]55f9f382012-07-31 11:02:181390 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
1391 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:081392 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:181393 description_with_path = '%s\n %s' % (path, rule_description)
1394 if rule_type == Rule.DISALLOW:
1395 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281396 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:181397 else:
1398 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:281399 warning_subjects.add("#includes")
1400
1401 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
1402 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:081403 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:281404 description_with_path = '%s\n %s' % (path, rule_description)
1405 if rule_type == Rule.DISALLOW:
1406 error_descriptions.append(description_with_path)
1407 error_subjects.add("imports")
1408 else:
1409 warning_descriptions.append(description_with_path)
1410 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:181411
Jinsuk Kim5a092672017-10-24 22:42:241412 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:021413 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:081414 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:241415 description_with_path = '%s\n %s' % (path, rule_description)
1416 if rule_type == Rule.DISALLOW:
1417 error_descriptions.append(description_with_path)
1418 error_subjects.add("imports")
1419 else:
1420 warning_descriptions.append(description_with_path)
1421 warning_subjects.add("imports")
1422
[email protected]55f9f382012-07-31 11:02:181423 results = []
1424 if error_descriptions:
1425 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:281426 'You added one or more %s that violate checkdeps rules.'
1427 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:181428 error_descriptions))
1429 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:421430 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:281431 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:181432 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:281433 '%s? See relevant DEPS file(s) for details and contacts.' %
1434 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:181435 warning_descriptions))
1436 return results
1437
1438
[email protected]fbcafe5a2012-08-08 15:31:221439def _CheckFilePermissions(input_api, output_api):
1440 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:151441 if input_api.platform == 'win32':
1442 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:291443 checkperms_tool = input_api.os_path.join(
1444 input_api.PresubmitLocalPath(),
1445 'tools', 'checkperms', 'checkperms.py')
1446 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:471447 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:391448 with input_api.CreateTemporaryFile() as file_list:
1449 for f in input_api.AffectedFiles():
1450 # checkperms.py file/directory arguments must be relative to the
1451 # repository.
1452 file_list.write(f.LocalPath() + '\n')
1453 file_list.close()
1454 args += ['--file-list', file_list.name]
1455 try:
1456 input_api.subprocess.check_output(args)
1457 return []
1458 except input_api.subprocess.CalledProcessError as error:
1459 return [output_api.PresubmitError(
1460 'checkperms.py failed:',
1461 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:221462
1463
robertocn832f5992017-01-04 19:01:301464def _CheckTeamTags(input_api, output_api):
1465 """Checks that OWNERS files have consistent TEAM and COMPONENT tags."""
1466 checkteamtags_tool = input_api.os_path.join(
1467 input_api.PresubmitLocalPath(),
1468 'tools', 'checkteamtags', 'checkteamtags.py')
1469 args = [input_api.python_executable, checkteamtags_tool,
1470 '--root', input_api.change.RepositoryRoot()]
robertocn5eb82312017-01-09 20:27:221471 files = [f.LocalPath() for f in input_api.AffectedFiles(include_deletes=False)
robertocn832f5992017-01-04 19:01:301472 if input_api.os_path.basename(f.AbsoluteLocalPath()).upper() ==
1473 'OWNERS']
1474 try:
1475 if files:
1476 input_api.subprocess.check_output(args + files)
1477 return []
1478 except input_api.subprocess.CalledProcessError as error:
1479 return [output_api.PresubmitError(
1480 'checkteamtags.py failed:',
1481 long_text=error.output)]
1482
1483
[email protected]c8278b32012-10-30 20:35:491484def _CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
1485 """Makes sure we don't include ui/aura/window_property.h
1486 in header files.
1487 """
1488 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
1489 errors = []
1490 for f in input_api.AffectedFiles():
1491 if not f.LocalPath().endswith('.h'):
1492 continue
1493 for line_num, line in f.ChangedContents():
1494 if pattern.match(line):
1495 errors.append(' %s:%d' % (f.LocalPath(), line_num))
1496
1497 results = []
1498 if errors:
1499 results.append(output_api.PresubmitError(
1500 'Header files should not include ui/aura/window_property.h', errors))
1501 return results
1502
1503
[email protected]70ca77752012-11-20 03:45:031504def _CheckForVersionControlConflictsInFile(input_api, f):
1505 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
1506 errors = []
1507 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:161508 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:231509 # First-level headers in markdown look a lot like version control
1510 # conflict markers. http://daringfireball.net/projects/markdown/basics
1511 continue
[email protected]70ca77752012-11-20 03:45:031512 if pattern.match(line):
1513 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1514 return errors
1515
1516
1517def _CheckForVersionControlConflicts(input_api, output_api):
1518 """Usually this is not intentional and will cause a compile failure."""
1519 errors = []
1520 for f in input_api.AffectedFiles():
1521 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
1522
1523 results = []
1524 if errors:
1525 results.append(output_api.PresubmitError(
1526 'Version control conflict markers found, please resolve.', errors))
1527 return results
1528
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201529
estadee17314a02017-01-12 16:22:161530def _CheckGoogleSupportAnswerUrl(input_api, output_api):
1531 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
1532 errors = []
1533 for f in input_api.AffectedFiles():
1534 for line_num, line in f.ChangedContents():
1535 if pattern.search(line):
1536 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
1537
1538 results = []
1539 if errors:
1540 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:501541 'Found Google support URL addressed by answer number. Please replace '
1542 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:161543 return results
1544
[email protected]70ca77752012-11-20 03:45:031545
[email protected]06e6d0ff2012-12-11 01:36:441546def _CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
1547 def FilterFile(affected_file):
1548 """Filter function for use with input_api.AffectedSourceFiles,
1549 below. This filters out everything except non-test files from
1550 top-level directories that generally speaking should not hard-code
1551 service URLs (e.g. src/android_webview/, src/content/ and others).
1552 """
1553 return input_api.FilterSourceFile(
1554 affected_file,
Egor Paskoce145c42018-09-28 19:31:041555 white_list=[r'^(android_webview|base|content|net)[\\/].*'],
[email protected]06e6d0ff2012-12-11 01:36:441556 black_list=(_EXCLUDED_PATHS +
1557 _TEST_CODE_EXCLUDED_PATHS +
1558 input_api.DEFAULT_BLACK_LIST))
1559
reillyi38965732015-11-16 18:27:331560 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
1561 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:461562 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
1563 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:441564 problems = [] # items are (filename, line_number, line)
1565 for f in input_api.AffectedSourceFiles(FilterFile):
1566 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:461567 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:441568 problems.append((f.LocalPath(), line_num, line))
1569
1570 if problems:
[email protected]f7051d52013-04-02 18:31:421571 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:441572 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:581573 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:441574 [' %s:%d: %s' % (
1575 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:031576 else:
1577 return []
[email protected]06e6d0ff2012-12-11 01:36:441578
1579
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491580# TODO: add unit tests.
[email protected]d2530012013-01-25 16:39:271581def _CheckNoAbbreviationInPngFileName(input_api, output_api):
1582 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:311583 The native_client_sdk directory is excluded because it has auto-generated PNG
1584 files for documentation.
[email protected]d2530012013-01-25 16:39:271585 """
[email protected]d2530012013-01-25 16:39:271586 errors = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491587 white_list = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
Egor Paskoce145c42018-09-28 19:31:041588 black_list = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:311589 file_filter = lambda f: input_api.FilterSourceFile(
1590 f, white_list=white_list, black_list=black_list)
1591 for f in input_api.AffectedFiles(include_deletes=False,
1592 file_filter=file_filter):
1593 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:271594
1595 results = []
1596 if errors:
1597 results.append(output_api.PresubmitError(
1598 'The name of PNG files should not have abbreviations. \n'
1599 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
1600 'Contact [email protected] if you have questions.', errors))
1601 return results
1602
1603
Daniel Cheng4dcdb6b2017-04-13 08:30:171604def _ExtractAddRulesFromParsedDeps(parsed_deps):
1605 """Extract the rules that add dependencies from a parsed DEPS file.
1606
1607 Args:
1608 parsed_deps: the locals dictionary from evaluating the DEPS file."""
1609 add_rules = set()
1610 add_rules.update([
1611 rule[1:] for rule in parsed_deps.get('include_rules', [])
1612 if rule.startswith('+') or rule.startswith('!')
1613 ])
Vaclav Brozekd5de76a2018-03-17 07:57:501614 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:171615 {}).iteritems():
1616 add_rules.update([
1617 rule[1:] for rule in rules
1618 if rule.startswith('+') or rule.startswith('!')
1619 ])
1620 return add_rules
1621
1622
1623def _ParseDeps(contents):
1624 """Simple helper for parsing DEPS files."""
1625 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:171626 class _VarImpl:
1627
1628 def __init__(self, local_scope):
1629 self._local_scope = local_scope
1630
1631 def Lookup(self, var_name):
1632 """Implements the Var syntax."""
1633 try:
1634 return self._local_scope['vars'][var_name]
1635 except KeyError:
1636 raise Exception('Var is not defined: %s' % var_name)
1637
1638 local_scope = {}
1639 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:171640 'Var': _VarImpl(local_scope).Lookup,
1641 }
1642 exec contents in global_scope, local_scope
1643 return local_scope
1644
1645
1646def _CalculateAddedDeps(os_path, old_contents, new_contents):
[email protected]f32e2d1e2013-07-26 21:39:081647 """Helper method for _CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:411648 a set of DEPS entries that we should look up.
1649
1650 For a directory (rather than a specific filename) we fake a path to
1651 a specific filename by adding /DEPS. This is chosen as a file that
1652 will seldom or never be subject to per-file include_rules.
1653 """
[email protected]2b438d62013-11-14 17:54:141654 # We ignore deps entries on auto-generated directories.
1655 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:081656
Daniel Cheng4dcdb6b2017-04-13 08:30:171657 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
1658 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
1659
1660 added_deps = new_deps.difference(old_deps)
1661
[email protected]2b438d62013-11-14 17:54:141662 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:171663 for added_dep in added_deps:
1664 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
1665 continue
1666 # Assume that a rule that ends in .h is a rule for a specific file.
1667 if added_dep.endswith('.h'):
1668 results.add(added_dep)
1669 else:
1670 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:081671 return results
1672
1673
[email protected]e871964c2013-05-13 14:14:551674def _CheckAddedDepsHaveTargetApprovals(input_api, output_api):
1675 """When a dependency prefixed with + is added to a DEPS file, we
1676 want to make sure that the change is reviewed by an OWNER of the
1677 target file or directory, to avoid layering violations from being
1678 introduced. This check verifies that this happens.
1679 """
Daniel Cheng4dcdb6b2017-04-13 08:30:171680 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:241681
1682 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:491683 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:241684 for f in input_api.AffectedFiles(include_deletes=False,
1685 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:551686 filename = input_api.os_path.basename(f.LocalPath())
1687 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:171688 virtual_depended_on_files.update(_CalculateAddedDeps(
1689 input_api.os_path,
1690 '\n'.join(f.OldContents()),
1691 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:551692
[email protected]e871964c2013-05-13 14:14:551693 if not virtual_depended_on_files:
1694 return []
1695
1696 if input_api.is_committing:
1697 if input_api.tbr:
1698 return [output_api.PresubmitNotifyResult(
1699 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:271700 if input_api.dry_run:
1701 return [output_api.PresubmitNotifyResult(
1702 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:551703 if not input_api.change.issue:
1704 return [output_api.PresubmitError(
1705 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:401706 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:551707 output = output_api.PresubmitError
1708 else:
1709 output = output_api.PresubmitNotifyResult
1710
1711 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:501712 owner_email, reviewers = (
1713 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
1714 input_api,
1715 owners_db.email_regexp,
1716 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:551717
1718 owner_email = owner_email or input_api.change.author_email
1719
[email protected]de4f7d22013-05-23 14:27:461720 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:511721 if owner_email:
[email protected]de4f7d22013-05-23 14:27:461722 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:551723 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
1724 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:411725
1726 # We strip the /DEPS part that was added by
1727 # _FilesToCheckForIncomingDeps to fake a path to a file in a
1728 # directory.
1729 def StripDeps(path):
1730 start_deps = path.rfind('/DEPS')
1731 if start_deps != -1:
1732 return path[:start_deps]
1733 else:
1734 return path
1735 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:551736 for path in missing_files]
1737
1738 if unapproved_dependencies:
1739 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:151740 output('You need LGTM from owners of depends-on paths in DEPS that were '
1741 'modified in this CL:\n %s' %
1742 '\n '.join(sorted(unapproved_dependencies)))]
1743 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
1744 output_list.append(output(
1745 'Suggested missing target path OWNERS:\n %s' %
1746 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:551747 return output_list
1748
1749 return []
1750
1751
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491752# TODO: add unit tests.
[email protected]85218562013-11-22 07:41:401753def _CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491754 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]85218562013-11-22 07:41:401755 black_list = (_EXCLUDED_PATHS +
1756 _TEST_CODE_EXCLUDED_PATHS +
1757 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:041758 (r"^base[\\/]logging\.h$",
1759 r"^base[\\/]logging\.cc$",
1760 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
1761 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
1762 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
[email protected]4de75262013-12-18 23:16:121763 r"startup_browser_creator\.cc$",
Nicolas Ouellet-Payeur16730ab2019-04-09 15:39:181764 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
Egor Paskoce145c42018-09-28 19:31:041765 r"^chrome[\\/]installer[\\/]setup[\\/].*",
1766 r"^chrome[\\/]chrome_cleaner[\\/].*",
1767 r"chrome[\\/]browser[\\/]diagnostics[\\/]" +
[email protected]f5b9a3f342014-08-08 22:06:031768 r"diagnostics_writer\.cc$",
Egor Paskoce145c42018-09-28 19:31:041769 r"^chrome_elf[\\/]dll_hash[\\/]dll_hash_main\.cc$",
1770 r"^chromecast[\\/]",
1771 r"^cloud_print[\\/]",
1772 r"^components[\\/]browser_watcher[\\/]"
manzagop85e629e2017-05-09 22:11:481773 r"dump_stability_report_main_win.cc$",
Egor Paskoce145c42018-09-28 19:31:041774 r"^components[\\/]html_viewer[\\/]"
jochen34415e52015-07-10 08:34:311775 r"web_test_delegate_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041776 r"^components[\\/]zucchini[\\/].*",
peter80739bb2015-10-20 11:17:461777 # TODO(peter): Remove this exception. https://crbug.com/534537
Egor Paskoce145c42018-09-28 19:31:041778 r"^content[\\/]browser[\\/]notifications[\\/]"
peter80739bb2015-10-20 11:17:461779 r"notification_event_dispatcher_impl\.cc$",
Egor Paskoce145c42018-09-28 19:31:041780 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
[email protected]9056e732014-01-08 06:25:251781 r"gl_helper_benchmark\.cc$",
Egor Paskoce145c42018-09-28 19:31:041782 r"^courgette[\\/]courgette_minimal_tool\.cc$",
1783 r"^courgette[\\/]courgette_tool\.cc$",
1784 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
Fabrice de Gans-Riberi3fa1c0fa2019-02-08 18:55:271785 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331786 r"^headless[\\/]app[\\/]headless_shell\.cc$",
Egor Paskoce145c42018-09-28 19:31:041787 r"^ipc[\\/]ipc_logging\.cc$",
1788 r"^native_client_sdk[\\/]",
1789 r"^remoting[\\/]base[\\/]logging\.h$",
1790 r"^remoting[\\/]host[\\/].*",
1791 r"^sandbox[\\/]linux[\\/].*",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331792 r"^storage[\\/]browser[\\/]fileapi[\\/]" +
1793 r"dump_file_system.cc$",
Egor Paskoce145c42018-09-28 19:31:041794 r"^tools[\\/]",
1795 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
1796 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
Fabrice de Gans-Riberi570201a22019-01-17 23:32:331797 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]"))
[email protected]85218562013-11-22 07:41:401798 source_file_filter = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491799 x, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]85218562013-11-22 07:41:401800
thomasanderson625d3932017-03-29 07:16:581801 log_info = set([])
1802 printf = set([])
[email protected]85218562013-11-22 07:41:401803
1804 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:581805 for _, line in f.ChangedContents():
1806 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
1807 log_info.add(f.LocalPath())
1808 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
1809 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:371810
thomasanderson625d3932017-03-29 07:16:581811 if input_api.re.search(r"\bprintf\(", line):
1812 printf.add(f.LocalPath())
1813 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
1814 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:401815
1816 if log_info:
1817 return [output_api.PresubmitError(
1818 'These files spam the console log with LOG(INFO):',
1819 items=log_info)]
1820 if printf:
1821 return [output_api.PresubmitError(
1822 'These files spam the console log with printf/fprintf:',
1823 items=printf)]
1824 return []
1825
1826
[email protected]49aa76a2013-12-04 06:59:161827def _CheckForAnonymousVariables(input_api, output_api):
1828 """These types are all expected to hold locks while in scope and
1829 so should never be anonymous (which causes them to be immediately
1830 destroyed)."""
1831 they_who_must_be_named = [
1832 'base::AutoLock',
1833 'base::AutoReset',
1834 'base::AutoUnlock',
1835 'SkAutoAlphaRestore',
1836 'SkAutoBitmapShaderInstall',
1837 'SkAutoBlitterChoose',
1838 'SkAutoBounderCommit',
1839 'SkAutoCallProc',
1840 'SkAutoCanvasRestore',
1841 'SkAutoCommentBlock',
1842 'SkAutoDescriptor',
1843 'SkAutoDisableDirectionCheck',
1844 'SkAutoDisableOvalCheck',
1845 'SkAutoFree',
1846 'SkAutoGlyphCache',
1847 'SkAutoHDC',
1848 'SkAutoLockColors',
1849 'SkAutoLockPixels',
1850 'SkAutoMalloc',
1851 'SkAutoMaskFreeImage',
1852 'SkAutoMutexAcquire',
1853 'SkAutoPathBoundsUpdate',
1854 'SkAutoPDFRelease',
1855 'SkAutoRasterClipValidate',
1856 'SkAutoRef',
1857 'SkAutoTime',
1858 'SkAutoTrace',
1859 'SkAutoUnref',
1860 ]
1861 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
1862 # bad: base::AutoLock(lock.get());
1863 # not bad: base::AutoLock lock(lock.get());
1864 bad_pattern = input_api.re.compile(anonymous)
1865 # good: new base::AutoLock(lock.get())
1866 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
1867 errors = []
1868
1869 for f in input_api.AffectedFiles():
1870 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
1871 continue
1872 for linenum, line in f.ChangedContents():
1873 if bad_pattern.search(line) and not good_pattern.search(line):
1874 errors.append('%s:%d' % (f.LocalPath(), linenum))
1875
1876 if errors:
1877 return [output_api.PresubmitError(
1878 'These lines create anonymous variables that need to be named:',
1879 items=errors)]
1880 return []
1881
1882
Peter Kasting4844e46e2018-02-23 07:27:101883def _CheckUniquePtr(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:531884 # Returns whether |template_str| is of the form <T, U...> for some types T
1885 # and U. Assumes that |template_str| is already in the form <...>.
1886 def HasMoreThanOneArg(template_str):
1887 # Level of <...> nesting.
1888 nesting = 0
1889 for c in template_str:
1890 if c == '<':
1891 nesting += 1
1892 elif c == '>':
1893 nesting -= 1
1894 elif c == ',' and nesting == 1:
1895 return True
1896 return False
1897
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491898 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:101899 sources = lambda affected_file: input_api.FilterSourceFile(
1900 affected_file,
1901 black_list=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
1902 input_api.DEFAULT_BLACK_LIST),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491903 white_list=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:551904
1905 # Pattern to capture a single "<...>" block of template arguments. It can
1906 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
1907 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
1908 # latter would likely require counting that < and > match, which is not
1909 # expressible in regular languages. Should the need arise, one can introduce
1910 # limited counting (matching up to a total number of nesting depth), which
1911 # should cover all practical cases for already a low nesting limit.
1912 template_arg_pattern = (
1913 r'<[^>]*' # Opening block of <.
1914 r'>([^<]*>)?') # Closing block of >.
1915 # Prefix expressing that whatever follows is not already inside a <...>
1916 # block.
1917 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:101918 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:551919 not_inside_template_arg_pattern
1920 + r'\bstd::unique_ptr'
1921 + template_arg_pattern
1922 + r'\(\)')
1923
1924 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
1925 template_arg_no_array_pattern = (
1926 r'<[^>]*[^]]' # Opening block of <.
1927 r'>([^(<]*[^]]>)?') # Closing block of >.
1928 # Prefix saying that what follows is the start of an expression.
1929 start_of_expr_pattern = r'(=|\breturn|^)\s*'
1930 # Suffix saying that what follows are call parentheses with a non-empty list
1931 # of arguments.
1932 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:531933 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:551934 return_construct_pattern = input_api.re.compile(
1935 start_of_expr_pattern
1936 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:531937 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:551938 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:531939 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:551940 + nonempty_arg_list_pattern)
1941
Vaclav Brozek851d9602018-04-04 16:13:051942 problems_constructor = []
1943 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:101944 for f in input_api.AffectedSourceFiles(sources):
1945 for line_number, line in f.ChangedContents():
1946 # Disallow:
1947 # return std::unique_ptr<T>(foo);
1948 # bar = std::unique_ptr<T>(foo);
1949 # But allow:
1950 # return std::unique_ptr<T[]>(foo);
1951 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:531952 # And also allow cases when the second template argument is present. Those
1953 # cases cannot be handled by std::make_unique:
1954 # return std::unique_ptr<T, U>(foo);
1955 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:051956 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:531957 return_construct_result = return_construct_pattern.search(line)
1958 if return_construct_result and not HasMoreThanOneArg(
1959 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:051960 problems_constructor.append(
1961 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:101962 # Disallow:
1963 # std::unique_ptr<T>()
1964 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:051965 problems_nullptr.append(
1966 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1967
1968 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:161969 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:051970 errors.append(output_api.PresubmitError(
1971 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161972 problems_nullptr))
1973 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:051974 errors.append(output_api.PresubmitError(
1975 'The following files use explicit std::unique_ptr constructor.'
1976 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:161977 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:101978 return errors
1979
1980
[email protected]999261d2014-03-03 20:08:081981def _CheckUserActionUpdate(input_api, output_api):
1982 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:521983 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:081984 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:521985 # If actions.xml is already included in the changelist, the PRESUBMIT
1986 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:081987 return []
1988
[email protected]999261d2014-03-03 20:08:081989 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
1990 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:521991 current_actions = None
[email protected]999261d2014-03-03 20:08:081992 for f in input_api.AffectedFiles(file_filter=file_filter):
1993 for line_num, line in f.ChangedContents():
1994 match = input_api.re.search(action_re, line)
1995 if match:
[email protected]2f92dec2014-03-07 19:21:521996 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
1997 # loaded only once.
1998 if not current_actions:
1999 with open('tools/metrics/actions/actions.xml') as actions_f:
2000 current_actions = actions_f.read()
2001 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082002 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522003 action = 'name="{0}"'.format(action_name)
2004 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082005 return [output_api.PresubmitPromptWarning(
2006 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522007 'tools/metrics/actions/actions.xml. Please run '
2008 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082009 % (f.LocalPath(), line_num, action_name))]
2010 return []
2011
2012
Daniel Cheng13ca61a882017-08-25 15:11:252013def _ImportJSONCommentEater(input_api):
2014 import sys
2015 sys.path = sys.path + [input_api.os_path.join(
2016 input_api.PresubmitLocalPath(),
2017 'tools', 'json_comment_eater')]
2018 import json_comment_eater
2019 return json_comment_eater
2020
2021
[email protected]99171a92014-06-03 08:44:472022def _GetJSONParseError(input_api, filename, eat_comments=True):
2023 try:
2024 contents = input_api.ReadFile(filename)
2025 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252026 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132027 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472028
2029 input_api.json.loads(contents)
2030 except ValueError as e:
2031 return e
2032 return None
2033
2034
2035def _GetIDLParseError(input_api, filename):
2036 try:
2037 contents = input_api.ReadFile(filename)
2038 idl_schema = input_api.os_path.join(
2039 input_api.PresubmitLocalPath(),
2040 'tools', 'json_schema_compiler', 'idl_schema.py')
2041 process = input_api.subprocess.Popen(
2042 [input_api.python_executable, idl_schema],
2043 stdin=input_api.subprocess.PIPE,
2044 stdout=input_api.subprocess.PIPE,
2045 stderr=input_api.subprocess.PIPE,
2046 universal_newlines=True)
2047 (_, error) = process.communicate(input=contents)
2048 return error or None
2049 except ValueError as e:
2050 return e
2051
2052
2053def _CheckParseErrors(input_api, output_api):
2054 """Check that IDL and JSON files do not contain syntax errors."""
2055 actions = {
2056 '.idl': _GetIDLParseError,
2057 '.json': _GetJSONParseError,
2058 }
[email protected]99171a92014-06-03 08:44:472059 # Most JSON files are preprocessed and support comments, but these do not.
2060 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042061 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472062 ]
2063 # Only run IDL checker on files in these directories.
2064 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042065 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2066 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472067 ]
2068
2069 def get_action(affected_file):
2070 filename = affected_file.LocalPath()
2071 return actions.get(input_api.os_path.splitext(filename)[1])
2072
[email protected]99171a92014-06-03 08:44:472073 def FilterFile(affected_file):
2074 action = get_action(affected_file)
2075 if not action:
2076 return False
2077 path = affected_file.LocalPath()
2078
Sean Kau46e29bc2017-08-28 16:31:162079 if _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS, path):
[email protected]99171a92014-06-03 08:44:472080 return False
2081
2082 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162083 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472084 return False
2085 return True
2086
2087 results = []
2088 for affected_file in input_api.AffectedFiles(
2089 file_filter=FilterFile, include_deletes=False):
2090 action = get_action(affected_file)
2091 kwargs = {}
2092 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162093 _MatchesFile(input_api, json_no_comments_patterns,
2094 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472095 kwargs['eat_comments'] = False
2096 parse_error = action(input_api,
2097 affected_file.AbsoluteLocalPath(),
2098 **kwargs)
2099 if parse_error:
2100 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2101 (affected_file.LocalPath(), parse_error)))
2102 return results
2103
2104
[email protected]760deea2013-12-10 19:33:492105def _CheckJavaStyle(input_api, output_api):
2106 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472107 import sys
[email protected]760deea2013-12-10 19:33:492108 original_sys_path = sys.path
2109 try:
2110 sys.path = sys.path + [input_api.os_path.join(
2111 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2112 import checkstyle
2113 finally:
2114 # Restore sys.path to what it was before.
2115 sys.path = original_sys_path
2116
2117 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092118 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
newtd8b7d30e92015-01-23 18:10:512119 black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
[email protected]760deea2013-12-10 19:33:492120
2121
Sean Kau46e29bc2017-08-28 16:31:162122def _MatchesFile(input_api, patterns, path):
2123 for pattern in patterns:
2124 if input_api.re.search(pattern, path):
2125 return True
2126 return False
2127
2128
Daniel Cheng7052cdf2017-11-21 19:23:292129def _GetOwnersFilesToCheckForIpcOwners(input_api):
2130 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172131
Daniel Cheng7052cdf2017-11-21 19:23:292132 Returns:
2133 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2134 contain to cover IPC-related files with noparent reviewer rules.
2135 """
2136 # Whether or not a file affects IPC is (mostly) determined by a simple list
2137 # of filename patterns.
dchenge07de812016-06-20 19:27:172138 file_patterns = [
palmerb19a0932017-01-24 04:00:312139 # Legacy IPC:
dchenge07de812016-06-20 19:27:172140 '*_messages.cc',
2141 '*_messages*.h',
2142 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312143 # Mojo IPC:
dchenge07de812016-06-20 19:27:172144 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472145 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172146 '*_struct_traits*.*',
2147 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312148 '*.typemap',
2149 # Android native IPC:
2150 '*.aidl',
2151 # Blink uses a different file naming convention:
2152 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472153 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172154 '*StructTraits*.*',
2155 '*TypeConverter*.*',
2156 ]
2157
scottmg7a6ed5ba2016-11-04 18:22:042158 # These third_party directories do not contain IPCs, but contain files
2159 # matching the above patterns, which trigger false positives.
2160 exclude_paths = [
2161 'third_party/crashpad/*',
Andres Medinae684cf42018-08-27 18:48:232162 'third_party/protobuf/benchmarks/python/*',
Daniel Chengebe635e2018-07-13 12:36:062163 'third_party/third_party/blink/renderer/platform/bindings/*',
Nico Weberee3dc9b2017-08-31 17:09:292164 'third_party/win_build_output/*',
scottmg7a6ed5ba2016-11-04 18:22:042165 ]
2166
dchenge07de812016-06-20 19:27:172167 # Dictionary mapping an OWNERS file path to Patterns.
2168 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2169 # rules ) to a PatternEntry.
2170 # PatternEntry is a dictionary with two keys:
2171 # - 'files': the files that are matched by this pattern
2172 # - 'rules': the per-file rules needed for this pattern
2173 # For example, if we expect OWNERS file to contain rules for *.mojom and
2174 # *_struct_traits*.*, Patterns might look like this:
2175 # {
2176 # '*.mojom': {
2177 # 'files': ...,
2178 # 'rules': [
2179 # 'per-file *.mojom=set noparent',
2180 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2181 # ],
2182 # },
2183 # '*_struct_traits*.*': {
2184 # 'files': ...,
2185 # 'rules': [
2186 # 'per-file *_struct_traits*.*=set noparent',
2187 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2188 # ],
2189 # },
2190 # }
2191 to_check = {}
2192
Daniel Cheng13ca61a882017-08-25 15:11:252193 def AddPatternToCheck(input_file, pattern):
2194 owners_file = input_api.os_path.join(
2195 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2196 if owners_file not in to_check:
2197 to_check[owners_file] = {}
2198 if pattern not in to_check[owners_file]:
2199 to_check[owners_file][pattern] = {
2200 'files': [],
2201 'rules': [
2202 'per-file %s=set noparent' % pattern,
2203 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2204 ]
2205 }
Vaclav Brozekd5de76a2018-03-17 07:57:502206 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252207
dchenge07de812016-06-20 19:27:172208 # Iterate through the affected files to see what we actually need to check
2209 # for. We should only nag patch authors about per-file rules if a file in that
2210 # directory would match that pattern. If a directory only contains *.mojom
2211 # files and no *_messages*.h files, we should only nag about rules for
2212 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252213 for f in input_api.AffectedFiles(include_deletes=False):
2214 # Manifest files don't have a strong naming convention. Instead, scan
Ken Rockot9f668262018-12-21 18:56:362215 # affected files for .json, .cc, and .h files which look like they contain
2216 # a manifest definition.
Sean Kau46e29bc2017-08-28 16:31:162217 if (f.LocalPath().endswith('.json') and
2218 not _MatchesFile(input_api, _KNOWN_INVALID_JSON_FILE_PATTERNS,
2219 f.LocalPath())):
Daniel Cheng13ca61a882017-08-25 15:11:252220 json_comment_eater = _ImportJSONCommentEater(input_api)
2221 mostly_json_lines = '\n'.join(f.NewContents())
2222 # Comments aren't allowed in strict JSON, so filter them out.
2223 json_lines = json_comment_eater.Nom(mostly_json_lines)
Daniel Chenge8efd092018-03-23 23:57:432224 try:
2225 json_content = input_api.json.loads(json_lines)
2226 except:
2227 # There's another PRESUBMIT check that already verifies that JSON files
2228 # are not invalid, so no need to emit another warning here.
2229 continue
Daniel Cheng13ca61a882017-08-25 15:11:252230 if 'interface_provider_specs' in json_content:
2231 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
Ken Rockot9f668262018-12-21 18:56:362232 else:
2233 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2234 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2235 if (manifest_pattern.search(f.LocalPath()) and not
2236 test_manifest_pattern.search(f.LocalPath())):
2237 # We expect all actual service manifest files to contain at least one
2238 # qualified reference to service_manager::Manifest.
2239 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
2240 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172241 for pattern in file_patterns:
2242 if input_api.fnmatch.fnmatch(
2243 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042244 skip = False
2245 for exclude in exclude_paths:
2246 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
2247 skip = True
2248 break
2249 if skip:
2250 continue
Daniel Cheng13ca61a882017-08-25 15:11:252251 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:172252 break
2253
Daniel Cheng7052cdf2017-11-21 19:23:292254 return to_check
2255
2256
2257def _CheckIpcOwners(input_api, output_api):
2258 """Checks that affected files involving IPC have an IPC OWNERS rule."""
2259 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
2260
2261 if to_check:
2262 # If there are any OWNERS files to check, there are IPC-related changes in
2263 # this CL. Auto-CC the review list.
2264 output_api.AppendCC('[email protected]')
2265
2266 # Go through the OWNERS files to check, filtering out rules that are already
2267 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:172268 for owners_file, patterns in to_check.iteritems():
2269 try:
2270 with file(owners_file) as f:
2271 lines = set(f.read().splitlines())
2272 for entry in patterns.itervalues():
2273 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
2274 ]
2275 except IOError:
2276 # No OWNERS file, so all the rules are definitely missing.
2277 continue
2278
2279 # All the remaining lines weren't found in OWNERS files, so emit an error.
2280 errors = []
2281 for owners_file, patterns in to_check.iteritems():
2282 missing_lines = []
2283 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:502284 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:172285 missing_lines.extend(entry['rules'])
2286 files.extend([' %s' % f.LocalPath() for f in entry['files']])
2287 if missing_lines:
2288 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:052289 'Because of the presence of files:\n%s\n\n'
2290 '%s needs the following %d lines added:\n\n%s' %
2291 ('\n'.join(files), owners_file, len(missing_lines),
2292 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:172293
2294 results = []
2295 if errors:
vabrf5ce3bf92016-07-11 14:52:412296 if input_api.is_committing:
2297 output = output_api.PresubmitError
2298 else:
2299 output = output_api.PresubmitPromptWarning
2300 results.append(output(
Daniel Cheng52111692017-06-14 08:00:592301 'Found OWNERS files that need to be updated for IPC security ' +
2302 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:172303 long_text='\n\n'.join(errors)))
2304
2305 return results
2306
2307
jbriance9e12f162016-11-25 07:57:502308def _CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:312309 """Checks that added or removed lines in non third party affected
2310 header files do not lead to new useless class or struct forward
2311 declaration.
jbriance9e12f162016-11-25 07:57:502312 """
2313 results = []
2314 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
2315 input_api.re.MULTILINE)
2316 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
2317 input_api.re.MULTILINE)
2318 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:312319 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:192320 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:492321 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:312322 continue
2323
jbriance9e12f162016-11-25 07:57:502324 if not f.LocalPath().endswith('.h'):
2325 continue
2326
2327 contents = input_api.ReadFile(f)
2328 fwd_decls = input_api.re.findall(class_pattern, contents)
2329 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
2330
2331 useless_fwd_decls = []
2332 for decl in fwd_decls:
2333 count = sum(1 for _ in input_api.re.finditer(
2334 r'\b%s\b' % input_api.re.escape(decl), contents))
2335 if count == 1:
2336 useless_fwd_decls.append(decl)
2337
2338 if not useless_fwd_decls:
2339 continue
2340
2341 for line in f.GenerateScmDiff().splitlines():
2342 if (line.startswith('-') and not line.startswith('--') or
2343 line.startswith('+') and not line.startswith('++')):
2344 for decl in useless_fwd_decls:
2345 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
2346 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:242347 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:502348 (f.LocalPath(), decl)))
2349 useless_fwd_decls.remove(decl)
2350
2351 return results
2352
2353
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492354# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:292355def _CheckAndroidToastUsage(input_api, output_api):
2356 """Checks that code uses org.chromium.ui.widget.Toast instead of
2357 android.widget.Toast (Chromium Toast doesn't force hardware
2358 acceleration on low-end devices, saving memory).
2359 """
2360 toast_import_pattern = input_api.re.compile(
2361 r'^import android\.widget\.Toast;$')
2362
2363 errors = []
2364
2365 sources = lambda affected_file: input_api.FilterSourceFile(
2366 affected_file,
2367 black_list=(_EXCLUDED_PATHS +
2368 _TEST_CODE_EXCLUDED_PATHS +
2369 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042370 (r'^chromecast[\\/].*',
2371 r'^remoting[\\/].*')),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492372 white_list=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:292373
2374 for f in input_api.AffectedSourceFiles(sources):
2375 for line_num, line in f.ChangedContents():
2376 if toast_import_pattern.search(line):
2377 errors.append("%s:%d" % (f.LocalPath(), line_num))
2378
2379 results = []
2380
2381 if errors:
2382 results.append(output_api.PresubmitError(
2383 'android.widget.Toast usage is detected. Android toasts use hardware'
2384 ' acceleration, and can be\ncostly on low-end devices. Please use'
2385 ' org.chromium.ui.widget.Toast instead.\n'
2386 'Contact [email protected] if you have any questions.',
2387 errors))
2388
2389 return results
2390
2391
dgnaa68d5e2015-06-10 10:08:222392def _CheckAndroidCrLogUsage(input_api, output_api):
2393 """Checks that new logs using org.chromium.base.Log:
2394 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:512395 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:222396 """
pkotwicza1dd0b002016-05-16 14:41:042397
torne89540622017-03-24 19:41:302398 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:042399 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:302400 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:042401 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:302402 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:042403 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
2404 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:092405 # The customtabs_benchmark is a small app that does not depend on Chromium
2406 # java pieces.
Egor Paskoce145c42018-09-28 19:31:042407 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:042408 ]
2409
dgnaa68d5e2015-06-10 10:08:222410 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:122411 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
2412 class_in_base_pattern = input_api.re.compile(
2413 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
2414 has_some_log_import_pattern = input_api.re.compile(
2415 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222416 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
dgn87d9fb62015-06-12 09:15:122417 log_call_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
dgnaa68d5e2015-06-10 10:08:222418 log_decl_pattern = input_api.re.compile(
dgn38736db2015-09-18 19:20:512419 r'^\s*private static final String TAG = "(?P<name>(.*))";',
dgnaa68d5e2015-06-10 10:08:222420 input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:222421
Vincent Scheib16d7b272015-09-15 18:09:072422 REF_MSG = ('See docs/android_logging.md '
dgnaa68d5e2015-06-10 10:08:222423 'or contact [email protected] for more info.')
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492424 sources = lambda x: input_api.FilterSourceFile(x, white_list=[r'.*\.java$'],
pkotwicza1dd0b002016-05-16 14:41:042425 black_list=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:122426
dgnaa68d5e2015-06-10 10:08:222427 tag_decl_errors = []
2428 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:122429 tag_errors = []
dgn38736db2015-09-18 19:20:512430 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:122431 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:222432
2433 for f in input_api.AffectedSourceFiles(sources):
2434 file_content = input_api.ReadFile(f)
2435 has_modified_logs = False
2436
2437 # Per line checks
dgn87d9fb62015-06-12 09:15:122438 if (cr_log_import_pattern.search(file_content) or
2439 (class_in_base_pattern.search(file_content) and
2440 not has_some_log_import_pattern.search(file_content))):
2441 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:222442 for line_num, line in f.ChangedContents():
2443
2444 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:122445 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:222446 if match:
2447 has_modified_logs = True
2448
2449 # Make sure it uses "TAG"
2450 if not match.group('tag') == 'TAG':
2451 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:122452 else:
2453 # Report non cr Log function calls in changed lines
2454 for line_num, line in f.ChangedContents():
2455 if log_call_pattern.search(line):
2456 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:222457
2458 # Per file checks
2459 if has_modified_logs:
2460 # Make sure the tag is using the "cr" prefix and is not too long
2461 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:512462 tag_name = match.group('name') if match else None
2463 if not tag_name:
dgnaa68d5e2015-06-10 10:08:222464 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512465 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:222466 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:512467 elif '.' in tag_name:
2468 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:222469
2470 results = []
2471 if tag_decl_errors:
2472 results.append(output_api.PresubmitPromptWarning(
2473 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:512474 '"private static final String TAG = "<package tag>".\n'
2475 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222476 tag_decl_errors))
2477
2478 if tag_length_errors:
2479 results.append(output_api.PresubmitError(
2480 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:512481 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:222482 tag_length_errors))
2483
2484 if tag_errors:
2485 results.append(output_api.PresubmitPromptWarning(
2486 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
2487 tag_errors))
2488
dgn87d9fb62015-06-12 09:15:122489 if util_log_errors:
dgn4401aa52015-04-29 16:26:172490 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:122491 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
2492 util_log_errors))
2493
dgn38736db2015-09-18 19:20:512494 if tag_with_dot_errors:
2495 results.append(output_api.PresubmitPromptWarning(
2496 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
2497 tag_with_dot_errors))
2498
dgn4401aa52015-04-29 16:26:172499 return results
2500
2501
Yoland Yanb92fa522017-08-28 17:37:062502def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
2503 """Checks that junit.framework.* is no longer used."""
2504 deprecated_junit_framework_pattern = input_api.re.compile(
2505 r'^import junit\.framework\..*;',
2506 input_api.re.MULTILINE)
2507 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492508 x, white_list=[r'.*\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062509 errors = []
2510 for f in input_api.AffectedFiles(sources):
2511 for line_num, line in f.ChangedContents():
2512 if deprecated_junit_framework_pattern.search(line):
2513 errors.append("%s:%d" % (f.LocalPath(), line_num))
2514
2515 results = []
2516 if errors:
2517 results.append(output_api.PresubmitError(
2518 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
2519 '(org.junit.*) from //third_party/junit. Contact [email protected]'
2520 ' if you have any question.', errors))
2521 return results
2522
2523
2524def _CheckAndroidTestJUnitInheritance(input_api, output_api):
2525 """Checks that if new Java test classes have inheritance.
2526 Either the new test class is JUnit3 test or it is a JUnit4 test class
2527 with a base class, either case is undesirable.
2528 """
2529 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
2530
2531 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492532 x, white_list=[r'.*Test\.java$'], black_list=None)
Yoland Yanb92fa522017-08-28 17:37:062533 errors = []
2534 for f in input_api.AffectedFiles(sources):
2535 if not f.OldContents():
2536 class_declaration_start_flag = False
2537 for line_num, line in f.ChangedContents():
2538 if class_declaration_pattern.search(line):
2539 class_declaration_start_flag = True
2540 if class_declaration_start_flag and ' extends ' in line:
2541 errors.append('%s:%d' % (f.LocalPath(), line_num))
2542 if '{' in line:
2543 class_declaration_start_flag = False
2544
2545 results = []
2546 if errors:
2547 results.append(output_api.PresubmitPromptWarning(
2548 'The newly created files include Test classes that inherits from base'
2549 ' class. Please do not use inheritance in JUnit4 tests or add new'
2550 ' JUnit3 tests. Contact [email protected] if you have any'
2551 ' questions.', errors))
2552 return results
2553
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202554
yolandyan45001472016-12-21 21:12:422555def _CheckAndroidTestAnnotationUsage(input_api, output_api):
2556 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
2557 deprecated_annotation_import_pattern = input_api.re.compile(
2558 r'^import android\.test\.suitebuilder\.annotation\..*;',
2559 input_api.re.MULTILINE)
2560 sources = lambda x: input_api.FilterSourceFile(
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492561 x, white_list=[r'.*\.java$'], black_list=None)
yolandyan45001472016-12-21 21:12:422562 errors = []
2563 for f in input_api.AffectedFiles(sources):
2564 for line_num, line in f.ChangedContents():
2565 if deprecated_annotation_import_pattern.search(line):
2566 errors.append("%s:%d" % (f.LocalPath(), line_num))
2567
2568 results = []
2569 if errors:
2570 results.append(output_api.PresubmitError(
2571 'Annotations in android.test.suitebuilder.annotation have been'
2572 ' deprecated since API level 24. Please use android.support.test.filters'
2573 ' from //third_party/android_support_test_runner:runner_java instead.'
2574 ' Contact [email protected] if you have any questions.', errors))
2575 return results
2576
2577
agrieve7b6479d82015-10-07 14:24:222578def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
2579 """Checks if MDPI assets are placed in a correct directory."""
2580 file_filter = lambda f: (f.LocalPath().endswith('.png') and
2581 ('/res/drawable/' in f.LocalPath() or
2582 '/res/drawable-ldrtl/' in f.LocalPath()))
2583 errors = []
2584 for f in input_api.AffectedFiles(include_deletes=False,
2585 file_filter=file_filter):
2586 errors.append(' %s' % f.LocalPath())
2587
2588 results = []
2589 if errors:
2590 results.append(output_api.PresubmitError(
2591 'MDPI assets should be placed in /res/drawable-mdpi/ or '
2592 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
2593 '/res/drawable-ldrtl/.\n'
2594 'Contact [email protected] if you have questions.', errors))
2595 return results
2596
2597
Nate Fischer535972b2017-09-16 01:06:182598def _CheckAndroidWebkitImports(input_api, output_api):
2599 """Checks that code uses org.chromium.base.Callback instead of
2600 android.widget.ValueCallback except in the WebView glue layer.
2601 """
2602 valuecallback_import_pattern = input_api.re.compile(
2603 r'^import android\.webkit\.ValueCallback;$')
2604
2605 errors = []
2606
2607 sources = lambda affected_file: input_api.FilterSourceFile(
2608 affected_file,
2609 black_list=(_EXCLUDED_PATHS +
2610 _TEST_CODE_EXCLUDED_PATHS +
2611 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042612 (r'^android_webview[\\/]glue[\\/].*',)),
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492613 white_list=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:182614
2615 for f in input_api.AffectedSourceFiles(sources):
2616 for line_num, line in f.ChangedContents():
2617 if valuecallback_import_pattern.search(line):
2618 errors.append("%s:%d" % (f.LocalPath(), line_num))
2619
2620 results = []
2621
2622 if errors:
2623 results.append(output_api.PresubmitError(
2624 'android.webkit.ValueCallback usage is detected outside of the glue'
2625 ' layer. To stay compatible with the support library, android.webkit.*'
2626 ' classes should only be used inside the glue layer and'
2627 ' org.chromium.base.Callback should be used instead.',
2628 errors))
2629
2630 return results
2631
2632
Becky Zhou7c69b50992018-12-10 19:37:572633def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
2634 """Checks Android XML styles """
2635 import sys
2636 original_sys_path = sys.path
2637 try:
2638 sys.path = sys.path + [input_api.os_path.join(
2639 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
2640 import checkxmlstyle
2641 finally:
2642 # Restore sys.path to what it was before.
2643 sys.path = original_sys_path
2644
2645 if is_check_on_upload:
2646 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
2647 else:
2648 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
2649
2650
agrievef32bcc72016-04-04 14:57:402651class PydepsChecker(object):
2652 def __init__(self, input_api, pydeps_files):
2653 self._file_cache = {}
2654 self._input_api = input_api
2655 self._pydeps_files = pydeps_files
2656
2657 def _LoadFile(self, path):
2658 """Returns the list of paths within a .pydeps file relative to //."""
2659 if path not in self._file_cache:
2660 with open(path) as f:
2661 self._file_cache[path] = f.read()
2662 return self._file_cache[path]
2663
2664 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
2665 """Returns an interable of paths within the .pydep, relativized to //."""
2666 os_path = self._input_api.os_path
2667 pydeps_dir = os_path.dirname(pydeps_path)
2668 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
2669 if not l.startswith('*'))
2670 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
2671
2672 def _CreateFilesToPydepsMap(self):
2673 """Returns a map of local_path -> list_of_pydeps."""
2674 ret = {}
2675 for pydep_local_path in self._pydeps_files:
2676 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
2677 ret.setdefault(path, []).append(pydep_local_path)
2678 return ret
2679
2680 def ComputeAffectedPydeps(self):
2681 """Returns an iterable of .pydeps files that might need regenerating."""
2682 affected_pydeps = set()
2683 file_to_pydeps_map = None
2684 for f in self._input_api.AffectedFiles(include_deletes=True):
2685 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:462686 # Changes to DEPS can lead to .pydeps changes if any .py files are in
2687 # subrepositories. We can't figure out which files change, so re-check
2688 # all files.
2689 # Changes to print_python_deps.py affect all .pydeps.
2690 if local_path == 'DEPS' or local_path.endswith('print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:402691 return self._pydeps_files
2692 elif local_path.endswith('.pydeps'):
2693 if local_path in self._pydeps_files:
2694 affected_pydeps.add(local_path)
2695 elif local_path.endswith('.py'):
2696 if file_to_pydeps_map is None:
2697 file_to_pydeps_map = self._CreateFilesToPydepsMap()
2698 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
2699 return affected_pydeps
2700
2701 def DetermineIfStale(self, pydeps_path):
2702 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:412703 import difflib
John Budorick47ca3fe2018-02-10 00:53:102704 import os
2705
agrievef32bcc72016-04-04 14:57:402706 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
2707 cmd = old_pydeps_data[1][1:].strip()
John Budorick47ca3fe2018-02-10 00:53:102708 env = dict(os.environ)
2709 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:402710 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:102711 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:412712 old_contents = old_pydeps_data[2:]
2713 new_contents = new_pydeps_data.splitlines()[2:]
agrievef32bcc72016-04-04 14:57:402714 if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
phajdan.jr0d9878552016-11-04 10:49:412715 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:402716
2717
2718def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
2719 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:402720 # This check is for Python dependency lists (.pydeps files), and involves
2721 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
2722 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:282723 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:002724 return []
Mostyn Bramley-Moore6b427322017-12-21 22:11:022725 # TODO(agrieve): Update when there's a better way to detect
2726 # this: crbug.com/570091
agrievef32bcc72016-04-04 14:57:402727 is_android = input_api.os_path.exists('third_party/android_tools')
2728 pydeps_files = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
2729 results = []
2730 # First, check for new / deleted .pydeps.
2731 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:032732 # Check whether we are running the presubmit check for a file in src.
2733 # f.LocalPath is relative to repo (src, or internal repo).
2734 # os_path.exists is relative to src repo.
2735 # Therefore if os_path.exists is true, it means f.LocalPath is relative
2736 # to src and we can conclude that the pydeps is in src.
2737 if input_api.os_path.exists(f.LocalPath()):
2738 if f.LocalPath().endswith('.pydeps'):
2739 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
2740 results.append(output_api.PresubmitError(
2741 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2742 'remove %s' % f.LocalPath()))
2743 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
2744 results.append(output_api.PresubmitError(
2745 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
2746 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:402747
2748 if results:
2749 return results
2750
2751 checker = checker_for_tests or PydepsChecker(input_api, pydeps_files)
2752
2753 for pydep_path in checker.ComputeAffectedPydeps():
2754 try:
phajdan.jr0d9878552016-11-04 10:49:412755 result = checker.DetermineIfStale(pydep_path)
2756 if result:
2757 cmd, diff = result
agrievef32bcc72016-04-04 14:57:402758 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:412759 'File is stale: %s\nDiff (apply to fix):\n%s\n'
2760 'To regenerate, run:\n\n %s' %
2761 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:402762 except input_api.subprocess.CalledProcessError as error:
2763 return [output_api.PresubmitError('Error running: %s' % error.cmd,
2764 long_text=error.output)]
2765
2766 return results
2767
2768
glidere61efad2015-02-18 17:39:432769def _CheckSingletonInHeaders(input_api, output_api):
2770 """Checks to make sure no header files have |Singleton<|."""
2771 def FileFilter(affected_file):
2772 # It's ok for base/memory/singleton.h to have |Singleton<|.
2773 black_list = (_EXCLUDED_PATHS +
2774 input_api.DEFAULT_BLACK_LIST +
Egor Paskoce145c42018-09-28 19:31:042775 (r"^base[\\/]memory[\\/]singleton\.h$",
2776 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
Michael Warrese4451492018-03-07 04:42:472777 r"quic_singleton_impl\.h$"))
glidere61efad2015-02-18 17:39:432778 return input_api.FilterSourceFile(affected_file, black_list=black_list)
2779
sergeyu34d21222015-09-16 00:11:442780 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:432781 files = []
2782 for f in input_api.AffectedSourceFiles(FileFilter):
2783 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
2784 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
2785 contents = input_api.ReadFile(f)
2786 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:242787 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:432788 pattern.search(line)):
2789 files.append(f)
2790 break
2791
2792 if files:
yolandyandaabc6d2016-04-18 18:29:392793 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:442794 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:432795 'Please move them to an appropriate source file so that the ' +
2796 'template gets instantiated in a single compilation unit.',
2797 files) ]
2798 return []
2799
2800
[email protected]fd20b902014-05-09 02:14:532801_DEPRECATED_CSS = [
2802 # Values
2803 ( "-webkit-box", "flex" ),
2804 ( "-webkit-inline-box", "inline-flex" ),
2805 ( "-webkit-flex", "flex" ),
2806 ( "-webkit-inline-flex", "inline-flex" ),
2807 ( "-webkit-min-content", "min-content" ),
2808 ( "-webkit-max-content", "max-content" ),
2809
2810 # Properties
2811 ( "-webkit-background-clip", "background-clip" ),
2812 ( "-webkit-background-origin", "background-origin" ),
2813 ( "-webkit-background-size", "background-size" ),
2814 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:442815 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:532816
2817 # Functions
2818 ( "-webkit-gradient", "gradient" ),
2819 ( "-webkit-repeating-gradient", "repeating-gradient" ),
2820 ( "-webkit-linear-gradient", "linear-gradient" ),
2821 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
2822 ( "-webkit-radial-gradient", "radial-gradient" ),
2823 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
2824]
2825
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202826
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492827# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242828def _CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:532829 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:252830 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:342831 documentation and iOS CSS for dom distiller
2832 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:252833 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:532834 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492835 file_inclusion_pattern = [r".+\.css$"]
[email protected]9a48e3f82014-05-22 00:06:252836 black_list = (_EXCLUDED_PATHS +
2837 _TEST_CODE_EXCLUDED_PATHS +
2838 input_api.DEFAULT_BLACK_LIST +
2839 (r"^chrome/common/extensions/docs",
2840 r"^chrome/docs",
mdjonesae0286c32015-06-10 18:10:342841 r"^components/dom_distiller/core/css/distilledpage_ios.css",
sdefresne6308d7f2016-02-15 09:38:442842 r"^components/neterror/resources/neterror.css",
[email protected]9a48e3f82014-05-22 00:06:252843 r"^native_client_sdk"))
2844 file_filter = lambda f: input_api.FilterSourceFile(
2845 f, white_list=file_inclusion_pattern, black_list=black_list)
[email protected]fd20b902014-05-09 02:14:532846 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2847 for line_num, line in fpath.ChangedContents():
2848 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:022849 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:532850 results.append(output_api.PresubmitError(
2851 "%s:%d: Use of deprecated CSS %s, use %s instead" %
2852 (fpath.LocalPath(), line_num, deprecated_value, value)))
2853 return results
2854
mohan.reddyf21db962014-10-16 12:26:472855
dbeam070cfe62014-10-22 06:44:022856_DEPRECATED_JS = [
2857 ( "__lookupGetter__", "Object.getOwnPropertyDescriptor" ),
2858 ( "__defineGetter__", "Object.defineProperty" ),
2859 ( "__defineSetter__", "Object.defineProperty" ),
2860]
2861
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202862
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492863# TODO: add unit tests
dbeam1ec68ac2016-12-15 05:22:242864def _CheckNoDeprecatedJs(input_api, output_api):
dbeam070cfe62014-10-22 06:44:022865 """Make sure that we don't use deprecated JS in Chrome code."""
2866 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492867 file_inclusion_pattern = [r".+\.js$"] # TODO(dbeam): .html?
dbeam070cfe62014-10-22 06:44:022868 black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2869 input_api.DEFAULT_BLACK_LIST)
2870 file_filter = lambda f: input_api.FilterSourceFile(
2871 f, white_list=file_inclusion_pattern, black_list=black_list)
2872 for fpath in input_api.AffectedFiles(file_filter=file_filter):
2873 for lnum, line in fpath.ChangedContents():
2874 for (deprecated, replacement) in _DEPRECATED_JS:
2875 if deprecated in line:
2876 results.append(output_api.PresubmitError(
2877 "%s:%d: Use of deprecated JS %s, use %s instead" %
2878 (fpath.LocalPath(), lnum, deprecated, replacement)))
2879 return results
2880
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202881
rlanday6802cf632017-05-30 17:48:362882def _CheckForRelativeIncludes(input_api, output_api):
2883 # Need to set the sys.path so PRESUBMIT_test.py runs properly
2884 import sys
2885 original_sys_path = sys.path
2886 try:
2887 sys.path = sys.path + [input_api.os_path.join(
2888 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
2889 from cpp_checker import CppChecker
2890 finally:
2891 # Restore sys.path to what it was before.
2892 sys.path = original_sys_path
2893
2894 bad_files = {}
2895 for f in input_api.AffectedFiles(include_deletes=False):
2896 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:492897 not f.LocalPath().startswith('third_party/blink') and
2898 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:362899 continue
2900
2901 if not CppChecker.IsCppFile(f.LocalPath()):
2902 continue
2903
Vaclav Brozekd5de76a2018-03-17 07:57:502904 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:362905 if "#include" in line and "../" in line]
2906 if not relative_includes:
2907 continue
2908 bad_files[f.LocalPath()] = relative_includes
2909
2910 if not bad_files:
2911 return []
2912
2913 error_descriptions = []
2914 for file_path, bad_lines in bad_files.iteritems():
2915 error_description = file_path
2916 for line in bad_lines:
2917 error_description += '\n ' + line
2918 error_descriptions.append(error_description)
2919
2920 results = []
2921 results.append(output_api.PresubmitError(
2922 'You added one or more relative #include paths (including "../").\n'
2923 'These shouldn\'t be used because they can be used to include headers\n'
2924 'from code that\'s not correctly specified as a dependency in the\n'
2925 'relevant BUILD.gn file(s).',
2926 error_descriptions))
2927
2928 return results
2929
Takeshi Yoshinoe387aa32017-08-02 13:16:132930
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202931def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
2932 if not isinstance(key, ast.Str):
2933 return 'Key at line %d must be a string literal' % key.lineno
2934 if not isinstance(value, ast.Dict):
2935 return 'Value at line %d must be a dict' % value.lineno
2936 if len(value.keys) != 1:
2937 return 'Dict at line %d must have single entry' % value.lineno
2938 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
2939 return (
2940 'Entry at line %d must have a string literal \'filepath\' as key' %
2941 value.lineno)
2942 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132943
Takeshi Yoshinoe387aa32017-08-02 13:16:132944
Sergey Ulanov4af16052018-11-08 02:41:462945def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202946 if not isinstance(key, ast.Str):
2947 return 'Key at line %d must be a string literal' % key.lineno
2948 if not isinstance(value, ast.List):
2949 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:462950 for element in value.elts:
2951 if not isinstance(element, ast.Str):
2952 return 'Watchlist elements on line %d is not a string' % key.lineno
2953 if not email_regex.match(element.s):
2954 return ('Watchlist element on line %d doesn\'t look like a valid ' +
2955 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202956 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:132957
Takeshi Yoshinoe387aa32017-08-02 13:16:132958
Sergey Ulanov4af16052018-11-08 02:41:462959def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202960 mismatch_template = (
2961 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
2962 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:132963
Sergey Ulanov4af16052018-11-08 02:41:462964 email_regex = input_api.re.compile(
2965 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
2966
2967 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202968 i = 0
2969 last_key = ''
2970 while True:
2971 if i >= len(wd_dict.keys):
2972 if i >= len(w_dict.keys):
2973 return None
2974 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
2975 elif i >= len(w_dict.keys):
2976 return (
2977 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:132978
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202979 wd_key = wd_dict.keys[i]
2980 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:132981
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202982 result = _CheckWatchlistDefinitionsEntrySyntax(
2983 wd_key, wd_dict.values[i], ast)
2984 if result is not None:
2985 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:132986
Sergey Ulanov4af16052018-11-08 02:41:462987 result = _CheckWatchlistsEntrySyntax(
2988 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:202989 if result is not None:
2990 return 'Bad entry in WATCHLISTS dict: %s' % result
2991
2992 if wd_key.s != w_key.s:
2993 return mismatch_template % (
2994 '%s at line %d' % (wd_key.s, wd_key.lineno),
2995 '%s at line %d' % (w_key.s, w_key.lineno))
2996
2997 if wd_key.s < last_key:
2998 return (
2999 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
3000 (wd_key.lineno, w_key.lineno))
3001 last_key = wd_key.s
3002
3003 i = i + 1
3004
3005
Sergey Ulanov4af16052018-11-08 02:41:463006def _CheckWATCHLISTSSyntax(expression, input_api):
3007 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203008 if not isinstance(expression, ast.Expression):
3009 return 'WATCHLISTS file must contain a valid expression'
3010 dictionary = expression.body
3011 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
3012 return 'WATCHLISTS file must have single dict with exactly two entries'
3013
3014 first_key = dictionary.keys[0]
3015 first_value = dictionary.values[0]
3016 second_key = dictionary.keys[1]
3017 second_value = dictionary.values[1]
3018
3019 if (not isinstance(first_key, ast.Str) or
3020 first_key.s != 'WATCHLIST_DEFINITIONS' or
3021 not isinstance(first_value, ast.Dict)):
3022 return (
3023 'The first entry of the dict in WATCHLISTS file must be '
3024 'WATCHLIST_DEFINITIONS dict')
3025
3026 if (not isinstance(second_key, ast.Str) or
3027 second_key.s != 'WATCHLISTS' or
3028 not isinstance(second_value, ast.Dict)):
3029 return (
3030 'The second entry of the dict in WATCHLISTS file must be '
3031 'WATCHLISTS dict')
3032
Sergey Ulanov4af16052018-11-08 02:41:463033 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:133034
3035
3036def _CheckWATCHLISTS(input_api, output_api):
3037 for f in input_api.AffectedFiles(include_deletes=False):
3038 if f.LocalPath() == 'WATCHLISTS':
3039 contents = input_api.ReadFile(f, 'r')
3040
3041 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203042 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:133043 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203044 # Get an AST tree for it and scan the tree for detailed style checking.
3045 expression = input_api.ast.parse(
3046 contents, filename='WATCHLISTS', mode='eval')
3047 except ValueError as e:
3048 return [output_api.PresubmitError(
3049 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3050 except SyntaxError as e:
3051 return [output_api.PresubmitError(
3052 'Cannot parse WATCHLISTS file', long_text=repr(e))]
3053 except TypeError as e:
3054 return [output_api.PresubmitError(
3055 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:133056
Sergey Ulanov4af16052018-11-08 02:41:463057 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203058 if result is not None:
3059 return [output_api.PresubmitError(result)]
3060 break
Takeshi Yoshinoe387aa32017-08-02 13:16:133061
3062 return []
3063
3064
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193065def _CheckNewHeaderWithoutGnChange(input_api, output_api):
3066 """Checks that newly added header files have corresponding GN changes.
3067 Note that this is only a heuristic. To be precise, run script:
3068 build/check_gn_headers.py.
3069 """
3070
3071 def headers(f):
3072 return input_api.FilterSourceFile(
3073 f, white_list=(r'.+%s' % _HEADER_EXTENSIONS, ))
3074
3075 new_headers = []
3076 for f in input_api.AffectedSourceFiles(headers):
3077 if f.Action() != 'A':
3078 continue
3079 new_headers.append(f.LocalPath())
3080
3081 def gn_files(f):
3082 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn', ))
3083
3084 all_gn_changed_contents = ''
3085 for f in input_api.AffectedSourceFiles(gn_files):
3086 for _, line in f.ChangedContents():
3087 all_gn_changed_contents += line
3088
3089 problems = []
3090 for header in new_headers:
3091 basename = input_api.os_path.basename(header)
3092 if basename not in all_gn_changed_contents:
3093 problems.append(header)
3094
3095 if problems:
3096 return [output_api.PresubmitPromptWarning(
3097 'Missing GN changes for new header files', items=sorted(problems),
3098 long_text='Please double check whether newly added header files need '
3099 'corresponding changes in gn or gni files.\nThis checking is only a '
3100 'heuristic. Run build/check_gn_headers.py to be precise.\n'
3101 'Read https://crbug.com/661774 for more info.')]
3102 return []
3103
3104
Michael Giuffridad3bc8672018-10-25 22:48:023105def _CheckCorrectProductNameInMessages(input_api, output_api):
3106 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
3107
3108 This assumes we won't intentionally reference one product from the other
3109 product.
3110 """
3111 all_problems = []
3112 test_cases = [{
3113 "filename_postfix": "google_chrome_strings.grd",
3114 "correct_name": "Chrome",
3115 "incorrect_name": "Chromium",
3116 }, {
3117 "filename_postfix": "chromium_strings.grd",
3118 "correct_name": "Chromium",
3119 "incorrect_name": "Chrome",
3120 }]
3121
3122 for test_case in test_cases:
3123 problems = []
3124 filename_filter = lambda x: x.LocalPath().endswith(
3125 test_case["filename_postfix"])
3126
3127 # Check each new line. Can yield false positives in multiline comments, but
3128 # easier than trying to parse the XML because messages can have nested
3129 # children, and associating message elements with affected lines is hard.
3130 for f in input_api.AffectedSourceFiles(filename_filter):
3131 for line_num, line in f.ChangedContents():
3132 if "<message" in line or "<!--" in line or "-->" in line:
3133 continue
3134 if test_case["incorrect_name"] in line:
3135 problems.append(
3136 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
3137
3138 if problems:
3139 message = (
3140 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
3141 % (test_case["correct_name"], test_case["correct_name"],
3142 test_case["incorrect_name"]))
3143 all_problems.append(
3144 output_api.PresubmitPromptWarning(message, items=problems))
3145
3146 return all_problems
3147
3148
Dirk Pranke3c18a382019-03-15 01:07:513149def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
3150 # TODO(crbug.com/941824): We need to make sure the entries in
3151 # //buildtools/DEPS are kept in sync with the entries in //DEPS
3152 # so that users of //buildtools in other projects get the same tooling
3153 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
3154 # support to gclient, we can eliminate the duplication and delete
3155 # this presubmit check.
3156
3157 # Update this regexp if new revisions are added to the files.
3158 rev_regexp = input_api.re.compile(
Dirk Pranke6d095b42019-03-15 23:44:013159 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:513160
3161 # If a user is changing one revision, they need to change the same
3162 # line in both files. This means that any given change should contain
3163 # exactly the same list of changed lines that match the regexps. The
3164 # replace(' ', '') call allows us to ignore whitespace changes to the
3165 # lines. The 'long_text' parameter to the error will contain the
3166 # list of changed lines in both files, which should make it easy enough
3167 # to spot the error without going overboard in this implementation.
3168 revs_changes = {
3169 'DEPS': {},
3170 'buildtools/DEPS': {},
3171 }
3172 long_text = ''
3173
3174 for f in input_api.AffectedFiles(
3175 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
3176 for line_num, line in f.ChangedContents():
3177 if rev_regexp.search(line):
3178 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
3179 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
3180
3181 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
3182 return [output_api.PresubmitError(
3183 'Change buildtools revisions in sync in both //DEPS and '
3184 '//buildtools/DEPS.', long_text=long_text + '\n')]
3185 else:
3186 return []
3187
3188
dgnaa68d5e2015-06-10 10:08:223189def _AndroidSpecificOnUploadChecks(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:573190 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:223191 results = []
dgnaa68d5e2015-06-10 10:08:223192 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:223193 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:293194 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:063195 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
3196 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:423197 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:183198 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573199 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
3200 return results
3201
3202def _AndroidSpecificOnCommitChecks(input_api, output_api):
3203 """Groups commit checks that target android code."""
3204 results = []
3205 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:223206 return results
3207
3208
[email protected]22c9bd72011-03-27 16:47:393209def _CommonChecks(input_api, output_api):
3210 """Checks common to both upload and commit."""
3211 results = []
3212 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:383213 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:543214 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:083215
3216 author = input_api.change.author_email
3217 if author and author not in _KNOWN_ROBOTS:
3218 results.extend(
3219 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
3220
[email protected]55459852011-08-10 15:17:193221 results.extend(
[email protected]760deea2013-12-10 19:33:493222 _CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api))
Vaclav Brozek7dbc28c2018-03-27 08:35:233223 results.extend(
3224 _CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api))
[email protected]10689ca2011-09-02 02:31:543225 results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
[email protected]72df4e782012-06-21 16:28:183226 results.extend(_CheckNoUNIT_TESTInSourceFiles(input_api, output_api))
Dominic Battre033531052018-09-24 15:45:343227 results.extend(_CheckNoDISABLETypoInTests(input_api, output_api))
danakj61c1aa22015-10-26 19:55:523228 results.extend(_CheckDCHECK_IS_ONHasBraces(input_api, output_api))
[email protected]8ea5d4b2011-09-13 21:49:223229 results.extend(_CheckNoNewWStrings(input_api, output_api))
[email protected]2a8ac9c2011-10-19 17:20:443230 results.extend(_CheckNoDEPSGIT(input_api, output_api))
[email protected]127f18ec2012-06-16 05:05:593231 results.extend(_CheckNoBannedFunctions(input_api, output_api))
[email protected]6c063c62012-07-11 19:11:063232 results.extend(_CheckNoPragmaOnce(input_api, output_api))
[email protected]e7479052012-09-19 00:26:123233 results.extend(_CheckNoTrinaryTrueFalse(input_api, output_api))
[email protected]55f9f382012-07-31 11:02:183234 results.extend(_CheckUnwantedDependencies(input_api, output_api))
[email protected]fbcafe5a2012-08-08 15:31:223235 results.extend(_CheckFilePermissions(input_api, output_api))
robertocn832f5992017-01-04 19:01:303236 results.extend(_CheckTeamTags(input_api, output_api))
[email protected]c8278b32012-10-30 20:35:493237 results.extend(_CheckNoAuraWindowPropertyHInHeaders(input_api, output_api))
[email protected]70ca77752012-11-20 03:45:033238 results.extend(_CheckForVersionControlConflicts(input_api, output_api))
[email protected]b8079ae4a2012-12-05 19:56:493239 results.extend(_CheckPatchFiles(input_api, output_api))
[email protected]06e6d0ff2012-12-11 01:36:443240 results.extend(_CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api))
[email protected]d2530012013-01-25 16:39:273241 results.extend(_CheckNoAbbreviationInPngFileName(input_api, output_api))
Kent Tamura5a8755d2017-06-29 23:37:073242 results.extend(_CheckBuildConfigMacrosWithoutInclude(input_api, output_api))
[email protected]b00342e7f2013-03-26 16:21:543243 results.extend(_CheckForInvalidOSMacros(input_api, output_api))
lliabraa35bab3932014-10-01 12:16:443244 results.extend(_CheckForInvalidIfDefinedMacros(input_api, output_api))
yolandyandaabc6d2016-04-18 18:29:393245 results.extend(_CheckFlakyTestUsage(input_api, output_api))
[email protected]e871964c2013-05-13 14:14:553246 results.extend(_CheckAddedDepsHaveTargetApprovals(input_api, output_api))
[email protected]9f919cc2013-07-31 03:04:043247 results.extend(
3248 input_api.canned_checks.CheckChangeHasNoTabs(
3249 input_api,
3250 output_api,
3251 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
[email protected]85218562013-11-22 07:41:403252 results.extend(_CheckSpamLogging(input_api, output_api))
[email protected]49aa76a2013-12-04 06:59:163253 results.extend(_CheckForAnonymousVariables(input_api, output_api))
[email protected]999261d2014-03-03 20:08:083254 results.extend(_CheckUserActionUpdate(input_api, output_api))
dbeam1ec68ac2016-12-15 05:22:243255 results.extend(_CheckNoDeprecatedCss(input_api, output_api))
3256 results.extend(_CheckNoDeprecatedJs(input_api, output_api))
[email protected]99171a92014-06-03 08:44:473257 results.extend(_CheckParseErrors(input_api, output_api))
mlamouria82272622014-09-16 18:45:043258 results.extend(_CheckForIPCRules(input_api, output_api))
Stephen Martinis97a394142018-06-07 23:06:053259 results.extend(_CheckForLongPathnames(input_api, output_api))
Daniel Bratell8ba52722018-03-02 16:06:143260 results.extend(_CheckForIncludeGuards(input_api, output_api))
mostynbb639aca52015-01-07 20:31:233261 results.extend(_CheckForWindowsLineEndings(input_api, output_api))
glidere61efad2015-02-18 17:39:433262 results.extend(_CheckSingletonInHeaders(input_api, output_api))
agrievef32bcc72016-04-04 14:57:403263 results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
wnwenbdc444e2016-05-25 13:44:153264 results.extend(_CheckJavaStyle(input_api, output_api))
dchenge07de812016-06-20 19:27:173265 results.extend(_CheckIpcOwners(input_api, output_api))
jbriance9e12f162016-11-25 07:57:503266 results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
rlanday6802cf632017-05-30 17:48:363267 results.extend(_CheckForRelativeIncludes(input_api, output_api))
Takeshi Yoshinoe387aa32017-08-02 13:16:133268 results.extend(_CheckWATCHLISTS(input_api, output_api))
Sergiy Byelozyorov366b6482017-11-06 18:20:433269 results.extend(input_api.RunTests(
3270 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143271 results.extend(_CheckTranslationScreenshots(input_api, output_api))
Michael Giuffridad3bc8672018-10-25 22:48:023272 results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
Dirk Pranke3c18a382019-03-15 01:07:513273 results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
[email protected]2299dcf2012-11-15 19:56:243274
Vaclav Brozekcdc7defb2018-03-20 09:54:353275 for f in input_api.AffectedFiles():
3276 path, name = input_api.os_path.split(f.LocalPath())
3277 if name == 'PRESUBMIT.py':
3278 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:003279 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
3280 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:073281 # The PRESUBMIT.py file (and the directory containing it) might
3282 # have been affected by being moved or removed, so only try to
3283 # run the tests if they still exist.
3284 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
3285 input_api, output_api, full_path,
3286 whitelist=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:393287 return results
[email protected]1f7b4172010-01-28 01:17:343288
[email protected]b337cb5b2011-01-23 21:24:053289
[email protected]b8079ae4a2012-12-05 19:56:493290def _CheckPatchFiles(input_api, output_api):
3291 problems = [f.LocalPath() for f in input_api.AffectedFiles()
3292 if f.LocalPath().endswith(('.orig', '.rej'))]
3293 if problems:
3294 return [output_api.PresubmitError(
3295 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:033296 else:
3297 return []
[email protected]b8079ae4a2012-12-05 19:56:493298
3299
Kent Tamura5a8755d2017-06-29 23:37:073300def _CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:213301 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
3302 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
3303 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:073304 include_re = input_api.re.compile(
3305 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
3306 extension_re = input_api.re.compile(r'\.[a-z]+$')
3307 errors = []
3308 for f in input_api.AffectedFiles():
3309 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
3310 continue
3311 found_line_number = None
3312 found_macro = None
3313 for line_num, line in f.ChangedContents():
3314 match = macro_re.search(line)
3315 if match:
3316 found_line_number = line_num
3317 found_macro = match.group(2)
3318 break
3319 if not found_line_number:
3320 continue
3321
3322 found_include = False
3323 for line in f.NewContents():
3324 if include_re.search(line):
3325 found_include = True
3326 break
3327 if found_include:
3328 continue
3329
3330 if not f.LocalPath().endswith('.h'):
3331 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
3332 try:
3333 content = input_api.ReadFile(primary_header_path, 'r')
3334 if include_re.search(content):
3335 continue
3336 except IOError:
3337 pass
3338 errors.append('%s:%d %s macro is used without including build/'
3339 'build_config.h.'
3340 % (f.LocalPath(), found_line_number, found_macro))
3341 if errors:
3342 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
3343 return []
3344
3345
[email protected]b00342e7f2013-03-26 16:21:543346def _DidYouMeanOSMacro(bad_macro):
3347 try:
3348 return {'A': 'OS_ANDROID',
3349 'B': 'OS_BSD',
3350 'C': 'OS_CHROMEOS',
3351 'F': 'OS_FREEBSD',
3352 'L': 'OS_LINUX',
3353 'M': 'OS_MACOSX',
3354 'N': 'OS_NACL',
3355 'O': 'OS_OPENBSD',
3356 'P': 'OS_POSIX',
3357 'S': 'OS_SOLARIS',
3358 'W': 'OS_WIN'}[bad_macro[3].upper()]
3359 except KeyError:
3360 return ''
3361
3362
3363def _CheckForInvalidOSMacrosInFile(input_api, f):
3364 """Check for sensible looking, totally invalid OS macros."""
3365 preprocessor_statement = input_api.re.compile(r'^\s*#')
3366 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
3367 results = []
3368 for lnum, line in f.ChangedContents():
3369 if preprocessor_statement.search(line):
3370 for match in os_macro.finditer(line):
3371 if not match.group(1) in _VALID_OS_MACROS:
3372 good = _DidYouMeanOSMacro(match.group(1))
3373 did_you_mean = ' (did you mean %s?)' % good if good else ''
3374 results.append(' %s:%d %s%s' % (f.LocalPath(),
3375 lnum,
3376 match.group(1),
3377 did_you_mean))
3378 return results
3379
3380
3381def _CheckForInvalidOSMacros(input_api, output_api):
3382 """Check all affected files for invalid OS macros."""
3383 bad_macros = []
tzik3f295992018-12-04 20:32:233384 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:473385 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:543386 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
3387
3388 if not bad_macros:
3389 return []
3390
3391 return [output_api.PresubmitError(
3392 'Possibly invalid OS macro[s] found. Please fix your code\n'
3393 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
3394
lliabraa35bab3932014-10-01 12:16:443395
3396def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
3397 """Check all affected files for invalid "if defined" macros."""
3398 ALWAYS_DEFINED_MACROS = (
3399 "TARGET_CPU_PPC",
3400 "TARGET_CPU_PPC64",
3401 "TARGET_CPU_68K",
3402 "TARGET_CPU_X86",
3403 "TARGET_CPU_ARM",
3404 "TARGET_CPU_MIPS",
3405 "TARGET_CPU_SPARC",
3406 "TARGET_CPU_ALPHA",
3407 "TARGET_IPHONE_SIMULATOR",
3408 "TARGET_OS_EMBEDDED",
3409 "TARGET_OS_IPHONE",
3410 "TARGET_OS_MAC",
3411 "TARGET_OS_UNIX",
3412 "TARGET_OS_WIN32",
3413 )
3414 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
3415 results = []
3416 for lnum, line in f.ChangedContents():
3417 for match in ifdef_macro.finditer(line):
3418 if match.group(1) in ALWAYS_DEFINED_MACROS:
3419 always_defined = ' %s is always defined. ' % match.group(1)
3420 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
3421 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
3422 lnum,
3423 always_defined,
3424 did_you_mean))
3425 return results
3426
3427
3428def _CheckForInvalidIfDefinedMacros(input_api, output_api):
3429 """Check all affected files for invalid "if defined" macros."""
3430 bad_macros = []
3431 for f in input_api.AffectedFiles():
sdefresne4e1eccb32017-05-24 08:45:213432 if f.LocalPath().startswith('third_party/sqlite/'):
3433 continue
lliabraa35bab3932014-10-01 12:16:443434 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
3435 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
3436
3437 if not bad_macros:
3438 return []
3439
3440 return [output_api.PresubmitError(
3441 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
3442 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
3443 bad_macros)]
3444
3445
mlamouria82272622014-09-16 18:45:043446def _CheckForIPCRules(input_api, output_api):
3447 """Check for same IPC rules described in
3448 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
3449 """
3450 base_pattern = r'IPC_ENUM_TRAITS\('
3451 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
3452 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
3453
3454 problems = []
3455 for f in input_api.AffectedSourceFiles(None):
3456 local_path = f.LocalPath()
3457 if not local_path.endswith('.h'):
3458 continue
3459 for line_number, line in f.ChangedContents():
3460 if inclusion_pattern.search(line) and not comment_pattern.search(line):
3461 problems.append(
3462 '%s:%d\n %s' % (local_path, line_number, line.strip()))
3463
3464 if problems:
3465 return [output_api.PresubmitPromptWarning(
3466 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
3467 else:
3468 return []
3469
[email protected]b00342e7f2013-03-26 16:21:543470
Stephen Martinis97a394142018-06-07 23:06:053471def _CheckForLongPathnames(input_api, output_api):
3472 """Check to make sure no files being submitted have long paths.
3473 This causes issues on Windows.
3474 """
3475 problems = []
3476 for f in input_api.AffectedSourceFiles(None):
3477 local_path = f.LocalPath()
3478 # Windows has a path limit of 260 characters. Limit path length to 200 so
3479 # that we have some extra for the prefix on dev machines and the bots.
3480 if len(local_path) > 200:
3481 problems.append(local_path)
3482
3483 if problems:
3484 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
3485 else:
3486 return []
3487
3488
Daniel Bratell8ba52722018-03-02 16:06:143489def _CheckForIncludeGuards(input_api, output_api):
3490 """Check that header files have proper guards against multiple inclusion.
3491 If a file should not have such guards (and it probably should) then it
3492 should include the string "no-include-guard-because-multiply-included".
3493 """
Daniel Bratell6a75baef62018-06-04 10:04:453494 def is_chromium_header_file(f):
3495 # We only check header files under the control of the Chromium
3496 # project. That is, those outside third_party apart from
3497 # third_party/blink.
3498 file_with_path = input_api.os_path.normpath(f.LocalPath())
3499 return (file_with_path.endswith('.h') and
3500 (not file_with_path.startswith('third_party') or
3501 file_with_path.startswith(
3502 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:143503
3504 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:343505 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:143506
3507 errors = []
3508
Daniel Bratell6a75baef62018-06-04 10:04:453509 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:143510 guard_name = None
3511 guard_line_number = None
3512 seen_guard_end = False
3513
3514 file_with_path = input_api.os_path.normpath(f.LocalPath())
3515 base_file_name = input_api.os_path.splitext(
3516 input_api.os_path.basename(file_with_path))[0]
3517 upper_base_file_name = base_file_name.upper()
3518
3519 expected_guard = replace_special_with_underscore(
3520 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:143521
3522 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:573523 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
3524 # are too many (1000+) files with slight deviations from the
3525 # coding style. The most important part is that the include guard
3526 # is there, and that it's unique, not the name so this check is
3527 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:143528 #
3529 # As code becomes more uniform, this could be made stricter.
3530
3531 guard_name_pattern_list = [
3532 # Anything with the right suffix (maybe with an extra _).
3533 r'\w+_H__?',
3534
Daniel Bratell39b5b062018-05-16 18:09:573535 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:143536 r'\w+_h',
3537
3538 # Anything including the uppercase name of the file.
3539 r'\w*' + input_api.re.escape(replace_special_with_underscore(
3540 upper_base_file_name)) + r'\w*',
3541 ]
3542 guard_name_pattern = '|'.join(guard_name_pattern_list)
3543 guard_pattern = input_api.re.compile(
3544 r'#ifndef\s+(' + guard_name_pattern + ')')
3545
3546 for line_number, line in enumerate(f.NewContents()):
3547 if 'no-include-guard-because-multiply-included' in line:
3548 guard_name = 'DUMMY' # To not trigger check outside the loop.
3549 break
3550
3551 if guard_name is None:
3552 match = guard_pattern.match(line)
3553 if match:
3554 guard_name = match.group(1)
3555 guard_line_number = line_number
3556
Daniel Bratell39b5b062018-05-16 18:09:573557 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:453558 # don't match the chromium style guide, but new files should
3559 # get it right.
3560 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:573561 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:143562 errors.append(output_api.PresubmitPromptWarning(
3563 'Header using the wrong include guard name %s' % guard_name,
3564 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Daniel Bratell39b5b062018-05-16 18:09:573565 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:143566 else:
3567 # The line after #ifndef should have a #define of the same name.
3568 if line_number == guard_line_number + 1:
3569 expected_line = '#define %s' % guard_name
3570 if line != expected_line:
3571 errors.append(output_api.PresubmitPromptWarning(
3572 'Missing "%s" for include guard' % expected_line,
3573 ['%s:%d' % (f.LocalPath(), line_number + 1)],
3574 'Expected: %r\nGot: %r' % (expected_line, line)))
3575
3576 if not seen_guard_end and line == '#endif // %s' % guard_name:
3577 seen_guard_end = True
3578 elif seen_guard_end:
3579 if line.strip() != '':
3580 errors.append(output_api.PresubmitPromptWarning(
3581 'Include guard %s not covering the whole file' % (
3582 guard_name), [f.LocalPath()]))
3583 break # Nothing else to check and enough to warn once.
3584
3585 if guard_name is None:
3586 errors.append(output_api.PresubmitPromptWarning(
3587 'Missing include guard %s' % expected_guard,
3588 [f.LocalPath()],
3589 'Missing include guard in %s\n'
3590 'Recommended name: %s\n'
3591 'This check can be disabled by having the string\n'
3592 'no-include-guard-because-multiply-included in the header.' %
3593 (f.LocalPath(), expected_guard)))
3594
3595 return errors
3596
3597
mostynbb639aca52015-01-07 20:31:233598def _CheckForWindowsLineEndings(input_api, output_api):
3599 """Check source code and known ascii text files for Windows style line
3600 endings.
3601 """
earthdok1b5e0ee2015-03-10 15:19:103602 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:233603
3604 file_inclusion_pattern = (
3605 known_text_files,
3606 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
3607 )
3608
mostynbb639aca52015-01-07 20:31:233609 problems = []
Andrew Grieve933d12e2017-10-30 20:22:533610 source_file_filter = lambda f: input_api.FilterSourceFile(
3611 f, white_list=file_inclusion_pattern, black_list=None)
3612 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:503613 include_file = False
3614 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:233615 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:503616 include_file = True
3617 if include_file:
3618 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:233619
3620 if problems:
3621 return [output_api.PresubmitPromptWarning('Are you sure that you want '
3622 'these files to contain Windows style line endings?\n' +
3623 '\n'.join(problems))]
3624
3625 return []
3626
3627
Vaclav Brozekd5de76a2018-03-17 07:57:503628def _CheckSyslogUseWarning(input_api, output_api, source_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:133629 """Checks that all source files use SYSLOG properly."""
3630 syslog_files = []
3631 for f in input_api.AffectedSourceFiles(source_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:563632 for line_number, line in f.ChangedContents():
3633 if 'SYSLOG' in line:
3634 syslog_files.append(f.LocalPath() + ':' + str(line_number))
3635
pastarmovj89f7ee12016-09-20 14:58:133636 if syslog_files:
3637 return [output_api.PresubmitPromptWarning(
3638 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
3639 ' calls.\nFiles to check:\n', items=syslog_files)]
3640 return []
3641
3642
[email protected]1f7b4172010-01-28 01:17:343643def CheckChangeOnUpload(input_api, output_api):
3644 results = []
3645 results.extend(_CommonChecks(input_api, output_api))
tandriief664692014-09-23 14:51:473646 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
scottmg39b29952014-12-08 18:31:283647 results.extend(
jam93a6ee792017-02-08 23:59:223648 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
mcasasb7440c282015-02-04 14:52:193649 results.extend(_CheckUmaHistogramChanges(input_api, output_api))
dgnaa68d5e2015-06-10 10:08:223650 results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
pastarmovj89f7ee12016-09-20 14:58:133651 results.extend(_CheckSyslogUseWarning(input_api, output_api))
estadee17314a02017-01-12 16:22:163652 results.extend(_CheckGoogleSupportAnswerUrl(input_api, output_api))
Vaclav Brozekea41ab22018-04-06 13:21:533653 results.extend(_CheckUniquePtr(input_api, output_api))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:193654 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543655 return results
[email protected]ca8d1982009-02-19 16:33:123656
3657
[email protected]1bfb8322014-04-23 01:02:413658def GetTryServerMasterForBot(bot):
3659 """Returns the Try Server master for the given bot.
3660
[email protected]0bb112362014-07-26 04:38:323661 It tries to guess the master from the bot name, but may still fail
3662 and return None. There is no longer a default master.
3663 """
3664 # Potentially ambiguous bot names are listed explicitly.
3665 master_map = {
tandriie5587792016-07-14 00:34:503666 'chromium_presubmit': 'master.tryserver.chromium.linux',
3667 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:413668 }
[email protected]0bb112362014-07-26 04:38:323669 master = master_map.get(bot)
3670 if not master:
wnwen4fbaab82016-05-25 12:54:363671 if 'android' in bot:
tandriie5587792016-07-14 00:34:503672 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:363673 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:503674 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:323675 elif 'win' in bot:
tandriie5587792016-07-14 00:34:503676 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:323677 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:503678 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:323679 return master
[email protected]1bfb8322014-04-23 01:02:413680
3681
[email protected]ca8d1982009-02-19 16:33:123682def CheckChangeOnCommit(input_api, output_api):
[email protected]fe5f57c52009-06-05 14:25:543683 results = []
[email protected]1f7b4172010-01-28 01:17:343684 results.extend(_CommonChecks(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:573685 results.extend(_AndroidSpecificOnCommitChecks(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543686 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:273687 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:343688 input_api,
3689 output_api,
[email protected]2fdd1f362013-01-16 03:56:033690 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:273691
jam93a6ee792017-02-08 23:59:223692 results.extend(
3693 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:543694 results.extend(input_api.canned_checks.CheckChangeHasBugField(
3695 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:413696 results.extend(input_api.canned_checks.CheckChangeHasDescription(
3697 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:543698 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143699
3700
3701def _CheckTranslationScreenshots(input_api, output_api):
3702 PART_FILE_TAG = "part"
3703 import os
3704 import sys
3705 from io import StringIO
3706
3707 try:
3708 old_sys_path = sys.path
3709 sys.path = sys.path + [input_api.os_path.join(
3710 input_api.PresubmitLocalPath(), 'tools', 'grit')]
3711 import grit.grd_reader
3712 import grit.node.message
3713 import grit.util
3714 finally:
3715 sys.path = old_sys_path
3716
3717 def _GetGrdMessages(grd_path_or_string, dir_path='.'):
3718 """Load the grd file and return a dict of message ids to messages.
3719
3720 Ignores any nested grdp files pointed by <part> tag.
3721 """
3722 doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
3723 stop_after=None, first_ids_file=None,
3724 debug=False, defines=None,
3725 tags_to_ignore=set([PART_FILE_TAG]))
3726 return {
3727 msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
3728 grit.node.message.MessageNode)
3729 }
3730
3731 def _GetGrdpMessagesFromString(grdp_string):
3732 """Parses the contents of a grdp file given in grdp_string.
3733
3734 grd_reader can't parse grdp files directly. Instead, this creates a
3735 temporary directory with a grd file pointing to the grdp file, and loads the
3736 grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
3737 """
3738 WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
3739 <grit latest_public_release="1" current_release="1">
3740 <release seq="1">
3741 <messages>
3742 <part file="sub.grdp" />
3743 </messages>
3744 </release>
3745 </grit>
3746 """
3747 with grit.util.TempDir({'main.grd': WRAPPER,
3748 'sub.grdp': grdp_string}) as temp_dir:
3749 return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
3750
3751 new_or_added_paths = set(f.LocalPath()
3752 for f in input_api.AffectedFiles()
3753 if (f.Action() == 'A' or f.Action() == 'M'))
3754 removed_paths = set(f.LocalPath()
3755 for f in input_api.AffectedFiles(include_deletes=True)
3756 if f.Action() == 'D')
3757
3758 affected_grds = [f for f in input_api.AffectedFiles()
3759 if (f.LocalPath().endswith('.grd') or
3760 f.LocalPath().endswith('.grdp'))]
3761 affected_png_paths = [f.AbsoluteLocalPath()
3762 for f in input_api.AffectedFiles()
3763 if (f.LocalPath().endswith('.png'))]
3764
3765 # Check for screenshots. Developers can upload screenshots using
3766 # tools/translation/upload_screenshots.py which finds and uploads
3767 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
3768 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
3769 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
3770 #
3771 # The logic here is as follows:
3772 #
3773 # - If the CL has a .png file under the screenshots directory for a grd
3774 # file, warn the developer. Actual images should never be checked into the
3775 # Chrome repo.
3776 #
3777 # - If the CL contains modified or new messages in grd files and doesn't
3778 # contain the corresponding .sha1 files, warn the developer to add images
3779 # and upload them via tools/translation/upload_screenshots.py.
3780 #
3781 # - If the CL contains modified or new messages in grd files and the
3782 # corresponding .sha1 files, everything looks good.
3783 #
3784 # - If the CL contains removed messages in grd files but the corresponding
3785 # .sha1 files aren't removed, warn the developer to remove them.
3786 unnecessary_screenshots = []
3787 missing_sha1 = []
3788 unnecessary_sha1_files = []
3789
3790
3791 def _CheckScreenshotAdded(screenshots_dir, message_id):
3792 sha1_path = input_api.os_path.join(
3793 screenshots_dir, message_id + '.png.sha1')
3794 if sha1_path not in new_or_added_paths:
3795 missing_sha1.append(sha1_path)
3796
3797
3798 def _CheckScreenshotRemoved(screenshots_dir, message_id):
3799 sha1_path = input_api.os_path.join(
3800 screenshots_dir, message_id + '.png.sha1')
3801 if sha1_path not in removed_paths:
3802 unnecessary_sha1_files.append(sha1_path)
3803
3804
3805 for f in affected_grds:
3806 file_path = f.LocalPath()
3807 old_id_to_msg_map = {}
3808 new_id_to_msg_map = {}
3809 if file_path.endswith('.grdp'):
3810 if f.OldContents():
3811 old_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393812 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143813 if f.NewContents():
3814 new_id_to_msg_map = _GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393815 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143816 else:
3817 if f.OldContents():
3818 old_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393819 StringIO(unicode('\n'.join(f.OldContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143820 if f.NewContents():
3821 new_id_to_msg_map = _GetGrdMessages(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393822 StringIO(unicode('\n'.join(f.NewContents()))))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143823
3824 # Compute added, removed and modified message IDs.
3825 old_ids = set(old_id_to_msg_map)
3826 new_ids = set(new_id_to_msg_map)
3827 added_ids = new_ids - old_ids
3828 removed_ids = old_ids - new_ids
3829 modified_ids = set([])
3830 for key in old_ids.intersection(new_ids):
3831 if (old_id_to_msg_map[key].FormatXml()
3832 != new_id_to_msg_map[key].FormatXml()):
3833 modified_ids.add(key)
3834
3835 grd_name, ext = input_api.os_path.splitext(
3836 input_api.os_path.basename(file_path))
3837 screenshots_dir = input_api.os_path.join(
3838 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
3839
3840 # Check the screenshot directory for .png files. Warn if there is any.
3841 for png_path in affected_png_paths:
3842 if png_path.startswith(screenshots_dir):
3843 unnecessary_screenshots.append(png_path)
3844
3845 for added_id in added_ids:
3846 _CheckScreenshotAdded(screenshots_dir, added_id)
3847
3848 for modified_id in modified_ids:
3849 _CheckScreenshotAdded(screenshots_dir, modified_id)
3850
3851 for removed_id in removed_ids:
3852 _CheckScreenshotRemoved(screenshots_dir, removed_id)
3853
3854 results = []
3855 if unnecessary_screenshots:
3856 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393857 'Do not include actual screenshots in the changelist. Run '
3858 'tools/translate/upload_screenshots.py to upload them instead:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143859 sorted(unnecessary_screenshots)))
3860
3861 if missing_sha1:
3862 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393863 'You are adding or modifying UI strings.\n'
3864 'To ensure the best translations, take screenshots of the relevant UI '
3865 '(https://g.co/chrome/translation) and add these files to your '
3866 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143867
3868 if unnecessary_sha1_files:
3869 results.append(output_api.PresubmitNotifyResult(
Mustafa Emre Acerc8a012d2018-07-31 00:00:393870 'You removed strings associated with these files. Remove:',
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143871 sorted(unnecessary_sha1_files)))
3872
3873 return results