blob: 69af581facdb658a37de67d27c10f8368c935112 [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"""
Saagar Sanghavifceeaae2020-08-12 16:40:3610PRESUBMIT_VERSION = '2.0.0'
[email protected]eea609a2011-11-18 13:10:1211
[email protected]379e7dd2010-01-28 17:39:2112_EXCLUDED_PATHS = (
Ilya Shermane8a7d2d2020-07-25 04:33:4713 # Generated file.
14 (r"^components[\\/]variations[\\/]proto[\\/]devtools[\\/]"
Ilya Shermanc167a962020-08-18 18:40:2615 r"client_variations.js"),
Egor Paskoce145c42018-09-28 19:31:0416 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_rules.py",
17 r"^native_client_sdk[\\/]src[\\/]build_tools[\\/]make_simple.py",
18 r"^native_client_sdk[\\/]src[\\/]tools[\\/].*.mk",
19 r"^net[\\/]tools[\\/]spdyshark[\\/].*",
20 r"^skia[\\/].*",
Kent Tamura32dbbcb2018-11-30 12:28:4921 r"^third_party[\\/]blink[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0422 r"^third_party[\\/]breakpad[\\/].*",
Darwin Huangd74a9d32019-07-17 17:58:4623 # sqlite is an imported third party dependency.
24 r"^third_party[\\/]sqlite[\\/].*",
Egor Paskoce145c42018-09-28 19:31:0425 r"^v8[\\/].*",
[email protected]3e4eb112011-01-18 03:29:5426 r".*MakeFile$",
[email protected]1084ccc2012-03-14 03:22:5327 r".+_autogen\.h$",
John Budorick1e701d322019-09-11 23:35:1228 r".+_pb2\.py$",
Egor Paskoce145c42018-09-28 19:31:0429 r".+[\\/]pnacl_shim\.c$",
30 r"^gpu[\\/]config[\\/].*_list_json\.cc$",
Egor Paskoce145c42018-09-28 19:31:0431 r"tools[\\/]md_browser[\\/].*\.css$",
Kenneth Russell077c8d92017-12-16 02:52:1432 # Test pages for Maps telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0433 r"tools[\\/]perf[\\/]page_sets[\\/]maps_perf_test.*",
ehmaldonado78eee2ed2017-03-28 13:16:5434 # Test pages for WebRTC telemetry tests.
Egor Paskoce145c42018-09-28 19:31:0435 r"tools[\\/]perf[\\/]page_sets[\\/]webrtc_cases.*",
[email protected]4306417642009-06-11 00:33:4036)
[email protected]ca8d1982009-02-19 16:33:1237
wnwenbdc444e2016-05-25 13:44:1538
[email protected]06e6d0ff2012-12-11 01:36:4439# Fragment of a regular expression that matches C++ and Objective-C++
40# implementation files.
41_IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
42
wnwenbdc444e2016-05-25 13:44:1543
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:1944# Fragment of a regular expression that matches C++ and Objective-C++
45# header files.
46_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
47
48
[email protected]06e6d0ff2012-12-11 01:36:4449# Regular expression that matches code only used for test binaries
50# (best effort).
51_TEST_CODE_EXCLUDED_PATHS = (
Egor Paskoce145c42018-09-28 19:31:0452 r'.*[\\/](fake_|test_|mock_).+%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4453 r'.+_test_(base|support|util)%s' % _IMPLEMENTATION_EXTENSIONS,
Steven Holte27008b7422018-01-29 20:55:4454 r'.+_(api|browser|eg|int|perf|pixel|unit|ui)?test(_[a-z]+)?%s' %
[email protected]e2d7e6f2013-04-23 12:57:1255 _IMPLEMENTATION_EXTENSIONS,
Matthew Denton63ea1e62019-03-25 20:39:1856 r'.+_(fuzz|fuzzer)(_[a-z]+)?%s' % _IMPLEMENTATION_EXTENSIONS,
[email protected]06e6d0ff2012-12-11 01:36:4457 r'.+profile_sync_service_harness%s' % _IMPLEMENTATION_EXTENSIONS,
Egor Paskoce145c42018-09-28 19:31:0458 r'.*[\\/](test|tool(s)?)[\\/].*',
danakj89f47082020-09-02 17:53:4359 # content_shell is used for running content_browsertests.
Egor Paskoce145c42018-09-28 19:31:0460 r'content[\\/]shell[\\/].*',
danakj89f47082020-09-02 17:53:4361 # Web test harness.
62 r'content[\\/]web_test[\\/].*',
[email protected]7b054982013-11-27 00:44:4763 # Non-production example code.
Egor Paskoce145c42018-09-28 19:31:0464 r'mojo[\\/]examples[\\/].*',
[email protected]8176de12014-06-20 19:07:0865 # Launcher for running iOS tests on the simulator.
Egor Paskoce145c42018-09-28 19:31:0466 r'testing[\\/]iossim[\\/]iossim\.mm$',
Olivier Robinbcea0fa2019-11-12 08:56:4167 # EarlGrey app side code for tests.
68 r'ios[\\/].*_app_interface\.mm$',
Allen Bauer0678d772020-05-11 22:25:1769 # Views Examples code
70 r'ui[\\/]views[\\/]examples[\\/].*',
[email protected]06e6d0ff2012-12-11 01:36:4471)
[email protected]ca8d1982009-02-19 16:33:1272
Daniel Bratell609102be2019-03-27 20:53:2173_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1574
[email protected]eea609a2011-11-18 13:10:1275_TEST_ONLY_WARNING = (
76 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:5577 'production code. If you are doing this from inside another method\n'
78 'named as *ForTesting(), then consider exposing things to have tests\n'
79 'make that same call directly.\n'
80 'If that is not possible, you may put a comment on the same line with\n'
81 ' // IN-TEST \n'
82 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
83 'method and can be ignored. Do not do this inside production code.\n'
84 'The android-binary-size trybot will block if the method exists in the\n'
85 'release apk.')
[email protected]eea609a2011-11-18 13:10:1286
87
[email protected]cf9b78f2012-11-14 11:40:2888_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4089 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2190 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
91 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2892
Michael Thiessen44457642020-02-06 00:24:1593# Format: Sequence of tuples containing:
94# * Full import path.
95# * Sequence of strings to show when the pattern matches.
96# * Sequence of path or filename exceptions to this rule
97_BANNED_JAVA_IMPORTS = (
98 (
Colin Blundell170d78c82020-03-12 13:56:0499 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:15100 (
101 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
102 ),
103 (
104 'net/android/javatests/src/org/chromium/net/'
105 'AndroidProxySelectorTest.java',
106 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04107 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15108 ),
109 ),
Michael Thiessened631912020-08-07 19:01:31110 (
111 'android.support.test.rule.UiThreadTestRule;',
112 (
113 'Do not use UiThreadTestRule, just use '
danakj89f47082020-09-02 17:53:43114 '@org.chromium.base.test.UiThreadTest on test methods that should run '
115 'on the UI thread. See https://crbug.com/1111893.',
Michael Thiessened631912020-08-07 19:01:31116 ),
117 (),
118 ),
119 (
120 'android.support.test.annotation.UiThreadTest;',
121 (
122 'Do not use android.support.test.annotation.UiThreadTest, use '
123 'org.chromium.base.test.UiThreadTest instead. See '
124 'https://crbug.com/1111893.',
125 ),
126 ()
127 )
Michael Thiessen44457642020-02-06 00:24:15128)
wnwenbdc444e2016-05-25 13:44:15129
Daniel Bratell609102be2019-03-27 20:53:21130# Format: Sequence of tuples containing:
131# * String pattern or, if starting with a slash, a regular expression.
132# * Sequence of strings to show when the pattern matches.
133# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41134_BANNED_JAVA_FUNCTIONS = (
135 (
136 'StrictMode.allowThreadDiskReads()',
137 (
138 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
139 'directly.',
140 ),
141 False,
142 ),
143 (
144 'StrictMode.allowThreadDiskWrites()',
145 (
146 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
147 'directly.',
148 ),
149 False,
150 ),
Michael Thiessen0f2547e2020-07-27 21:55:36151 (
152 '.waitForIdleSync()',
153 (
154 'Do not use waitForIdleSync as it masks underlying issues. There is '
155 'almost always something else you should wait on instead.',
156 ),
157 False,
158 ),
Eric Stevensona9a980972017-09-23 00:04:41159)
160
Daniel Bratell609102be2019-03-27 20:53:21161# Format: Sequence of tuples containing:
162# * String pattern or, if starting with a slash, a regular expression.
163# * Sequence of strings to show when the pattern matches.
164# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59165_BANNED_OBJC_FUNCTIONS = (
166 (
167 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20168 (
169 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59170 'prohibited. Please use CrTrackingArea instead.',
171 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
172 ),
173 False,
174 ),
175 (
[email protected]eaae1972014-04-16 04:17:26176 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20177 (
178 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59179 'instead.',
180 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
181 ),
182 False,
183 ),
184 (
185 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20186 (
187 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59188 'Please use |convertPoint:(point) fromView:nil| instead.',
189 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
190 ),
191 True,
192 ),
193 (
194 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20195 (
196 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59197 'Please use |convertPoint:(point) toView:nil| instead.',
198 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
199 ),
200 True,
201 ),
202 (
203 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20204 (
205 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59206 'Please use |convertRect:(point) fromView:nil| instead.',
207 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
208 ),
209 True,
210 ),
211 (
212 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20213 (
214 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59215 'Please use |convertRect:(point) toView:nil| instead.',
216 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
217 ),
218 True,
219 ),
220 (
221 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20222 (
223 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59224 'Please use |convertSize:(point) fromView:nil| instead.',
225 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
226 ),
227 True,
228 ),
229 (
230 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20231 (
232 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59233 'Please use |convertSize:(point) toView:nil| instead.',
234 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
235 ),
236 True,
237 ),
jif65398702016-10-27 10:19:48238 (
239 r"/\s+UTF8String\s*]",
240 (
241 'The use of -[NSString UTF8String] is dangerous as it can return null',
242 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
243 'Please use |SysNSStringToUTF8| instead.',
244 ),
245 True,
246 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34247 (
248 r'__unsafe_unretained',
249 (
250 'The use of __unsafe_unretained is almost certainly wrong, unless',
251 'when interacting with NSFastEnumeration or NSInvocation.',
252 'Please use __weak in files build with ARC, nothing otherwise.',
253 ),
254 False,
255 ),
Avi Drissman7382afa02019-04-29 23:27:13256 (
257 'freeWhenDone:NO',
258 (
259 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
260 'Foundation types is prohibited.',
261 ),
262 True,
263 ),
[email protected]127f18ec2012-06-16 05:05:59264)
265
Daniel Bratell609102be2019-03-27 20:53:21266# Format: Sequence of tuples containing:
267# * String pattern or, if starting with a slash, a regular expression.
268# * Sequence of strings to show when the pattern matches.
269# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54270_BANNED_IOS_OBJC_FUNCTIONS = (
271 (
272 r'/\bTEST[(]',
273 (
274 'TEST() macro should not be used in Objective-C++ code as it does not ',
275 'drain the autorelease pool at the end of the test. Use TEST_F() ',
276 'macro instead with a fixture inheriting from PlatformTest (or a ',
277 'typedef).'
278 ),
279 True,
280 ),
281 (
282 r'/\btesting::Test\b',
283 (
284 'testing::Test should not be used in Objective-C++ code as it does ',
285 'not drain the autorelease pool at the end of the test. Use ',
286 'PlatformTest instead.'
287 ),
288 True,
289 ),
290)
291
Peter K. Lee6c03ccff2019-07-15 14:40:05292# Format: Sequence of tuples containing:
293# * String pattern or, if starting with a slash, a regular expression.
294# * Sequence of strings to show when the pattern matches.
295# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
296_BANNED_IOS_EGTEST_FUNCTIONS = (
297 (
298 r'/\bEXPECT_OCMOCK_VERIFY\b',
299 (
300 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
301 'it is meant for GTests. Use [mock verify] instead.'
302 ),
303 True,
304 ),
305)
306
danakj7a2b7082019-05-21 21:13:51307# Directories that contain deprecated Bind() or Callback types.
308# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36309# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51310# echo "-- $i"
danakj710b4c02019-11-28 16:08:45311# (cd $i; git grep -nP 'base::(Bind\(|(Callback<|Closure))'|wc -l)
danakj7a2b7082019-05-21 21:13:51312# done
313#
314# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
315# when they have been converted to modern callback types (OnceCallback,
316# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
317# checks for them and prevent regressions.
318_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
danakj7a2b7082019-05-21 21:13:51319 '^base/callback.h', # Intentional.
Alexander Cooper6b447b22020-07-22 00:47:18320 '^chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc',
321 '^chrome/browser/apps/guest_view/',
Alexander Cooper6b447b22020-07-22 00:47:18322 '^chrome/browser/browsing_data/',
323 '^chrome/browser/captive_portal/captive_portal_browsertest.cc',
324 '^chrome/browser/chromeos/',
325 '^chrome/browser/component_updater/',
Peter Wen6367b882020-08-05 16:55:50326 '^chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.cc', # pylint: disable=line-too-long
Alexander Cooper6b447b22020-07-22 00:47:18327 '^chrome/browser/devtools/',
328 '^chrome/browser/download/',
329 '^chrome/browser/extensions/',
Alexander Cooper6b447b22020-07-22 00:47:18330 '^chrome/browser/history/',
Alexander Cooper6b447b22020-07-22 00:47:18331 '^chrome/browser/lifetime/',
332 '^chrome/browser/media_galleries/',
333 '^chrome/browser/media/',
334 '^chrome/browser/metrics/',
Alexander Cooper6b447b22020-07-22 00:47:18335 '^chrome/browser/net/',
336 '^chrome/browser/notifications/',
337 '^chrome/browser/ntp_tiles/ntp_tiles_browsertest.cc',
338 '^chrome/browser/offline_pages/',
Peter Wen6367b882020-08-05 16:55:50339 '^chrome/browser/page_load_metrics/observers/data_saver_site_breakdown_metrics_observer_browsertest.cc', # pylint: disable=line-too-long
Alexander Cooper6b447b22020-07-22 00:47:18340 '^chrome/browser/payments/payment_manifest_parser_browsertest.cc',
341 '^chrome/browser/pdf/pdf_extension_test.cc',
342 '^chrome/browser/plugins/',
343 '^chrome/browser/policy/',
344 '^chrome/browser/portal/portal_browsertest.cc',
345 '^chrome/browser/prefs/profile_pref_store_manager_unittest.cc',
346 '^chrome/browser/prerender/',
347 '^chrome/browser/previews/',
348 '^chrome/browser/printing/printing_message_filter.cc',
349 '^chrome/browser/profiles/',
350 '^chrome/browser/profiling_host/profiling_process_host.cc',
351 '^chrome/browser/push_messaging/',
352 '^chrome/browser/recovery/recovery_install_global_error.cc',
353 '^chrome/browser/renderer_context_menu/',
354 '^chrome/browser/renderer_host/pepper/',
355 '^chrome/browser/resource_coordinator/',
356 '^chrome/browser/resources/chromeos/accessibility/',
357 '^chrome/browser/rlz/chrome_rlz_tracker_delegate.cc',
358 '^chrome/browser/safe_browsing/',
359 '^chrome/browser/search_engines/',
360 '^chrome/browser/service_process/',
361 '^chrome/browser/signin/',
362 '^chrome/browser/site_isolation/site_per_process_text_input_browsertest.cc',
363 '^chrome/browser/ssl/',
364 '^chrome/browser/subresource_filter/',
365 '^chrome/browser/supervised_user/',
366 '^chrome/browser/sync_file_system/',
367 '^chrome/browser/sync/',
368 '^chrome/browser/themes/theme_service.cc',
369 '^chrome/browser/thumbnail/cc/',
Alexander Cooper6b447b22020-07-22 00:47:18370 '^chrome/browser/translate/',
371 '^chrome/browser/ui/',
Alexander Cooper6b447b22020-07-22 00:47:18372 '^chrome/browser/web_applications/',
373 '^chrome/browser/win/',
danakj7a2b7082019-05-21 21:13:51374 '^chrome/services/',
375 '^chrome/test/',
376 '^chrome/tools/',
danakj7a2b7082019-05-21 21:13:51377 '^chromecast/media/',
danakj7a2b7082019-05-21 21:13:51378 '^chromeos/attestation/',
danakj7a2b7082019-05-21 21:13:51379 '^chromeos/components/',
danakj7a2b7082019-05-21 21:13:51380 '^components/arc/',
danakj7a2b7082019-05-21 21:13:51381 '^components/cast_channel/',
danakj7a2b7082019-05-21 21:13:51382 '^components/component_updater/',
383 '^components/content_settings/',
danakj7a2b7082019-05-21 21:13:51384 '^components/drive/',
danakj7a2b7082019-05-21 21:13:51385 '^components/nacl/',
386 '^components/navigation_interception/',
danakj7a2b7082019-05-21 21:13:51387 '^components/ownership/',
danakj7a2b7082019-05-21 21:13:51388 '^components/policy/',
danakj7a2b7082019-05-21 21:13:51389 '^components/search_engines/',
danakj7a2b7082019-05-21 21:13:51390 '^components/security_interstitials/',
danakj7a2b7082019-05-21 21:13:51391 '^components/signin/',
danakj7a2b7082019-05-21 21:13:51392 '^components/sync/',
danakj7a2b7082019-05-21 21:13:51393 '^components/ukm/',
danakj7a2b7082019-05-21 21:13:51394 '^components/webcrypto/',
Alan Cutter04a00642020-03-02 01:45:20395 '^extensions/browser/',
396 '^extensions/renderer/',
Alexander Cooper922f2112020-07-22 16:27:43397 '^google_apis/drive/',
danakj7a2b7082019-05-21 21:13:51398 '^ios/chrome/',
399 '^ios/components/',
400 '^ios/net/',
401 '^ios/web/',
402 '^ios/web_view/',
403 '^ipc/',
danakjc8576092019-11-26 19:01:36404 '^media/blink/',
danakj7a2b7082019-05-21 21:13:51405 '^media/cast/',
406 '^media/cdm/',
danakj7a2b7082019-05-21 21:13:51407 '^media/filters/',
danakj7a2b7082019-05-21 21:13:51408 '^media/gpu/',
409 '^media/mojo/',
Steve Kobes334b6ed2020-07-09 07:26:31410 '^net/http/',
411 '^net/url_request/',
danakj7a2b7082019-05-21 21:13:51412 '^ppapi/proxy/',
danakj7a2b7082019-05-21 21:13:51413 '^services/',
danakj7a2b7082019-05-21 21:13:51414 '^third_party/blink/',
danakj7a2b7082019-05-21 21:13:51415 '^tools/clang/base_bind_rewriters/', # Intentional.
416 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51417))
[email protected]127f18ec2012-06-16 05:05:59418
Daniel Bratell609102be2019-03-27 20:53:21419# Format: Sequence of tuples containing:
420# * String pattern or, if starting with a slash, a regular expression.
421# * Sequence of strings to show when the pattern matches.
422# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
423# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59424_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20425 (
Dave Tapuska98199b612019-07-10 13:30:44426 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53427 (
428 'New code should not use NULL. Use nullptr instead.',
429 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20430 False,
thomasandersone7caaa9b2017-03-29 19:22:53431 (),
432 ),
Peter Kasting94a56c42019-10-25 21:54:04433 (
434 r'/\busing namespace ',
435 (
436 'Using directives ("using namespace x") are banned by the Google Style',
437 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
438 'Explicitly qualify symbols or use using declarations ("using x::foo").',
439 ),
440 True,
441 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
442 ),
Antonio Gomes07300d02019-03-13 20:59:57443 # Make sure that gtest's FRIEND_TEST() macro is not used; the
444 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
445 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53446 (
[email protected]23e6cbc2012-06-16 18:51:20447 'FRIEND_TEST(',
448 (
[email protected]e3c945502012-06-26 20:01:49449 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20450 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
451 ),
452 False,
[email protected]7345da02012-11-27 14:31:49453 (),
[email protected]23e6cbc2012-06-16 18:51:20454 ),
455 (
tomhudsone2c14d552016-05-26 17:07:46456 'setMatrixClip',
457 (
458 'Overriding setMatrixClip() is prohibited; ',
459 'the base function is deprecated. ',
460 ),
461 True,
462 (),
463 ),
464 (
[email protected]52657f62013-05-20 05:30:31465 'SkRefPtr',
466 (
467 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22468 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31469 ),
470 True,
471 (),
472 ),
473 (
474 'SkAutoRef',
475 (
476 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22477 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31478 ),
479 True,
480 (),
481 ),
482 (
483 'SkAutoTUnref',
484 (
485 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22486 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31487 ),
488 True,
489 (),
490 ),
491 (
492 'SkAutoUnref',
493 (
494 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
495 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22496 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31497 ),
498 True,
499 (),
500 ),
[email protected]d89eec82013-12-03 14:10:59501 (
502 r'/HANDLE_EINTR\(.*close',
503 (
504 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
505 'descriptor will be closed, and it is incorrect to retry the close.',
506 'Either call close directly and ignore its return value, or wrap close',
507 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
508 ),
509 True,
510 (),
511 ),
512 (
513 r'/IGNORE_EINTR\((?!.*close)',
514 (
515 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
516 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
517 ),
518 True,
519 (
520 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04521 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
522 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59523 ),
524 ),
[email protected]ec5b3f02014-04-04 18:43:43525 (
526 r'/v8::Extension\(',
527 (
528 'Do not introduce new v8::Extensions into the code base, use',
529 'gin::Wrappable instead. See http://crbug.com/334679',
530 ),
531 True,
[email protected]f55c90ee62014-04-12 00:50:03532 (
Egor Paskoce145c42018-09-28 19:31:04533 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03534 ),
[email protected]ec5b3f02014-04-04 18:43:43535 ),
skyostilf9469f72015-04-20 10:38:52536 (
jame2d1a952016-04-02 00:27:10537 '#pragma comment(lib,',
538 (
539 'Specify libraries to link with in build files and not in the source.',
540 ),
541 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41542 (
tzik3f295992018-12-04 20:32:23543 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04544 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41545 ),
jame2d1a952016-04-02 00:27:10546 ),
fdorayc4ac18d2017-05-01 21:39:59547 (
Gabriel Charette7cc6c432018-04-25 20:52:02548 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59549 (
550 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
551 ),
552 False,
553 (),
554 ),
555 (
Gabriel Charette7cc6c432018-04-25 20:52:02556 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59557 (
558 'Consider using THREAD_CHECKER macros instead of the class directly.',
559 ),
560 False,
561 (),
562 ),
dbeamb6f4fde2017-06-15 04:03:06563 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06564 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
565 (
566 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
567 'deprecated (http://crbug.com/634507). Please avoid converting away',
568 'from the Time types in Chromium code, especially if any math is',
569 'being done on time values. For interfacing with platform/library',
570 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
571 'type converter methods instead. For faking TimeXXX values (for unit',
572 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
573 'other use cases, please contact base/time/OWNERS.',
574 ),
575 False,
576 (),
577 ),
578 (
dbeamb6f4fde2017-06-15 04:03:06579 'CallJavascriptFunctionUnsafe',
580 (
581 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
582 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
583 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
584 ),
585 False,
586 (
Egor Paskoce145c42018-09-28 19:31:04587 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
588 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
589 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06590 ),
591 ),
dskiba1474c2bfd62017-07-20 02:19:24592 (
593 'leveldb::DB::Open',
594 (
595 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
596 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
597 "Chrome's tracing, making their memory usage visible.",
598 ),
599 True,
600 (
601 r'^third_party/leveldatabase/.*\.(cc|h)$',
602 ),
Gabriel Charette0592c3a2017-07-26 12:02:04603 ),
604 (
Chris Mumfordc38afb62017-10-09 17:55:08605 'leveldb::NewMemEnv',
606 (
607 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58608 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
609 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08610 ),
611 True,
612 (
613 r'^third_party/leveldatabase/.*\.(cc|h)$',
614 ),
615 ),
616 (
Gabriel Charetted9839bc2017-07-29 14:17:47617 'RunLoop::QuitCurrent',
618 (
Robert Liao64b7ab22017-08-04 23:03:43619 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
620 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47621 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41622 False,
Gabriel Charetted9839bc2017-07-29 14:17:47623 (),
Gabriel Charettea44975052017-08-21 23:14:04624 ),
625 (
626 'base::ScopedMockTimeMessageLoopTaskRunner',
627 (
Gabriel Charette87cc1af2018-04-25 20:52:51628 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11629 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51630 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
631 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
632 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04633 ),
Gabriel Charette87cc1af2018-04-25 20:52:51634 False,
Gabriel Charettea44975052017-08-21 23:14:04635 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57636 ),
637 (
Dave Tapuska98199b612019-07-10 13:30:44638 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57639 (
640 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02641 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57642 ),
643 True,
644 (),
Francois Doray43670e32017-09-27 12:40:38645 ),
646 (
Peter Kasting991618a62019-06-17 22:00:09647 r'/\bstd::stoi\b',
648 (
649 'std::stoi uses exceptions to communicate results. ',
650 'Use base::StringToInt() instead.',
651 ),
652 True,
653 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
654 ),
655 (
656 r'/\bstd::stol\b',
657 (
658 'std::stol uses exceptions to communicate results. ',
659 'Use base::StringToInt() instead.',
660 ),
661 True,
662 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
663 ),
664 (
665 r'/\bstd::stoul\b',
666 (
667 'std::stoul uses exceptions to communicate results. ',
668 'Use base::StringToUint() instead.',
669 ),
670 True,
671 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
672 ),
673 (
674 r'/\bstd::stoll\b',
675 (
676 'std::stoll uses exceptions to communicate results. ',
677 'Use base::StringToInt64() instead.',
678 ),
679 True,
680 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
681 ),
682 (
683 r'/\bstd::stoull\b',
684 (
685 'std::stoull uses exceptions to communicate results. ',
686 'Use base::StringToUint64() instead.',
687 ),
688 True,
689 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
690 ),
691 (
692 r'/\bstd::stof\b',
693 (
694 'std::stof uses exceptions to communicate results. ',
695 'For locale-independent values, e.g. reading numbers from disk',
696 'profiles, use base::StringToDouble().',
697 'For user-visible values, parse using ICU.',
698 ),
699 True,
700 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
701 ),
702 (
703 r'/\bstd::stod\b',
704 (
705 'std::stod uses exceptions to communicate results. ',
706 'For locale-independent values, e.g. reading numbers from disk',
707 'profiles, use base::StringToDouble().',
708 'For user-visible values, parse using ICU.',
709 ),
710 True,
711 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
712 ),
713 (
714 r'/\bstd::stold\b',
715 (
716 'std::stold uses exceptions to communicate results. ',
717 'For locale-independent values, e.g. reading numbers from disk',
718 'profiles, use base::StringToDouble().',
719 'For user-visible values, parse using ICU.',
720 ),
721 True,
722 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
723 ),
724 (
Daniel Bratell69334cc2019-03-26 11:07:45725 r'/\bstd::to_string\b',
726 (
727 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09728 'For locale-independent strings, e.g. writing numbers to disk',
729 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45730 'For user-visible strings, use base::FormatNumber() and',
731 'the related functions in base/i18n/number_formatting.h.',
732 ),
Peter Kasting991618a62019-06-17 22:00:09733 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21734 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45735 ),
736 (
737 r'/\bstd::shared_ptr\b',
738 (
739 'std::shared_ptr should not be used. Use scoped_refptr instead.',
740 ),
741 True,
Alex Chau9eb03cdd52020-07-13 21:04:57742 ['^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
743 'array_buffer_contents\.(cc|h)',
744 # Needed for interop with third-party library
745 'chrome/services/sharing/nearby/',
746 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21747 ),
748 (
Peter Kasting991618a62019-06-17 22:00:09749 r'/\bstd::weak_ptr\b',
750 (
751 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
752 ),
753 True,
754 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
755 ),
756 (
Daniel Bratell609102be2019-03-27 20:53:21757 r'/\blong long\b',
758 (
759 'long long is banned. Use stdint.h if you need a 64 bit number.',
760 ),
761 False, # Only a warning since it is already used.
762 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
763 ),
764 (
765 r'/\bstd::bind\b',
766 (
767 'std::bind is banned because of lifetime risks.',
768 'Use base::BindOnce or base::BindRepeating instead.',
769 ),
770 True,
771 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
772 ),
773 (
774 r'/\b#include <chrono>\b',
775 (
776 '<chrono> overlaps with Time APIs in base. Keep using',
777 'base classes.',
778 ),
779 True,
780 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
781 ),
782 (
783 r'/\b#include <exception>\b',
784 (
785 'Exceptions are banned and disabled in Chromium.',
786 ),
787 True,
788 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
789 ),
790 (
791 r'/\bstd::function\b',
792 (
793 'std::function is banned. Instead use base::Callback which directly',
794 'supports Chromium\'s weak pointers, ref counting and more.',
795 ),
Peter Kasting991618a62019-06-17 22:00:09796 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21797 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
798 ),
799 (
800 r'/\b#include <random>\b',
801 (
802 'Do not use any random number engines from <random>. Instead',
803 'use base::RandomBitGenerator.',
804 ),
805 True,
806 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
807 ),
808 (
Tom Andersona95e12042020-09-09 23:08:00809 r'/\b#include <X11/',
810 (
811 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
812 ),
813 True,
814 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
815 ),
816 (
Daniel Bratell609102be2019-03-27 20:53:21817 r'/\bstd::ratio\b',
818 (
819 'std::ratio is banned by the Google Style Guide.',
820 ),
821 True,
822 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45823 ),
824 (
Francois Doray43670e32017-09-27 12:40:38825 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
826 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
827 (
828 'Use the new API in base/threading/thread_restrictions.h.',
829 ),
Gabriel Charette04b138f2018-08-06 00:03:22830 False,
Francois Doray43670e32017-09-27 12:40:38831 (),
832 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38833 (
danakj7a2b7082019-05-21 21:13:51834 r'/\bbase::Bind\(',
835 (
836 'Please use base::Bind{Once,Repeating} instead',
837 'of base::Bind. (crbug.com/714018)',
838 ),
839 False,
Erik Staaba737d7602019-11-25 18:41:07840 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51841 ),
842 (
843 r'/\bbase::Callback[<:]',
844 (
845 'Please use base::{Once,Repeating}Callback instead',
846 'of base::Callback. (crbug.com/714018)',
847 ),
848 False,
Erik Staaba737d7602019-11-25 18:41:07849 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51850 ),
851 (
852 r'/\bbase::Closure\b',
853 (
854 'Please use base::{Once,Repeating}Closure instead',
855 'of base::Closure. (crbug.com/714018)',
856 ),
857 False,
Erik Staaba737d7602019-11-25 18:41:07858 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51859 ),
860 (
Michael Giuffrida7f93d6922019-04-19 14:39:58861 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19862 (
863 'RunMessageLoop is deprecated, use RunLoop instead.',
864 ),
865 False,
866 (),
867 ),
868 (
Dave Tapuska98199b612019-07-10 13:30:44869 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19870 (
871 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
872 ),
873 False,
874 (),
875 ),
876 (
Dave Tapuska98199b612019-07-10 13:30:44877 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19878 (
879 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
880 "if you're convinced you need this.",
881 ),
882 False,
883 (),
884 ),
885 (
Dave Tapuska98199b612019-07-10 13:30:44886 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19887 (
888 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04889 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19890 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
891 'async events instead of flushing threads.',
892 ),
893 False,
894 (),
895 ),
896 (
897 r'MessageLoopRunner',
898 (
899 'MessageLoopRunner is deprecated, use RunLoop instead.',
900 ),
901 False,
902 (),
903 ),
904 (
Dave Tapuska98199b612019-07-10 13:30:44905 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19906 (
907 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
908 "gab@ if you found a use case where this is the only solution.",
909 ),
910 False,
911 (),
912 ),
913 (
Victor Costane48a2e82019-03-15 22:02:34914 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16915 (
Victor Costane48a2e82019-03-15 22:02:34916 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16917 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
918 ),
919 True,
920 (
921 r'^sql/initialization\.(cc|h)$',
922 r'^third_party/sqlite/.*\.(c|cc|h)$',
923 ),
924 ),
Matt Menke7f520a82018-03-28 21:38:37925 (
Dave Tapuska98199b612019-07-10 13:30:44926 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47927 (
928 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
929 'base::RandomShuffle instead.'
930 ),
931 True,
932 (),
933 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24934 (
935 'ios/web/public/test/http_server',
936 (
937 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
938 ),
939 False,
940 (),
941 ),
Robert Liao764c9492019-01-24 18:46:28942 (
943 'GetAddressOf',
944 (
945 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53946 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11947 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53948 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28949 ),
950 True,
951 (),
952 ),
Antonio Gomes07300d02019-03-13 20:59:57953 (
954 'DEFINE_TYPE_CASTS',
955 (
956 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
957 '//third_party/blink/renderer/platform/casting.h.'
958 ),
959 True,
960 (
961 r'^third_party/blink/renderer/.*\.(cc|h)$',
962 ),
963 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38964 (
Abhijeet Kandalkar1e7c2502019-10-29 15:05:45965 r'/\bIsHTML.+Element\(\b',
966 (
967 'Function IsHTMLXXXXElement is deprecated. Instead, use downcast ',
968 ' helpers IsA<HTMLXXXXElement> from ',
969 '//third_party/blink/renderer/platform/casting.h.'
970 ),
971 False,
972 (
973 r'^third_party/blink/renderer/.*\.(cc|h)$',
974 ),
975 ),
976 (
977 r'/\bToHTML.+Element(|OrNull)\(\b',
978 (
979 'Function ToHTMLXXXXElement and ToHTMLXXXXElementOrNull are '
980 'deprecated. Instead, use downcast helpers To<HTMLXXXXElement> '
981 'and DynamicTo<HTMLXXXXElement> from ',
982 '//third_party/blink/renderer/platform/casting.h.'
983 'auto* html_xxxx_ele = To<HTMLXXXXElement>(n)'
984 'auto* html_xxxx_ele_or_null = DynamicTo<HTMLXXXXElement>(n)'
985 ),
986 False,
987 (
988 r'^third_party/blink/renderer/.*\.(cc|h)$',
989 ),
990 ),
991 (
Kinuko Yasuda376c2ce12019-04-16 01:20:37992 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:38993 (
994 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
995 ),
996 True,
997 (),
998 ),
Ben Lewisa9514602019-04-29 17:53:05999 (
1000 'SHFileOperation',
1001 (
1002 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1003 'complex functions to achieve the same goals. Use IFileOperation for ',
1004 'any esoteric actions instead.'
1005 ),
1006 True,
1007 (),
1008 ),
Cliff Smolinskyb11abed2019-04-29 19:43:181009 (
Cliff Smolinsky81951642019-04-30 21:39:511010 'StringFromGUID2',
1011 (
1012 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241013 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511014 ),
1015 True,
1016 (
1017 r'/base/win/win_util_unittest.cc'
1018 ),
1019 ),
1020 (
1021 'StringFromCLSID',
1022 (
1023 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241024 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511025 ),
1026 True,
1027 (
1028 r'/base/win/win_util_unittest.cc'
1029 ),
1030 ),
1031 (
Avi Drissman7382afa02019-04-29 23:27:131032 'kCFAllocatorNull',
1033 (
1034 'The use of kCFAllocatorNull with the NoCopy creation of ',
1035 'CoreFoundation types is prohibited.',
1036 ),
1037 True,
1038 (),
1039 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291040 (
1041 'mojo::ConvertTo',
1042 (
1043 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1044 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1045 'StringTraits if you would like to convert between custom types and',
1046 'the wire format of mojom types.'
1047 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221048 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291049 (
Wezf89dec092019-09-11 19:38:331050 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1051 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291052 r'^third_party/blink/.*\.(cc|h)$',
1053 r'^content/renderer/.*\.(cc|h)$',
1054 ),
1055 ),
Robert Liao1d78df52019-11-11 20:02:011056 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161057 'GetInterfaceProvider',
1058 (
1059 'InterfaceProvider is deprecated.',
1060 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1061 'or Platform::GetBrowserInterfaceBroker.'
1062 ),
1063 False,
1064 (),
1065 ),
1066 (
Robert Liao1d78df52019-11-11 20:02:011067 'CComPtr',
1068 (
1069 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1070 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1071 'details.'
1072 ),
1073 False,
1074 (),
1075 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201076 (
1077 r'/\b(IFACE|STD)METHOD_?\(',
1078 (
1079 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1080 'Instead, always use IFACEMETHODIMP in the declaration.'
1081 ),
1082 False,
1083 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1084 ),
Allen Bauer53b43fb12020-03-12 17:21:471085 (
1086 'set_owned_by_client',
1087 (
1088 'set_owned_by_client is deprecated.',
1089 'views::View already owns the child views by default. This introduces ',
1090 'a competing ownership model which makes the code difficult to reason ',
1091 'about. See http://crbug.com/1044687 for more details.'
1092 ),
1093 False,
1094 (),
1095 ),
Eric Secklerbe6f48d2020-05-06 18:09:121096 (
1097 r'/\bTRACE_EVENT_ASYNC_',
1098 (
1099 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1100 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1101 ),
1102 False,
1103 (
1104 r'^base/trace_event/.*',
1105 r'^base/tracing/.*',
1106 ),
1107 ),
[email protected]127f18ec2012-06-16 05:05:591108)
1109
Mario Sanchez Prada2472cab2019-09-18 10:58:311110# Format: Sequence of tuples containing:
1111# * String pattern or, if starting with a slash, a regular expression.
1112# * Sequence of strings to show when the pattern matches.
1113_DEPRECATED_MOJO_TYPES = (
1114 (
1115 r'/\bmojo::AssociatedBinding\b',
1116 (
1117 'mojo::AssociatedBinding<Interface> is deprecated.',
1118 'Use mojo::AssociatedReceiver<Interface> instead.',
1119 ),
1120 ),
1121 (
1122 r'/\bmojo::AssociatedBindingSet\b',
1123 (
1124 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1125 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1126 ),
1127 ),
1128 (
1129 r'/\bmojo::AssociatedInterfacePtr\b',
1130 (
1131 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1132 'Use mojo::AssociatedRemote<Interface> instead.',
1133 ),
1134 ),
1135 (
1136 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1137 (
1138 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1139 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1140 ),
1141 ),
1142 (
1143 r'/\bmojo::AssociatedInterfaceRequest\b',
1144 (
1145 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1146 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1147 ),
1148 ),
1149 (
1150 r'/\bmojo::Binding\b',
1151 (
1152 'mojo::Binding<Interface> is deprecated.',
1153 'Use mojo::Receiver<Interface> instead.',
1154 ),
1155 ),
1156 (
1157 r'/\bmojo::BindingSet\b',
1158 (
1159 'mojo::BindingSet<Interface> is deprecated.',
1160 'Use mojo::ReceiverSet<Interface> instead.',
1161 ),
1162 ),
1163 (
1164 r'/\bmojo::InterfacePtr\b',
1165 (
1166 'mojo::InterfacePtr<Interface> is deprecated.',
1167 'Use mojo::Remote<Interface> instead.',
1168 ),
1169 ),
1170 (
1171 r'/\bmojo::InterfacePtrInfo\b',
1172 (
1173 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1174 'Use mojo::PendingRemote<Interface> instead.',
1175 ),
1176 ),
1177 (
1178 r'/\bmojo::InterfaceRequest\b',
1179 (
1180 'mojo::InterfaceRequest<Interface> is deprecated.',
1181 'Use mojo::PendingReceiver<Interface> instead.',
1182 ),
1183 ),
1184 (
1185 r'/\bmojo::MakeRequest\b',
1186 (
1187 'mojo::MakeRequest is deprecated.',
1188 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1189 ),
1190 ),
1191 (
1192 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1193 (
1194 'mojo::MakeRequest is deprecated.',
1195 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181196 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311197 ),
1198 ),
1199 (
1200 r'/\bmojo::MakeStrongBinding\b',
1201 (
1202 'mojo::MakeStrongBinding is deprecated.',
1203 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1204 'mojo::MakeSelfOwnedReceiver() instead.',
1205 ),
1206 ),
1207 (
1208 r'/\bmojo::MakeStrongAssociatedBinding\b',
1209 (
1210 'mojo::MakeStrongAssociatedBinding is deprecated.',
1211 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1212 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1213 ),
1214 ),
1215 (
Gyuyoung Kim4952ba62020-07-07 07:33:441216 r'/\bmojo::StrongAssociatedBinding\b',
1217 (
1218 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1219 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1220 ),
1221 ),
1222 (
1223 r'/\bmojo::StrongBinding\b',
1224 (
1225 'mojo::StrongBinding<Interface> is deprecated.',
1226 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1227 ),
1228 ),
1229 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311230 r'/\bmojo::StrongAssociatedBindingSet\b',
1231 (
1232 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1233 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1234 ),
1235 ),
1236 (
1237 r'/\bmojo::StrongBindingSet\b',
1238 (
1239 'mojo::StrongBindingSet<Interface> is deprecated.',
1240 'Use mojo::UniqueReceiverSet<Interface> instead.',
1241 ),
1242 ),
1243)
wnwenbdc444e2016-05-25 13:44:151244
mlamouria82272622014-09-16 18:45:041245_IPC_ENUM_TRAITS_DEPRECATED = (
1246 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501247 'See http://www.chromium.org/Home/chromium-security/education/'
1248 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041249
Stephen Martinis97a394142018-06-07 23:06:051250_LONG_PATH_ERROR = (
1251 'Some files included in this CL have file names that are too long (> 200'
1252 ' characters). If committed, these files will cause issues on Windows. See'
1253 ' https://crbug.com/612667 for more details.'
1254)
1255
Shenghua Zhangbfaa38b82017-11-16 21:58:021256_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041257 r".*[\\/]BuildHooksAndroidImpl\.java",
1258 r".*[\\/]LicenseContentProvider\.java",
1259 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281260 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021261]
[email protected]127f18ec2012-06-16 05:05:591262
Mohamed Heikald048240a2019-11-12 16:57:371263# List of image extensions that are used as resources in chromium.
1264_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1265
Sean Kau46e29bc2017-08-28 16:31:161266# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401267_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041268 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401269 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041270 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1271 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041272 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431273 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161274]
1275
1276
[email protected]b00342e7f2013-03-26 16:21:541277_VALID_OS_MACROS = (
1278 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081279 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541280 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441281 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121282 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541283 'OS_BSD',
1284 'OS_CAT', # For testing.
1285 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041286 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541287 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371288 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541289 'OS_IOS',
1290 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441291 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541292 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211293 'OS_NACL_NONSFI',
1294 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121295 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541296 'OS_OPENBSD',
1297 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371298 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541299 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541300 'OS_WIN',
1301)
1302
1303
Andrew Grieveb773bad2020-06-05 18:00:381304# These are not checked on the public chromium-presubmit trybot.
1305# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041306# checkouts.
agrievef32bcc72016-04-04 14:57:401307_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381308 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381309]
1310
1311
1312_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041313 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361314 'base/android/jni_generator/jni_generator.pydeps',
1315 'base/android/jni_generator/jni_registration_generator.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041316 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361317 'build/android/gyp/aar.pydeps',
1318 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271319 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361320 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381321 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361322 'build/android/gyp/bytecode_processor.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111323 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361324 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361325 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361326 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111327 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041328 'build/android/gyp/create_app_bundle_apks.pydeps',
1329 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361330 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121331 'build/android/gyp/create_r_java.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221332 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001333 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361334 'build/android/gyp/desugar.pydeps',
1335 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421336 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041337 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361338 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361339 'build/android/gyp/filter_zip.pydeps',
1340 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361341 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361342 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581343 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361344 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141345 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261346 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011347 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041348 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361349 'build/android/gyp/lint.pydeps',
1350 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361351 'build/android/gyp/merge_manifest.pydeps',
1352 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221353 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361354 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461355 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241356 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361357 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461358 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561359 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361360 'build/android/incremental_install/generate_android_manifest.pydeps',
1361 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041362 'build/android/resource_sizes.pydeps',
1363 'build/android/test_runner.pydeps',
1364 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361365 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361366 'build/protoc_java.pydeps',
Peter Wenefb56c72020-06-04 15:12:271367 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1368 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001369 'components/cronet/tools/generate_javadoc.pydeps',
1370 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381371 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001372 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381373 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041374 'testing/scripts/run_android_wpt.pydeps',
1375 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421376 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1377 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131378 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Caleb Raitto28864fc2020-01-07 00:18:191379 ('third_party/blink/renderer/bindings/scripts/'
1380 'generate_high_entropy_list.pydeps'),
John Budorickbc3571aa2019-04-25 02:20:061381 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221382 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401383]
1384
wnwenbdc444e2016-05-25 13:44:151385
agrievef32bcc72016-04-04 14:57:401386_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1387
1388
Eric Boren6fd2b932018-01-25 15:05:081389# Bypass the AUTHORS check for these accounts.
1390_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591391 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451392 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591393 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521394 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
1395 'wpt-autoroller',)
Eric Boren835d71f2018-09-07 21:09:041396 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271397 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041398 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301399 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081400
1401
Daniel Bratell65b033262019-04-23 08:17:061402def _IsCPlusPlusFile(input_api, file_path):
1403 """Returns True if this file contains C++-like code (and not Python,
1404 Go, Java, MarkDown, ...)"""
1405
1406 ext = input_api.os_path.splitext(file_path)[1]
1407 # This list is compatible with CppChecker.IsCppFile but we should
1408 # consider adding ".c" to it. If we do that we can use this function
1409 # at more places in the code.
1410 return ext in (
1411 '.h',
1412 '.cc',
1413 '.cpp',
1414 '.m',
1415 '.mm',
1416 )
1417
1418def _IsCPlusPlusHeaderFile(input_api, file_path):
1419 return input_api.os_path.splitext(file_path)[1] == ".h"
1420
1421
1422def _IsJavaFile(input_api, file_path):
1423 return input_api.os_path.splitext(file_path)[1] == ".java"
1424
1425
1426def _IsProtoFile(input_api, file_path):
1427 return input_api.os_path.splitext(file_path)[1] == ".proto"
1428
Saagar Sanghavifceeaae2020-08-12 16:40:361429def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191430 """Attempts to prevent use of functions intended only for testing in
1431 non-testing code. For now this is just a best-effort implementation
1432 that ignores header files and may have some false positives. A
1433 better implementation would probably need a proper C++ parser.
1434 """
1435 # We only scan .cc files and the like, as the declaration of
1436 # for-testing functions in header files are hard to distinguish from
1437 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491438 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191439
jochenc0d4808c2015-07-27 09:25:421440 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191441 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091442 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131443 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191444 exclusion_pattern = input_api.re.compile(
1445 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1446 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131447 # Avoid a false positive in this case, where the method name, the ::, and
1448 # the closing { are all on different lines due to line wrapping.
1449 # HelperClassForTesting::
1450 # HelperClassForTesting(
1451 # args)
1452 # : member(0) {}
1453 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191454
1455 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441456 files_to_skip = (_EXCLUDED_PATHS +
1457 _TEST_CODE_EXCLUDED_PATHS +
1458 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191459 return input_api.FilterSourceFile(
1460 affected_file,
James Cook24a504192020-07-23 00:08:441461 files_to_check=file_inclusion_pattern,
1462 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191463
1464 problems = []
1465 for f in input_api.AffectedSourceFiles(FilterFile):
1466 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131467 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241468 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031469 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461470 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131471 not exclusion_pattern.search(line) and
1472 not allowlist_pattern.search(line) and
1473 not in_method_defn):
[email protected]55459852011-08-10 15:17:191474 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031475 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131476 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191477
1478 if problems:
[email protected]f7051d52013-04-02 18:31:421479 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031480 else:
1481 return []
[email protected]55459852011-08-10 15:17:191482
1483
Saagar Sanghavifceeaae2020-08-12 16:40:361484def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231485 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591486 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231487 """
1488 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1489 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1490 name_pattern = r'ForTest(s|ing)?'
1491 # Describes an occurrence of "ForTest*" inside a // comment.
1492 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501493 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
1494 annotation_re = input_api.re.compile(r'@VisibleForTesting\(otherwise')
Vaclav Brozek7dbc28c2018-03-27 08:35:231495 # Catch calls.
1496 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1497 # Ignore definitions. (Comments are ignored separately.)
1498 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1499
1500 problems = []
1501 sources = lambda x: input_api.FilterSourceFile(
1502 x,
James Cook24a504192020-07-23 00:08:441503 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1504 + input_api.DEFAULT_FILES_TO_SKIP),
1505 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231506 )
1507 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1508 local_path = f.LocalPath()
1509 is_inside_javadoc = False
1510 for line_number, line in f.ChangedContents():
1511 if is_inside_javadoc and javadoc_end_re.search(line):
1512 is_inside_javadoc = False
1513 if not is_inside_javadoc and javadoc_start_re.search(line):
1514 is_inside_javadoc = True
1515 if is_inside_javadoc:
1516 continue
1517 if (inclusion_re.search(line) and
1518 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501519 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231520 not exclusion_re.search(line)):
1521 problems.append(
1522 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1523
1524 if problems:
1525 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1526 else:
1527 return []
1528
1529
Saagar Sanghavifceeaae2020-08-12 16:40:361530def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541531 """Checks to make sure no .h files include <iostream>."""
1532 files = []
1533 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1534 input_api.re.MULTILINE)
1535 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1536 if not f.LocalPath().endswith('.h'):
1537 continue
1538 contents = input_api.ReadFile(f)
1539 if pattern.search(contents):
1540 files.append(f)
1541
1542 if len(files):
yolandyandaabc6d2016-04-18 18:29:391543 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061544 'Do not #include <iostream> in header files, since it inserts static '
1545 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541546 '#include <ostream>. See http://crbug.com/94794',
1547 files) ]
1548 return []
1549
Danil Chapovalov3518f362018-08-11 16:13:431550def _CheckNoStrCatRedefines(input_api, output_api):
1551 """Checks no windows headers with StrCat redefined are included directly."""
1552 files = []
1553 pattern_deny = input_api.re.compile(
1554 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1555 input_api.re.MULTILINE)
1556 pattern_allow = input_api.re.compile(
1557 r'^#include\s"base/win/windows_defines.inc"',
1558 input_api.re.MULTILINE)
1559 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1560 contents = input_api.ReadFile(f)
1561 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1562 files.append(f.LocalPath())
1563
1564 if len(files):
1565 return [output_api.PresubmitError(
1566 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1567 'directly since they pollute code with StrCat macro. Instead, '
1568 'include matching header from base/win. See http://crbug.com/856536',
1569 files) ]
1570 return []
1571
[email protected]10689ca2011-09-02 02:31:541572
Saagar Sanghavifceeaae2020-08-12 16:40:361573def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521574 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181575 problems = []
1576 for f in input_api.AffectedFiles():
1577 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1578 continue
1579
1580 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041581 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181582 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1583
1584 if not problems:
1585 return []
1586 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1587 '\n'.join(problems))]
1588
Saagar Sanghavifceeaae2020-08-12 16:40:361589def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341590 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1591
1592 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1593 instead of DISABLED_. To filter false positives, reports are only generated
1594 if a corresponding MAYBE_ line exists.
1595 """
1596 problems = []
1597
1598 # The following two patterns are looked for in tandem - is a test labeled
1599 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1600 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1601 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1602
1603 # This is for the case that a test is disabled on all platforms.
1604 full_disable_pattern = input_api.re.compile(
1605 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1606 input_api.re.MULTILINE)
1607
Katie Df13948e2018-09-25 07:33:441608 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341609 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1610 continue
1611
1612 # Search for MABYE_, DISABLE_ pairs.
1613 disable_lines = {} # Maps of test name to line number.
1614 maybe_lines = {}
1615 for line_num, line in f.ChangedContents():
1616 disable_match = disable_pattern.search(line)
1617 if disable_match:
1618 disable_lines[disable_match.group(1)] = line_num
1619 maybe_match = maybe_pattern.search(line)
1620 if maybe_match:
1621 maybe_lines[maybe_match.group(1)] = line_num
1622
1623 # Search for DISABLE_ occurrences within a TEST() macro.
1624 disable_tests = set(disable_lines.keys())
1625 maybe_tests = set(maybe_lines.keys())
1626 for test in disable_tests.intersection(maybe_tests):
1627 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1628
1629 contents = input_api.ReadFile(f)
1630 full_disable_match = full_disable_pattern.search(contents)
1631 if full_disable_match:
1632 problems.append(' %s' % f.LocalPath())
1633
1634 if not problems:
1635 return []
1636 return [
1637 output_api.PresubmitPromptWarning(
1638 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1639 '\n'.join(problems))
1640 ]
1641
[email protected]72df4e782012-06-21 16:28:181642
Saagar Sanghavifceeaae2020-08-12 16:40:361643def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571644 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521645 errors = []
Hans Wennborg944479f2020-06-25 21:39:251646 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521647 input_api.re.MULTILINE)
1648 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1649 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1650 continue
1651 for lnum, line in f.ChangedContents():
1652 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171653 errors.append(output_api.PresubmitError(
1654 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571655 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171656 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521657 return errors
1658
1659
Makoto Shimazu3ad422cd2019-05-08 02:35:141660def _FindHistogramNameInChunk(histogram_name, chunk):
1661 """Tries to find a histogram name or prefix in a line.
1662
1663 Returns the existence of the histogram name, or None if it needs more chunk
1664 to determine."""
mcasasb7440c282015-02-04 14:52:191665 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1666 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141667 if '<affected-histogram' in chunk:
1668 # If the tag is not completed, needs more chunk to get the name.
1669 if not '>' in chunk:
1670 return None
1671 if not 'name="' in chunk:
1672 return False
1673 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1674 # expect the only attribute is the name.
1675 histogram_prefix = chunk.split('"')[1]
1676 return histogram_prefix in histogram_name
1677 # Typically the whole histogram name should in the line.
1678 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191679
1680
Saagar Sanghavifceeaae2020-08-12 16:40:361681def CheckUmaHistogramChangesOnUpload(input_api, output_api):
mcasasb7440c282015-02-04 14:52:191682 """Check that UMA histogram names in touched lines can still be found in other
1683 lines of the patch or in histograms.xml. Note that this check would not catch
1684 the reverse: changes in histograms.xml not matched in the code itself."""
1685 touched_histograms = []
1686 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471687 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1688 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1689 name_pattern = r'"(.*?)"'
1690 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1691 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1692 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1693 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1694 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171695 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191696 for f in input_api.AffectedFiles():
1697 # If histograms.xml itself is modified, keep the modified lines for later.
1698 if f.LocalPath().endswith(('histograms.xml')):
1699 histograms_xml_modifications = f.ChangedContents()
1700 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471701 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1702 single_line_re = single_line_c_re
1703 split_line_prefix_re = split_line_c_prefix_re
1704 elif f.LocalPath().endswith(('java')):
1705 single_line_re = single_line_java_re
1706 split_line_prefix_re = split_line_java_prefix_re
1707 else:
mcasasb7440c282015-02-04 14:52:191708 continue
1709 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171710 if last_line_matched_prefix:
1711 suffix_found = split_line_suffix_re.search(line)
1712 if suffix_found :
1713 touched_histograms.append([suffix_found.group(1), f, line_num])
1714 last_line_matched_prefix = False
1715 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061716 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191717 if found:
1718 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171719 continue
1720 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191721
1722 # Search for the touched histogram names in the local modifications to
1723 # histograms.xml, and, if not found, on the base histograms.xml file.
1724 unmatched_histograms = []
1725 for histogram_info in touched_histograms:
1726 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141727 chunk = ''
mcasasb7440c282015-02-04 14:52:191728 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141729 chunk += line
1730 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1731 if histogram_name_found is None:
1732 continue
1733 chunk = ''
mcasasb7440c282015-02-04 14:52:191734 if histogram_name_found:
1735 break
1736 if not histogram_name_found:
1737 unmatched_histograms.append(histogram_info)
1738
eromanb90c82e7e32015-04-01 15:13:491739 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191740 problems = []
1741 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491742 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191743 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451744 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191745 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141746 chunk = ''
mcasasb7440c282015-02-04 14:52:191747 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141748 chunk += line
1749 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1750 chunk)
1751 if histogram_name_found is None:
1752 continue
1753 chunk = ''
mcasasb7440c282015-02-04 14:52:191754 if histogram_name_found:
1755 break
1756 if not histogram_name_found:
1757 problems.append(' [%s:%d] %s' %
1758 (f.LocalPath(), line_num, histogram_name))
1759
1760 if not problems:
1761 return []
1762 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1763 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491764 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191765
wnwenbdc444e2016-05-25 13:44:151766
Saagar Sanghavifceeaae2020-08-12 16:40:361767def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391768 """Check that FlakyTest annotation is our own instead of the android one"""
1769 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1770 files = []
1771 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1772 if f.LocalPath().endswith('Test.java'):
1773 if pattern.search(input_api.ReadFile(f)):
1774 files.append(f)
1775 if len(files):
1776 return [output_api.PresubmitError(
1777 'Use org.chromium.base.test.util.FlakyTest instead of '
1778 'android.test.FlakyTest',
1779 files)]
1780 return []
mcasasb7440c282015-02-04 14:52:191781
wnwenbdc444e2016-05-25 13:44:151782
Saagar Sanghavifceeaae2020-08-12 16:40:361783def CheckNoNewWStrings(input_api, output_api):
[email protected]8ea5d4b2011-09-13 21:49:221784 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271785 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221786 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201787 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571788 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341789 '/win/' in f.LocalPath() or
1790 'chrome_elf' in f.LocalPath() or
1791 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201792 continue
[email protected]8ea5d4b2011-09-13 21:49:221793
[email protected]a11dbe9b2012-08-07 01:32:581794 allowWString = False
[email protected]b5c24292011-11-28 14:38:201795 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581796 if 'presubmit: allow wstring' in line:
1797 allowWString = True
1798 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271799 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581800 allowWString = False
1801 else:
1802 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221803
[email protected]55463aa62011-10-12 00:48:271804 if not problems:
1805 return []
1806 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581807 ' If you are calling a cross-platform API that accepts a wstring, '
1808 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271809 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221810
1811
Saagar Sanghavifceeaae2020-08-12 16:40:361812def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441813 """Make sure .DEPS.git is never modified manually."""
1814 if any(f.LocalPath().endswith('.DEPS.git') for f in
1815 input_api.AffectedFiles()):
1816 return [output_api.PresubmitError(
1817 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1818 'automated system based on what\'s in DEPS and your changes will be\n'
1819 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501820 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1821 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441822 'for more information')]
1823 return []
1824
1825
Saagar Sanghavifceeaae2020-08-12 16:40:361826def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471827 """Checks that DEPS file deps are from allowed_hosts."""
1828 # Run only if DEPS file has been modified to annoy fewer bystanders.
1829 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1830 return []
1831 # Outsource work to gclient verify
1832 try:
John Budorickf20c0042019-04-25 23:23:401833 gclient_path = input_api.os_path.join(
1834 input_api.PresubmitLocalPath(),
1835 'third_party', 'depot_tools', 'gclient.py')
1836 input_api.subprocess.check_output(
1837 [input_api.python_executable, gclient_path, 'verify'],
1838 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471839 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201840 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471841 return [output_api.PresubmitError(
1842 'DEPS file must have only git dependencies.',
1843 long_text=error.output)]
1844
1845
Mario Sanchez Prada2472cab2019-09-18 10:58:311846def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1847 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591848 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311849
1850 Returns an string composed of the name of the file, the line number where the
1851 match has been found and the additional text passed as |message| in case the
1852 target type name matches the text inside the line passed as parameter.
1853 """
Peng Huang9c5949a02020-06-11 19:20:541854 result = []
1855
1856 if line.endswith(" nocheck"):
1857 return result
1858
Mario Sanchez Prada2472cab2019-09-18 10:58:311859 matched = False
1860 if type_name[0:1] == '/':
1861 regex = type_name[1:]
1862 if input_api.re.search(regex, line):
1863 matched = True
1864 elif type_name in line:
1865 matched = True
1866
Mario Sanchez Prada2472cab2019-09-18 10:58:311867 if matched:
1868 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1869 for message_line in message:
1870 result.append(' %s' % message_line)
1871
1872 return result
1873
1874
Saagar Sanghavifceeaae2020-08-12 16:40:361875def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591876 """Make sure that banned functions are not used."""
1877 warnings = []
1878 errors = []
1879
James Cook24a504192020-07-23 00:08:441880 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151881 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441882 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151883 if input_api.re.match(item, local_path):
1884 return True
1885 return False
1886
Peter K. Lee6c03ccff2019-07-15 14:40:051887 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541888 local_path = affected_file.LocalPath()
1889 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1890 return False
1891 basename = input_api.os_path.basename(local_path)
1892 if 'ios' in basename.split('_'):
1893 return True
1894 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1895 if sep and 'ios' in local_path.split(sep):
1896 return True
1897 return False
1898
wnwenbdc444e2016-05-25 13:44:151899 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311900 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1901 func_name, message)
1902 if problems:
wnwenbdc444e2016-05-25 13:44:151903 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311904 errors.extend(problems)
1905 else:
1906 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151907
Eric Stevensona9a980972017-09-23 00:04:411908 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1909 for f in input_api.AffectedFiles(file_filter=file_filter):
1910 for line_num, line in f.ChangedContents():
1911 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1912 CheckForMatch(f, line_num, line, func_name, message, error)
1913
[email protected]127f18ec2012-06-16 05:05:591914 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1915 for f in input_api.AffectedFiles(file_filter=file_filter):
1916 for line_num, line in f.ChangedContents():
1917 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151918 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591919
Peter K. Lee6c03ccff2019-07-15 14:40:051920 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541921 for line_num, line in f.ChangedContents():
1922 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1923 CheckForMatch(f, line_num, line, func_name, message, error)
1924
Peter K. Lee6c03ccff2019-07-15 14:40:051925 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1926 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1927 for line_num, line in f.ChangedContents():
1928 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1929 CheckForMatch(f, line_num, line, func_name, message, error)
1930
[email protected]127f18ec2012-06-16 05:05:591931 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1932 for f in input_api.AffectedFiles(file_filter=file_filter):
1933 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491934 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441935 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491936 continue
wnwenbdc444e2016-05-25 13:44:151937 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591938
1939 result = []
1940 if (warnings):
1941 result.append(output_api.PresubmitPromptWarning(
1942 'Banned functions were used.\n' + '\n'.join(warnings)))
1943 if (errors):
1944 result.append(output_api.PresubmitError(
1945 'Banned functions were used.\n' + '\n'.join(errors)))
1946 return result
1947
1948
Michael Thiessen44457642020-02-06 00:24:151949def _CheckAndroidNoBannedImports(input_api, output_api):
1950 """Make sure that banned java imports are not used."""
1951 errors = []
1952
1953 def IsException(path, exceptions):
1954 for exception in exceptions:
1955 if (path.startswith(exception)):
1956 return True
1957 return False
1958
1959 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1960 for f in input_api.AffectedFiles(file_filter=file_filter):
1961 for line_num, line in f.ChangedContents():
1962 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1963 if IsException(f.LocalPath(), exceptions):
1964 continue;
1965 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1966 'import ' + import_name, message)
1967 if problems:
1968 errors.extend(problems)
1969 result = []
1970 if (errors):
1971 result.append(output_api.PresubmitError(
1972 'Banned imports were used.\n' + '\n'.join(errors)))
1973 return result
1974
1975
Saagar Sanghavifceeaae2020-08-12 16:40:361976def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311977 """Make sure that old Mojo types are not used."""
1978 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571979 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311980
Mario Sanchez Pradaaab91382019-12-19 08:57:091981 # For any path that is not an "ok" or an "error" path, a warning will be
1982 # raised if deprecated mojo types are found.
1983 ok_paths = ['components/arc']
1984 error_paths = ['third_party/blink', 'content']
1985
Mario Sanchez Prada2472cab2019-09-18 10:58:311986 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1987 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571988 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091989 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311990 continue
1991
1992 for line_num, line in f.ChangedContents():
1993 for func_name, message in _DEPRECATED_MOJO_TYPES:
1994 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1995 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571996
Mario Sanchez Prada2472cab2019-09-18 10:58:311997 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:091998 # Raise errors inside |error_paths| and warnings everywhere else.
1999 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:572000 errors.extend(problems)
2001 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:312002 warnings.extend(problems)
2003
2004 result = []
2005 if (warnings):
2006 result.append(output_api.PresubmitPromptWarning(
2007 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:572008 if (errors):
2009 result.append(output_api.PresubmitError(
2010 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:312011 return result
2012
2013
Saagar Sanghavifceeaae2020-08-12 16:40:362014def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:062015 """Make sure that banned functions are not used."""
2016 files = []
2017 pattern = input_api.re.compile(r'^#pragma\s+once',
2018 input_api.re.MULTILINE)
2019 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2020 if not f.LocalPath().endswith('.h'):
2021 continue
2022 contents = input_api.ReadFile(f)
2023 if pattern.search(contents):
2024 files.append(f)
2025
2026 if files:
2027 return [output_api.PresubmitError(
2028 'Do not use #pragma once in header files.\n'
2029 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2030 files)]
2031 return []
2032
[email protected]127f18ec2012-06-16 05:05:592033
Saagar Sanghavifceeaae2020-08-12 16:40:362034def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:122035 """Checks to make sure we don't introduce use of foo ? true : false."""
2036 problems = []
2037 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2038 for f in input_api.AffectedFiles():
2039 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2040 continue
2041
2042 for line_num, line in f.ChangedContents():
2043 if pattern.match(line):
2044 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2045
2046 if not problems:
2047 return []
2048 return [output_api.PresubmitPromptWarning(
2049 'Please consider avoiding the "? true : false" pattern if possible.\n' +
2050 '\n'.join(problems))]
2051
2052
Saagar Sanghavifceeaae2020-08-12 16:40:362053def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:282054 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:182055 change. Breaking - rules is an error, breaking ! rules is a
2056 warning.
2057 """
mohan.reddyf21db962014-10-16 12:26:472058 import sys
[email protected]55f9f382012-07-31 11:02:182059 # We need to wait until we have an input_api object and use this
2060 # roundabout construct to import checkdeps because this file is
2061 # eval-ed and thus doesn't have __file__.
2062 original_sys_path = sys.path
2063 try:
2064 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:472065 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:182066 import checkdeps
[email protected]55f9f382012-07-31 11:02:182067 from rules import Rule
2068 finally:
2069 # Restore sys.path to what it was before.
2070 sys.path = original_sys_path
2071
2072 added_includes = []
rhalavati08acd232017-04-03 07:23:282073 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242074 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182075 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062076 if _IsCPlusPlusFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502077 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082078 added_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062079 elif _IsProtoFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502080 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082081 added_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062082 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502083 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082084 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182085
[email protected]26385172013-05-09 23:11:352086 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182087
2088 error_descriptions = []
2089 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282090 error_subjects = set()
2091 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:362092
[email protected]55f9f382012-07-31 11:02:182093 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2094 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082095 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182096 description_with_path = '%s\n %s' % (path, rule_description)
2097 if rule_type == Rule.DISALLOW:
2098 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282099 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182100 else:
2101 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282102 warning_subjects.add("#includes")
2103
2104 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2105 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082106 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282107 description_with_path = '%s\n %s' % (path, rule_description)
2108 if rule_type == Rule.DISALLOW:
2109 error_descriptions.append(description_with_path)
2110 error_subjects.add("imports")
2111 else:
2112 warning_descriptions.append(description_with_path)
2113 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182114
Jinsuk Kim5a092672017-10-24 22:42:242115 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022116 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082117 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242118 description_with_path = '%s\n %s' % (path, rule_description)
2119 if rule_type == Rule.DISALLOW:
2120 error_descriptions.append(description_with_path)
2121 error_subjects.add("imports")
2122 else:
2123 warning_descriptions.append(description_with_path)
2124 warning_subjects.add("imports")
2125
[email protected]55f9f382012-07-31 11:02:182126 results = []
2127 if error_descriptions:
2128 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282129 'You added one or more %s that violate checkdeps rules.'
2130 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182131 error_descriptions))
2132 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422133 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282134 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182135 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282136 '%s? See relevant DEPS file(s) for details and contacts.' %
2137 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182138 warning_descriptions))
2139 return results
2140
2141
Saagar Sanghavifceeaae2020-08-12 16:40:362142def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222143 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152144 if input_api.platform == 'win32':
2145 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292146 checkperms_tool = input_api.os_path.join(
2147 input_api.PresubmitLocalPath(),
2148 'tools', 'checkperms', 'checkperms.py')
2149 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472150 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392151 with input_api.CreateTemporaryFile() as file_list:
2152 for f in input_api.AffectedFiles():
2153 # checkperms.py file/directory arguments must be relative to the
2154 # repository.
2155 file_list.write(f.LocalPath() + '\n')
2156 file_list.close()
2157 args += ['--file-list', file_list.name]
2158 try:
2159 input_api.subprocess.check_output(args)
2160 return []
2161 except input_api.subprocess.CalledProcessError as error:
2162 return [output_api.PresubmitError(
2163 'checkperms.py failed:',
2164 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222165
2166
Saagar Sanghavifceeaae2020-08-12 16:40:362167def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492168 """Makes sure we don't include ui/aura/window_property.h
2169 in header files.
2170 """
2171 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2172 errors = []
2173 for f in input_api.AffectedFiles():
2174 if not f.LocalPath().endswith('.h'):
2175 continue
2176 for line_num, line in f.ChangedContents():
2177 if pattern.match(line):
2178 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2179
2180 results = []
2181 if errors:
2182 results.append(output_api.PresubmitError(
2183 'Header files should not include ui/aura/window_property.h', errors))
2184 return results
2185
2186
[email protected]70ca77752012-11-20 03:45:032187def _CheckForVersionControlConflictsInFile(input_api, f):
2188 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2189 errors = []
2190 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162191 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232192 # First-level headers in markdown look a lot like version control
2193 # conflict markers. http://daringfireball.net/projects/markdown/basics
2194 continue
[email protected]70ca77752012-11-20 03:45:032195 if pattern.match(line):
2196 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2197 return errors
2198
2199
Saagar Sanghavifceeaae2020-08-12 16:40:362200def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032201 """Usually this is not intentional and will cause a compile failure."""
2202 errors = []
2203 for f in input_api.AffectedFiles():
2204 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2205
2206 results = []
2207 if errors:
2208 results.append(output_api.PresubmitError(
2209 'Version control conflict markers found, please resolve.', errors))
2210 return results
2211
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202212
Saagar Sanghavifceeaae2020-08-12 16:40:362213def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162214 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2215 errors = []
2216 for f in input_api.AffectedFiles():
2217 for line_num, line in f.ChangedContents():
2218 if pattern.search(line):
2219 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2220
2221 results = []
2222 if errors:
2223 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502224 'Found Google support URL addressed by answer number. Please replace '
2225 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162226 return results
2227
[email protected]70ca77752012-11-20 03:45:032228
Saagar Sanghavifceeaae2020-08-12 16:40:362229def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442230 def FilterFile(affected_file):
2231 """Filter function for use with input_api.AffectedSourceFiles,
2232 below. This filters out everything except non-test files from
2233 top-level directories that generally speaking should not hard-code
2234 service URLs (e.g. src/android_webview/, src/content/ and others).
2235 """
2236 return input_api.FilterSourceFile(
2237 affected_file,
James Cook24a504192020-07-23 00:08:442238 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2239 files_to_skip=(_EXCLUDED_PATHS +
2240 _TEST_CODE_EXCLUDED_PATHS +
2241 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442242
reillyi38965732015-11-16 18:27:332243 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2244 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462245 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2246 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442247 problems = [] # items are (filename, line_number, line)
2248 for f in input_api.AffectedSourceFiles(FilterFile):
2249 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462250 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442251 problems.append((f.LocalPath(), line_num, line))
2252
2253 if problems:
[email protected]f7051d52013-04-02 18:31:422254 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442255 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582256 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442257 [' %s:%d: %s' % (
2258 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032259 else:
2260 return []
[email protected]06e6d0ff2012-12-11 01:36:442261
2262
Saagar Sanghavifceeaae2020-08-12 16:40:362263def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292264 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2265 def FileFilter(affected_file):
2266 """Includes directories known to be Chrome OS only."""
2267 return input_api.FilterSourceFile(
2268 affected_file,
James Cook24a504192020-07-23 00:08:442269 files_to_check=('^ash/',
2270 '^chromeos/', # Top-level src/chromeos.
2271 '/chromeos/', # Any path component.
2272 '^components/arc',
2273 '^components/exo'),
2274 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292275
2276 prefs = []
2277 priority_prefs = []
2278 for f in input_api.AffectedFiles(file_filter=FileFilter):
2279 for line_num, line in f.ChangedContents():
2280 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2281 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2282 prefs.append(' %s' % line)
2283 if input_api.re.search(
2284 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2285 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2286 priority_prefs.append(' %s' % line)
2287
2288 results = []
2289 if (prefs):
2290 results.append(output_api.PresubmitPromptWarning(
2291 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2292 'by browser sync settings. If these prefs should be controlled by OS '
2293 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2294 if (priority_prefs):
2295 results.append(output_api.PresubmitPromptWarning(
2296 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2297 'controlled by browser sync settings. If these prefs should be '
2298 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2299 'instead.\n' + '\n'.join(prefs)))
2300 return results
2301
2302
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492303# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362304def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272305 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312306 The native_client_sdk directory is excluded because it has auto-generated PNG
2307 files for documentation.
[email protected]d2530012013-01-25 16:39:272308 """
[email protected]d2530012013-01-25 16:39:272309 errors = []
James Cook24a504192020-07-23 00:08:442310 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2311 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312312 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442313 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312314 for f in input_api.AffectedFiles(include_deletes=False,
2315 file_filter=file_filter):
2316 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272317
2318 results = []
2319 if errors:
2320 results.append(output_api.PresubmitError(
2321 'The name of PNG files should not have abbreviations. \n'
2322 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2323 'Contact [email protected] if you have questions.', errors))
2324 return results
2325
2326
Daniel Cheng4dcdb6b2017-04-13 08:30:172327def _ExtractAddRulesFromParsedDeps(parsed_deps):
2328 """Extract the rules that add dependencies from a parsed DEPS file.
2329
2330 Args:
2331 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2332 add_rules = set()
2333 add_rules.update([
2334 rule[1:] for rule in parsed_deps.get('include_rules', [])
2335 if rule.startswith('+') or rule.startswith('!')
2336 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502337 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172338 {}).iteritems():
2339 add_rules.update([
2340 rule[1:] for rule in rules
2341 if rule.startswith('+') or rule.startswith('!')
2342 ])
2343 return add_rules
2344
2345
2346def _ParseDeps(contents):
2347 """Simple helper for parsing DEPS files."""
2348 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172349 class _VarImpl:
2350
2351 def __init__(self, local_scope):
2352 self._local_scope = local_scope
2353
2354 def Lookup(self, var_name):
2355 """Implements the Var syntax."""
2356 try:
2357 return self._local_scope['vars'][var_name]
2358 except KeyError:
2359 raise Exception('Var is not defined: %s' % var_name)
2360
2361 local_scope = {}
2362 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172363 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592364 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172365 }
2366 exec contents in global_scope, local_scope
2367 return local_scope
2368
2369
2370def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592371 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412372 a set of DEPS entries that we should look up.
2373
2374 For a directory (rather than a specific filename) we fake a path to
2375 a specific filename by adding /DEPS. This is chosen as a file that
2376 will seldom or never be subject to per-file include_rules.
2377 """
[email protected]2b438d62013-11-14 17:54:142378 # We ignore deps entries on auto-generated directories.
2379 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082380
Daniel Cheng4dcdb6b2017-04-13 08:30:172381 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2382 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2383
2384 added_deps = new_deps.difference(old_deps)
2385
[email protected]2b438d62013-11-14 17:54:142386 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172387 for added_dep in added_deps:
2388 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2389 continue
2390 # Assume that a rule that ends in .h is a rule for a specific file.
2391 if added_dep.endswith('.h'):
2392 results.add(added_dep)
2393 else:
2394 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082395 return results
2396
2397
Saagar Sanghavifceeaae2020-08-12 16:40:362398def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552399 """When a dependency prefixed with + is added to a DEPS file, we
2400 want to make sure that the change is reviewed by an OWNER of the
2401 target file or directory, to avoid layering violations from being
2402 introduced. This check verifies that this happens.
2403 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172404 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242405
2406 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492407 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242408 for f in input_api.AffectedFiles(include_deletes=False,
2409 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552410 filename = input_api.os_path.basename(f.LocalPath())
2411 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172412 virtual_depended_on_files.update(_CalculateAddedDeps(
2413 input_api.os_path,
2414 '\n'.join(f.OldContents()),
2415 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552416
[email protected]e871964c2013-05-13 14:14:552417 if not virtual_depended_on_files:
2418 return []
2419
2420 if input_api.is_committing:
2421 if input_api.tbr:
2422 return [output_api.PresubmitNotifyResult(
2423 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272424 if input_api.dry_run:
2425 return [output_api.PresubmitNotifyResult(
2426 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552427 if not input_api.change.issue:
2428 return [output_api.PresubmitError(
2429 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402430 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552431 output = output_api.PresubmitError
2432 else:
2433 output = output_api.PresubmitNotifyResult
2434
2435 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502436 owner_email, reviewers = (
2437 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2438 input_api,
2439 owners_db.email_regexp,
2440 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552441
2442 owner_email = owner_email or input_api.change.author_email
2443
[email protected]de4f7d22013-05-23 14:27:462444 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512445 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462446 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552447 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2448 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412449
2450 # We strip the /DEPS part that was added by
2451 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2452 # directory.
2453 def StripDeps(path):
2454 start_deps = path.rfind('/DEPS')
2455 if start_deps != -1:
2456 return path[:start_deps]
2457 else:
2458 return path
2459 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552460 for path in missing_files]
2461
2462 if unapproved_dependencies:
2463 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152464 output('You need LGTM from owners of depends-on paths in DEPS that were '
2465 'modified in this CL:\n %s' %
2466 '\n '.join(sorted(unapproved_dependencies)))]
2467 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2468 output_list.append(output(
2469 'Suggested missing target path OWNERS:\n %s' %
2470 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552471 return output_list
2472
2473 return []
2474
2475
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492476# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362477def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492478 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442479 files_to_skip = (_EXCLUDED_PATHS +
2480 _TEST_CODE_EXCLUDED_PATHS +
2481 input_api.DEFAULT_FILES_TO_SKIP +
2482 (r"^base[\\/]logging\.h$",
2483 r"^base[\\/]logging\.cc$",
2484 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2485 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2486 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2487 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2488 r"startup_browser_creator\.cc$",
2489 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2490 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2491 r"diagnostics_writer\.cc$",
2492 r"^chrome[\\/]chrome_cleaner[\\/].*",
2493 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2494 r"dll_hash_main\.cc$",
2495 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2496 r"^chromecast[\\/]",
2497 r"^cloud_print[\\/]",
2498 r"^components[\\/]browser_watcher[\\/]"
2499 r"dump_stability_report_main_win.cc$",
2500 r"^components[\\/]media_control[\\/]renderer[\\/]"
2501 r"media_playback_options\.cc$",
2502 r"^components[\\/]zucchini[\\/].*",
2503 # TODO(peter): Remove exception. https://crbug.com/534537
2504 r"^content[\\/]browser[\\/]notifications[\\/]"
2505 r"notification_event_dispatcher_impl\.cc$",
2506 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2507 r"gl_helper_benchmark\.cc$",
2508 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2509 r"^courgette[\\/]courgette_tool\.cc$",
2510 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2511 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2512 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
2513 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2514 r"^ipc[\\/]ipc_logging\.cc$",
2515 r"^native_client_sdk[\\/]",
2516 r"^remoting[\\/]base[\\/]logging\.h$",
2517 r"^remoting[\\/]host[\\/].*",
2518 r"^sandbox[\\/]linux[\\/].*",
2519 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2520 r"dump_file_system.cc$",
2521 r"^tools[\\/]",
2522 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2523 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2524 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2525 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2526 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402527 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442528 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402529
thomasanderson625d3932017-03-29 07:16:582530 log_info = set([])
2531 printf = set([])
[email protected]85218562013-11-22 07:41:402532
2533 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582534 for _, line in f.ChangedContents():
2535 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2536 log_info.add(f.LocalPath())
2537 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2538 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372539
thomasanderson625d3932017-03-29 07:16:582540 if input_api.re.search(r"\bprintf\(", line):
2541 printf.add(f.LocalPath())
2542 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2543 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402544
2545 if log_info:
2546 return [output_api.PresubmitError(
2547 'These files spam the console log with LOG(INFO):',
2548 items=log_info)]
2549 if printf:
2550 return [output_api.PresubmitError(
2551 'These files spam the console log with printf/fprintf:',
2552 items=printf)]
2553 return []
2554
2555
Saagar Sanghavifceeaae2020-08-12 16:40:362556def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162557 """These types are all expected to hold locks while in scope and
2558 so should never be anonymous (which causes them to be immediately
2559 destroyed)."""
2560 they_who_must_be_named = [
2561 'base::AutoLock',
2562 'base::AutoReset',
2563 'base::AutoUnlock',
2564 'SkAutoAlphaRestore',
2565 'SkAutoBitmapShaderInstall',
2566 'SkAutoBlitterChoose',
2567 'SkAutoBounderCommit',
2568 'SkAutoCallProc',
2569 'SkAutoCanvasRestore',
2570 'SkAutoCommentBlock',
2571 'SkAutoDescriptor',
2572 'SkAutoDisableDirectionCheck',
2573 'SkAutoDisableOvalCheck',
2574 'SkAutoFree',
2575 'SkAutoGlyphCache',
2576 'SkAutoHDC',
2577 'SkAutoLockColors',
2578 'SkAutoLockPixels',
2579 'SkAutoMalloc',
2580 'SkAutoMaskFreeImage',
2581 'SkAutoMutexAcquire',
2582 'SkAutoPathBoundsUpdate',
2583 'SkAutoPDFRelease',
2584 'SkAutoRasterClipValidate',
2585 'SkAutoRef',
2586 'SkAutoTime',
2587 'SkAutoTrace',
2588 'SkAutoUnref',
2589 ]
2590 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2591 # bad: base::AutoLock(lock.get());
2592 # not bad: base::AutoLock lock(lock.get());
2593 bad_pattern = input_api.re.compile(anonymous)
2594 # good: new base::AutoLock(lock.get())
2595 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2596 errors = []
2597
2598 for f in input_api.AffectedFiles():
2599 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2600 continue
2601 for linenum, line in f.ChangedContents():
2602 if bad_pattern.search(line) and not good_pattern.search(line):
2603 errors.append('%s:%d' % (f.LocalPath(), linenum))
2604
2605 if errors:
2606 return [output_api.PresubmitError(
2607 'These lines create anonymous variables that need to be named:',
2608 items=errors)]
2609 return []
2610
2611
Saagar Sanghavifceeaae2020-08-12 16:40:362612def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532613 # Returns whether |template_str| is of the form <T, U...> for some types T
2614 # and U. Assumes that |template_str| is already in the form <...>.
2615 def HasMoreThanOneArg(template_str):
2616 # Level of <...> nesting.
2617 nesting = 0
2618 for c in template_str:
2619 if c == '<':
2620 nesting += 1
2621 elif c == '>':
2622 nesting -= 1
2623 elif c == ',' and nesting == 1:
2624 return True
2625 return False
2626
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492627 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102628 sources = lambda affected_file: input_api.FilterSourceFile(
2629 affected_file,
James Cook24a504192020-07-23 00:08:442630 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2631 input_api.DEFAULT_FILES_TO_SKIP),
2632 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552633
2634 # Pattern to capture a single "<...>" block of template arguments. It can
2635 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2636 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2637 # latter would likely require counting that < and > match, which is not
2638 # expressible in regular languages. Should the need arise, one can introduce
2639 # limited counting (matching up to a total number of nesting depth), which
2640 # should cover all practical cases for already a low nesting limit.
2641 template_arg_pattern = (
2642 r'<[^>]*' # Opening block of <.
2643 r'>([^<]*>)?') # Closing block of >.
2644 # Prefix expressing that whatever follows is not already inside a <...>
2645 # block.
2646 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102647 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552648 not_inside_template_arg_pattern
2649 + r'\bstd::unique_ptr'
2650 + template_arg_pattern
2651 + r'\(\)')
2652
2653 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2654 template_arg_no_array_pattern = (
2655 r'<[^>]*[^]]' # Opening block of <.
2656 r'>([^(<]*[^]]>)?') # Closing block of >.
2657 # Prefix saying that what follows is the start of an expression.
2658 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2659 # Suffix saying that what follows are call parentheses with a non-empty list
2660 # of arguments.
2661 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532662 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552663 return_construct_pattern = input_api.re.compile(
2664 start_of_expr_pattern
2665 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532666 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552667 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532668 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552669 + nonempty_arg_list_pattern)
2670
Vaclav Brozek851d9602018-04-04 16:13:052671 problems_constructor = []
2672 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102673 for f in input_api.AffectedSourceFiles(sources):
2674 for line_number, line in f.ChangedContents():
2675 # Disallow:
2676 # return std::unique_ptr<T>(foo);
2677 # bar = std::unique_ptr<T>(foo);
2678 # But allow:
2679 # return std::unique_ptr<T[]>(foo);
2680 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532681 # And also allow cases when the second template argument is present. Those
2682 # cases cannot be handled by std::make_unique:
2683 # return std::unique_ptr<T, U>(foo);
2684 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052685 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532686 return_construct_result = return_construct_pattern.search(line)
2687 if return_construct_result and not HasMoreThanOneArg(
2688 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052689 problems_constructor.append(
2690 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102691 # Disallow:
2692 # std::unique_ptr<T>()
2693 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052694 problems_nullptr.append(
2695 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2696
2697 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162698 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052699 errors.append(output_api.PresubmitError(
2700 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162701 problems_nullptr))
2702 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052703 errors.append(output_api.PresubmitError(
2704 'The following files use explicit std::unique_ptr constructor.'
2705 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162706 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102707 return errors
2708
2709
Saagar Sanghavifceeaae2020-08-12 16:40:362710def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082711 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522712 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082713 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522714 # If actions.xml is already included in the changelist, the PRESUBMIT
2715 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082716 return []
2717
[email protected]999261d2014-03-03 20:08:082718 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2719 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522720 current_actions = None
[email protected]999261d2014-03-03 20:08:082721 for f in input_api.AffectedFiles(file_filter=file_filter):
2722 for line_num, line in f.ChangedContents():
2723 match = input_api.re.search(action_re, line)
2724 if match:
[email protected]2f92dec2014-03-07 19:21:522725 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2726 # loaded only once.
2727 if not current_actions:
2728 with open('tools/metrics/actions/actions.xml') as actions_f:
2729 current_actions = actions_f.read()
2730 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082731 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522732 action = 'name="{0}"'.format(action_name)
2733 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082734 return [output_api.PresubmitPromptWarning(
2735 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522736 'tools/metrics/actions/actions.xml. Please run '
2737 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082738 % (f.LocalPath(), line_num, action_name))]
2739 return []
2740
2741
Daniel Cheng13ca61a882017-08-25 15:11:252742def _ImportJSONCommentEater(input_api):
2743 import sys
2744 sys.path = sys.path + [input_api.os_path.join(
2745 input_api.PresubmitLocalPath(),
2746 'tools', 'json_comment_eater')]
2747 import json_comment_eater
2748 return json_comment_eater
2749
2750
[email protected]99171a92014-06-03 08:44:472751def _GetJSONParseError(input_api, filename, eat_comments=True):
2752 try:
2753 contents = input_api.ReadFile(filename)
2754 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252755 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132756 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472757
2758 input_api.json.loads(contents)
2759 except ValueError as e:
2760 return e
2761 return None
2762
2763
2764def _GetIDLParseError(input_api, filename):
2765 try:
2766 contents = input_api.ReadFile(filename)
2767 idl_schema = input_api.os_path.join(
2768 input_api.PresubmitLocalPath(),
2769 'tools', 'json_schema_compiler', 'idl_schema.py')
2770 process = input_api.subprocess.Popen(
2771 [input_api.python_executable, idl_schema],
2772 stdin=input_api.subprocess.PIPE,
2773 stdout=input_api.subprocess.PIPE,
2774 stderr=input_api.subprocess.PIPE,
2775 universal_newlines=True)
2776 (_, error) = process.communicate(input=contents)
2777 return error or None
2778 except ValueError as e:
2779 return e
2780
2781
Saagar Sanghavifceeaae2020-08-12 16:40:362782def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472783 """Check that IDL and JSON files do not contain syntax errors."""
2784 actions = {
2785 '.idl': _GetIDLParseError,
2786 '.json': _GetJSONParseError,
2787 }
[email protected]99171a92014-06-03 08:44:472788 # Most JSON files are preprocessed and support comments, but these do not.
2789 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042790 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472791 ]
2792 # Only run IDL checker on files in these directories.
2793 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042794 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2795 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472796 ]
2797
2798 def get_action(affected_file):
2799 filename = affected_file.LocalPath()
2800 return actions.get(input_api.os_path.splitext(filename)[1])
2801
[email protected]99171a92014-06-03 08:44:472802 def FilterFile(affected_file):
2803 action = get_action(affected_file)
2804 if not action:
2805 return False
2806 path = affected_file.LocalPath()
2807
Erik Staab2dd72b12020-04-16 15:03:402808 if _MatchesFile(input_api,
2809 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2810 path):
[email protected]99171a92014-06-03 08:44:472811 return False
2812
2813 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162814 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472815 return False
2816 return True
2817
2818 results = []
2819 for affected_file in input_api.AffectedFiles(
2820 file_filter=FilterFile, include_deletes=False):
2821 action = get_action(affected_file)
2822 kwargs = {}
2823 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162824 _MatchesFile(input_api, json_no_comments_patterns,
2825 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472826 kwargs['eat_comments'] = False
2827 parse_error = action(input_api,
2828 affected_file.AbsoluteLocalPath(),
2829 **kwargs)
2830 if parse_error:
2831 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2832 (affected_file.LocalPath(), parse_error)))
2833 return results
2834
2835
Saagar Sanghavifceeaae2020-08-12 16:40:362836def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492837 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472838 import sys
[email protected]760deea2013-12-10 19:33:492839 original_sys_path = sys.path
2840 try:
2841 sys.path = sys.path + [input_api.os_path.join(
2842 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2843 import checkstyle
2844 finally:
2845 # Restore sys.path to what it was before.
2846 sys.path = original_sys_path
2847
2848 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092849 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442850 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492851
2852
Saagar Sanghavifceeaae2020-08-12 16:40:362853def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002854 """Checks to make sure devil is initialized correctly in python scripts."""
2855 script_common_initialize_pattern = input_api.re.compile(
2856 r'script_common\.InitializeEnvironment\(')
2857 devil_env_config_initialize = input_api.re.compile(
2858 r'devil_env\.config\.Initialize\(')
2859
2860 errors = []
2861
2862 sources = lambda affected_file: input_api.FilterSourceFile(
2863 affected_file,
James Cook24a504192020-07-23 00:08:442864 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2865 (r'^build[\\/]android[\\/]devil_chromium\.py',
2866 r'^third_party[\\/].*',)),
2867 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002868
2869 for f in input_api.AffectedSourceFiles(sources):
2870 for line_num, line in f.ChangedContents():
2871 if (script_common_initialize_pattern.search(line) or
2872 devil_env_config_initialize.search(line)):
2873 errors.append("%s:%d" % (f.LocalPath(), line_num))
2874
2875 results = []
2876
2877 if errors:
2878 results.append(output_api.PresubmitError(
2879 'Devil initialization should always be done using '
2880 'devil_chromium.Initialize() in the chromium project, to use better '
2881 'defaults for dependencies (ex. up-to-date version of adb).',
2882 errors))
2883
2884 return results
2885
2886
Sean Kau46e29bc2017-08-28 16:31:162887def _MatchesFile(input_api, patterns, path):
2888 for pattern in patterns:
2889 if input_api.re.search(pattern, path):
2890 return True
2891 return False
2892
2893
Daniel Cheng7052cdf2017-11-21 19:23:292894def _GetOwnersFilesToCheckForIpcOwners(input_api):
2895 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172896
Daniel Cheng7052cdf2017-11-21 19:23:292897 Returns:
2898 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2899 contain to cover IPC-related files with noparent reviewer rules.
2900 """
2901 # Whether or not a file affects IPC is (mostly) determined by a simple list
2902 # of filename patterns.
dchenge07de812016-06-20 19:27:172903 file_patterns = [
palmerb19a0932017-01-24 04:00:312904 # Legacy IPC:
dchenge07de812016-06-20 19:27:172905 '*_messages.cc',
2906 '*_messages*.h',
2907 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312908 # Mojo IPC:
dchenge07de812016-06-20 19:27:172909 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472910 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172911 '*_struct_traits*.*',
2912 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312913 '*.typemap',
2914 # Android native IPC:
2915 '*.aidl',
2916 # Blink uses a different file naming convention:
2917 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472918 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172919 '*StructTraits*.*',
2920 '*TypeConverter*.*',
2921 ]
2922
scottmg7a6ed5ba2016-11-04 18:22:042923 # These third_party directories do not contain IPCs, but contain files
2924 # matching the above patterns, which trigger false positives.
2925 exclude_paths = [
2926 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162927 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232928 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292929 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542930 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162931 # These files are just used to communicate between class loaders running
2932 # in the same process.
2933 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572934 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2935
scottmg7a6ed5ba2016-11-04 18:22:042936 ]
2937
dchenge07de812016-06-20 19:27:172938 # Dictionary mapping an OWNERS file path to Patterns.
2939 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2940 # rules ) to a PatternEntry.
2941 # PatternEntry is a dictionary with two keys:
2942 # - 'files': the files that are matched by this pattern
2943 # - 'rules': the per-file rules needed for this pattern
2944 # For example, if we expect OWNERS file to contain rules for *.mojom and
2945 # *_struct_traits*.*, Patterns might look like this:
2946 # {
2947 # '*.mojom': {
2948 # 'files': ...,
2949 # 'rules': [
2950 # 'per-file *.mojom=set noparent',
2951 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2952 # ],
2953 # },
2954 # '*_struct_traits*.*': {
2955 # 'files': ...,
2956 # 'rules': [
2957 # 'per-file *_struct_traits*.*=set noparent',
2958 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2959 # ],
2960 # },
2961 # }
2962 to_check = {}
2963
Daniel Cheng13ca61a882017-08-25 15:11:252964 def AddPatternToCheck(input_file, pattern):
2965 owners_file = input_api.os_path.join(
2966 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2967 if owners_file not in to_check:
2968 to_check[owners_file] = {}
2969 if pattern not in to_check[owners_file]:
2970 to_check[owners_file][pattern] = {
2971 'files': [],
2972 'rules': [
2973 'per-file %s=set noparent' % pattern,
2974 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2975 ]
2976 }
Vaclav Brozekd5de76a2018-03-17 07:57:502977 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252978
dchenge07de812016-06-20 19:27:172979 # Iterate through the affected files to see what we actually need to check
2980 # for. We should only nag patch authors about per-file rules if a file in that
2981 # directory would match that pattern. If a directory only contains *.mojom
2982 # files and no *_messages*.h files, we should only nag about rules for
2983 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252984 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262985 # Manifest files don't have a strong naming convention. Instead, try to find
2986 # affected .cc and .h files which look like they contain a manifest
2987 # definition.
2988 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2989 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2990 if (manifest_pattern.search(f.LocalPath()) and not
2991 test_manifest_pattern.search(f.LocalPath())):
2992 # We expect all actual service manifest files to contain at least one
2993 # qualified reference to service_manager::Manifest.
2994 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252995 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172996 for pattern in file_patterns:
2997 if input_api.fnmatch.fnmatch(
2998 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:042999 skip = False
3000 for exclude in exclude_paths:
3001 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
3002 skip = True
3003 break
3004 if skip:
3005 continue
Daniel Cheng13ca61a882017-08-25 15:11:253006 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:173007 break
3008
Daniel Cheng7052cdf2017-11-21 19:23:293009 return to_check
3010
3011
Wez17c66962020-04-29 15:26:033012def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
3013 """Adds OWNERS files to check for correct Fuchsia security owners."""
3014
3015 file_patterns = [
3016 # Component specifications.
3017 '*.cml', # Component Framework v2.
3018 '*.cmx', # Component Framework v1.
3019
3020 # Fuchsia IDL protocol specifications.
3021 '*.fidl',
3022 ]
3023
3024 def AddPatternToCheck(input_file, pattern):
3025 owners_file = input_api.os_path.join(
3026 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
3027 if owners_file not in to_check:
3028 to_check[owners_file] = {}
3029 if pattern not in to_check[owners_file]:
3030 to_check[owners_file][pattern] = {
3031 'files': [],
3032 'rules': [
3033 'per-file %s=set noparent' % pattern,
3034 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
3035 ]
3036 }
3037 to_check[owners_file][pattern]['files'].append(input_file)
3038
3039 # Iterate through the affected files to see what we actually need to check
3040 # for. We should only nag patch authors about per-file rules if a file in that
3041 # directory would match that pattern.
3042 for f in input_api.AffectedFiles(include_deletes=False):
3043 for pattern in file_patterns:
3044 if input_api.fnmatch.fnmatch(
3045 input_api.os_path.basename(f.LocalPath()), pattern):
3046 AddPatternToCheck(f, pattern)
3047 break
3048
3049 return to_check
3050
3051
Saagar Sanghavifceeaae2020-08-12 16:40:363052def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293053 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3054 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033055 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293056
3057 if to_check:
3058 # If there are any OWNERS files to check, there are IPC-related changes in
3059 # this CL. Auto-CC the review list.
3060 output_api.AppendCC('[email protected]')
3061
3062 # Go through the OWNERS files to check, filtering out rules that are already
3063 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173064 for owners_file, patterns in to_check.iteritems():
3065 try:
3066 with file(owners_file) as f:
3067 lines = set(f.read().splitlines())
3068 for entry in patterns.itervalues():
3069 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3070 ]
3071 except IOError:
3072 # No OWNERS file, so all the rules are definitely missing.
3073 continue
3074
3075 # All the remaining lines weren't found in OWNERS files, so emit an error.
3076 errors = []
3077 for owners_file, patterns in to_check.iteritems():
3078 missing_lines = []
3079 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503080 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173081 missing_lines.extend(entry['rules'])
3082 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3083 if missing_lines:
3084 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053085 'Because of the presence of files:\n%s\n\n'
3086 '%s needs the following %d lines added:\n\n%s' %
3087 ('\n'.join(files), owners_file, len(missing_lines),
3088 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173089
3090 results = []
3091 if errors:
vabrf5ce3bf92016-07-11 14:52:413092 if input_api.is_committing:
3093 output = output_api.PresubmitError
3094 else:
3095 output = output_api.PresubmitPromptWarning
3096 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593097 'Found OWNERS files that need to be updated for IPC security ' +
3098 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173099 long_text='\n\n'.join(errors)))
3100
3101 return results
3102
3103
Robert Sesek2c905332020-05-06 23:17:133104def _GetFilesUsingSecurityCriticalFunctions(input_api):
3105 """Checks affected files for changes to security-critical calls. This
3106 function checks the full change diff, to catch both additions/changes
3107 and removals.
3108
3109 Returns a dict keyed by file name, and the value is a set of detected
3110 functions.
3111 """
3112 # Map of function pretty name (displayed in an error) to the pattern to
3113 # match it with.
3114 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373115 'content::GetServiceSandboxType<>()':
3116 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133117 }
3118 _PATTERNS_TO_CHECK = {
3119 k: input_api.re.compile(v)
3120 for k, v in _PATTERNS_TO_CHECK.items()
3121 }
3122
3123 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3124 files_to_functions = {}
3125 for f in input_api.AffectedFiles():
3126 diff = f.GenerateScmDiff()
3127 for line in diff.split('\n'):
3128 # Not using just RightHandSideLines() because removing a
3129 # call to a security-critical function can be just as important
3130 # as adding or changing the arguments.
3131 if line.startswith('-') or (line.startswith('+') and
3132 not line.startswith('++')):
3133 for name, pattern in _PATTERNS_TO_CHECK.items():
3134 if pattern.search(line):
3135 path = f.LocalPath()
3136 if not path in files_to_functions:
3137 files_to_functions[path] = set()
3138 files_to_functions[path].add(name)
3139 return files_to_functions
3140
3141
Saagar Sanghavifceeaae2020-08-12 16:40:363142def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133143 """Checks that changes involving security-critical functions are reviewed
3144 by the security team.
3145 """
3146 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3147 if len(files_to_functions):
3148 owners_db = input_api.owners_db
3149 owner_email, reviewers = (
3150 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3151 input_api,
3152 owners_db.email_regexp,
3153 approval_needed=input_api.is_committing))
3154
3155 # Load the OWNERS file for security changes.
3156 owners_file = 'ipc/SECURITY_OWNERS'
3157 security_owners = owners_db.owners_rooted_at_file(owners_file)
3158
3159 has_security_owner = any([owner in reviewers for owner in security_owners])
3160 if not has_security_owner:
3161 msg = 'The following files change calls to security-sensive functions\n' \
3162 'that need to be reviewed by {}.\n'.format(owners_file)
3163 for path, names in files_to_functions.items():
3164 msg += ' {}\n'.format(path)
3165 for name in names:
3166 msg += ' {}\n'.format(name)
3167 msg += '\n'
3168
3169 if input_api.is_committing:
3170 output = output_api.PresubmitError
3171 else:
3172 output = output_api.PresubmitNotifyResult
3173 return [output(msg)]
3174
3175 return []
3176
3177
Saagar Sanghavifceeaae2020-08-12 16:40:363178def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263179 """Checks that set noparent is only used together with an OWNERS file in
3180 //build/OWNERS.setnoparent (see also
3181 //docs/code_reviews.md#owners-files-details)
3182 """
3183 errors = []
3184
3185 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3186 allowed_owners_files = set()
3187 with open(allowed_owners_files_file, 'r') as f:
3188 for line in f:
3189 line = line.strip()
3190 if not line or line.startswith('#'):
3191 continue
3192 allowed_owners_files.add(line)
3193
3194 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3195
3196 for f in input_api.AffectedFiles(include_deletes=False):
3197 if not f.LocalPath().endswith('OWNERS'):
3198 continue
3199
3200 found_owners_files = set()
3201 found_set_noparent_lines = dict()
3202
3203 # Parse the OWNERS file.
3204 for lineno, line in enumerate(f.NewContents(), 1):
3205 line = line.strip()
3206 if line.startswith('set noparent'):
3207 found_set_noparent_lines[''] = lineno
3208 if line.startswith('file://'):
3209 if line in allowed_owners_files:
3210 found_owners_files.add('')
3211 if line.startswith('per-file'):
3212 match = per_file_pattern.match(line)
3213 if match:
3214 glob = match.group(1).strip()
3215 directive = match.group(2).strip()
3216 if directive == 'set noparent':
3217 found_set_noparent_lines[glob] = lineno
3218 if directive.startswith('file://'):
3219 if directive in allowed_owners_files:
3220 found_owners_files.add(glob)
3221
3222 # Check that every set noparent line has a corresponding file:// line
3223 # listed in build/OWNERS.setnoparent.
3224 for set_noparent_line in found_set_noparent_lines:
3225 if set_noparent_line in found_owners_files:
3226 continue
3227 errors.append(' %s:%d' % (f.LocalPath(),
3228 found_set_noparent_lines[set_noparent_line]))
3229
3230 results = []
3231 if errors:
3232 if input_api.is_committing:
3233 output = output_api.PresubmitError
3234 else:
3235 output = output_api.PresubmitPromptWarning
3236 results.append(output(
3237 'Found the following "set noparent" restrictions in OWNERS files that '
3238 'do not include owners from build/OWNERS.setnoparent:',
3239 long_text='\n\n'.join(errors)))
3240 return results
3241
3242
Saagar Sanghavifceeaae2020-08-12 16:40:363243def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313244 """Checks that added or removed lines in non third party affected
3245 header files do not lead to new useless class or struct forward
3246 declaration.
jbriance9e12f162016-11-25 07:57:503247 """
3248 results = []
3249 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3250 input_api.re.MULTILINE)
3251 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3252 input_api.re.MULTILINE)
3253 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313254 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193255 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493256 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313257 continue
3258
jbriance9e12f162016-11-25 07:57:503259 if not f.LocalPath().endswith('.h'):
3260 continue
3261
3262 contents = input_api.ReadFile(f)
3263 fwd_decls = input_api.re.findall(class_pattern, contents)
3264 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3265
3266 useless_fwd_decls = []
3267 for decl in fwd_decls:
3268 count = sum(1 for _ in input_api.re.finditer(
3269 r'\b%s\b' % input_api.re.escape(decl), contents))
3270 if count == 1:
3271 useless_fwd_decls.append(decl)
3272
3273 if not useless_fwd_decls:
3274 continue
3275
3276 for line in f.GenerateScmDiff().splitlines():
3277 if (line.startswith('-') and not line.startswith('--') or
3278 line.startswith('+') and not line.startswith('++')):
3279 for decl in useless_fwd_decls:
3280 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3281 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243282 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503283 (f.LocalPath(), decl)))
3284 useless_fwd_decls.remove(decl)
3285
3286 return results
3287
Jinsong Fan91ebbbd2019-04-16 14:57:173288def _CheckAndroidDebuggableBuild(input_api, output_api):
3289 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3290 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3291 this is a debuggable build of Android.
3292 """
3293 build_type_check_pattern = input_api.re.compile(
3294 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3295
3296 errors = []
3297
3298 sources = lambda affected_file: input_api.FilterSourceFile(
3299 affected_file,
James Cook24a504192020-07-23 00:08:443300 files_to_skip=(_EXCLUDED_PATHS +
3301 _TEST_CODE_EXCLUDED_PATHS +
3302 input_api.DEFAULT_FILES_TO_SKIP +
3303 (r"^android_webview[\\/]support_library[\\/]"
3304 "boundary_interfaces[\\/]",
3305 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3306 r'^third_party[\\/].*',
3307 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3308 r"webview[\\/]chromium[\\/]License.*",)),
3309 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173310
3311 for f in input_api.AffectedSourceFiles(sources):
3312 for line_num, line in f.ChangedContents():
3313 if build_type_check_pattern.search(line):
3314 errors.append("%s:%d" % (f.LocalPath(), line_num))
3315
3316 results = []
3317
3318 if errors:
3319 results.append(output_api.PresubmitPromptWarning(
3320 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3321 ' Please use BuildInfo.isDebugAndroid() instead.',
3322 errors))
3323
3324 return results
jbriance9e12f162016-11-25 07:57:503325
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493326# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293327def _CheckAndroidToastUsage(input_api, output_api):
3328 """Checks that code uses org.chromium.ui.widget.Toast instead of
3329 android.widget.Toast (Chromium Toast doesn't force hardware
3330 acceleration on low-end devices, saving memory).
3331 """
3332 toast_import_pattern = input_api.re.compile(
3333 r'^import android\.widget\.Toast;$')
3334
3335 errors = []
3336
3337 sources = lambda affected_file: input_api.FilterSourceFile(
3338 affected_file,
James Cook24a504192020-07-23 00:08:443339 files_to_skip=(_EXCLUDED_PATHS +
3340 _TEST_CODE_EXCLUDED_PATHS +
3341 input_api.DEFAULT_FILES_TO_SKIP +
3342 (r'^chromecast[\\/].*',
3343 r'^remoting[\\/].*')),
3344 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293345
3346 for f in input_api.AffectedSourceFiles(sources):
3347 for line_num, line in f.ChangedContents():
3348 if toast_import_pattern.search(line):
3349 errors.append("%s:%d" % (f.LocalPath(), line_num))
3350
3351 results = []
3352
3353 if errors:
3354 results.append(output_api.PresubmitError(
3355 'android.widget.Toast usage is detected. Android toasts use hardware'
3356 ' acceleration, and can be\ncostly on low-end devices. Please use'
3357 ' org.chromium.ui.widget.Toast instead.\n'
3358 'Contact [email protected] if you have any questions.',
3359 errors))
3360
3361 return results
3362
3363
dgnaa68d5e2015-06-10 10:08:223364def _CheckAndroidCrLogUsage(input_api, output_api):
3365 """Checks that new logs using org.chromium.base.Log:
3366 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513367 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223368 """
pkotwicza1dd0b002016-05-16 14:41:043369
torne89540622017-03-24 19:41:303370 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043371 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303372 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043373 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303374 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043375 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3376 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093377 # The customtabs_benchmark is a small app that does not depend on Chromium
3378 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043379 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043380 ]
3381
dgnaa68d5e2015-06-10 10:08:223382 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123383 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3384 class_in_base_pattern = input_api.re.compile(
3385 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3386 has_some_log_import_pattern = input_api.re.compile(
3387 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223388 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553389 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223390 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463391 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553392 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223393
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463394 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443395 sources = lambda x: input_api.FilterSourceFile(x,
3396 files_to_check=[r'.*\.java$'],
3397 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123398
dgnaa68d5e2015-06-10 10:08:223399 tag_decl_errors = []
3400 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123401 tag_errors = []
dgn38736db2015-09-18 19:20:513402 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123403 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223404
3405 for f in input_api.AffectedSourceFiles(sources):
3406 file_content = input_api.ReadFile(f)
3407 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223408 # Per line checks
dgn87d9fb62015-06-12 09:15:123409 if (cr_log_import_pattern.search(file_content) or
3410 (class_in_base_pattern.search(file_content) and
3411 not has_some_log_import_pattern.search(file_content))):
3412 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223413 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553414 if rough_log_decl_pattern.search(line):
3415 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223416
3417 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123418 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223419 if match:
3420 has_modified_logs = True
3421
3422 # Make sure it uses "TAG"
3423 if not match.group('tag') == 'TAG':
3424 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123425 else:
3426 # Report non cr Log function calls in changed lines
3427 for line_num, line in f.ChangedContents():
3428 if log_call_pattern.search(line):
3429 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223430
3431 # Per file checks
3432 if has_modified_logs:
3433 # Make sure the tag is using the "cr" prefix and is not too long
3434 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513435 tag_name = match.group('name') if match else None
3436 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223437 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513438 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223439 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513440 elif '.' in tag_name:
3441 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223442
3443 results = []
3444 if tag_decl_errors:
3445 results.append(output_api.PresubmitPromptWarning(
3446 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513447 '"private static final String TAG = "<package tag>".\n'
3448 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223449 tag_decl_errors))
3450
3451 if tag_length_errors:
3452 results.append(output_api.PresubmitError(
3453 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513454 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223455 tag_length_errors))
3456
3457 if tag_errors:
3458 results.append(output_api.PresubmitPromptWarning(
3459 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3460 tag_errors))
3461
dgn87d9fb62015-06-12 09:15:123462 if util_log_errors:
dgn4401aa52015-04-29 16:26:173463 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123464 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3465 util_log_errors))
3466
dgn38736db2015-09-18 19:20:513467 if tag_with_dot_errors:
3468 results.append(output_api.PresubmitPromptWarning(
3469 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3470 tag_with_dot_errors))
3471
dgn4401aa52015-04-29 16:26:173472 return results
3473
3474
Yoland Yanb92fa522017-08-28 17:37:063475def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3476 """Checks that junit.framework.* is no longer used."""
3477 deprecated_junit_framework_pattern = input_api.re.compile(
3478 r'^import junit\.framework\..*;',
3479 input_api.re.MULTILINE)
3480 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443481 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063482 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133483 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063484 for line_num, line in f.ChangedContents():
3485 if deprecated_junit_framework_pattern.search(line):
3486 errors.append("%s:%d" % (f.LocalPath(), line_num))
3487
3488 results = []
3489 if errors:
3490 results.append(output_api.PresubmitError(
3491 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3492 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3493 ' if you have any question.', errors))
3494 return results
3495
3496
3497def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3498 """Checks that if new Java test classes have inheritance.
3499 Either the new test class is JUnit3 test or it is a JUnit4 test class
3500 with a base class, either case is undesirable.
3501 """
3502 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3503
3504 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443505 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063506 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133507 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063508 if not f.OldContents():
3509 class_declaration_start_flag = False
3510 for line_num, line in f.ChangedContents():
3511 if class_declaration_pattern.search(line):
3512 class_declaration_start_flag = True
3513 if class_declaration_start_flag and ' extends ' in line:
3514 errors.append('%s:%d' % (f.LocalPath(), line_num))
3515 if '{' in line:
3516 class_declaration_start_flag = False
3517
3518 results = []
3519 if errors:
3520 results.append(output_api.PresubmitPromptWarning(
3521 'The newly created files include Test classes that inherits from base'
3522 ' class. Please do not use inheritance in JUnit4 tests or add new'
3523 ' JUnit3 tests. Contact [email protected] if you have any'
3524 ' questions.', errors))
3525 return results
3526
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203527
yolandyan45001472016-12-21 21:12:423528def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3529 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3530 deprecated_annotation_import_pattern = input_api.re.compile(
3531 r'^import android\.test\.suitebuilder\.annotation\..*;',
3532 input_api.re.MULTILINE)
3533 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443534 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423535 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133536 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423537 for line_num, line in f.ChangedContents():
3538 if deprecated_annotation_import_pattern.search(line):
3539 errors.append("%s:%d" % (f.LocalPath(), line_num))
3540
3541 results = []
3542 if errors:
3543 results.append(output_api.PresubmitError(
3544 'Annotations in android.test.suitebuilder.annotation have been'
3545 ' deprecated since API level 24. Please use android.support.test.filters'
3546 ' from //third_party/android_support_test_runner:runner_java instead.'
3547 ' Contact [email protected] if you have any questions.', errors))
3548 return results
3549
3550
agrieve7b6479d82015-10-07 14:24:223551def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3552 """Checks if MDPI assets are placed in a correct directory."""
3553 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3554 ('/res/drawable/' in f.LocalPath() or
3555 '/res/drawable-ldrtl/' in f.LocalPath()))
3556 errors = []
3557 for f in input_api.AffectedFiles(include_deletes=False,
3558 file_filter=file_filter):
3559 errors.append(' %s' % f.LocalPath())
3560
3561 results = []
3562 if errors:
3563 results.append(output_api.PresubmitError(
3564 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3565 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3566 '/res/drawable-ldrtl/.\n'
3567 'Contact [email protected] if you have questions.', errors))
3568 return results
3569
3570
Nate Fischer535972b2017-09-16 01:06:183571def _CheckAndroidWebkitImports(input_api, output_api):
3572 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353573 android.webview.ValueCallback except in the WebView glue layer
3574 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183575 """
3576 valuecallback_import_pattern = input_api.re.compile(
3577 r'^import android\.webkit\.ValueCallback;$')
3578
3579 errors = []
3580
3581 sources = lambda affected_file: input_api.FilterSourceFile(
3582 affected_file,
James Cook24a504192020-07-23 00:08:443583 files_to_skip=(_EXCLUDED_PATHS +
3584 _TEST_CODE_EXCLUDED_PATHS +
3585 input_api.DEFAULT_FILES_TO_SKIP +
3586 (r'^android_webview[\\/]glue[\\/].*',
3587 r'^weblayer[\\/].*',)),
3588 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183589
3590 for f in input_api.AffectedSourceFiles(sources):
3591 for line_num, line in f.ChangedContents():
3592 if valuecallback_import_pattern.search(line):
3593 errors.append("%s:%d" % (f.LocalPath(), line_num))
3594
3595 results = []
3596
3597 if errors:
3598 results.append(output_api.PresubmitError(
3599 'android.webkit.ValueCallback usage is detected outside of the glue'
3600 ' layer. To stay compatible with the support library, android.webkit.*'
3601 ' classes should only be used inside the glue layer and'
3602 ' org.chromium.base.Callback should be used instead.',
3603 errors))
3604
3605 return results
3606
3607
Becky Zhou7c69b50992018-12-10 19:37:573608def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3609 """Checks Android XML styles """
3610 import sys
3611 original_sys_path = sys.path
3612 try:
3613 sys.path = sys.path + [input_api.os_path.join(
3614 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3615 import checkxmlstyle
3616 finally:
3617 # Restore sys.path to what it was before.
3618 sys.path = original_sys_path
3619
3620 if is_check_on_upload:
3621 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3622 else:
3623 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3624
3625
agrievef32bcc72016-04-04 14:57:403626class PydepsChecker(object):
3627 def __init__(self, input_api, pydeps_files):
3628 self._file_cache = {}
3629 self._input_api = input_api
3630 self._pydeps_files = pydeps_files
3631
3632 def _LoadFile(self, path):
3633 """Returns the list of paths within a .pydeps file relative to //."""
3634 if path not in self._file_cache:
3635 with open(path) as f:
3636 self._file_cache[path] = f.read()
3637 return self._file_cache[path]
3638
3639 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3640 """Returns an interable of paths within the .pydep, relativized to //."""
3641 os_path = self._input_api.os_path
3642 pydeps_dir = os_path.dirname(pydeps_path)
3643 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3644 if not l.startswith('*'))
3645 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3646
3647 def _CreateFilesToPydepsMap(self):
3648 """Returns a map of local_path -> list_of_pydeps."""
3649 ret = {}
3650 for pydep_local_path in self._pydeps_files:
3651 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3652 ret.setdefault(path, []).append(pydep_local_path)
3653 return ret
3654
3655 def ComputeAffectedPydeps(self):
3656 """Returns an iterable of .pydeps files that might need regenerating."""
3657 affected_pydeps = set()
3658 file_to_pydeps_map = None
3659 for f in self._input_api.AffectedFiles(include_deletes=True):
3660 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463661 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3662 # subrepositories. We can't figure out which files change, so re-check
3663 # all files.
3664 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383665 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3666 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403667 return self._pydeps_files
3668 elif local_path.endswith('.pydeps'):
3669 if local_path in self._pydeps_files:
3670 affected_pydeps.add(local_path)
3671 elif local_path.endswith('.py'):
3672 if file_to_pydeps_map is None:
3673 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3674 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3675 return affected_pydeps
3676
3677 def DetermineIfStale(self, pydeps_path):
3678 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413679 import difflib
John Budorick47ca3fe2018-02-10 00:53:103680 import os
3681
agrievef32bcc72016-04-04 14:57:403682 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033683 if old_pydeps_data:
3684 cmd = old_pydeps_data[1][1:].strip()
3685 old_contents = old_pydeps_data[2:]
3686 else:
3687 # A default cmd that should work in most cases (as long as pydeps filename
3688 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3689 # file is empty/new.
3690 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3691 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3692 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103693 env = dict(os.environ)
3694 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403695 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103696 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413697 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033698 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413699 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403700
3701
Tibor Goldschwendt360793f72019-06-25 18:23:493702def _ParseGclientArgs():
3703 args = {}
3704 with open('build/config/gclient_args.gni', 'r') as f:
3705 for line in f:
3706 line = line.strip()
3707 if not line or line.startswith('#'):
3708 continue
3709 attribute, value = line.split('=')
3710 args[attribute.strip()] = value.strip()
3711 return args
3712
3713
Saagar Sanghavifceeaae2020-08-12 16:40:363714def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403715 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403716 # This check is for Python dependency lists (.pydeps files), and involves
3717 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3718 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283719 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003720 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493721 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403722 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403723 results = []
3724 # First, check for new / deleted .pydeps.
3725 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033726 # Check whether we are running the presubmit check for a file in src.
3727 # f.LocalPath is relative to repo (src, or internal repo).
3728 # os_path.exists is relative to src repo.
3729 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3730 # to src and we can conclude that the pydeps is in src.
3731 if input_api.os_path.exists(f.LocalPath()):
3732 if f.LocalPath().endswith('.pydeps'):
3733 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3734 results.append(output_api.PresubmitError(
3735 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3736 'remove %s' % f.LocalPath()))
3737 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3738 results.append(output_api.PresubmitError(
3739 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3740 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403741
3742 if results:
3743 return results
3744
Mohamed Heikal7cd4d8312020-06-16 16:49:403745 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3746 affected_pydeps = set(checker.ComputeAffectedPydeps())
3747 affected_android_pydeps = affected_pydeps.intersection(
3748 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3749 if affected_android_pydeps and not is_android:
3750 results.append(output_api.PresubmitPromptOrNotify(
3751 'You have changed python files that may affect pydeps for android\n'
3752 'specific scripts. However, the relevant presumbit check cannot be\n'
3753 'run because you are not using an Android checkout. To validate that\n'
3754 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3755 'use the android-internal-presubmit optional trybot.\n'
3756 'Possibly stale pydeps files:\n{}'.format(
3757 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403758
Mohamed Heikal7cd4d8312020-06-16 16:49:403759 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3760 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403761 try:
phajdan.jr0d9878552016-11-04 10:49:413762 result = checker.DetermineIfStale(pydep_path)
3763 if result:
3764 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403765 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413766 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3767 'To regenerate, run:\n\n %s' %
3768 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403769 except input_api.subprocess.CalledProcessError as error:
3770 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3771 long_text=error.output)]
3772
3773 return results
3774
3775
Saagar Sanghavifceeaae2020-08-12 16:40:363776def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433777 """Checks to make sure no header files have |Singleton<|."""
3778 def FileFilter(affected_file):
3779 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443780 files_to_skip = (_EXCLUDED_PATHS +
3781 input_api.DEFAULT_FILES_TO_SKIP +
3782 (r"^base[\\/]memory[\\/]singleton\.h$",
3783 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3784 r"quic_singleton_impl\.h$"))
3785 return input_api.FilterSourceFile(affected_file,
3786 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433787
sergeyu34d21222015-09-16 00:11:443788 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433789 files = []
3790 for f in input_api.AffectedSourceFiles(FileFilter):
3791 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3792 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3793 contents = input_api.ReadFile(f)
3794 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243795 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433796 pattern.search(line)):
3797 files.append(f)
3798 break
3799
3800 if files:
yolandyandaabc6d2016-04-18 18:29:393801 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443802 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433803 'Please move them to an appropriate source file so that the ' +
3804 'template gets instantiated in a single compilation unit.',
3805 files) ]
3806 return []
3807
3808
[email protected]fd20b902014-05-09 02:14:533809_DEPRECATED_CSS = [
3810 # Values
3811 ( "-webkit-box", "flex" ),
3812 ( "-webkit-inline-box", "inline-flex" ),
3813 ( "-webkit-flex", "flex" ),
3814 ( "-webkit-inline-flex", "inline-flex" ),
3815 ( "-webkit-min-content", "min-content" ),
3816 ( "-webkit-max-content", "max-content" ),
3817
3818 # Properties
3819 ( "-webkit-background-clip", "background-clip" ),
3820 ( "-webkit-background-origin", "background-origin" ),
3821 ( "-webkit-background-size", "background-size" ),
3822 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443823 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533824
3825 # Functions
3826 ( "-webkit-gradient", "gradient" ),
3827 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3828 ( "-webkit-linear-gradient", "linear-gradient" ),
3829 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3830 ( "-webkit-radial-gradient", "radial-gradient" ),
3831 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3832]
3833
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203834
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493835# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363836def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533837 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253838 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343839 documentation and iOS CSS for dom distiller
3840 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253841 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533842 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493843 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443844 files_to_skip = (_EXCLUDED_PATHS +
3845 _TEST_CODE_EXCLUDED_PATHS +
3846 input_api.DEFAULT_FILES_TO_SKIP +
3847 (r"^chrome/common/extensions/docs",
3848 r"^chrome/docs",
3849 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3850 r"^components/neterror/resources/neterror.css",
3851 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253852 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443853 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533854 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3855 for line_num, line in fpath.ChangedContents():
3856 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023857 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533858 results.append(output_api.PresubmitError(
3859 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3860 (fpath.LocalPath(), line_num, deprecated_value, value)))
3861 return results
3862
mohan.reddyf21db962014-10-16 12:26:473863
Saagar Sanghavifceeaae2020-08-12 16:40:363864def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363865 bad_files = {}
3866 for f in input_api.AffectedFiles(include_deletes=False):
3867 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493868 not f.LocalPath().startswith('third_party/blink') and
3869 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363870 continue
3871
Daniel Bratell65b033262019-04-23 08:17:063872 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363873 continue
3874
Vaclav Brozekd5de76a2018-03-17 07:57:503875 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363876 if "#include" in line and "../" in line]
3877 if not relative_includes:
3878 continue
3879 bad_files[f.LocalPath()] = relative_includes
3880
3881 if not bad_files:
3882 return []
3883
3884 error_descriptions = []
3885 for file_path, bad_lines in bad_files.iteritems():
3886 error_description = file_path
3887 for line in bad_lines:
3888 error_description += '\n ' + line
3889 error_descriptions.append(error_description)
3890
3891 results = []
3892 results.append(output_api.PresubmitError(
3893 'You added one or more relative #include paths (including "../").\n'
3894 'These shouldn\'t be used because they can be used to include headers\n'
3895 'from code that\'s not correctly specified as a dependency in the\n'
3896 'relevant BUILD.gn file(s).',
3897 error_descriptions))
3898
3899 return results
3900
Takeshi Yoshinoe387aa32017-08-02 13:16:133901
Saagar Sanghavifceeaae2020-08-12 16:40:363902def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063903 """Check that nobody tries to include a cc file. It's a relatively
3904 common error which results in duplicate symbols in object
3905 files. This may not always break the build until someone later gets
3906 very confusing linking errors."""
3907 results = []
3908 for f in input_api.AffectedFiles(include_deletes=False):
3909 # We let third_party code do whatever it wants
3910 if (f.LocalPath().startswith('third_party') and
3911 not f.LocalPath().startswith('third_party/blink') and
3912 not f.LocalPath().startswith('third_party\\blink')):
3913 continue
3914
3915 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3916 continue
3917
3918 for _, line in f.ChangedContents():
3919 if line.startswith('#include "'):
3920 included_file = line.split('"')[1]
3921 if _IsCPlusPlusFile(input_api, included_file):
3922 # The most common naming for external files with C++ code,
3923 # apart from standard headers, is to call them foo.inc, but
3924 # Chromium sometimes uses foo-inc.cc so allow that as well.
3925 if not included_file.endswith(('.h', '-inc.cc')):
3926 results.append(output_api.PresubmitError(
3927 'Only header files or .inc files should be included in other\n'
3928 'C++ files. Compiling the contents of a cc file more than once\n'
3929 'will cause duplicate information in the build which may later\n'
3930 'result in strange link_errors.\n' +
3931 f.LocalPath() + ':\n ' +
3932 line))
3933
3934 return results
3935
3936
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203937def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3938 if not isinstance(key, ast.Str):
3939 return 'Key at line %d must be a string literal' % key.lineno
3940 if not isinstance(value, ast.Dict):
3941 return 'Value at line %d must be a dict' % value.lineno
3942 if len(value.keys) != 1:
3943 return 'Dict at line %d must have single entry' % value.lineno
3944 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3945 return (
3946 'Entry at line %d must have a string literal \'filepath\' as key' %
3947 value.lineno)
3948 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133949
Takeshi Yoshinoe387aa32017-08-02 13:16:133950
Sergey Ulanov4af16052018-11-08 02:41:463951def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203952 if not isinstance(key, ast.Str):
3953 return 'Key at line %d must be a string literal' % key.lineno
3954 if not isinstance(value, ast.List):
3955 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463956 for element in value.elts:
3957 if not isinstance(element, ast.Str):
3958 return 'Watchlist elements on line %d is not a string' % key.lineno
3959 if not email_regex.match(element.s):
3960 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3961 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203962 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133963
Takeshi Yoshinoe387aa32017-08-02 13:16:133964
Sergey Ulanov4af16052018-11-08 02:41:463965def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203966 mismatch_template = (
3967 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3968 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133969
Sergey Ulanov4af16052018-11-08 02:41:463970 email_regex = input_api.re.compile(
3971 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3972
3973 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203974 i = 0
3975 last_key = ''
3976 while True:
3977 if i >= len(wd_dict.keys):
3978 if i >= len(w_dict.keys):
3979 return None
3980 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3981 elif i >= len(w_dict.keys):
3982 return (
3983 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133984
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203985 wd_key = wd_dict.keys[i]
3986 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133987
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203988 result = _CheckWatchlistDefinitionsEntrySyntax(
3989 wd_key, wd_dict.values[i], ast)
3990 if result is not None:
3991 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133992
Sergey Ulanov4af16052018-11-08 02:41:463993 result = _CheckWatchlistsEntrySyntax(
3994 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203995 if result is not None:
3996 return 'Bad entry in WATCHLISTS dict: %s' % result
3997
3998 if wd_key.s != w_key.s:
3999 return mismatch_template % (
4000 '%s at line %d' % (wd_key.s, wd_key.lineno),
4001 '%s at line %d' % (w_key.s, w_key.lineno))
4002
4003 if wd_key.s < last_key:
4004 return (
4005 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
4006 (wd_key.lineno, w_key.lineno))
4007 last_key = wd_key.s
4008
4009 i = i + 1
4010
4011
Sergey Ulanov4af16052018-11-08 02:41:464012def _CheckWATCHLISTSSyntax(expression, input_api):
4013 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204014 if not isinstance(expression, ast.Expression):
4015 return 'WATCHLISTS file must contain a valid expression'
4016 dictionary = expression.body
4017 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4018 return 'WATCHLISTS file must have single dict with exactly two entries'
4019
4020 first_key = dictionary.keys[0]
4021 first_value = dictionary.values[0]
4022 second_key = dictionary.keys[1]
4023 second_value = dictionary.values[1]
4024
4025 if (not isinstance(first_key, ast.Str) or
4026 first_key.s != 'WATCHLIST_DEFINITIONS' or
4027 not isinstance(first_value, ast.Dict)):
4028 return (
4029 'The first entry of the dict in WATCHLISTS file must be '
4030 'WATCHLIST_DEFINITIONS dict')
4031
4032 if (not isinstance(second_key, ast.Str) or
4033 second_key.s != 'WATCHLISTS' or
4034 not isinstance(second_value, ast.Dict)):
4035 return (
4036 'The second entry of the dict in WATCHLISTS file must be '
4037 'WATCHLISTS dict')
4038
Sergey Ulanov4af16052018-11-08 02:41:464039 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134040
4041
Saagar Sanghavifceeaae2020-08-12 16:40:364042def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:134043 for f in input_api.AffectedFiles(include_deletes=False):
4044 if f.LocalPath() == 'WATCHLISTS':
4045 contents = input_api.ReadFile(f, 'r')
4046
4047 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204048 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134049 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204050 # Get an AST tree for it and scan the tree for detailed style checking.
4051 expression = input_api.ast.parse(
4052 contents, filename='WATCHLISTS', mode='eval')
4053 except ValueError as e:
4054 return [output_api.PresubmitError(
4055 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4056 except SyntaxError as e:
4057 return [output_api.PresubmitError(
4058 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4059 except TypeError as e:
4060 return [output_api.PresubmitError(
4061 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134062
Sergey Ulanov4af16052018-11-08 02:41:464063 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204064 if result is not None:
4065 return [output_api.PresubmitError(result)]
4066 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134067
4068 return []
4069
4070
Saagar Sanghavifceeaae2020-08-12 16:40:364071def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194072 """Checks that newly added header files have corresponding GN changes.
4073 Note that this is only a heuristic. To be precise, run script:
4074 build/check_gn_headers.py.
4075 """
4076
4077 def headers(f):
4078 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444079 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194080
4081 new_headers = []
4082 for f in input_api.AffectedSourceFiles(headers):
4083 if f.Action() != 'A':
4084 continue
4085 new_headers.append(f.LocalPath())
4086
4087 def gn_files(f):
James Cook24a504192020-07-23 00:08:444088 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194089
4090 all_gn_changed_contents = ''
4091 for f in input_api.AffectedSourceFiles(gn_files):
4092 for _, line in f.ChangedContents():
4093 all_gn_changed_contents += line
4094
4095 problems = []
4096 for header in new_headers:
4097 basename = input_api.os_path.basename(header)
4098 if basename not in all_gn_changed_contents:
4099 problems.append(header)
4100
4101 if problems:
4102 return [output_api.PresubmitPromptWarning(
4103 'Missing GN changes for new header files', items=sorted(problems),
4104 long_text='Please double check whether newly added header files need '
4105 'corresponding changes in gn or gni files.\nThis checking is only a '
4106 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4107 'Read https://crbug.com/661774 for more info.')]
4108 return []
4109
4110
Saagar Sanghavifceeaae2020-08-12 16:40:364111def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024112 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4113
4114 This assumes we won't intentionally reference one product from the other
4115 product.
4116 """
4117 all_problems = []
4118 test_cases = [{
4119 "filename_postfix": "google_chrome_strings.grd",
4120 "correct_name": "Chrome",
4121 "incorrect_name": "Chromium",
4122 }, {
4123 "filename_postfix": "chromium_strings.grd",
4124 "correct_name": "Chromium",
4125 "incorrect_name": "Chrome",
4126 }]
4127
4128 for test_case in test_cases:
4129 problems = []
4130 filename_filter = lambda x: x.LocalPath().endswith(
4131 test_case["filename_postfix"])
4132
4133 # Check each new line. Can yield false positives in multiline comments, but
4134 # easier than trying to parse the XML because messages can have nested
4135 # children, and associating message elements with affected lines is hard.
4136 for f in input_api.AffectedSourceFiles(filename_filter):
4137 for line_num, line in f.ChangedContents():
4138 if "<message" in line or "<!--" in line or "-->" in line:
4139 continue
4140 if test_case["incorrect_name"] in line:
4141 problems.append(
4142 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4143
4144 if problems:
4145 message = (
4146 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4147 % (test_case["correct_name"], test_case["correct_name"],
4148 test_case["incorrect_name"]))
4149 all_problems.append(
4150 output_api.PresubmitPromptWarning(message, items=problems))
4151
4152 return all_problems
4153
4154
Saagar Sanghavifceeaae2020-08-12 16:40:364155def CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
Dirk Pranke3c18a382019-03-15 01:07:514156 # TODO(crbug.com/941824): We need to make sure the entries in
4157 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4158 # so that users of //buildtools in other projects get the same tooling
4159 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4160 # support to gclient, we can eliminate the duplication and delete
4161 # this presubmit check.
4162
4163 # Update this regexp if new revisions are added to the files.
4164 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264165 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514166
4167 # If a user is changing one revision, they need to change the same
4168 # line in both files. This means that any given change should contain
4169 # exactly the same list of changed lines that match the regexps. The
4170 # replace(' ', '') call allows us to ignore whitespace changes to the
4171 # lines. The 'long_text' parameter to the error will contain the
4172 # list of changed lines in both files, which should make it easy enough
4173 # to spot the error without going overboard in this implementation.
4174 revs_changes = {
4175 'DEPS': {},
4176 'buildtools/DEPS': {},
4177 }
4178 long_text = ''
4179
4180 for f in input_api.AffectedFiles(
4181 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4182 for line_num, line in f.ChangedContents():
4183 if rev_regexp.search(line):
4184 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4185 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4186
4187 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4188 return [output_api.PresubmitError(
4189 'Change buildtools revisions in sync in both //DEPS and '
4190 '//buildtools/DEPS.', long_text=long_text + '\n')]
4191 else:
4192 return []
4193
4194
Saagar Sanghavifceeaae2020-08-12 16:40:364195def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364196 """Avoid large files, especially binary files, in the repository since
4197 git doesn't scale well for those. They will be in everyone's repo
4198 clones forever, forever making Chromium slower to clone and work
4199 with."""
4200
4201 # Uploading files to cloud storage is not trivial so we don't want
4202 # to set the limit too low, but the upper limit for "normal" large
4203 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4204 # anything over 20 MB is exceptional.
4205 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4206
4207 too_large_files = []
4208 for f in input_api.AffectedFiles():
4209 # Check both added and modified files (but not deleted files).
4210 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384211 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364212 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4213 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4214
4215 if too_large_files:
4216 message = (
4217 'Do not commit large files to git since git scales badly for those.\n' +
4218 'Instead put the large files in cloud storage and use DEPS to\n' +
4219 'fetch them.\n' + '\n'.join(too_large_files)
4220 )
4221 return [output_api.PresubmitError(
4222 'Too large files found in commit', long_text=message + '\n')]
4223 else:
4224 return []
4225
Max Morozb47503b2019-08-08 21:03:274226
Saagar Sanghavifceeaae2020-08-12 16:40:364227def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274228 """Checks specific for fuzz target sources."""
4229 EXPORTED_SYMBOLS = [
4230 'LLVMFuzzerInitialize',
4231 'LLVMFuzzerCustomMutator',
4232 'LLVMFuzzerCustomCrossOver',
4233 'LLVMFuzzerMutate',
4234 ]
4235
4236 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4237
4238 def FilterFile(affected_file):
4239 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444240 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4241 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274242
4243 return input_api.FilterSourceFile(
4244 affected_file,
James Cook24a504192020-07-23 00:08:444245 files_to_check=[files_to_check],
4246 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274247
4248 files_with_missing_header = []
4249 for f in input_api.AffectedSourceFiles(FilterFile):
4250 contents = input_api.ReadFile(f, 'r')
4251 if REQUIRED_HEADER in contents:
4252 continue
4253
4254 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4255 files_with_missing_header.append(f.LocalPath())
4256
4257 if not files_with_missing_header:
4258 return []
4259
4260 long_text = (
4261 'If you define any of the libFuzzer optional functions (%s), it is '
4262 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4263 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4264 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4265 'to access command line arguments passed to the fuzzer. Instead, prefer '
4266 'static initialization and shared resources as documented in '
4267 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4268 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4269 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4270 )
4271
4272 return [output_api.PresubmitPromptWarning(
4273 message="Missing '%s' in:" % REQUIRED_HEADER,
4274 items=files_with_missing_header,
4275 long_text=long_text)]
4276
4277
Mohamed Heikald048240a2019-11-12 16:57:374278def _CheckNewImagesWarning(input_api, output_api):
4279 """
4280 Warns authors who add images into the repo to make sure their images are
4281 optimized before committing.
4282 """
4283 images_added = False
4284 image_paths = []
4285 errors = []
4286 filter_lambda = lambda x: input_api.FilterSourceFile(
4287 x,
James Cook24a504192020-07-23 00:08:444288 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4289 + input_api.DEFAULT_FILES_TO_SKIP),
4290 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374291 )
4292 for f in input_api.AffectedFiles(
4293 include_deletes=False, file_filter=filter_lambda):
4294 local_path = f.LocalPath().lower()
4295 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4296 images_added = True
4297 image_paths.append(f)
4298 if images_added:
4299 errors.append(output_api.PresubmitPromptWarning(
4300 'It looks like you are trying to commit some images. If these are '
4301 'non-test-only images, please make sure to read and apply the tips in '
4302 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4303 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4304 'FYI only and will not block your CL on the CQ.', image_paths))
4305 return errors
4306
4307
Saagar Sanghavifceeaae2020-08-12 16:40:364308def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574309 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224310 results = []
dgnaa68d5e2015-06-10 10:08:224311 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174312 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224313 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294314 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064315 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4316 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424317 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184318 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574319 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374320 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154321 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574322 return results
4323
Saagar Sanghavifceeaae2020-08-12 16:40:364324def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574325 """Groups commit checks that target android code."""
4326 results = []
4327 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224328 return results
4329
Chris Hall59f8d0c72020-05-01 07:31:194330# TODO(chrishall): could we additionally match on any path owned by
4331# ui/accessibility/OWNERS ?
4332_ACCESSIBILITY_PATHS = (
4333 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4334 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4335 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4336 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4337 r"^content[\\/]browser[\\/]accessibility[\\/]",
4338 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4339 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4340 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4341 r"^ui[\\/]accessibility[\\/]",
4342 r"^ui[\\/]views[\\/]accessibility[\\/]",
4343)
4344
Saagar Sanghavifceeaae2020-08-12 16:40:364345def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194346 """Checks that commits to accessibility code contain an AX-Relnotes field in
4347 their commit message."""
4348 def FileFilter(affected_file):
4349 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444350 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194351
4352 # Only consider changes affecting accessibility paths.
4353 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4354 return []
4355
Akihiro Ota08108e542020-05-20 15:30:534356 # AX-Relnotes can appear in either the description or the footer.
4357 # When searching the description, require 'AX-Relnotes:' to appear at the
4358 # beginning of a line.
4359 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4360 description_has_relnotes = any(ax_regex.match(line)
4361 for line in input_api.change.DescriptionText().lower().splitlines())
4362
4363 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4364 'AX-Relnotes', [])
4365 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194366 return []
4367
4368 # TODO(chrishall): link to Relnotes documentation in message.
4369 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4370 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4371 "user-facing changes"
4372 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4373 "user-facing effects"
4374 "\n if this is confusing or annoying then please contact members "
4375 "of ui/accessibility/OWNERS.")
4376
4377 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224378
Saagar Sanghavifceeaae2020-08-12 16:40:364379def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394380 """Checks common to both upload and commit."""
4381 results = []
4382 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384383 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544384 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084385
4386 author = input_api.change.author_email
4387 if author and author not in _KNOWN_ROBOTS:
4388 results.extend(
4389 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4390
[email protected]9f919cc2013-07-31 03:04:044391 results.extend(
4392 input_api.canned_checks.CheckChangeHasNoTabs(
4393 input_api,
4394 output_api,
4395 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434396 results.extend(input_api.RunTests(
4397 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244398
Edward Lesmesce51df52020-08-04 22:10:174399 dirmd_bin = input_api.os_path.join(
4400 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4401 results.extend(input_api.RunTests(
4402 input_api.canned_checks.CheckDirMetadataFormat(
4403 input_api, output_api, dirmd_bin)))
4404 results.extend(
4405 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4406 input_api, output_api))
4407
Vaclav Brozekcdc7defb2018-03-20 09:54:354408 for f in input_api.AffectedFiles():
4409 path, name = input_api.os_path.split(f.LocalPath())
4410 if name == 'PRESUBMIT.py':
4411 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004412 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4413 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074414 # The PRESUBMIT.py file (and the directory containing it) might
4415 # have been affected by being moved or removed, so only try to
4416 # run the tests if they still exist.
4417 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4418 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444419 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394420 return results
[email protected]1f7b4172010-01-28 01:17:344421
[email protected]b337cb5b2011-01-23 21:24:054422
Saagar Sanghavifceeaae2020-08-12 16:40:364423def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494424 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4425 if f.LocalPath().endswith(('.orig', '.rej'))]
4426 if problems:
4427 return [output_api.PresubmitError(
4428 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034429 else:
4430 return []
[email protected]b8079ae4a2012-12-05 19:56:494431
4432
Saagar Sanghavifceeaae2020-08-12 16:40:364433def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214434 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4435 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4436 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074437 include_re = input_api.re.compile(
4438 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4439 extension_re = input_api.re.compile(r'\.[a-z]+$')
4440 errors = []
4441 for f in input_api.AffectedFiles():
4442 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4443 continue
4444 found_line_number = None
4445 found_macro = None
4446 for line_num, line in f.ChangedContents():
4447 match = macro_re.search(line)
4448 if match:
4449 found_line_number = line_num
4450 found_macro = match.group(2)
4451 break
4452 if not found_line_number:
4453 continue
4454
4455 found_include = False
4456 for line in f.NewContents():
4457 if include_re.search(line):
4458 found_include = True
4459 break
4460 if found_include:
4461 continue
4462
4463 if not f.LocalPath().endswith('.h'):
4464 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4465 try:
4466 content = input_api.ReadFile(primary_header_path, 'r')
4467 if include_re.search(content):
4468 continue
4469 except IOError:
4470 pass
4471 errors.append('%s:%d %s macro is used without including build/'
4472 'build_config.h.'
4473 % (f.LocalPath(), found_line_number, found_macro))
4474 if errors:
4475 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4476 return []
4477
4478
[email protected]b00342e7f2013-03-26 16:21:544479def _DidYouMeanOSMacro(bad_macro):
4480 try:
4481 return {'A': 'OS_ANDROID',
4482 'B': 'OS_BSD',
4483 'C': 'OS_CHROMEOS',
4484 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444485 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544486 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444487 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544488 'N': 'OS_NACL',
4489 'O': 'OS_OPENBSD',
4490 'P': 'OS_POSIX',
4491 'S': 'OS_SOLARIS',
4492 'W': 'OS_WIN'}[bad_macro[3].upper()]
4493 except KeyError:
4494 return ''
4495
4496
4497def _CheckForInvalidOSMacrosInFile(input_api, f):
4498 """Check for sensible looking, totally invalid OS macros."""
4499 preprocessor_statement = input_api.re.compile(r'^\s*#')
4500 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4501 results = []
4502 for lnum, line in f.ChangedContents():
4503 if preprocessor_statement.search(line):
4504 for match in os_macro.finditer(line):
4505 if not match.group(1) in _VALID_OS_MACROS:
4506 good = _DidYouMeanOSMacro(match.group(1))
4507 did_you_mean = ' (did you mean %s?)' % good if good else ''
4508 results.append(' %s:%d %s%s' % (f.LocalPath(),
4509 lnum,
4510 match.group(1),
4511 did_you_mean))
4512 return results
4513
4514
Saagar Sanghavifceeaae2020-08-12 16:40:364515def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544516 """Check all affected files for invalid OS macros."""
4517 bad_macros = []
tzik3f295992018-12-04 20:32:234518 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474519 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544520 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4521
4522 if not bad_macros:
4523 return []
4524
4525 return [output_api.PresubmitError(
4526 'Possibly invalid OS macro[s] found. Please fix your code\n'
4527 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4528
lliabraa35bab3932014-10-01 12:16:444529
4530def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4531 """Check all affected files for invalid "if defined" macros."""
4532 ALWAYS_DEFINED_MACROS = (
4533 "TARGET_CPU_PPC",
4534 "TARGET_CPU_PPC64",
4535 "TARGET_CPU_68K",
4536 "TARGET_CPU_X86",
4537 "TARGET_CPU_ARM",
4538 "TARGET_CPU_MIPS",
4539 "TARGET_CPU_SPARC",
4540 "TARGET_CPU_ALPHA",
4541 "TARGET_IPHONE_SIMULATOR",
4542 "TARGET_OS_EMBEDDED",
4543 "TARGET_OS_IPHONE",
4544 "TARGET_OS_MAC",
4545 "TARGET_OS_UNIX",
4546 "TARGET_OS_WIN32",
4547 )
4548 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4549 results = []
4550 for lnum, line in f.ChangedContents():
4551 for match in ifdef_macro.finditer(line):
4552 if match.group(1) in ALWAYS_DEFINED_MACROS:
4553 always_defined = ' %s is always defined. ' % match.group(1)
4554 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4555 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4556 lnum,
4557 always_defined,
4558 did_you_mean))
4559 return results
4560
4561
Saagar Sanghavifceeaae2020-08-12 16:40:364562def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444563 """Check all affected files for invalid "if defined" macros."""
4564 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054565 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444566 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054567 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214568 continue
lliabraa35bab3932014-10-01 12:16:444569 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4570 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4571
4572 if not bad_macros:
4573 return []
4574
4575 return [output_api.PresubmitError(
4576 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4577 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4578 bad_macros)]
4579
4580
Saagar Sanghavifceeaae2020-08-12 16:40:364581def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044582 """Check for same IPC rules described in
4583 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4584 """
4585 base_pattern = r'IPC_ENUM_TRAITS\('
4586 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4587 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4588
4589 problems = []
4590 for f in input_api.AffectedSourceFiles(None):
4591 local_path = f.LocalPath()
4592 if not local_path.endswith('.h'):
4593 continue
4594 for line_number, line in f.ChangedContents():
4595 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4596 problems.append(
4597 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4598
4599 if problems:
4600 return [output_api.PresubmitPromptWarning(
4601 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4602 else:
4603 return []
4604
[email protected]b00342e7f2013-03-26 16:21:544605
Saagar Sanghavifceeaae2020-08-12 16:40:364606def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054607 """Check to make sure no files being submitted have long paths.
4608 This causes issues on Windows.
4609 """
4610 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194611 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054612 local_path = f.LocalPath()
4613 # Windows has a path limit of 260 characters. Limit path length to 200 so
4614 # that we have some extra for the prefix on dev machines and the bots.
4615 if len(local_path) > 200:
4616 problems.append(local_path)
4617
4618 if problems:
4619 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4620 else:
4621 return []
4622
4623
Saagar Sanghavifceeaae2020-08-12 16:40:364624def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144625 """Check that header files have proper guards against multiple inclusion.
4626 If a file should not have such guards (and it probably should) then it
4627 should include the string "no-include-guard-because-multiply-included".
4628 """
Daniel Bratell6a75baef62018-06-04 10:04:454629 def is_chromium_header_file(f):
4630 # We only check header files under the control of the Chromium
4631 # project. That is, those outside third_party apart from
4632 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324633 # We also exclude *_message_generator.h headers as they use
4634 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454635 file_with_path = input_api.os_path.normpath(f.LocalPath())
4636 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324637 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454638 (not file_with_path.startswith('third_party') or
4639 file_with_path.startswith(
4640 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144641
4642 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344643 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144644
4645 errors = []
4646
Daniel Bratell6a75baef62018-06-04 10:04:454647 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144648 guard_name = None
4649 guard_line_number = None
4650 seen_guard_end = False
4651
4652 file_with_path = input_api.os_path.normpath(f.LocalPath())
4653 base_file_name = input_api.os_path.splitext(
4654 input_api.os_path.basename(file_with_path))[0]
4655 upper_base_file_name = base_file_name.upper()
4656
4657 expected_guard = replace_special_with_underscore(
4658 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144659
4660 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574661 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4662 # are too many (1000+) files with slight deviations from the
4663 # coding style. The most important part is that the include guard
4664 # is there, and that it's unique, not the name so this check is
4665 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144666 #
4667 # As code becomes more uniform, this could be made stricter.
4668
4669 guard_name_pattern_list = [
4670 # Anything with the right suffix (maybe with an extra _).
4671 r'\w+_H__?',
4672
Daniel Bratell39b5b062018-05-16 18:09:574673 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144674 r'\w+_h',
4675
4676 # Anything including the uppercase name of the file.
4677 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4678 upper_base_file_name)) + r'\w*',
4679 ]
4680 guard_name_pattern = '|'.join(guard_name_pattern_list)
4681 guard_pattern = input_api.re.compile(
4682 r'#ifndef\s+(' + guard_name_pattern + ')')
4683
4684 for line_number, line in enumerate(f.NewContents()):
4685 if 'no-include-guard-because-multiply-included' in line:
4686 guard_name = 'DUMMY' # To not trigger check outside the loop.
4687 break
4688
4689 if guard_name is None:
4690 match = guard_pattern.match(line)
4691 if match:
4692 guard_name = match.group(1)
4693 guard_line_number = line_number
4694
Daniel Bratell39b5b062018-05-16 18:09:574695 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454696 # don't match the chromium style guide, but new files should
4697 # get it right.
4698 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574699 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144700 errors.append(output_api.PresubmitPromptWarning(
4701 'Header using the wrong include guard name %s' % guard_name,
4702 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574703 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144704 else:
4705 # The line after #ifndef should have a #define of the same name.
4706 if line_number == guard_line_number + 1:
4707 expected_line = '#define %s' % guard_name
4708 if line != expected_line:
4709 errors.append(output_api.PresubmitPromptWarning(
4710 'Missing "%s" for include guard' % expected_line,
4711 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4712 'Expected: %r\nGot: %r' % (expected_line, line)))
4713
4714 if not seen_guard_end and line == '#endif // %s' % guard_name:
4715 seen_guard_end = True
4716 elif seen_guard_end:
4717 if line.strip() != '':
4718 errors.append(output_api.PresubmitPromptWarning(
4719 'Include guard %s not covering the whole file' % (
4720 guard_name), [f.LocalPath()]))
4721 break # Nothing else to check and enough to warn once.
4722
4723 if guard_name is None:
4724 errors.append(output_api.PresubmitPromptWarning(
4725 'Missing include guard %s' % expected_guard,
4726 [f.LocalPath()],
4727 'Missing include guard in %s\n'
4728 'Recommended name: %s\n'
4729 'This check can be disabled by having the string\n'
4730 'no-include-guard-because-multiply-included in the header.' %
4731 (f.LocalPath(), expected_guard)))
4732
4733 return errors
4734
4735
Saagar Sanghavifceeaae2020-08-12 16:40:364736def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234737 """Check source code and known ascii text files for Windows style line
4738 endings.
4739 """
earthdok1b5e0ee2015-03-10 15:19:104740 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234741
4742 file_inclusion_pattern = (
4743 known_text_files,
4744 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4745 )
4746
mostynbb639aca52015-01-07 20:31:234747 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534748 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444749 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534750 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504751 include_file = False
4752 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234753 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504754 include_file = True
4755 if include_file:
4756 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234757
4758 if problems:
4759 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4760 'these files to contain Windows style line endings?\n' +
4761 '\n'.join(problems))]
4762
4763 return []
4764
4765
Saagar Sanghavifceeaae2020-08-12 16:40:364766def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134767 """Checks that all source files use SYSLOG properly."""
4768 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364769 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564770 for line_number, line in f.ChangedContents():
4771 if 'SYSLOG' in line:
4772 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4773
pastarmovj89f7ee12016-09-20 14:58:134774 if syslog_files:
4775 return [output_api.PresubmitPromptWarning(
4776 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4777 ' calls.\nFiles to check:\n', items=syslog_files)]
4778 return []
4779
4780
[email protected]1f7b4172010-01-28 01:17:344781def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364782 if input_api.version < [2, 0, 0]:
4783 return [output_api.PresubmitError("Your depot_tools is out of date. "
4784 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4785 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344786 results = []
scottmg39b29952014-12-08 18:31:284787 results.extend(
jam93a6ee792017-02-08 23:59:224788 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544789 return results
[email protected]ca8d1982009-02-19 16:33:124790
4791
[email protected]1bfb8322014-04-23 01:02:414792def GetTryServerMasterForBot(bot):
4793 """Returns the Try Server master for the given bot.
4794
[email protected]0bb112362014-07-26 04:38:324795 It tries to guess the master from the bot name, but may still fail
4796 and return None. There is no longer a default master.
4797 """
4798 # Potentially ambiguous bot names are listed explicitly.
4799 master_map = {
tandriie5587792016-07-14 00:34:504800 'chromium_presubmit': 'master.tryserver.chromium.linux',
4801 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414802 }
[email protected]0bb112362014-07-26 04:38:324803 master = master_map.get(bot)
4804 if not master:
wnwen4fbaab82016-05-25 12:54:364805 if 'android' in bot:
tandriie5587792016-07-14 00:34:504806 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364807 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504808 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324809 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504810 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324811 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504812 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324813 return master
[email protected]1bfb8322014-04-23 01:02:414814
4815
[email protected]ca8d1982009-02-19 16:33:124816def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364817 if input_api.version < [2, 0, 0]:
4818 return [output_api.PresubmitError("Your depot_tools is out of date. "
4819 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4820 "but your version is %d.%d.%d" % tuple(input_api.version))]
4821
[email protected]fe5f57c52009-06-05 14:25:544822 results = []
[email protected]fe5f57c52009-06-05 14:25:544823 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274824 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344825 input_api,
4826 output_api,
[email protected]2fdd1f362013-01-16 03:56:034827 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274828
jam93a6ee792017-02-08 23:59:224829 results.extend(
4830 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544831 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4832 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384833 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4834 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414835 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4836 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544837 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144838
4839
Saagar Sanghavifceeaae2020-08-12 16:40:364840def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264841 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024842 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4843 # footer is set to true.
4844 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264845 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024846 footer.lower()
4847 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264848 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024849
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144850 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264851 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144852 import sys
4853 from io import StringIO
4854
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144855 new_or_added_paths = set(f.LocalPath()
4856 for f in input_api.AffectedFiles()
4857 if (f.Action() == 'A' or f.Action() == 'M'))
4858 removed_paths = set(f.LocalPath()
4859 for f in input_api.AffectedFiles(include_deletes=True)
4860 if f.Action() == 'D')
4861
Andrew Grieve0e8790c2020-09-03 17:27:324862 affected_grds = [
4863 f for f in input_api.AffectedFiles()
4864 if f.LocalPath().endswith(('.grd', '.grdp'))
4865 ]
4866 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164867 if not affected_grds:
4868 return []
4869
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144870 affected_png_paths = [f.AbsoluteLocalPath()
4871 for f in input_api.AffectedFiles()
4872 if (f.LocalPath().endswith('.png'))]
4873
4874 # Check for screenshots. Developers can upload screenshots using
4875 # tools/translation/upload_screenshots.py which finds and uploads
4876 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4877 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4878 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4879 #
4880 # The logic here is as follows:
4881 #
4882 # - If the CL has a .png file under the screenshots directory for a grd
4883 # file, warn the developer. Actual images should never be checked into the
4884 # Chrome repo.
4885 #
4886 # - If the CL contains modified or new messages in grd files and doesn't
4887 # contain the corresponding .sha1 files, warn the developer to add images
4888 # and upload them via tools/translation/upload_screenshots.py.
4889 #
4890 # - If the CL contains modified or new messages in grd files and the
4891 # corresponding .sha1 files, everything looks good.
4892 #
4893 # - If the CL contains removed messages in grd files but the corresponding
4894 # .sha1 files aren't removed, warn the developer to remove them.
4895 unnecessary_screenshots = []
4896 missing_sha1 = []
4897 unnecessary_sha1_files = []
4898
Rainhard Findlingfc31844c52020-05-15 09:58:264899 # This checks verifies that the ICU syntax of messages this CL touched is
4900 # valid, and reports any found syntax errors.
4901 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4902 # without developers being aware of them. Later on, such ICU syntax errors
4903 # break message extraction for translation, hence would block Chromium
4904 # translations until they are fixed.
4905 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144906
4907 def _CheckScreenshotAdded(screenshots_dir, message_id):
4908 sha1_path = input_api.os_path.join(
4909 screenshots_dir, message_id + '.png.sha1')
4910 if sha1_path not in new_or_added_paths:
4911 missing_sha1.append(sha1_path)
4912
4913
4914 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4915 sha1_path = input_api.os_path.join(
4916 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034917 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144918 unnecessary_sha1_files.append(sha1_path)
4919
Rainhard Findlingfc31844c52020-05-15 09:58:264920
4921 def _ValidateIcuSyntax(text, level, signatures):
4922 """Validates ICU syntax of a text string.
4923
4924 Check if text looks similar to ICU and checks for ICU syntax correctness
4925 in this case. Reports various issues with ICU syntax and values of
4926 variants. Supports checking of nested messages. Accumulate information of
4927 each ICU messages found in the text for further checking.
4928
4929 Args:
4930 text: a string to check.
4931 level: a number of current nesting level.
4932 signatures: an accumulator, a list of tuple of (level, variable,
4933 kind, variants).
4934
4935 Returns:
4936 None if a string is not ICU or no issue detected.
4937 A tuple of (message, start index, end index) if an issue detected.
4938 """
4939 valid_types = {
4940 'plural': (frozenset(
4941 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4942 frozenset(['=1', 'other'])),
4943 'selectordinal': (frozenset(
4944 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4945 frozenset(['one', 'other'])),
4946 'select': (frozenset(), frozenset(['other'])),
4947 }
4948
4949 # Check if the message looks like an attempt to use ICU
4950 # plural. If yes - check if its syntax strictly matches ICU format.
4951 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4952 if not like:
4953 signatures.append((level, None, None, None))
4954 return
4955
4956 # Check for valid prefix and suffix
4957 m = re.match(
4958 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4959 r'(plural|selectordinal|select),\s*'
4960 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4961 if not m:
4962 return (('This message looks like an ICU plural, '
4963 'but does not follow ICU syntax.'), like.start(), like.end())
4964 starting, variable, kind, variant_pairs = m.groups()
4965 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4966 if depth:
4967 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4968 len(text))
4969 first = text[0]
4970 ending = text[last_pos:]
4971 if not starting:
4972 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4973 last_pos)
4974 if not ending or '}' not in ending:
4975 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4976 last_pos)
4977 elif first != '{':
4978 return (
4979 ('Invalid ICU format. Extra characters at the start of a complex '
4980 'message (go/icu-message-migration): "%s"') %
4981 starting, 0, len(starting))
4982 elif ending != '}':
4983 return (('Invalid ICU format. Extra characters at the end of a complex '
4984 'message (go/icu-message-migration): "%s"')
4985 % ending, last_pos - 1, len(text) - 1)
4986 if kind not in valid_types:
4987 return (('Unknown ICU message type %s. '
4988 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4989 known, required = valid_types[kind]
4990 defined_variants = set()
4991 for variant, variant_range, value, value_range in variants:
4992 start, end = variant_range
4993 if variant in defined_variants:
4994 return ('Variant "%s" is defined more than once' % variant,
4995 start, end)
4996 elif known and variant not in known:
4997 return ('Variant "%s" is not valid for %s message' % (variant, kind),
4998 start, end)
4999 defined_variants.add(variant)
5000 # Check for nested structure
5001 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5002 if res:
5003 return (res[0], res[1] + value_range[0] + 1,
5004 res[2] + value_range[0] + 1)
5005 missing = required - defined_variants
5006 if missing:
5007 return ('Required variants missing: %s' % ', '.join(missing), 0,
5008 len(text))
5009 signatures.append((level, variable, kind, defined_variants))
5010
5011
5012 def _ParseIcuVariants(text, offset=0):
5013 """Parse variants part of ICU complex message.
5014
5015 Builds a tuple of variant names and values, as well as
5016 their offsets in the input string.
5017
5018 Args:
5019 text: a string to parse
5020 offset: additional offset to add to positions in the text to get correct
5021 position in the complete ICU string.
5022
5023 Returns:
5024 List of tuples, each tuple consist of four fields: variant name,
5025 variant name span (tuple of two integers), variant value, value
5026 span (tuple of two integers).
5027 """
5028 depth, start, end = 0, -1, -1
5029 variants = []
5030 key = None
5031 for idx, char in enumerate(text):
5032 if char == '{':
5033 if not depth:
5034 start = idx
5035 chunk = text[end + 1:start]
5036 key = chunk.strip()
5037 pos = offset + end + 1 + chunk.find(key)
5038 span = (pos, pos + len(key))
5039 depth += 1
5040 elif char == '}':
5041 if not depth:
5042 return variants, depth, offset + idx
5043 depth -= 1
5044 if not depth:
5045 end = idx
5046 variants.append((key, span, text[start:end + 1], (offset + start,
5047 offset + end + 1)))
5048 return variants, depth, offset + end + 1
5049
meacer8c0d3832019-12-26 21:46:165050 try:
5051 old_sys_path = sys.path
5052 sys.path = sys.path + [input_api.os_path.join(
5053 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5054 from helper import grd_helper
5055 finally:
5056 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145057
5058 for f in affected_grds:
5059 file_path = f.LocalPath()
5060 old_id_to_msg_map = {}
5061 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385062 # Note that this code doesn't check if the file has been deleted. This is
5063 # OK because it only uses the old and new file contents and doesn't load
5064 # the file via its path.
5065 # It's also possible that a file's content refers to a renamed or deleted
5066 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5067 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5068 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145069 if file_path.endswith('.grdp'):
5070 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585071 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395072 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145073 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585074 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395075 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145076 else:
meacerff8a9b62019-12-10 19:43:585077 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145078 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585079 old_id_to_msg_map = grd_helper.GetGrdMessages(
5080 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145081 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585082 new_id_to_msg_map = grd_helper.GetGrdMessages(
5083 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145084
Rainhard Findlingd8d04372020-08-13 13:30:095085 grd_name, ext = input_api.os_path.splitext(
5086 input_api.os_path.basename(file_path))
5087 screenshots_dir = input_api.os_path.join(
5088 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5089
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145090 # Compute added, removed and modified message IDs.
5091 old_ids = set(old_id_to_msg_map)
5092 new_ids = set(new_id_to_msg_map)
5093 added_ids = new_ids - old_ids
5094 removed_ids = old_ids - new_ids
5095 modified_ids = set([])
5096 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355097 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095098 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5099 # The message content itself changed. Require an updated screenshot.
5100 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355101 elif old_id_to_msg_map[key].attrs['meaning'] != \
5102 new_id_to_msg_map[key].attrs['meaning']:
5103 # The message meaning changed. Ensure there is a screenshot for it.
5104 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5105 if sha1_path not in new_or_added_paths and not \
5106 input_api.os_path.exists(sha1_path):
5107 # There is neither a previous screenshot nor is a new one added now.
5108 # Require a screenshot.
5109 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145110
Rainhard Findlingfc31844c52020-05-15 09:58:265111 if run_screenshot_check:
5112 # Check the screenshot directory for .png files. Warn if there is any.
5113 for png_path in affected_png_paths:
5114 if png_path.startswith(screenshots_dir):
5115 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145116
Rainhard Findlingfc31844c52020-05-15 09:58:265117 for added_id in added_ids:
5118 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145119
Rainhard Findlingfc31844c52020-05-15 09:58:265120 for modified_id in modified_ids:
5121 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145122
Rainhard Findlingfc31844c52020-05-15 09:58:265123 for removed_id in removed_ids:
5124 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5125
5126 # Check new and changed strings for ICU syntax errors.
5127 for key in added_ids.union(modified_ids):
5128 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5129 err = _ValidateIcuSyntax(msg, 0, [])
5130 if err is not None:
5131 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145132
5133 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265134 if run_screenshot_check:
5135 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005136 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265137 'Do not include actual screenshots in the changelist. Run '
5138 'tools/translate/upload_screenshots.py to upload them instead:',
5139 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145140
Rainhard Findlingfc31844c52020-05-15 09:58:265141 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005142 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265143 'You are adding or modifying UI strings.\n'
5144 'To ensure the best translations, take screenshots of the relevant UI '
5145 '(https://g.co/chrome/translation) and add these files to your '
5146 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145147
Rainhard Findlingfc31844c52020-05-15 09:58:265148 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005149 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265150 'You removed strings associated with these files. Remove:',
5151 sorted(unnecessary_sha1_files)))
5152 else:
5153 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5154 'screenshots check.'))
5155
5156 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075157 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265158 'ICU syntax errors were found in the following strings (problems or '
5159 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145160
5161 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125162
5163
Saagar Sanghavifceeaae2020-08-12 16:40:365164def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125165 repo_root=None,
5166 translation_expectations_path=None,
5167 grd_files=None):
5168 import sys
5169 affected_grds = [f for f in input_api.AffectedFiles()
5170 if (f.LocalPath().endswith('.grd') or
5171 f.LocalPath().endswith('.grdp'))]
5172 if not affected_grds:
5173 return []
5174
5175 try:
5176 old_sys_path = sys.path
5177 sys.path = sys.path + [
5178 input_api.os_path.join(
5179 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5180 from helper import git_helper
5181 from helper import translation_helper
5182 finally:
5183 sys.path = old_sys_path
5184
5185 # Check that translation expectations can be parsed and we can get a list of
5186 # translatable grd files. |repo_root| and |translation_expectations_path| are
5187 # only passed by tests.
5188 if not repo_root:
5189 repo_root = input_api.PresubmitLocalPath()
5190 if not translation_expectations_path:
5191 translation_expectations_path = input_api.os_path.join(
5192 repo_root, 'tools', 'gritsettings',
5193 'translation_expectations.pyl')
5194 if not grd_files:
5195 grd_files = git_helper.list_grds_in_repository(repo_root)
5196
5197 try:
5198 translation_helper.get_translatable_grds(repo_root, grd_files,
5199 translation_expectations_path)
5200 except Exception as e:
5201 return [output_api.PresubmitNotifyResult(
5202 'Failed to get a list of translatable grd files. This happens when:\n'
5203 ' - One of the modified grd or grdp files cannot be parsed or\n'
5204 ' - %s is not updated.\n'
5205 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5206 return []
Ken Rockotc31f4832020-05-29 18:58:515207
5208
Saagar Sanghavifceeaae2020-08-12 16:40:365209def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515210 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095211 changed_mojoms = input_api.AffectedFiles(
5212 include_deletes=True,
5213 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515214 delta = []
5215 for mojom in changed_mojoms:
5216 old_contents = ''.join(mojom.OldContents()) or None
5217 new_contents = ''.join(mojom.NewContents()) or None
5218 delta.append({
5219 'filename': mojom.LocalPath(),
5220 'old': '\n'.join(mojom.OldContents()) or None,
5221 'new': '\n'.join(mojom.NewContents()) or None,
5222 })
5223
5224 process = input_api.subprocess.Popen(
5225 [input_api.python_executable,
5226 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5227 'public', 'tools', 'mojom',
5228 'check_stable_mojom_compatibility.py'),
5229 '--src-root', input_api.PresubmitLocalPath()],
5230 stdin=input_api.subprocess.PIPE,
5231 stdout=input_api.subprocess.PIPE,
5232 stderr=input_api.subprocess.PIPE,
5233 universal_newlines=True)
5234 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5235 if process.returncode:
5236 return [output_api.PresubmitError(
5237 'One or more [Stable] mojom definitions appears to have been changed '
5238 'in a way that is not backward-compatible.',
5239 long_text=error)]
5240 return []