blob: 9c2f3d5ba90254313bcbbf55f5bcdb50d512d0e9 [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[\\/].*',
Austin Sullivan33da70a2020-10-07 15:39:4171 # Chromium Codelab
72 r'codelabs[\\/]*'
[email protected]06e6d0ff2012-12-11 01:36:4473)
[email protected]ca8d1982009-02-19 16:33:1274
Daniel Bratell609102be2019-03-27 20:53:2175_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
wnwenbdc444e2016-05-25 13:44:1576
[email protected]eea609a2011-11-18 13:10:1277_TEST_ONLY_WARNING = (
78 'You might be calling functions intended only for testing from\n'
danakj5f6e3b82020-09-10 13:52:5579 'production code. If you are doing this from inside another method\n'
80 'named as *ForTesting(), then consider exposing things to have tests\n'
81 'make that same call directly.\n'
82 'If that is not possible, you may put a comment on the same line with\n'
83 ' // IN-TEST \n'
84 'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
85 'method and can be ignored. Do not do this inside production code.\n'
86 'The android-binary-size trybot will block if the method exists in the\n'
87 'release apk.')
[email protected]eea609a2011-11-18 13:10:1288
89
[email protected]cf9b78f2012-11-14 11:40:2890_INCLUDE_ORDER_WARNING = (
marjaa017dc482015-03-09 17:13:4091 'Your #include order seems to be broken. Remember to use the right '
avice9a8982015-11-24 20:36:2192 'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
93 'cppguide.html#Names_and_Order_of_Includes')
[email protected]cf9b78f2012-11-14 11:40:2894
Michael Thiessen44457642020-02-06 00:24:1595# Format: Sequence of tuples containing:
96# * Full import path.
97# * Sequence of strings to show when the pattern matches.
98# * Sequence of path or filename exceptions to this rule
99_BANNED_JAVA_IMPORTS = (
100 (
Colin Blundell170d78c82020-03-12 13:56:04101 'java.net.URI;',
Michael Thiessen44457642020-02-06 00:24:15102 (
103 'Use org.chromium.url.GURL instead of java.net.URI, where possible.',
104 ),
105 (
106 'net/android/javatests/src/org/chromium/net/'
107 'AndroidProxySelectorTest.java',
108 'components/cronet/',
Ben Joyce615ba2b2020-05-20 18:22:04109 'third_party/robolectric/local/',
Michael Thiessen44457642020-02-06 00:24:15110 ),
111 ),
Michael Thiessened631912020-08-07 19:01:31112 (
113 'android.support.test.rule.UiThreadTestRule;',
114 (
115 'Do not use UiThreadTestRule, just use '
danakj89f47082020-09-02 17:53:43116 '@org.chromium.base.test.UiThreadTest on test methods that should run '
117 'on the UI thread. See https://crbug.com/1111893.',
Michael Thiessened631912020-08-07 19:01:31118 ),
119 (),
120 ),
121 (
122 'android.support.test.annotation.UiThreadTest;',
123 (
124 'Do not use android.support.test.annotation.UiThreadTest, use '
125 'org.chromium.base.test.UiThreadTest instead. See '
126 'https://crbug.com/1111893.',
127 ),
128 ()
129 )
Michael Thiessen44457642020-02-06 00:24:15130)
wnwenbdc444e2016-05-25 13:44:15131
Daniel Bratell609102be2019-03-27 20:53:21132# Format: Sequence of tuples containing:
133# * String pattern or, if starting with a slash, a regular expression.
134# * Sequence of strings to show when the pattern matches.
135# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Eric Stevensona9a980972017-09-23 00:04:41136_BANNED_JAVA_FUNCTIONS = (
137 (
138 'StrictMode.allowThreadDiskReads()',
139 (
140 'Prefer using StrictModeContext.allowDiskReads() to using StrictMode '
141 'directly.',
142 ),
143 False,
144 ),
145 (
146 'StrictMode.allowThreadDiskWrites()',
147 (
148 'Prefer using StrictModeContext.allowDiskWrites() to using StrictMode '
149 'directly.',
150 ),
151 False,
152 ),
Michael Thiessen0f2547e2020-07-27 21:55:36153 (
154 '.waitForIdleSync()',
155 (
156 'Do not use waitForIdleSync as it masks underlying issues. There is '
157 'almost always something else you should wait on instead.',
158 ),
159 False,
160 ),
Eric Stevensona9a980972017-09-23 00:04:41161)
162
Daniel Bratell609102be2019-03-27 20:53:21163# Format: Sequence of tuples containing:
164# * String pattern or, if starting with a slash, a regular expression.
165# * Sequence of strings to show when the pattern matches.
166# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
[email protected]127f18ec2012-06-16 05:05:59167_BANNED_OBJC_FUNCTIONS = (
168 (
169 'addTrackingRect:',
[email protected]23e6cbc2012-06-16 18:51:20170 (
171 'The use of -[NSView addTrackingRect:owner:userData:assumeInside:] is'
[email protected]127f18ec2012-06-16 05:05:59172 'prohibited. Please use CrTrackingArea instead.',
173 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
174 ),
175 False,
176 ),
177 (
[email protected]eaae1972014-04-16 04:17:26178 r'/NSTrackingArea\W',
[email protected]23e6cbc2012-06-16 18:51:20179 (
180 'The use of NSTrackingAreas is prohibited. Please use CrTrackingArea',
[email protected]127f18ec2012-06-16 05:05:59181 'instead.',
182 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
183 ),
184 False,
185 ),
186 (
187 'convertPointFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20188 (
189 'The use of -[NSView convertPointFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59190 'Please use |convertPoint:(point) fromView:nil| instead.',
191 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
192 ),
193 True,
194 ),
195 (
196 'convertPointToBase:',
[email protected]23e6cbc2012-06-16 18:51:20197 (
198 'The use of -[NSView convertPointToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59199 'Please use |convertPoint:(point) toView:nil| instead.',
200 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
201 ),
202 True,
203 ),
204 (
205 'convertRectFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20206 (
207 'The use of -[NSView convertRectFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59208 'Please use |convertRect:(point) fromView:nil| instead.',
209 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
210 ),
211 True,
212 ),
213 (
214 'convertRectToBase:',
[email protected]23e6cbc2012-06-16 18:51:20215 (
216 'The use of -[NSView convertRectToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59217 'Please use |convertRect:(point) toView:nil| instead.',
218 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
219 ),
220 True,
221 ),
222 (
223 'convertSizeFromBase:',
[email protected]23e6cbc2012-06-16 18:51:20224 (
225 'The use of -[NSView convertSizeFromBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59226 'Please use |convertSize:(point) fromView:nil| instead.',
227 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
228 ),
229 True,
230 ),
231 (
232 'convertSizeToBase:',
[email protected]23e6cbc2012-06-16 18:51:20233 (
234 'The use of -[NSView convertSizeToBase:] is almost certainly wrong.',
[email protected]127f18ec2012-06-16 05:05:59235 'Please use |convertSize:(point) toView:nil| instead.',
236 'http://dev.chromium.org/developers/coding-style/cocoa-dos-and-donts',
237 ),
238 True,
239 ),
jif65398702016-10-27 10:19:48240 (
241 r"/\s+UTF8String\s*]",
242 (
243 'The use of -[NSString UTF8String] is dangerous as it can return null',
244 'even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES.',
245 'Please use |SysNSStringToUTF8| instead.',
246 ),
247 True,
248 ),
Sylvain Defresne4cf1d182017-09-18 14:16:34249 (
250 r'__unsafe_unretained',
251 (
252 'The use of __unsafe_unretained is almost certainly wrong, unless',
253 'when interacting with NSFastEnumeration or NSInvocation.',
254 'Please use __weak in files build with ARC, nothing otherwise.',
255 ),
256 False,
257 ),
Avi Drissman7382afa02019-04-29 23:27:13258 (
259 'freeWhenDone:NO',
260 (
261 'The use of "freeWhenDone:NO" with the NoCopy creation of ',
262 'Foundation types is prohibited.',
263 ),
264 True,
265 ),
[email protected]127f18ec2012-06-16 05:05:59266)
267
Daniel Bratell609102be2019-03-27 20:53:21268# Format: Sequence of tuples containing:
269# * String pattern or, if starting with a slash, a regular expression.
270# * Sequence of strings to show when the pattern matches.
271# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
Sylvain Defresnea8b73d252018-02-28 15:45:54272_BANNED_IOS_OBJC_FUNCTIONS = (
273 (
274 r'/\bTEST[(]',
275 (
276 'TEST() macro should not be used in Objective-C++ code as it does not ',
277 'drain the autorelease pool at the end of the test. Use TEST_F() ',
278 'macro instead with a fixture inheriting from PlatformTest (or a ',
279 'typedef).'
280 ),
281 True,
282 ),
283 (
284 r'/\btesting::Test\b',
285 (
286 'testing::Test should not be used in Objective-C++ code as it does ',
287 'not drain the autorelease pool at the end of the test. Use ',
288 'PlatformTest instead.'
289 ),
290 True,
291 ),
292)
293
Peter K. Lee6c03ccff2019-07-15 14:40:05294# Format: Sequence of tuples containing:
295# * String pattern or, if starting with a slash, a regular expression.
296# * Sequence of strings to show when the pattern matches.
297# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
298_BANNED_IOS_EGTEST_FUNCTIONS = (
299 (
300 r'/\bEXPECT_OCMOCK_VERIFY\b',
301 (
302 'EXPECT_OCMOCK_VERIFY should not be used in EarlGrey tests because ',
303 'it is meant for GTests. Use [mock verify] instead.'
304 ),
305 True,
306 ),
307)
308
danakj7a2b7082019-05-21 21:13:51309# Directories that contain deprecated Bind() or Callback types.
310# Find sub-directories from a given directory by running:
danakjc8576092019-11-26 19:01:36311# for i in `find . -maxdepth 1 -type d|sort`; do
danakj7a2b7082019-05-21 21:13:51312# echo "-- $i"
danakj710b4c02019-11-28 16:08:45313# (cd $i; git grep -nP 'base::(Bind\(|(Callback<|Closure))'|wc -l)
danakj7a2b7082019-05-21 21:13:51314# done
315#
316# TODO(crbug.com/714018): Remove (or narrow the scope of) paths from this list
317# when they have been converted to modern callback types (OnceCallback,
318# RepeatingCallback, BindOnce, BindRepeating) in order to enable presubmit
319# checks for them and prevent regressions.
320_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK = '|'.join((
danakj7a2b7082019-05-21 21:13:51321 '^base/callback.h', # Intentional.
Alexander Cooper6b447b22020-07-22 00:47:18322 '^chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc',
323 '^chrome/browser/apps/guest_view/',
Alexander Cooper6b447b22020-07-22 00:47:18324 '^chrome/browser/browsing_data/',
325 '^chrome/browser/captive_portal/captive_portal_browsertest.cc',
326 '^chrome/browser/chromeos/',
327 '^chrome/browser/component_updater/',
Peter Wen6367b882020-08-05 16:55:50328 '^chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.cc', # pylint: disable=line-too-long
Alexander Cooper6b447b22020-07-22 00:47:18329 '^chrome/browser/devtools/',
330 '^chrome/browser/download/',
331 '^chrome/browser/extensions/',
Alexander Cooper6b447b22020-07-22 00:47:18332 '^chrome/browser/history/',
Alexander Cooper6b447b22020-07-22 00:47:18333 '^chrome/browser/lifetime/',
334 '^chrome/browser/media_galleries/',
335 '^chrome/browser/media/',
336 '^chrome/browser/metrics/',
Alexander Cooper6b447b22020-07-22 00:47:18337 '^chrome/browser/net/',
338 '^chrome/browser/notifications/',
339 '^chrome/browser/ntp_tiles/ntp_tiles_browsertest.cc',
340 '^chrome/browser/offline_pages/',
Peter Wen6367b882020-08-05 16:55:50341 '^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:18342 '^chrome/browser/payments/payment_manifest_parser_browsertest.cc',
343 '^chrome/browser/pdf/pdf_extension_test.cc',
344 '^chrome/browser/plugins/',
345 '^chrome/browser/policy/',
346 '^chrome/browser/portal/portal_browsertest.cc',
347 '^chrome/browser/prefs/profile_pref_store_manager_unittest.cc',
348 '^chrome/browser/prerender/',
349 '^chrome/browser/previews/',
350 '^chrome/browser/printing/printing_message_filter.cc',
351 '^chrome/browser/profiles/',
352 '^chrome/browser/profiling_host/profiling_process_host.cc',
353 '^chrome/browser/push_messaging/',
354 '^chrome/browser/recovery/recovery_install_global_error.cc',
355 '^chrome/browser/renderer_context_menu/',
356 '^chrome/browser/renderer_host/pepper/',
357 '^chrome/browser/resource_coordinator/',
358 '^chrome/browser/resources/chromeos/accessibility/',
359 '^chrome/browser/rlz/chrome_rlz_tracker_delegate.cc',
360 '^chrome/browser/safe_browsing/',
361 '^chrome/browser/search_engines/',
362 '^chrome/browser/service_process/',
363 '^chrome/browser/signin/',
364 '^chrome/browser/site_isolation/site_per_process_text_input_browsertest.cc',
365 '^chrome/browser/ssl/',
366 '^chrome/browser/subresource_filter/',
367 '^chrome/browser/supervised_user/',
368 '^chrome/browser/sync_file_system/',
369 '^chrome/browser/sync/',
370 '^chrome/browser/themes/theme_service.cc',
371 '^chrome/browser/thumbnail/cc/',
Alexander Cooper6b447b22020-07-22 00:47:18372 '^chrome/browser/translate/',
373 '^chrome/browser/ui/',
Alexander Cooper6b447b22020-07-22 00:47:18374 '^chrome/browser/web_applications/',
375 '^chrome/browser/win/',
danakj7a2b7082019-05-21 21:13:51376 '^chrome/services/',
377 '^chrome/test/',
378 '^chrome/tools/',
danakj7a2b7082019-05-21 21:13:51379 '^chromecast/media/',
danakj7a2b7082019-05-21 21:13:51380 '^chromeos/attestation/',
danakj7a2b7082019-05-21 21:13:51381 '^chromeos/components/',
danakj7a2b7082019-05-21 21:13:51382 '^components/arc/',
danakj7a2b7082019-05-21 21:13:51383 '^components/cast_channel/',
danakj7a2b7082019-05-21 21:13:51384 '^components/component_updater/',
385 '^components/content_settings/',
danakj7a2b7082019-05-21 21:13:51386 '^components/drive/',
danakj7a2b7082019-05-21 21:13:51387 '^components/nacl/',
388 '^components/navigation_interception/',
danakj7a2b7082019-05-21 21:13:51389 '^components/ownership/',
danakj7a2b7082019-05-21 21:13:51390 '^components/policy/',
danakj7a2b7082019-05-21 21:13:51391 '^components/search_engines/',
danakj7a2b7082019-05-21 21:13:51392 '^components/security_interstitials/',
danakj7a2b7082019-05-21 21:13:51393 '^components/signin/',
danakj7a2b7082019-05-21 21:13:51394 '^components/sync/',
danakj7a2b7082019-05-21 21:13:51395 '^components/ukm/',
danakj7a2b7082019-05-21 21:13:51396 '^components/webcrypto/',
Alan Cutter04a00642020-03-02 01:45:20397 '^extensions/browser/',
398 '^extensions/renderer/',
Alexander Cooper922f2112020-07-22 16:27:43399 '^google_apis/drive/',
danakj7a2b7082019-05-21 21:13:51400 '^ios/chrome/',
401 '^ios/components/',
402 '^ios/net/',
403 '^ios/web/',
404 '^ios/web_view/',
405 '^ipc/',
danakjc8576092019-11-26 19:01:36406 '^media/blink/',
danakj7a2b7082019-05-21 21:13:51407 '^media/cast/',
408 '^media/cdm/',
danakj7a2b7082019-05-21 21:13:51409 '^media/filters/',
danakj7a2b7082019-05-21 21:13:51410 '^media/gpu/',
411 '^media/mojo/',
Steve Kobes334b6ed2020-07-09 07:26:31412 '^net/http/',
413 '^net/url_request/',
danakj7a2b7082019-05-21 21:13:51414 '^ppapi/proxy/',
danakj7a2b7082019-05-21 21:13:51415 '^services/',
danakj7a2b7082019-05-21 21:13:51416 '^third_party/blink/',
danakj7a2b7082019-05-21 21:13:51417 '^tools/clang/base_bind_rewriters/', # Intentional.
418 '^tools/gdb/gdb_chrome.py', # Intentional.
danakj7a2b7082019-05-21 21:13:51419))
[email protected]127f18ec2012-06-16 05:05:59420
Daniel Bratell609102be2019-03-27 20:53:21421# Format: Sequence of tuples containing:
422# * String pattern or, if starting with a slash, a regular expression.
423# * Sequence of strings to show when the pattern matches.
424# * Error flag. True if a match is a presubmit error, otherwise it's a warning.
425# * Sequence of paths to *not* check (regexps).
[email protected]127f18ec2012-06-16 05:05:59426_BANNED_CPP_FUNCTIONS = (
[email protected]23e6cbc2012-06-16 18:51:20427 (
Dave Tapuska98199b612019-07-10 13:30:44428 r'/\bNULL\b',
thomasandersone7caaa9b2017-03-29 19:22:53429 (
430 'New code should not use NULL. Use nullptr instead.',
431 ),
Mohamed Amir Yosefea381072019-08-09 08:13:20432 False,
thomasandersone7caaa9b2017-03-29 19:22:53433 (),
434 ),
Peter Kasting94a56c42019-10-25 21:54:04435 (
436 r'/\busing namespace ',
437 (
438 'Using directives ("using namespace x") are banned by the Google Style',
439 'Guide ( http://google.github.io/styleguide/cppguide.html#Namespaces ).',
440 'Explicitly qualify symbols or use using declarations ("using x::foo").',
441 ),
442 True,
443 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
444 ),
Antonio Gomes07300d02019-03-13 20:59:57445 # Make sure that gtest's FRIEND_TEST() macro is not used; the
446 # FRIEND_TEST_ALL_PREFIXES() macro from base/gtest_prod_util.h should be
447 # used instead since that allows for FLAKY_ and DISABLED_ prefixes.
thomasandersone7caaa9b2017-03-29 19:22:53448 (
[email protected]23e6cbc2012-06-16 18:51:20449 'FRIEND_TEST(',
450 (
[email protected]e3c945502012-06-26 20:01:49451 'Chromium code should not use gtest\'s FRIEND_TEST() macro. Include',
[email protected]23e6cbc2012-06-16 18:51:20452 'base/gtest_prod_util.h and use FRIEND_TEST_ALL_PREFIXES() instead.',
453 ),
454 False,
[email protected]7345da02012-11-27 14:31:49455 (),
[email protected]23e6cbc2012-06-16 18:51:20456 ),
457 (
tomhudsone2c14d552016-05-26 17:07:46458 'setMatrixClip',
459 (
460 'Overriding setMatrixClip() is prohibited; ',
461 'the base function is deprecated. ',
462 ),
463 True,
464 (),
465 ),
466 (
[email protected]52657f62013-05-20 05:30:31467 'SkRefPtr',
468 (
469 'The use of SkRefPtr is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22470 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31471 ),
472 True,
473 (),
474 ),
475 (
476 'SkAutoRef',
477 (
478 'The indirect use of SkRefPtr via SkAutoRef is prohibited. ',
tomhudson7e6e0512016-04-19 19:27:22479 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31480 ),
481 True,
482 (),
483 ),
484 (
485 'SkAutoTUnref',
486 (
487 'The use of SkAutoTUnref is dangerous because it implicitly ',
tomhudson7e6e0512016-04-19 19:27:22488 'converts to a raw pointer. Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31489 ),
490 True,
491 (),
492 ),
493 (
494 'SkAutoUnref',
495 (
496 'The indirect use of SkAutoTUnref through SkAutoUnref is dangerous ',
497 'because it implicitly converts to a raw pointer. ',
tomhudson7e6e0512016-04-19 19:27:22498 'Please use sk_sp<> instead.'
[email protected]52657f62013-05-20 05:30:31499 ),
500 True,
501 (),
502 ),
[email protected]d89eec82013-12-03 14:10:59503 (
504 r'/HANDLE_EINTR\(.*close',
505 (
506 'HANDLE_EINTR(close) is invalid. If close fails with EINTR, the file',
507 'descriptor will be closed, and it is incorrect to retry the close.',
508 'Either call close directly and ignore its return value, or wrap close',
509 'in IGNORE_EINTR to use its return value. See http://crbug.com/269623'
510 ),
511 True,
512 (),
513 ),
514 (
515 r'/IGNORE_EINTR\((?!.*close)',
516 (
517 'IGNORE_EINTR is only valid when wrapping close. To wrap other system',
518 'calls, use HANDLE_EINTR. See http://crbug.com/269623',
519 ),
520 True,
521 (
522 # Files that #define IGNORE_EINTR.
Egor Paskoce145c42018-09-28 19:31:04523 r'^base[\\/]posix[\\/]eintr_wrapper\.h$',
524 r'^ppapi[\\/]tests[\\/]test_broker\.cc$',
[email protected]d89eec82013-12-03 14:10:59525 ),
526 ),
[email protected]ec5b3f02014-04-04 18:43:43527 (
528 r'/v8::Extension\(',
529 (
530 'Do not introduce new v8::Extensions into the code base, use',
531 'gin::Wrappable instead. See http://crbug.com/334679',
532 ),
533 True,
[email protected]f55c90ee62014-04-12 00:50:03534 (
Egor Paskoce145c42018-09-28 19:31:04535 r'extensions[\\/]renderer[\\/]safe_builtins\.*',
[email protected]f55c90ee62014-04-12 00:50:03536 ),
[email protected]ec5b3f02014-04-04 18:43:43537 ),
skyostilf9469f72015-04-20 10:38:52538 (
jame2d1a952016-04-02 00:27:10539 '#pragma comment(lib,',
540 (
541 'Specify libraries to link with in build files and not in the source.',
542 ),
543 True,
Mirko Bonadeif4f0f0e2018-04-12 09:29:41544 (
tzik3f295992018-12-04 20:32:23545 r'^base[\\/]third_party[\\/]symbolize[\\/].*',
Egor Paskoce145c42018-09-28 19:31:04546 r'^third_party[\\/]abseil-cpp[\\/].*',
Mirko Bonadeif4f0f0e2018-04-12 09:29:41547 ),
jame2d1a952016-04-02 00:27:10548 ),
fdorayc4ac18d2017-05-01 21:39:59549 (
Gabriel Charette7cc6c432018-04-25 20:52:02550 r'/base::SequenceChecker\b',
gabd52c912a2017-05-11 04:15:59551 (
552 'Consider using SEQUENCE_CHECKER macros instead of the class directly.',
553 ),
554 False,
555 (),
556 ),
557 (
Gabriel Charette7cc6c432018-04-25 20:52:02558 r'/base::ThreadChecker\b',
gabd52c912a2017-05-11 04:15:59559 (
560 'Consider using THREAD_CHECKER macros instead of the class directly.',
561 ),
562 False,
563 (),
564 ),
dbeamb6f4fde2017-06-15 04:03:06565 (
Yuri Wiitala2f8de5c2017-07-21 00:11:06566 r'/(Time(|Delta|Ticks)|ThreadTicks)::FromInternalValue|ToInternalValue',
567 (
568 'base::TimeXXX::FromInternalValue() and ToInternalValue() are',
569 'deprecated (http://crbug.com/634507). Please avoid converting away',
570 'from the Time types in Chromium code, especially if any math is',
571 'being done on time values. For interfacing with platform/library',
572 'APIs, use FromMicroseconds() or InMicroseconds(), or one of the other',
573 'type converter methods instead. For faking TimeXXX values (for unit',
574 'testing only), use TimeXXX() + TimeDelta::FromMicroseconds(N). For',
575 'other use cases, please contact base/time/OWNERS.',
576 ),
577 False,
578 (),
579 ),
580 (
dbeamb6f4fde2017-06-15 04:03:06581 'CallJavascriptFunctionUnsafe',
582 (
583 "Don't use CallJavascriptFunctionUnsafe() in new code. Instead, use",
584 'AllowJavascript(), OnJavascriptAllowed()/OnJavascriptDisallowed(),',
585 'and CallJavascriptFunction(). See https://goo.gl/qivavq.',
586 ),
587 False,
588 (
Egor Paskoce145c42018-09-28 19:31:04589 r'^content[\\/]browser[\\/]webui[\\/]web_ui_impl\.(cc|h)$',
590 r'^content[\\/]public[\\/]browser[\\/]web_ui\.h$',
591 r'^content[\\/]public[\\/]test[\\/]test_web_ui\.(cc|h)$',
dbeamb6f4fde2017-06-15 04:03:06592 ),
593 ),
dskiba1474c2bfd62017-07-20 02:19:24594 (
595 'leveldb::DB::Open',
596 (
597 'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
598 'third_party/leveldatabase/env_chromium.h. It exposes databases to',
599 "Chrome's tracing, making their memory usage visible.",
600 ),
601 True,
602 (
603 r'^third_party/leveldatabase/.*\.(cc|h)$',
604 ),
Gabriel Charette0592c3a2017-07-26 12:02:04605 ),
606 (
Chris Mumfordc38afb62017-10-09 17:55:08607 'leveldb::NewMemEnv',
608 (
609 'Instead of leveldb::NewMemEnv() use leveldb_chrome::NewMemEnv() from',
Chris Mumford8d26d10a2018-04-20 17:07:58610 'third_party/leveldatabase/leveldb_chrome.h. It exposes environments',
611 "to Chrome's tracing, making their memory usage visible.",
Chris Mumfordc38afb62017-10-09 17:55:08612 ),
613 True,
614 (
615 r'^third_party/leveldatabase/.*\.(cc|h)$',
616 ),
617 ),
618 (
Gabriel Charetted9839bc2017-07-29 14:17:47619 'RunLoop::QuitCurrent',
620 (
Robert Liao64b7ab22017-08-04 23:03:43621 'Please migrate away from RunLoop::QuitCurrent*() methods. Use member',
622 'methods of a specific RunLoop instance instead.',
Gabriel Charetted9839bc2017-07-29 14:17:47623 ),
Gabriel Charettec0a8f3ee2018-04-25 20:49:41624 False,
Gabriel Charetted9839bc2017-07-29 14:17:47625 (),
Gabriel Charettea44975052017-08-21 23:14:04626 ),
627 (
628 'base::ScopedMockTimeMessageLoopTaskRunner',
629 (
Gabriel Charette87cc1af2018-04-25 20:52:51630 'ScopedMockTimeMessageLoopTaskRunner is deprecated. Prefer',
Gabriel Charettedfa36042019-08-19 17:30:11631 'TaskEnvironment::TimeSource::MOCK_TIME. There are still a',
Gabriel Charette87cc1af2018-04-25 20:52:51632 'few cases that may require a ScopedMockTimeMessageLoopTaskRunner',
633 '(i.e. mocking the main MessageLoopForUI in browser_tests), but check',
634 'with gab@ first if you think you need it)',
Gabriel Charettea44975052017-08-21 23:14:04635 ),
Gabriel Charette87cc1af2018-04-25 20:52:51636 False,
Gabriel Charettea44975052017-08-21 23:14:04637 (),
Eric Stevenson6b47b44c2017-08-30 20:41:57638 ),
639 (
Dave Tapuska98199b612019-07-10 13:30:44640 'std::regex',
Eric Stevenson6b47b44c2017-08-30 20:41:57641 (
642 'Using std::regex adds unnecessary binary size to Chrome. Please use',
Mostyn Bramley-Moore6b427322017-12-21 22:11:02643 're2::RE2 instead (crbug.com/755321)',
Eric Stevenson6b47b44c2017-08-30 20:41:57644 ),
645 True,
646 (),
Francois Doray43670e32017-09-27 12:40:38647 ),
648 (
Peter Kasting991618a62019-06-17 22:00:09649 r'/\bstd::stoi\b',
650 (
651 'std::stoi uses exceptions to communicate results. ',
652 'Use base::StringToInt() instead.',
653 ),
654 True,
655 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
656 ),
657 (
658 r'/\bstd::stol\b',
659 (
660 'std::stol uses exceptions to communicate results. ',
661 'Use base::StringToInt() instead.',
662 ),
663 True,
664 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
665 ),
666 (
667 r'/\bstd::stoul\b',
668 (
669 'std::stoul uses exceptions to communicate results. ',
670 'Use base::StringToUint() instead.',
671 ),
672 True,
673 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
674 ),
675 (
676 r'/\bstd::stoll\b',
677 (
678 'std::stoll uses exceptions to communicate results. ',
679 'Use base::StringToInt64() instead.',
680 ),
681 True,
682 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
683 ),
684 (
685 r'/\bstd::stoull\b',
686 (
687 'std::stoull uses exceptions to communicate results. ',
688 'Use base::StringToUint64() instead.',
689 ),
690 True,
691 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
692 ),
693 (
694 r'/\bstd::stof\b',
695 (
696 'std::stof uses exceptions to communicate results. ',
697 'For locale-independent values, e.g. reading numbers from disk',
698 'profiles, use base::StringToDouble().',
699 'For user-visible values, parse using ICU.',
700 ),
701 True,
702 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
703 ),
704 (
705 r'/\bstd::stod\b',
706 (
707 'std::stod uses exceptions to communicate results. ',
708 'For locale-independent values, e.g. reading numbers from disk',
709 'profiles, use base::StringToDouble().',
710 'For user-visible values, parse using ICU.',
711 ),
712 True,
713 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
714 ),
715 (
716 r'/\bstd::stold\b',
717 (
718 'std::stold uses exceptions to communicate results. ',
719 'For locale-independent values, e.g. reading numbers from disk',
720 'profiles, use base::StringToDouble().',
721 'For user-visible values, parse using ICU.',
722 ),
723 True,
724 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
725 ),
726 (
Daniel Bratell69334cc2019-03-26 11:07:45727 r'/\bstd::to_string\b',
728 (
729 'std::to_string is locale dependent and slower than alternatives.',
Peter Kasting991618a62019-06-17 22:00:09730 'For locale-independent strings, e.g. writing numbers to disk',
731 'profiles, use base::NumberToString().',
Daniel Bratell69334cc2019-03-26 11:07:45732 'For user-visible strings, use base::FormatNumber() and',
733 'the related functions in base/i18n/number_formatting.h.',
734 ),
Peter Kasting991618a62019-06-17 22:00:09735 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21736 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45737 ),
738 (
739 r'/\bstd::shared_ptr\b',
740 (
741 'std::shared_ptr should not be used. Use scoped_refptr instead.',
742 ),
743 True,
Alex Chau9eb03cdd52020-07-13 21:04:57744 ['^third_party/blink/renderer/core/typed_arrays/array_buffer/' +
745 'array_buffer_contents\.(cc|h)',
746 # Needed for interop with third-party library
747 'chrome/services/sharing/nearby/',
748 _THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell609102be2019-03-27 20:53:21749 ),
750 (
Peter Kasting991618a62019-06-17 22:00:09751 r'/\bstd::weak_ptr\b',
752 (
753 'std::weak_ptr should not be used. Use base::WeakPtr instead.',
754 ),
755 True,
756 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
757 ),
758 (
Daniel Bratell609102be2019-03-27 20:53:21759 r'/\blong long\b',
760 (
761 'long long is banned. Use stdint.h if you need a 64 bit number.',
762 ),
763 False, # Only a warning since it is already used.
764 [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders.
765 ),
766 (
767 r'/\bstd::bind\b',
768 (
769 'std::bind is banned because of lifetime risks.',
770 'Use base::BindOnce or base::BindRepeating instead.',
771 ),
772 True,
773 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
774 ),
775 (
776 r'/\b#include <chrono>\b',
777 (
778 '<chrono> overlaps with Time APIs in base. Keep using',
779 'base classes.',
780 ),
781 True,
782 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
783 ),
784 (
785 r'/\b#include <exception>\b',
786 (
787 'Exceptions are banned and disabled in Chromium.',
788 ),
789 True,
790 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
791 ),
792 (
793 r'/\bstd::function\b',
794 (
795 'std::function is banned. Instead use base::Callback which directly',
796 'supports Chromium\'s weak pointers, ref counting and more.',
797 ),
Peter Kasting991618a62019-06-17 22:00:09798 False, # Only a warning since it is already used.
Daniel Bratell609102be2019-03-27 20:53:21799 [_THIRD_PARTY_EXCEPT_BLINK], # Do not warn in third_party folders.
800 ),
801 (
802 r'/\b#include <random>\b',
803 (
804 'Do not use any random number engines from <random>. Instead',
805 'use base::RandomBitGenerator.',
806 ),
807 True,
808 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
809 ),
810 (
Tom Andersona95e12042020-09-09 23:08:00811 r'/\b#include <X11/',
812 (
813 'Do not use Xlib. Use xproto (from //ui/gfx/x:xproto) instead.',
814 ),
815 True,
816 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
817 ),
818 (
Daniel Bratell609102be2019-03-27 20:53:21819 r'/\bstd::ratio\b',
820 (
821 'std::ratio is banned by the Google Style Guide.',
822 ),
823 True,
824 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
Daniel Bratell69334cc2019-03-26 11:07:45825 ),
826 (
Francois Doray43670e32017-09-27 12:40:38827 (r'/base::ThreadRestrictions::(ScopedAllowIO|AssertIOAllowed|'
828 r'DisallowWaiting|AssertWaitAllowed|SetWaitAllowed|ScopedAllowWait)'),
829 (
830 'Use the new API in base/threading/thread_restrictions.h.',
831 ),
Gabriel Charette04b138f2018-08-06 00:03:22832 False,
Francois Doray43670e32017-09-27 12:40:38833 (),
834 ),
Luis Hector Chavez9bbaed532017-11-30 18:25:38835 (
danakj7a2b7082019-05-21 21:13:51836 r'/\bbase::Bind\(',
837 (
838 'Please use base::Bind{Once,Repeating} instead',
839 'of base::Bind. (crbug.com/714018)',
840 ),
841 False,
Erik Staaba737d7602019-11-25 18:41:07842 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51843 ),
844 (
845 r'/\bbase::Callback[<:]',
846 (
847 'Please use base::{Once,Repeating}Callback instead',
848 'of base::Callback. (crbug.com/714018)',
849 ),
850 False,
Erik Staaba737d7602019-11-25 18:41:07851 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51852 ),
853 (
854 r'/\bbase::Closure\b',
855 (
856 'Please use base::{Once,Repeating}Closure instead',
857 'of base::Closure. (crbug.com/714018)',
858 ),
859 False,
Erik Staaba737d7602019-11-25 18:41:07860 (_NOT_CONVERTED_TO_MODERN_BIND_AND_CALLBACK,),
danakj7a2b7082019-05-21 21:13:51861 ),
862 (
Michael Giuffrida7f93d6922019-04-19 14:39:58863 r'/\bRunMessageLoop\b',
Gabriel Charette147335ea2018-03-22 15:59:19864 (
865 'RunMessageLoop is deprecated, use RunLoop instead.',
866 ),
867 False,
868 (),
869 ),
870 (
Dave Tapuska98199b612019-07-10 13:30:44871 'RunThisRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19872 (
873 'RunThisRunLoop is deprecated, use RunLoop directly instead.',
874 ),
875 False,
876 (),
877 ),
878 (
Dave Tapuska98199b612019-07-10 13:30:44879 'RunAllPendingInMessageLoop()',
Gabriel Charette147335ea2018-03-22 15:59:19880 (
881 "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@",
882 "if you're convinced you need this.",
883 ),
884 False,
885 (),
886 ),
887 (
Dave Tapuska98199b612019-07-10 13:30:44888 'RunAllPendingInMessageLoop(BrowserThread',
Gabriel Charette147335ea2018-03-22 15:59:19889 (
890 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for',
Gabriel Charette798fde72019-08-20 22:24:04891 'BrowserThread::UI, BrowserTaskEnvironment::RunIOThreadUntilIdle',
Gabriel Charette147335ea2018-03-22 15:59:19892 'for BrowserThread::IO, and prefer RunLoop::QuitClosure to observe',
893 'async events instead of flushing threads.',
894 ),
895 False,
896 (),
897 ),
898 (
899 r'MessageLoopRunner',
900 (
901 'MessageLoopRunner is deprecated, use RunLoop instead.',
902 ),
903 False,
904 (),
905 ),
906 (
Dave Tapuska98199b612019-07-10 13:30:44907 'GetDeferredQuitTaskForRunLoop',
Gabriel Charette147335ea2018-03-22 15:59:19908 (
909 "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact",
910 "gab@ if you found a use case where this is the only solution.",
911 ),
912 False,
913 (),
914 ),
915 (
Victor Costane48a2e82019-03-15 22:02:34916 'sqlite3_initialize(',
Victor Costan3653df62018-02-08 21:38:16917 (
Victor Costane48a2e82019-03-15 22:02:34918 'Instead of calling sqlite3_initialize(), depend on //sql, ',
Victor Costan3653df62018-02-08 21:38:16919 '#include "sql/initialize.h" and use sql::EnsureSqliteInitialized().',
920 ),
921 True,
922 (
923 r'^sql/initialization\.(cc|h)$',
924 r'^third_party/sqlite/.*\.(c|cc|h)$',
925 ),
926 ),
Matt Menke7f520a82018-03-28 21:38:37927 (
Dave Tapuska98199b612019-07-10 13:30:44928 'std::random_shuffle',
tzik5de2157f2018-05-08 03:42:47929 (
930 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use',
931 'base::RandomShuffle instead.'
932 ),
933 True,
934 (),
935 ),
Javier Ernesto Flores Robles749e6c22018-10-08 09:36:24936 (
937 'ios/web/public/test/http_server',
938 (
939 'web::HTTPserver is deprecated use net::EmbeddedTestServer instead.',
940 ),
941 False,
942 (),
943 ),
Robert Liao764c9492019-01-24 18:46:28944 (
945 'GetAddressOf',
946 (
947 'Improper use of Microsoft::WRL::ComPtr<T>::GetAddressOf() has been ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53948 'implicated in a few leaks. ReleaseAndGetAddressOf() is safe but ',
Joshua Berenhaus8b972ec2020-09-11 20:00:11949 'operator& is generally recommended. So always use operator& instead. ',
Xiaohan Wangfb31b4cd2020-07-08 01:18:53950 'See http://crbug.com/914910 for more conversion guidance.'
Robert Liao764c9492019-01-24 18:46:28951 ),
952 True,
953 (),
954 ),
Antonio Gomes07300d02019-03-13 20:59:57955 (
956 'DEFINE_TYPE_CASTS',
957 (
958 'DEFINE_TYPE_CASTS is deprecated. Instead, use downcast helpers from ',
959 '//third_party/blink/renderer/platform/casting.h.'
960 ),
961 True,
962 (
963 r'^third_party/blink/renderer/.*\.(cc|h)$',
964 ),
965 ),
Carlos Knippschildab192b8c2019-04-08 20:02:38966 (
Abhijeet Kandalkar1e7c2502019-10-29 15:05:45967 r'/\bIsHTML.+Element\(\b',
968 (
969 'Function IsHTMLXXXXElement is deprecated. Instead, use downcast ',
970 ' helpers IsA<HTMLXXXXElement> from ',
971 '//third_party/blink/renderer/platform/casting.h.'
972 ),
973 False,
974 (
975 r'^third_party/blink/renderer/.*\.(cc|h)$',
976 ),
977 ),
978 (
979 r'/\bToHTML.+Element(|OrNull)\(\b',
980 (
981 'Function ToHTMLXXXXElement and ToHTMLXXXXElementOrNull are '
982 'deprecated. Instead, use downcast helpers To<HTMLXXXXElement> '
983 'and DynamicTo<HTMLXXXXElement> from ',
984 '//third_party/blink/renderer/platform/casting.h.'
985 'auto* html_xxxx_ele = To<HTMLXXXXElement>(n)'
986 'auto* html_xxxx_ele_or_null = DynamicTo<HTMLXXXXElement>(n)'
987 ),
988 False,
989 (
990 r'^third_party/blink/renderer/.*\.(cc|h)$',
991 ),
992 ),
993 (
Kinuko Yasuda376c2ce12019-04-16 01:20:37994 r'/\bmojo::DataPipe\b',
Carlos Knippschildab192b8c2019-04-08 20:02:38995 (
996 'mojo::DataPipe is deprecated. Use mojo::CreateDataPipe instead.',
997 ),
998 True,
999 (),
1000 ),
Ben Lewisa9514602019-04-29 17:53:051001 (
1002 'SHFileOperation',
1003 (
1004 'SHFileOperation was deprecated in Windows Vista, and there are less ',
1005 'complex functions to achieve the same goals. Use IFileOperation for ',
1006 'any esoteric actions instead.'
1007 ),
1008 True,
1009 (),
1010 ),
Cliff Smolinskyb11abed2019-04-29 19:43:181011 (
Cliff Smolinsky81951642019-04-30 21:39:511012 'StringFromGUID2',
1013 (
1014 'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241015 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511016 ),
1017 True,
1018 (
1019 r'/base/win/win_util_unittest.cc'
1020 ),
1021 ),
1022 (
1023 'StringFromCLSID',
1024 (
1025 'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
Jan Wilken Dörrieec815922020-07-22 07:46:241026 'Use base::win::WStringFromGUID instead.'
Cliff Smolinsky81951642019-04-30 21:39:511027 ),
1028 True,
1029 (
1030 r'/base/win/win_util_unittest.cc'
1031 ),
1032 ),
1033 (
Avi Drissman7382afa02019-04-29 23:27:131034 'kCFAllocatorNull',
1035 (
1036 'The use of kCFAllocatorNull with the NoCopy creation of ',
1037 'CoreFoundation types is prohibited.',
1038 ),
1039 True,
1040 (),
1041 ),
Oksana Zhuravlovafd247772019-05-16 16:57:291042 (
1043 'mojo::ConvertTo',
1044 (
1045 'mojo::ConvertTo and TypeConverter are deprecated. Please consider',
1046 'StructTraits / UnionTraits / EnumTraits / ArrayTraits / MapTraits /',
1047 'StringTraits if you would like to convert between custom types and',
1048 'the wire format of mojom types.'
1049 ),
Oksana Zhuravlova1d3b59de2019-05-17 00:08:221050 False,
Oksana Zhuravlovafd247772019-05-16 16:57:291051 (
Wezf89dec092019-09-11 19:38:331052 r'^fuchsia/engine/browser/url_request_rewrite_rules_manager\.cc$',
1053 r'^fuchsia/engine/url_request_rewrite_type_converters\.cc$',
Oksana Zhuravlovafd247772019-05-16 16:57:291054 r'^third_party/blink/.*\.(cc|h)$',
1055 r'^content/renderer/.*\.(cc|h)$',
1056 ),
1057 ),
Robert Liao1d78df52019-11-11 20:02:011058 (
Oksana Zhuravlovac8222d22019-12-19 19:21:161059 'GetInterfaceProvider',
1060 (
1061 'InterfaceProvider is deprecated.',
1062 'Please use ExecutionContext::GetBrowserInterfaceBroker and overrides',
1063 'or Platform::GetBrowserInterfaceBroker.'
1064 ),
1065 False,
1066 (),
1067 ),
1068 (
Robert Liao1d78df52019-11-11 20:02:011069 'CComPtr',
1070 (
1071 'New code should use Microsoft::WRL::ComPtr from wrl/client.h as a ',
1072 'replacement for CComPtr from ATL. See http://crbug.com/5027 for more ',
1073 'details.'
1074 ),
1075 False,
1076 (),
1077 ),
Xiaohan Wang72bd2ba2020-02-18 21:38:201078 (
1079 r'/\b(IFACE|STD)METHOD_?\(',
1080 (
1081 'IFACEMETHOD() and STDMETHOD() make code harder to format and read.',
1082 'Instead, always use IFACEMETHODIMP in the declaration.'
1083 ),
1084 False,
1085 [_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
1086 ),
Allen Bauer53b43fb12020-03-12 17:21:471087 (
1088 'set_owned_by_client',
1089 (
1090 'set_owned_by_client is deprecated.',
1091 'views::View already owns the child views by default. This introduces ',
1092 'a competing ownership model which makes the code difficult to reason ',
1093 'about. See http://crbug.com/1044687 for more details.'
1094 ),
1095 False,
1096 (),
1097 ),
Eric Secklerbe6f48d2020-05-06 18:09:121098 (
1099 r'/\bTRACE_EVENT_ASYNC_',
1100 (
1101 'Please use TRACE_EVENT_NESTABLE_ASYNC_.. macros instead',
1102 'of TRACE_EVENT_ASYNC_.. (crbug.com/1038710).',
1103 ),
1104 False,
1105 (
1106 r'^base/trace_event/.*',
1107 r'^base/tracing/.*',
1108 ),
1109 ),
[email protected]127f18ec2012-06-16 05:05:591110)
1111
Mario Sanchez Prada2472cab2019-09-18 10:58:311112# Format: Sequence of tuples containing:
1113# * String pattern or, if starting with a slash, a regular expression.
1114# * Sequence of strings to show when the pattern matches.
1115_DEPRECATED_MOJO_TYPES = (
1116 (
1117 r'/\bmojo::AssociatedBinding\b',
1118 (
1119 'mojo::AssociatedBinding<Interface> is deprecated.',
1120 'Use mojo::AssociatedReceiver<Interface> instead.',
1121 ),
1122 ),
1123 (
1124 r'/\bmojo::AssociatedBindingSet\b',
1125 (
1126 'mojo::AssociatedBindingSet<Interface> is deprecated.',
1127 'Use mojo::AssociatedReceiverSet<Interface> instead.',
1128 ),
1129 ),
1130 (
1131 r'/\bmojo::AssociatedInterfacePtr\b',
1132 (
1133 'mojo::AssociatedInterfacePtr<Interface> is deprecated.',
1134 'Use mojo::AssociatedRemote<Interface> instead.',
1135 ),
1136 ),
1137 (
1138 r'/\bmojo::AssociatedInterfacePtrInfo\b',
1139 (
1140 'mojo::AssociatedInterfacePtrInfo<Interface> is deprecated.',
1141 'Use mojo::PendingAssociatedRemote<Interface> instead.',
1142 ),
1143 ),
1144 (
1145 r'/\bmojo::AssociatedInterfaceRequest\b',
1146 (
1147 'mojo::AssociatedInterfaceRequest<Interface> is deprecated.',
1148 'Use mojo::PendingAssociatedReceiver<Interface> instead.',
1149 ),
1150 ),
1151 (
1152 r'/\bmojo::Binding\b',
1153 (
1154 'mojo::Binding<Interface> is deprecated.',
1155 'Use mojo::Receiver<Interface> instead.',
1156 ),
1157 ),
1158 (
1159 r'/\bmojo::BindingSet\b',
1160 (
1161 'mojo::BindingSet<Interface> is deprecated.',
1162 'Use mojo::ReceiverSet<Interface> instead.',
1163 ),
1164 ),
1165 (
1166 r'/\bmojo::InterfacePtr\b',
1167 (
1168 'mojo::InterfacePtr<Interface> is deprecated.',
1169 'Use mojo::Remote<Interface> instead.',
1170 ),
1171 ),
1172 (
1173 r'/\bmojo::InterfacePtrInfo\b',
1174 (
1175 'mojo::InterfacePtrInfo<Interface> is deprecated.',
1176 'Use mojo::PendingRemote<Interface> instead.',
1177 ),
1178 ),
1179 (
1180 r'/\bmojo::InterfaceRequest\b',
1181 (
1182 'mojo::InterfaceRequest<Interface> is deprecated.',
1183 'Use mojo::PendingReceiver<Interface> instead.',
1184 ),
1185 ),
1186 (
1187 r'/\bmojo::MakeRequest\b',
1188 (
1189 'mojo::MakeRequest is deprecated.',
1190 'Use mojo::Remote::BindNewPipeAndPassReceiver() instead.',
1191 ),
1192 ),
1193 (
1194 r'/\bmojo::MakeRequestAssociatedWithDedicatedPipe\b',
1195 (
1196 'mojo::MakeRequest is deprecated.',
1197 'Use mojo::AssociatedRemote::'
Gyuyoung Kim7dd486c2020-09-15 01:47:181198 'BindNewEndpointAndPassDedicatedReceiver() instead.',
Mario Sanchez Prada2472cab2019-09-18 10:58:311199 ),
1200 ),
1201 (
1202 r'/\bmojo::MakeStrongBinding\b',
1203 (
1204 'mojo::MakeStrongBinding is deprecated.',
1205 'Either migrate to mojo::UniqueReceiverSet, if possible, or use',
1206 'mojo::MakeSelfOwnedReceiver() instead.',
1207 ),
1208 ),
1209 (
1210 r'/\bmojo::MakeStrongAssociatedBinding\b',
1211 (
1212 'mojo::MakeStrongAssociatedBinding is deprecated.',
1213 'Either migrate to mojo::UniqueAssociatedReceiverSet, if possible, or',
1214 'use mojo::MakeSelfOwnedAssociatedReceiver() instead.',
1215 ),
1216 ),
1217 (
Gyuyoung Kim4952ba62020-07-07 07:33:441218 r'/\bmojo::StrongAssociatedBinding\b',
1219 (
1220 'mojo::StrongAssociatedBinding<Interface> is deprecated.',
1221 'Use mojo::MakeSelfOwnedAssociatedReceiver<Interface> instead.',
1222 ),
1223 ),
1224 (
1225 r'/\bmojo::StrongBinding\b',
1226 (
1227 'mojo::StrongBinding<Interface> is deprecated.',
1228 'Use mojo::MakeSelfOwnedReceiver<Interface> instead.',
1229 ),
1230 ),
1231 (
Mario Sanchez Prada2472cab2019-09-18 10:58:311232 r'/\bmojo::StrongAssociatedBindingSet\b',
1233 (
1234 'mojo::StrongAssociatedBindingSet<Interface> is deprecated.',
1235 'Use mojo::UniqueAssociatedReceiverSet<Interface> instead.',
1236 ),
1237 ),
1238 (
1239 r'/\bmojo::StrongBindingSet\b',
1240 (
1241 'mojo::StrongBindingSet<Interface> is deprecated.',
1242 'Use mojo::UniqueReceiverSet<Interface> instead.',
1243 ),
1244 ),
1245)
wnwenbdc444e2016-05-25 13:44:151246
mlamouria82272622014-09-16 18:45:041247_IPC_ENUM_TRAITS_DEPRECATED = (
1248 'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501249 'See http://www.chromium.org/Home/chromium-security/education/'
1250 'security-tips-for-ipc')
mlamouria82272622014-09-16 18:45:041251
Stephen Martinis97a394142018-06-07 23:06:051252_LONG_PATH_ERROR = (
1253 'Some files included in this CL have file names that are too long (> 200'
1254 ' characters). If committed, these files will cause issues on Windows. See'
1255 ' https://crbug.com/612667 for more details.'
1256)
1257
Shenghua Zhangbfaa38b82017-11-16 21:58:021258_JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS = [
Egor Paskoce145c42018-09-28 19:31:041259 r".*[\\/]BuildHooksAndroidImpl\.java",
1260 r".*[\\/]LicenseContentProvider\.java",
1261 r".*[\\/]PlatformServiceBridgeImpl.java",
Patrick Noland5475bc0d2018-10-01 20:04:281262 r".*chrome[\\\/]android[\\\/]feed[\\\/]dummy[\\\/].*\.java",
Shenghua Zhangbfaa38b82017-11-16 21:58:021263]
[email protected]127f18ec2012-06-16 05:05:591264
Mohamed Heikald048240a2019-11-12 16:57:371265# List of image extensions that are used as resources in chromium.
1266_IMAGE_EXTENSIONS = ['.svg', '.png', '.webp']
1267
Sean Kau46e29bc2017-08-28 16:31:161268# These paths contain test data and other known invalid JSON files.
Erik Staab2dd72b12020-04-16 15:03:401269_KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS = [
Egor Paskoce145c42018-09-28 19:31:041270 r'test[\\/]data[\\/]',
Erik Staab2dd72b12020-04-16 15:03:401271 r'testing[\\/]buildbot[\\/]',
Egor Paskoce145c42018-09-28 19:31:041272 r'^components[\\/]policy[\\/]resources[\\/]policy_templates\.json$',
1273 r'^third_party[\\/]protobuf[\\/]',
Egor Paskoce145c42018-09-28 19:31:041274 r'^third_party[\\/]blink[\\/]renderer[\\/]devtools[\\/]protocol\.json$',
Kent Tamura77578cc2018-11-25 22:33:431275 r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]',
Sean Kau46e29bc2017-08-28 16:31:161276]
1277
1278
[email protected]b00342e7f2013-03-26 16:21:541279_VALID_OS_MACROS = (
1280 # Please keep sorted.
rayb0088ee52017-04-26 22:35:081281 'OS_AIX',
[email protected]b00342e7f2013-03-26 16:21:541282 'OS_ANDROID',
Avi Drissman34594e902020-07-25 05:35:441283 'OS_APPLE',
Henrique Nakashimaafff0502018-01-24 17:14:121284 'OS_ASMJS',
[email protected]b00342e7f2013-03-26 16:21:541285 'OS_BSD',
1286 'OS_CAT', # For testing.
1287 'OS_CHROMEOS',
Eugene Kliuchnikovb99125c2018-11-26 17:33:041288 'OS_CYGWIN', # third_party code.
[email protected]b00342e7f2013-03-26 16:21:541289 'OS_FREEBSD',
scottmg2f97ee122017-05-12 17:50:371290 'OS_FUCHSIA',
[email protected]b00342e7f2013-03-26 16:21:541291 'OS_IOS',
1292 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:441293 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:541294 'OS_NACL',
hidehikof7295f22014-10-28 11:57:211295 'OS_NACL_NONSFI',
1296 'OS_NACL_SFI',
krytarowski969759f2016-07-31 23:55:121297 'OS_NETBSD',
[email protected]b00342e7f2013-03-26 16:21:541298 'OS_OPENBSD',
1299 'OS_POSIX',
[email protected]eda7afa12014-02-06 12:27:371300 'OS_QNX',
[email protected]b00342e7f2013-03-26 16:21:541301 'OS_SOLARIS',
[email protected]b00342e7f2013-03-26 16:21:541302 'OS_WIN',
1303)
1304
1305
Andrew Grieveb773bad2020-06-05 18:00:381306# These are not checked on the public chromium-presubmit trybot.
1307# Add files here that rely on .py files that exists only for target_os="android"
Samuel Huangc2f5d6bb2020-08-17 23:46:041308# checkouts.
agrievef32bcc72016-04-04 14:57:401309_ANDROID_SPECIFIC_PYDEPS_FILES = [
Andrew Grieveb773bad2020-06-05 18:00:381310 'chrome/android/features/create_stripped_java_factory.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381311]
1312
1313
1314_GENERIC_PYDEPS_FILES = [
Samuel Huangc2f5d6bb2020-08-17 23:46:041315 'android_webview/tools/run_cts.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361316 'base/android/jni_generator/jni_generator.pydeps',
1317 'base/android/jni_generator/jni_registration_generator.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041318 'build/android/devil_chromium.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361319 'build/android/gyp/aar.pydeps',
1320 'build/android/gyp/aidl.pydeps',
Tibor Goldschwendt0bef2d7a2019-10-24 21:19:271321 'build/android/gyp/allot_native_libraries.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361322 'build/android/gyp/apkbuilder.pydeps',
Andrew Grievea417ad302019-02-06 19:54:381323 'build/android/gyp/assert_static_initializers.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361324 'build/android/gyp/bytecode_processor.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111325 'build/android/gyp/compile_java.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361326 'build/android/gyp/compile_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361327 'build/android/gyp/copy_ex.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361328 'build/android/gyp/create_apk_operations_script.pydeps',
Andrew Grieve8d083ea2019-12-13 06:49:111329 'build/android/gyp/create_app_bundle.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041330 'build/android/gyp/create_app_bundle_apks.pydeps',
1331 'build/android/gyp/create_bundle_wrapper_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361332 'build/android/gyp/create_java_binary_script.pydeps',
Mohamed Heikaladbe4e482020-07-09 19:25:121333 'build/android/gyp/create_r_java.pydeps',
Andrew Grieveb838d832019-02-11 16:55:221334 'build/android/gyp/create_size_info_files.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001335 'build/android/gyp/create_ui_locale_resources.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361336 'build/android/gyp/desugar.pydeps',
1337 'build/android/gyp/dex.pydeps',
Andrew Grieve723c1502020-04-23 16:27:421338 'build/android/gyp/dex_jdk_libs.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041339 'build/android/gyp/dexsplitter.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361340 'build/android/gyp/dist_aar.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361341 'build/android/gyp/filter_zip.pydeps',
1342 'build/android/gyp/gcc_preprocess.pydeps',
Christopher Grant99e0e20062018-11-21 21:22:361343 'build/android/gyp/generate_linker_version_script.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361344 'build/android/gyp/ijar.pydeps',
Yun Liueb4075ddf2019-05-13 19:47:581345 'build/android/gyp/jacoco_instr.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361346 'build/android/gyp/java_cpp_enum.pydeps',
Nate Fischerac07b2622020-10-01 20:20:141347 'build/android/gyp/java_cpp_features.pydeps',
Ian Vollickb99472e2019-03-07 21:35:261348 'build/android/gyp/java_cpp_strings.pydeps',
Andrew Grieve5853fbd2020-02-20 17:26:011349 'build/android/gyp/jetify_jar.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041350 'build/android/gyp/jinja_template.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361351 'build/android/gyp/lint.pydeps',
1352 'build/android/gyp/main_dex_list.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361353 'build/android/gyp/merge_manifest.pydeps',
1354 'build/android/gyp/prepare_resources.pydeps',
Mohamed Heikalf85138b2020-10-06 15:43:221355 'build/android/gyp/process_native_prebuilt.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361356 'build/android/gyp/proguard.pydeps',
Peter Wen578730b2020-03-19 19:55:461357 'build/android/gyp/turbine.pydeps',
Eric Stevensona82cf6082019-07-24 14:35:241358 'build/android/gyp/validate_static_library_dex_references.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361359 'build/android/gyp/write_build_config.pydeps',
Tibor Goldschwendtc4caae92019-07-12 00:33:461360 'build/android/gyp/write_native_libraries_java.pydeps',
Andrew Grieve9ff17792018-11-30 04:55:561361 'build/android/gyp/zip.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361362 'build/android/incremental_install/generate_android_manifest.pydeps',
1363 'build/android/incremental_install/write_installer_json.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041364 'build/android/resource_sizes.pydeps',
1365 'build/android/test_runner.pydeps',
1366 'build/android/test_wrapper/logdog_wrapper.pydeps',
Samuel Huange65eb3f12020-08-14 19:04:361367 'build/lacros/lacros_resource_sizes.pydeps',
David 'Digit' Turner0006f4732018-08-07 07:12:361368 'build/protoc_java.pydeps',
Peter Kotwicz64667b02020-10-18 06:43:321369 'chrome/android/monochrome/scripts/monochrome_python_tests.pydeps',
Peter Wenefb56c72020-06-04 15:12:271370 'chrome/test/chromedriver/log_replay/client_replay_unittest.pydeps',
1371 'chrome/test/chromedriver/test/run_py_tests.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001372 'components/cronet/tools/generate_javadoc.pydeps',
1373 'components/cronet/tools/jar_src.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381374 'components/module_installer/android/module_desc_java.pydeps',
Andrew Grieve5a01ad32020-06-25 18:06:001375 'content/public/android/generate_child_service.pydeps',
Andrew Grieveb773bad2020-06-05 18:00:381376 'net/tools/testserver/testserver.pydeps',
Samuel Huangc2f5d6bb2020-08-17 23:46:041377 'testing/scripts/run_android_wpt.pydeps',
1378 'third_party/android_platform/development/scripts/stack.pydeps',
Hitoshi Yoshida0f228c42019-08-07 09:37:421379 'third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps',
1380 'third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps',
Yuki Shiinoe7827aa2019-09-13 12:26:131381 'third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps',
Caleb Raitto28864fc2020-01-07 00:18:191382 ('third_party/blink/renderer/bindings/scripts/'
1383 'generate_high_entropy_list.pydeps'),
John Budorickbc3571aa2019-04-25 02:20:061384 'tools/binary_size/sizes.pydeps',
Andrew Grievea7f1ee902018-05-18 16:17:221385 'tools/binary_size/supersize.pydeps',
agrievef32bcc72016-04-04 14:57:401386]
1387
wnwenbdc444e2016-05-25 13:44:151388
agrievef32bcc72016-04-04 14:57:401389_ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
1390
1391
Eric Boren6fd2b932018-01-25 15:05:081392# Bypass the AUTHORS check for these accounts.
1393_KNOWN_ROBOTS = set(
Sergiy Byelozyorov47158a52018-06-13 22:38:591394 ) | set('%[email protected]' % s for s in ('findit-for-me',)
Achuith Bhandarkar35905562018-07-25 19:28:451395 ) | set('%[email protected]' % s for s in ('3su6n15k.default',)
Sergiy Byelozyorov47158a52018-06-13 22:38:591396 ) | set('%[email protected]' % s
smutde797052019-12-04 02:03:521397 for s in ('bling-autoroll-builder', 'v8-ci-autoroll-builder',
Rakib M. Hasan015291ed2020-10-14 17:13:071398 'wpt-autoroller', 'chrome-weblayer-builder')
Eric Boren835d71f2018-09-07 21:09:041399 ) | set('%[email protected]' % s
Eric Boren66150e52020-01-08 11:20:271400 for s in ('chromium-autoroll', 'chromium-release-autoroll')
Eric Boren835d71f2018-09-07 21:09:041401 ) | set('%[email protected]' % s
Eric Boren2b7e3c3c2018-09-13 18:14:301402 for s in ('chromium-internal-autoroll',))
Eric Boren6fd2b932018-01-25 15:05:081403
1404
Daniel Bratell65b033262019-04-23 08:17:061405def _IsCPlusPlusFile(input_api, file_path):
1406 """Returns True if this file contains C++-like code (and not Python,
1407 Go, Java, MarkDown, ...)"""
1408
1409 ext = input_api.os_path.splitext(file_path)[1]
1410 # This list is compatible with CppChecker.IsCppFile but we should
1411 # consider adding ".c" to it. If we do that we can use this function
1412 # at more places in the code.
1413 return ext in (
1414 '.h',
1415 '.cc',
1416 '.cpp',
1417 '.m',
1418 '.mm',
1419 )
1420
1421def _IsCPlusPlusHeaderFile(input_api, file_path):
1422 return input_api.os_path.splitext(file_path)[1] == ".h"
1423
1424
1425def _IsJavaFile(input_api, file_path):
1426 return input_api.os_path.splitext(file_path)[1] == ".java"
1427
1428
1429def _IsProtoFile(input_api, file_path):
1430 return input_api.os_path.splitext(file_path)[1] == ".proto"
1431
Saagar Sanghavifceeaae2020-08-12 16:40:361432def CheckNoProductionCodeUsingTestOnlyFunctions(input_api, output_api):
[email protected]55459852011-08-10 15:17:191433 """Attempts to prevent use of functions intended only for testing in
1434 non-testing code. For now this is just a best-effort implementation
1435 that ignores header files and may have some false positives. A
1436 better implementation would probably need a proper C++ parser.
1437 """
1438 # We only scan .cc files and the like, as the declaration of
1439 # for-testing functions in header files are hard to distinguish from
1440 # calls to such functions without a proper C++ parser.
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:491441 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
[email protected]55459852011-08-10 15:17:191442
jochenc0d4808c2015-07-27 09:25:421443 base_function_pattern = r'[ :]test::[^\s]+|ForTest(s|ing)?|for_test(s|ing)?'
[email protected]55459852011-08-10 15:17:191444 inclusion_pattern = input_api.re.compile(r'(%s)\s*\(' % base_function_pattern)
[email protected]23501822014-05-14 02:06:091445 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_function_pattern)
danakjf26536bf2020-09-10 00:46:131446 allowlist_pattern = input_api.re.compile(r'// IN-TEST$')
[email protected]55459852011-08-10 15:17:191447 exclusion_pattern = input_api.re.compile(
1448 r'::[A-Za-z0-9_]+(%s)|(%s)[^;]+\{' % (
1449 base_function_pattern, base_function_pattern))
danakjf26536bf2020-09-10 00:46:131450 # Avoid a false positive in this case, where the method name, the ::, and
1451 # the closing { are all on different lines due to line wrapping.
1452 # HelperClassForTesting::
1453 # HelperClassForTesting(
1454 # args)
1455 # : member(0) {}
1456 method_defn_pattern = input_api.re.compile(r'[A-Za-z0-9_]+::$')
[email protected]55459852011-08-10 15:17:191457
1458 def FilterFile(affected_file):
James Cook24a504192020-07-23 00:08:441459 files_to_skip = (_EXCLUDED_PATHS +
1460 _TEST_CODE_EXCLUDED_PATHS +
1461 input_api.DEFAULT_FILES_TO_SKIP)
[email protected]55459852011-08-10 15:17:191462 return input_api.FilterSourceFile(
1463 affected_file,
James Cook24a504192020-07-23 00:08:441464 files_to_check=file_inclusion_pattern,
1465 files_to_skip=files_to_skip)
[email protected]55459852011-08-10 15:17:191466
1467 problems = []
1468 for f in input_api.AffectedSourceFiles(FilterFile):
1469 local_path = f.LocalPath()
danakjf26536bf2020-09-10 00:46:131470 in_method_defn = False
[email protected]825d27182014-01-02 21:24:241471 for line_number, line in f.ChangedContents():
[email protected]2fdd1f362013-01-16 03:56:031472 if (inclusion_pattern.search(line) and
[email protected]de4f7d22013-05-23 14:27:461473 not comment_pattern.search(line) and
danakjf26536bf2020-09-10 00:46:131474 not exclusion_pattern.search(line) and
1475 not allowlist_pattern.search(line) and
1476 not in_method_defn):
[email protected]55459852011-08-10 15:17:191477 problems.append(
[email protected]2fdd1f362013-01-16 03:56:031478 '%s:%d\n %s' % (local_path, line_number, line.strip()))
danakjf26536bf2020-09-10 00:46:131479 in_method_defn = method_defn_pattern.search(line)
[email protected]55459852011-08-10 15:17:191480
1481 if problems:
[email protected]f7051d52013-04-02 18:31:421482 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
[email protected]2fdd1f362013-01-16 03:56:031483 else:
1484 return []
[email protected]55459852011-08-10 15:17:191485
1486
Saagar Sanghavifceeaae2020-08-12 16:40:361487def CheckNoProductionCodeUsingTestOnlyFunctionsJava(input_api, output_api):
Vaclav Brozek7dbc28c2018-03-27 08:35:231488 """This is a simplified version of
Saagar Sanghavi0bc3e692020-08-13 19:46:591489 CheckNoProductionCodeUsingTestOnlyFunctions for Java files.
Vaclav Brozek7dbc28c2018-03-27 08:35:231490 """
1491 javadoc_start_re = input_api.re.compile(r'^\s*/\*\*')
1492 javadoc_end_re = input_api.re.compile(r'^\s*\*/')
1493 name_pattern = r'ForTest(s|ing)?'
1494 # Describes an occurrence of "ForTest*" inside a // comment.
1495 comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
Peter Wen6367b882020-08-05 16:55:501496 # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
Sky Malice9e6d6032020-10-15 22:49:551497 annotation_re = input_api.re.compile(r'@VisibleForTesting\(')
Vaclav Brozek7dbc28c2018-03-27 08:35:231498 # Catch calls.
1499 inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
1500 # Ignore definitions. (Comments are ignored separately.)
1501 exclusion_re = input_api.re.compile(r'(%s)[^;]+\{' % name_pattern)
1502
1503 problems = []
1504 sources = lambda x: input_api.FilterSourceFile(
1505 x,
James Cook24a504192020-07-23 00:08:441506 files_to_skip=(('(?i).*test', r'.*\/junit\/')
1507 + input_api.DEFAULT_FILES_TO_SKIP),
1508 files_to_check=[r'.*\.java$']
Vaclav Brozek7dbc28c2018-03-27 08:35:231509 )
1510 for f in input_api.AffectedFiles(include_deletes=False, file_filter=sources):
1511 local_path = f.LocalPath()
1512 is_inside_javadoc = False
1513 for line_number, line in f.ChangedContents():
1514 if is_inside_javadoc and javadoc_end_re.search(line):
1515 is_inside_javadoc = False
1516 if not is_inside_javadoc and javadoc_start_re.search(line):
1517 is_inside_javadoc = True
1518 if is_inside_javadoc:
1519 continue
1520 if (inclusion_re.search(line) and
1521 not comment_re.search(line) and
Peter Wen6367b882020-08-05 16:55:501522 not annotation_re.search(line) and
Vaclav Brozek7dbc28c2018-03-27 08:35:231523 not exclusion_re.search(line)):
1524 problems.append(
1525 '%s:%d\n %s' % (local_path, line_number, line.strip()))
1526
1527 if problems:
1528 return [output_api.PresubmitPromptOrNotify(_TEST_ONLY_WARNING, problems)]
1529 else:
1530 return []
1531
1532
Saagar Sanghavifceeaae2020-08-12 16:40:361533def CheckNoIOStreamInHeaders(input_api, output_api):
[email protected]10689ca2011-09-02 02:31:541534 """Checks to make sure no .h files include <iostream>."""
1535 files = []
1536 pattern = input_api.re.compile(r'^#include\s*<iostream>',
1537 input_api.re.MULTILINE)
1538 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1539 if not f.LocalPath().endswith('.h'):
1540 continue
1541 contents = input_api.ReadFile(f)
1542 if pattern.search(contents):
1543 files.append(f)
1544
1545 if len(files):
yolandyandaabc6d2016-04-18 18:29:391546 return [output_api.PresubmitError(
[email protected]6c063c62012-07-11 19:11:061547 'Do not #include <iostream> in header files, since it inserts static '
1548 'initialization into every file including the header. Instead, '
[email protected]10689ca2011-09-02 02:31:541549 '#include <ostream>. See http://crbug.com/94794',
1550 files) ]
1551 return []
1552
Danil Chapovalov3518f362018-08-11 16:13:431553def _CheckNoStrCatRedefines(input_api, output_api):
1554 """Checks no windows headers with StrCat redefined are included directly."""
1555 files = []
1556 pattern_deny = input_api.re.compile(
1557 r'^#include\s*[<"](shlwapi|atlbase|propvarutil|sphelper).h[">]',
1558 input_api.re.MULTILINE)
1559 pattern_allow = input_api.re.compile(
1560 r'^#include\s"base/win/windows_defines.inc"',
1561 input_api.re.MULTILINE)
1562 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1563 contents = input_api.ReadFile(f)
1564 if pattern_deny.search(contents) and not pattern_allow.search(contents):
1565 files.append(f.LocalPath())
1566
1567 if len(files):
1568 return [output_api.PresubmitError(
1569 'Do not #include shlwapi.h, atlbase.h, propvarutil.h or sphelper.h '
1570 'directly since they pollute code with StrCat macro. Instead, '
1571 'include matching header from base/win. See http://crbug.com/856536',
1572 files) ]
1573 return []
1574
[email protected]10689ca2011-09-02 02:31:541575
Saagar Sanghavifceeaae2020-08-12 16:40:361576def CheckNoUNIT_TESTInSourceFiles(input_api, output_api):
danakj61c1aa22015-10-26 19:55:521577 """Checks to make sure no source files use UNIT_TEST."""
[email protected]72df4e782012-06-21 16:28:181578 problems = []
1579 for f in input_api.AffectedFiles():
1580 if (not f.LocalPath().endswith(('.cc', '.mm'))):
1581 continue
1582
1583 for line_num, line in f.ChangedContents():
[email protected]549f86a2013-11-19 13:00:041584 if 'UNIT_TEST ' in line or line.endswith('UNIT_TEST'):
[email protected]72df4e782012-06-21 16:28:181585 problems.append(' %s:%d' % (f.LocalPath(), line_num))
1586
1587 if not problems:
1588 return []
1589 return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' +
1590 '\n'.join(problems))]
1591
Saagar Sanghavifceeaae2020-08-12 16:40:361592def CheckNoDISABLETypoInTests(input_api, output_api):
Dominic Battre033531052018-09-24 15:45:341593 """Checks to prevent attempts to disable tests with DISABLE_ prefix.
1594
1595 This test warns if somebody tries to disable a test with the DISABLE_ prefix
1596 instead of DISABLED_. To filter false positives, reports are only generated
1597 if a corresponding MAYBE_ line exists.
1598 """
1599 problems = []
1600
1601 # The following two patterns are looked for in tandem - is a test labeled
1602 # as MAYBE_ followed by a DISABLE_ (instead of the correct DISABLED)
1603 maybe_pattern = input_api.re.compile(r'MAYBE_([a-zA-Z0-9_]+)')
1604 disable_pattern = input_api.re.compile(r'DISABLE_([a-zA-Z0-9_]+)')
1605
1606 # This is for the case that a test is disabled on all platforms.
1607 full_disable_pattern = input_api.re.compile(
1608 r'^\s*TEST[^(]*\([a-zA-Z0-9_]+,\s*DISABLE_[a-zA-Z0-9_]+\)',
1609 input_api.re.MULTILINE)
1610
Katie Df13948e2018-09-25 07:33:441611 for f in input_api.AffectedFiles(False):
Dominic Battre033531052018-09-24 15:45:341612 if not 'test' in f.LocalPath() or not f.LocalPath().endswith('.cc'):
1613 continue
1614
1615 # Search for MABYE_, DISABLE_ pairs.
1616 disable_lines = {} # Maps of test name to line number.
1617 maybe_lines = {}
1618 for line_num, line in f.ChangedContents():
1619 disable_match = disable_pattern.search(line)
1620 if disable_match:
1621 disable_lines[disable_match.group(1)] = line_num
1622 maybe_match = maybe_pattern.search(line)
1623 if maybe_match:
1624 maybe_lines[maybe_match.group(1)] = line_num
1625
1626 # Search for DISABLE_ occurrences within a TEST() macro.
1627 disable_tests = set(disable_lines.keys())
1628 maybe_tests = set(maybe_lines.keys())
1629 for test in disable_tests.intersection(maybe_tests):
1630 problems.append(' %s:%d' % (f.LocalPath(), disable_lines[test]))
1631
1632 contents = input_api.ReadFile(f)
1633 full_disable_match = full_disable_pattern.search(contents)
1634 if full_disable_match:
1635 problems.append(' %s' % f.LocalPath())
1636
1637 if not problems:
1638 return []
1639 return [
1640 output_api.PresubmitPromptWarning(
1641 'Attempt to disable a test with DISABLE_ instead of DISABLED_?\n' +
1642 '\n'.join(problems))
1643 ]
1644
[email protected]72df4e782012-06-21 16:28:181645
Saagar Sanghavifceeaae2020-08-12 16:40:361646def CheckDCHECK_IS_ONHasBraces(input_api, output_api):
kjellanderaee306632017-02-22 19:26:571647 """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
danakj61c1aa22015-10-26 19:55:521648 errors = []
Hans Wennborg944479f2020-06-25 21:39:251649 pattern = input_api.re.compile(r'DCHECK_IS_ON\b(?!\(\))',
danakj61c1aa22015-10-26 19:55:521650 input_api.re.MULTILINE)
1651 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1652 if (not f.LocalPath().endswith(('.cc', '.mm', '.h'))):
1653 continue
1654 for lnum, line in f.ChangedContents():
1655 if input_api.re.search(pattern, line):
dchenge07de812016-06-20 19:27:171656 errors.append(output_api.PresubmitError(
1657 ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
kjellanderaee306632017-02-22 19:26:571658 'DCHECK_IS_ON()", not forgetting the parentheses.')
dchenge07de812016-06-20 19:27:171659 % (f.LocalPath(), lnum)))
danakj61c1aa22015-10-26 19:55:521660 return errors
1661
1662
Makoto Shimazu3ad422cd2019-05-08 02:35:141663def _FindHistogramNameInChunk(histogram_name, chunk):
1664 """Tries to find a histogram name or prefix in a line.
1665
1666 Returns the existence of the histogram name, or None if it needs more chunk
1667 to determine."""
mcasasb7440c282015-02-04 14:52:191668 # A histogram_suffixes tag type has an affected-histogram name as a prefix of
1669 # the histogram_name.
Makoto Shimazu3ad422cd2019-05-08 02:35:141670 if '<affected-histogram' in chunk:
1671 # If the tag is not completed, needs more chunk to get the name.
1672 if not '>' in chunk:
1673 return None
1674 if not 'name="' in chunk:
1675 return False
1676 # Retrieve the first portion of the chunk wrapped by double-quotations. We
1677 # expect the only attribute is the name.
1678 histogram_prefix = chunk.split('"')[1]
1679 return histogram_prefix in histogram_name
1680 # Typically the whole histogram name should in the line.
1681 return histogram_name in chunk
mcasasb7440c282015-02-04 14:52:191682
1683
Saagar Sanghavifceeaae2020-08-12 16:40:361684def CheckUmaHistogramChangesOnUpload(input_api, output_api):
mcasasb7440c282015-02-04 14:52:191685 """Check that UMA histogram names in touched lines can still be found in other
1686 lines of the patch or in histograms.xml. Note that this check would not catch
1687 the reverse: changes in histograms.xml not matched in the code itself."""
1688 touched_histograms = []
1689 histograms_xml_modifications = []
Vaclav Brozekbdac817c2018-03-24 06:30:471690 call_pattern_c = r'\bUMA_HISTOGRAM.*\('
1691 call_pattern_java = r'\bRecordHistogram\.record[a-zA-Z]+Histogram\('
1692 name_pattern = r'"(.*?)"'
1693 single_line_c_re = input_api.re.compile(call_pattern_c + name_pattern)
1694 single_line_java_re = input_api.re.compile(call_pattern_java + name_pattern)
1695 split_line_c_prefix_re = input_api.re.compile(call_pattern_c)
1696 split_line_java_prefix_re = input_api.re.compile(call_pattern_java)
1697 split_line_suffix_re = input_api.re.compile(r'^\s*' + name_pattern)
Vaclav Brozek0e730cbd2018-03-24 06:18:171698 last_line_matched_prefix = False
mcasasb7440c282015-02-04 14:52:191699 for f in input_api.AffectedFiles():
1700 # If histograms.xml itself is modified, keep the modified lines for later.
1701 if f.LocalPath().endswith(('histograms.xml')):
1702 histograms_xml_modifications = f.ChangedContents()
1703 continue
Vaclav Brozekbdac817c2018-03-24 06:30:471704 if f.LocalPath().endswith(('cc', 'mm', 'cpp')):
1705 single_line_re = single_line_c_re
1706 split_line_prefix_re = split_line_c_prefix_re
1707 elif f.LocalPath().endswith(('java')):
1708 single_line_re = single_line_java_re
1709 split_line_prefix_re = split_line_java_prefix_re
1710 else:
mcasasb7440c282015-02-04 14:52:191711 continue
1712 for line_num, line in f.ChangedContents():
Vaclav Brozek0e730cbd2018-03-24 06:18:171713 if last_line_matched_prefix:
1714 suffix_found = split_line_suffix_re.search(line)
1715 if suffix_found :
1716 touched_histograms.append([suffix_found.group(1), f, line_num])
1717 last_line_matched_prefix = False
1718 continue
Vaclav Brozek8a8e2e202018-03-23 22:01:061719 found = single_line_re.search(line)
mcasasb7440c282015-02-04 14:52:191720 if found:
1721 touched_histograms.append([found.group(1), f, line_num])
Vaclav Brozek0e730cbd2018-03-24 06:18:171722 continue
1723 last_line_matched_prefix = split_line_prefix_re.search(line)
mcasasb7440c282015-02-04 14:52:191724
1725 # Search for the touched histogram names in the local modifications to
1726 # histograms.xml, and, if not found, on the base histograms.xml file.
1727 unmatched_histograms = []
1728 for histogram_info in touched_histograms:
1729 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141730 chunk = ''
mcasasb7440c282015-02-04 14:52:191731 for line_num, line in histograms_xml_modifications:
Makoto Shimazu3ad422cd2019-05-08 02:35:141732 chunk += line
1733 histogram_name_found = _FindHistogramNameInChunk(histogram_info[0], chunk)
1734 if histogram_name_found is None:
1735 continue
1736 chunk = ''
mcasasb7440c282015-02-04 14:52:191737 if histogram_name_found:
1738 break
1739 if not histogram_name_found:
1740 unmatched_histograms.append(histogram_info)
1741
eromanb90c82e7e32015-04-01 15:13:491742 histograms_xml_path = 'tools/metrics/histograms/histograms.xml'
mcasasb7440c282015-02-04 14:52:191743 problems = []
1744 if unmatched_histograms:
eromanb90c82e7e32015-04-01 15:13:491745 with open(histograms_xml_path) as histograms_xml:
mcasasb7440c282015-02-04 14:52:191746 for histogram_name, f, line_num in unmatched_histograms:
mcasas39c1b8b2015-02-25 15:33:451747 histograms_xml.seek(0)
mcasasb7440c282015-02-04 14:52:191748 histogram_name_found = False
Makoto Shimazu3ad422cd2019-05-08 02:35:141749 chunk = ''
mcasasb7440c282015-02-04 14:52:191750 for line in histograms_xml:
Makoto Shimazu3ad422cd2019-05-08 02:35:141751 chunk += line
1752 histogram_name_found = _FindHistogramNameInChunk(histogram_name,
1753 chunk)
1754 if histogram_name_found is None:
1755 continue
1756 chunk = ''
mcasasb7440c282015-02-04 14:52:191757 if histogram_name_found:
1758 break
1759 if not histogram_name_found:
1760 problems.append(' [%s:%d] %s' %
1761 (f.LocalPath(), line_num, histogram_name))
1762
1763 if not problems:
1764 return []
1765 return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
1766 'been modified and the associated histogram name has no match in either '
eromanb90c82e7e32015-04-01 15:13:491767 '%s or the modifications of it:' % (histograms_xml_path), problems)]
mcasasb7440c282015-02-04 14:52:191768
wnwenbdc444e2016-05-25 13:44:151769
Saagar Sanghavifceeaae2020-08-12 16:40:361770def CheckFlakyTestUsage(input_api, output_api):
yolandyandaabc6d2016-04-18 18:29:391771 """Check that FlakyTest annotation is our own instead of the android one"""
1772 pattern = input_api.re.compile(r'import android.test.FlakyTest;')
1773 files = []
1774 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
1775 if f.LocalPath().endswith('Test.java'):
1776 if pattern.search(input_api.ReadFile(f)):
1777 files.append(f)
1778 if len(files):
1779 return [output_api.PresubmitError(
1780 'Use org.chromium.base.test.util.FlakyTest instead of '
1781 'android.test.FlakyTest',
1782 files)]
1783 return []
mcasasb7440c282015-02-04 14:52:191784
wnwenbdc444e2016-05-25 13:44:151785
Saagar Sanghavifceeaae2020-08-12 16:40:361786def CheckNoNewWStrings(input_api, output_api):
[email protected]8ea5d4b2011-09-13 21:49:221787 """Checks to make sure we don't introduce use of wstrings."""
[email protected]55463aa62011-10-12 00:48:271788 problems = []
[email protected]8ea5d4b2011-09-13 21:49:221789 for f in input_api.AffectedFiles():
[email protected]b5c24292011-11-28 14:38:201790 if (not f.LocalPath().endswith(('.cc', '.h')) or
scottmge6f04402014-11-05 01:59:571791 f.LocalPath().endswith(('test.cc', '_win.cc', '_win.h')) or
pennymac84fd6692016-07-13 22:35:341792 '/win/' in f.LocalPath() or
1793 'chrome_elf' in f.LocalPath() or
1794 'install_static' in f.LocalPath()):
[email protected]b5c24292011-11-28 14:38:201795 continue
[email protected]8ea5d4b2011-09-13 21:49:221796
[email protected]a11dbe9b2012-08-07 01:32:581797 allowWString = False
[email protected]b5c24292011-11-28 14:38:201798 for line_num, line in f.ChangedContents():
[email protected]a11dbe9b2012-08-07 01:32:581799 if 'presubmit: allow wstring' in line:
1800 allowWString = True
1801 elif not allowWString and 'wstring' in line:
[email protected]55463aa62011-10-12 00:48:271802 problems.append(' %s:%d' % (f.LocalPath(), line_num))
[email protected]a11dbe9b2012-08-07 01:32:581803 allowWString = False
1804 else:
1805 allowWString = False
[email protected]8ea5d4b2011-09-13 21:49:221806
[email protected]55463aa62011-10-12 00:48:271807 if not problems:
1808 return []
1809 return [output_api.PresubmitPromptWarning('New code should not use wstrings.'
[email protected]a11dbe9b2012-08-07 01:32:581810 ' If you are calling a cross-platform API that accepts a wstring, '
1811 'fix the API.\n' +
[email protected]55463aa62011-10-12 00:48:271812 '\n'.join(problems))]
[email protected]8ea5d4b2011-09-13 21:49:221813
1814
Saagar Sanghavifceeaae2020-08-12 16:40:361815def CheckNoDEPSGIT(input_api, output_api):
[email protected]2a8ac9c2011-10-19 17:20:441816 """Make sure .DEPS.git is never modified manually."""
1817 if any(f.LocalPath().endswith('.DEPS.git') for f in
1818 input_api.AffectedFiles()):
1819 return [output_api.PresubmitError(
1820 'Never commit changes to .DEPS.git. This file is maintained by an\n'
1821 'automated system based on what\'s in DEPS and your changes will be\n'
1822 'overwritten.\n'
Vaclav Brozekd5de76a2018-03-17 07:57:501823 'See https://sites.google.com/a/chromium.org/dev/developers/how-tos/'
1824 'get-the-code#Rolling_DEPS\n'
[email protected]2a8ac9c2011-10-19 17:20:441825 'for more information')]
1826 return []
1827
1828
Saagar Sanghavifceeaae2020-08-12 16:40:361829def CheckValidHostsInDEPSOnUpload(input_api, output_api):
tandriief664692014-09-23 14:51:471830 """Checks that DEPS file deps are from allowed_hosts."""
1831 # Run only if DEPS file has been modified to annoy fewer bystanders.
1832 if all(f.LocalPath() != 'DEPS' for f in input_api.AffectedFiles()):
1833 return []
1834 # Outsource work to gclient verify
1835 try:
John Budorickf20c0042019-04-25 23:23:401836 gclient_path = input_api.os_path.join(
1837 input_api.PresubmitLocalPath(),
1838 'third_party', 'depot_tools', 'gclient.py')
1839 input_api.subprocess.check_output(
1840 [input_api.python_executable, gclient_path, 'verify'],
1841 stderr=input_api.subprocess.STDOUT)
tandriief664692014-09-23 14:51:471842 return []
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:201843 except input_api.subprocess.CalledProcessError as error:
tandriief664692014-09-23 14:51:471844 return [output_api.PresubmitError(
1845 'DEPS file must have only git dependencies.',
1846 long_text=error.output)]
1847
1848
Mario Sanchez Prada2472cab2019-09-18 10:58:311849def _GetMessageForMatchingType(input_api, affected_file, line_number, line,
1850 type_name, message):
Saagar Sanghavi0bc3e692020-08-13 19:46:591851 """Helper method for CheckNoBannedFunctions and CheckNoDeprecatedMojoTypes.
Mario Sanchez Prada2472cab2019-09-18 10:58:311852
1853 Returns an string composed of the name of the file, the line number where the
1854 match has been found and the additional text passed as |message| in case the
1855 target type name matches the text inside the line passed as parameter.
1856 """
Peng Huang9c5949a02020-06-11 19:20:541857 result = []
1858
1859 if line.endswith(" nocheck"):
1860 return result
1861
Mario Sanchez Prada2472cab2019-09-18 10:58:311862 matched = False
1863 if type_name[0:1] == '/':
1864 regex = type_name[1:]
1865 if input_api.re.search(regex, line):
1866 matched = True
1867 elif type_name in line:
1868 matched = True
1869
Mario Sanchez Prada2472cab2019-09-18 10:58:311870 if matched:
1871 result.append(' %s:%d:' % (affected_file.LocalPath(), line_number))
1872 for message_line in message:
1873 result.append(' %s' % message_line)
1874
1875 return result
1876
1877
Saagar Sanghavifceeaae2020-08-12 16:40:361878def CheckNoBannedFunctions(input_api, output_api):
[email protected]127f18ec2012-06-16 05:05:591879 """Make sure that banned functions are not used."""
1880 warnings = []
1881 errors = []
1882
James Cook24a504192020-07-23 00:08:441883 def IsExcludedFile(affected_file, excluded_paths):
wnwenbdc444e2016-05-25 13:44:151884 local_path = affected_file.LocalPath()
James Cook24a504192020-07-23 00:08:441885 for item in excluded_paths:
wnwenbdc444e2016-05-25 13:44:151886 if input_api.re.match(item, local_path):
1887 return True
1888 return False
1889
Peter K. Lee6c03ccff2019-07-15 14:40:051890 def IsIosObjcFile(affected_file):
Sylvain Defresnea8b73d252018-02-28 15:45:541891 local_path = affected_file.LocalPath()
1892 if input_api.os_path.splitext(local_path)[-1] not in ('.mm', '.m', '.h'):
1893 return False
1894 basename = input_api.os_path.basename(local_path)
1895 if 'ios' in basename.split('_'):
1896 return True
1897 for sep in (input_api.os_path.sep, input_api.os_path.altsep):
1898 if sep and 'ios' in local_path.split(sep):
1899 return True
1900 return False
1901
wnwenbdc444e2016-05-25 13:44:151902 def CheckForMatch(affected_file, line_num, line, func_name, message, error):
Mario Sanchez Prada2472cab2019-09-18 10:58:311903 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1904 func_name, message)
1905 if problems:
wnwenbdc444e2016-05-25 13:44:151906 if error:
Mario Sanchez Prada2472cab2019-09-18 10:58:311907 errors.extend(problems)
1908 else:
1909 warnings.extend(problems)
wnwenbdc444e2016-05-25 13:44:151910
Eric Stevensona9a980972017-09-23 00:04:411911 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1912 for f in input_api.AffectedFiles(file_filter=file_filter):
1913 for line_num, line in f.ChangedContents():
1914 for func_name, message, error in _BANNED_JAVA_FUNCTIONS:
1915 CheckForMatch(f, line_num, line, func_name, message, error)
1916
[email protected]127f18ec2012-06-16 05:05:591917 file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
1918 for f in input_api.AffectedFiles(file_filter=file_filter):
1919 for line_num, line in f.ChangedContents():
1920 for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
wnwenbdc444e2016-05-25 13:44:151921 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591922
Peter K. Lee6c03ccff2019-07-15 14:40:051923 for f in input_api.AffectedFiles(file_filter=IsIosObjcFile):
Sylvain Defresnea8b73d252018-02-28 15:45:541924 for line_num, line in f.ChangedContents():
1925 for func_name, message, error in _BANNED_IOS_OBJC_FUNCTIONS:
1926 CheckForMatch(f, line_num, line, func_name, message, error)
1927
Peter K. Lee6c03ccff2019-07-15 14:40:051928 egtest_filter = lambda f: f.LocalPath().endswith(('_egtest.mm'))
1929 for f in input_api.AffectedFiles(file_filter=egtest_filter):
1930 for line_num, line in f.ChangedContents():
1931 for func_name, message, error in _BANNED_IOS_EGTEST_FUNCTIONS:
1932 CheckForMatch(f, line_num, line, func_name, message, error)
1933
[email protected]127f18ec2012-06-16 05:05:591934 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1935 for f in input_api.AffectedFiles(file_filter=file_filter):
1936 for line_num, line in f.ChangedContents():
[email protected]7345da02012-11-27 14:31:491937 for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
James Cook24a504192020-07-23 00:08:441938 if IsExcludedFile(f, excluded_paths):
[email protected]7345da02012-11-27 14:31:491939 continue
wnwenbdc444e2016-05-25 13:44:151940 CheckForMatch(f, line_num, line, func_name, message, error)
[email protected]127f18ec2012-06-16 05:05:591941
1942 result = []
1943 if (warnings):
1944 result.append(output_api.PresubmitPromptWarning(
1945 'Banned functions were used.\n' + '\n'.join(warnings)))
1946 if (errors):
1947 result.append(output_api.PresubmitError(
1948 'Banned functions were used.\n' + '\n'.join(errors)))
1949 return result
1950
1951
Michael Thiessen44457642020-02-06 00:24:151952def _CheckAndroidNoBannedImports(input_api, output_api):
1953 """Make sure that banned java imports are not used."""
1954 errors = []
1955
1956 def IsException(path, exceptions):
1957 for exception in exceptions:
1958 if (path.startswith(exception)):
1959 return True
1960 return False
1961
1962 file_filter = lambda f: f.LocalPath().endswith(('.java'))
1963 for f in input_api.AffectedFiles(file_filter=file_filter):
1964 for line_num, line in f.ChangedContents():
1965 for import_name, message, exceptions in _BANNED_JAVA_IMPORTS:
1966 if IsException(f.LocalPath(), exceptions):
1967 continue;
1968 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1969 'import ' + import_name, message)
1970 if problems:
1971 errors.extend(problems)
1972 result = []
1973 if (errors):
1974 result.append(output_api.PresubmitError(
1975 'Banned imports were used.\n' + '\n'.join(errors)))
1976 return result
1977
1978
Saagar Sanghavifceeaae2020-08-12 16:40:361979def CheckNoDeprecatedMojoTypes(input_api, output_api):
Mario Sanchez Prada2472cab2019-09-18 10:58:311980 """Make sure that old Mojo types are not used."""
1981 warnings = []
Mario Sanchez Pradacec9cef2019-12-15 11:54:571982 errors = []
Mario Sanchez Prada2472cab2019-09-18 10:58:311983
Mario Sanchez Pradaaab91382019-12-19 08:57:091984 # For any path that is not an "ok" or an "error" path, a warning will be
1985 # raised if deprecated mojo types are found.
1986 ok_paths = ['components/arc']
1987 error_paths = ['third_party/blink', 'content']
1988
Mario Sanchez Prada2472cab2019-09-18 10:58:311989 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
1990 for f in input_api.AffectedFiles(file_filter=file_filter):
Mario Sanchez Pradacec9cef2019-12-15 11:54:571991 # Don't check //components/arc, not yet migrated (see crrev.com/c/1868870).
Mario Sanchez Pradaaab91382019-12-19 08:57:091992 if any(map(lambda path: f.LocalPath().startswith(path), ok_paths)):
Mario Sanchez Prada2472cab2019-09-18 10:58:311993 continue
1994
1995 for line_num, line in f.ChangedContents():
1996 for func_name, message in _DEPRECATED_MOJO_TYPES:
1997 problems = _GetMessageForMatchingType(input_api, f, line_num, line,
1998 func_name, message)
Mario Sanchez Pradacec9cef2019-12-15 11:54:571999
Mario Sanchez Prada2472cab2019-09-18 10:58:312000 if problems:
Mario Sanchez Pradaaab91382019-12-19 08:57:092001 # Raise errors inside |error_paths| and warnings everywhere else.
2002 if any(map(lambda path: f.LocalPath().startswith(path), error_paths)):
Mario Sanchez Pradacec9cef2019-12-15 11:54:572003 errors.extend(problems)
2004 else:
Mario Sanchez Prada2472cab2019-09-18 10:58:312005 warnings.extend(problems)
2006
2007 result = []
2008 if (warnings):
2009 result.append(output_api.PresubmitPromptWarning(
2010 'Banned Mojo types were used.\n' + '\n'.join(warnings)))
Mario Sanchez Pradacec9cef2019-12-15 11:54:572011 if (errors):
2012 result.append(output_api.PresubmitError(
2013 'Banned Mojo types were used.\n' + '\n'.join(errors)))
Mario Sanchez Prada2472cab2019-09-18 10:58:312014 return result
2015
2016
Saagar Sanghavifceeaae2020-08-12 16:40:362017def CheckNoPragmaOnce(input_api, output_api):
[email protected]6c063c62012-07-11 19:11:062018 """Make sure that banned functions are not used."""
2019 files = []
2020 pattern = input_api.re.compile(r'^#pragma\s+once',
2021 input_api.re.MULTILINE)
2022 for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
2023 if not f.LocalPath().endswith('.h'):
2024 continue
2025 contents = input_api.ReadFile(f)
2026 if pattern.search(contents):
2027 files.append(f)
2028
2029 if files:
2030 return [output_api.PresubmitError(
2031 'Do not use #pragma once in header files.\n'
2032 'See http://www.chromium.org/developers/coding-style#TOC-File-headers',
2033 files)]
2034 return []
2035
[email protected]127f18ec2012-06-16 05:05:592036
Saagar Sanghavifceeaae2020-08-12 16:40:362037def CheckNoTrinaryTrueFalse(input_api, output_api):
[email protected]e7479052012-09-19 00:26:122038 """Checks to make sure we don't introduce use of foo ? true : false."""
2039 problems = []
2040 pattern = input_api.re.compile(r'\?\s*(true|false)\s*:\s*(true|false)')
2041 for f in input_api.AffectedFiles():
2042 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2043 continue
2044
2045 for line_num, line in f.ChangedContents():
2046 if pattern.match(line):
2047 problems.append(' %s:%d' % (f.LocalPath(), line_num))
2048
2049 if not problems:
2050 return []
2051 return [output_api.PresubmitPromptWarning(
2052 'Please consider avoiding the "? true : false" pattern if possible.\n' +
2053 '\n'.join(problems))]
2054
2055
Saagar Sanghavifceeaae2020-08-12 16:40:362056def CheckUnwantedDependencies(input_api, output_api):
rhalavati08acd232017-04-03 07:23:282057 """Runs checkdeps on #include and import statements added in this
[email protected]55f9f382012-07-31 11:02:182058 change. Breaking - rules is an error, breaking ! rules is a
2059 warning.
2060 """
mohan.reddyf21db962014-10-16 12:26:472061 import sys
[email protected]55f9f382012-07-31 11:02:182062 # We need to wait until we have an input_api object and use this
2063 # roundabout construct to import checkdeps because this file is
2064 # eval-ed and thus doesn't have __file__.
2065 original_sys_path = sys.path
2066 try:
2067 sys.path = sys.path + [input_api.os_path.join(
[email protected]5298cc982014-05-29 20:53:472068 input_api.PresubmitLocalPath(), 'buildtools', 'checkdeps')]
[email protected]55f9f382012-07-31 11:02:182069 import checkdeps
[email protected]55f9f382012-07-31 11:02:182070 from rules import Rule
2071 finally:
2072 # Restore sys.path to what it was before.
2073 sys.path = original_sys_path
2074
2075 added_includes = []
rhalavati08acd232017-04-03 07:23:282076 added_imports = []
Jinsuk Kim5a092672017-10-24 22:42:242077 added_java_imports = []
[email protected]55f9f382012-07-31 11:02:182078 for f in input_api.AffectedFiles():
Daniel Bratell65b033262019-04-23 08:17:062079 if _IsCPlusPlusFile(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_includes.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062082 elif _IsProtoFile(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_imports.append([f.AbsoluteLocalPath(), changed_lines])
Daniel Bratell65b033262019-04-23 08:17:062085 elif _IsJavaFile(input_api, f.LocalPath()):
Vaclav Brozekd5de76a2018-03-17 07:57:502086 changed_lines = [line for _, line in f.ChangedContents()]
Andrew Grieve085f29f2017-11-02 09:14:082087 added_java_imports.append([f.AbsoluteLocalPath(), changed_lines])
[email protected]55f9f382012-07-31 11:02:182088
[email protected]26385172013-05-09 23:11:352089 deps_checker = checkdeps.DepsChecker(input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182090
2091 error_descriptions = []
2092 warning_descriptions = []
rhalavati08acd232017-04-03 07:23:282093 error_subjects = set()
2094 warning_subjects = set()
Saagar Sanghavifceeaae2020-08-12 16:40:362095
[email protected]55f9f382012-07-31 11:02:182096 for path, rule_type, rule_description in deps_checker.CheckAddedCppIncludes(
2097 added_includes):
Andrew Grieve085f29f2017-11-02 09:14:082098 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
[email protected]55f9f382012-07-31 11:02:182099 description_with_path = '%s\n %s' % (path, rule_description)
2100 if rule_type == Rule.DISALLOW:
2101 error_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282102 error_subjects.add("#includes")
[email protected]55f9f382012-07-31 11:02:182103 else:
2104 warning_descriptions.append(description_with_path)
rhalavati08acd232017-04-03 07:23:282105 warning_subjects.add("#includes")
2106
2107 for path, rule_type, rule_description in deps_checker.CheckAddedProtoImports(
2108 added_imports):
Andrew Grieve085f29f2017-11-02 09:14:082109 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
rhalavati08acd232017-04-03 07:23:282110 description_with_path = '%s\n %s' % (path, rule_description)
2111 if rule_type == Rule.DISALLOW:
2112 error_descriptions.append(description_with_path)
2113 error_subjects.add("imports")
2114 else:
2115 warning_descriptions.append(description_with_path)
2116 warning_subjects.add("imports")
[email protected]55f9f382012-07-31 11:02:182117
Jinsuk Kim5a092672017-10-24 22:42:242118 for path, rule_type, rule_description in deps_checker.CheckAddedJavaImports(
Shenghua Zhangbfaa38b82017-11-16 21:58:022119 added_java_imports, _JAVA_MULTIPLE_DEFINITION_EXCLUDED_PATHS):
Andrew Grieve085f29f2017-11-02 09:14:082120 path = input_api.os_path.relpath(path, input_api.PresubmitLocalPath())
Jinsuk Kim5a092672017-10-24 22:42:242121 description_with_path = '%s\n %s' % (path, rule_description)
2122 if rule_type == Rule.DISALLOW:
2123 error_descriptions.append(description_with_path)
2124 error_subjects.add("imports")
2125 else:
2126 warning_descriptions.append(description_with_path)
2127 warning_subjects.add("imports")
2128
[email protected]55f9f382012-07-31 11:02:182129 results = []
2130 if error_descriptions:
2131 results.append(output_api.PresubmitError(
rhalavati08acd232017-04-03 07:23:282132 'You added one or more %s that violate checkdeps rules.'
2133 % " and ".join(error_subjects),
[email protected]55f9f382012-07-31 11:02:182134 error_descriptions))
2135 if warning_descriptions:
[email protected]f7051d52013-04-02 18:31:422136 results.append(output_api.PresubmitPromptOrNotify(
rhalavati08acd232017-04-03 07:23:282137 'You added one or more %s of files that are temporarily\n'
[email protected]55f9f382012-07-31 11:02:182138 'allowed but being removed. Can you avoid introducing the\n'
rhalavati08acd232017-04-03 07:23:282139 '%s? See relevant DEPS file(s) for details and contacts.' %
2140 (" and ".join(warning_subjects), "/".join(warning_subjects)),
[email protected]55f9f382012-07-31 11:02:182141 warning_descriptions))
2142 return results
2143
2144
Saagar Sanghavifceeaae2020-08-12 16:40:362145def CheckFilePermissions(input_api, output_api):
[email protected]fbcafe5a2012-08-08 15:31:222146 """Check that all files have their permissions properly set."""
[email protected]791507202014-02-03 23:19:152147 if input_api.platform == 'win32':
2148 return []
raphael.kubo.da.costac1d13e60b2016-04-01 11:49:292149 checkperms_tool = input_api.os_path.join(
2150 input_api.PresubmitLocalPath(),
2151 'tools', 'checkperms', 'checkperms.py')
2152 args = [input_api.python_executable, checkperms_tool,
mohan.reddyf21db962014-10-16 12:26:472153 '--root', input_api.change.RepositoryRoot()]
Raphael Kubo da Costa6ff391d2017-11-13 16:43:392154 with input_api.CreateTemporaryFile() as file_list:
2155 for f in input_api.AffectedFiles():
2156 # checkperms.py file/directory arguments must be relative to the
2157 # repository.
2158 file_list.write(f.LocalPath() + '\n')
2159 file_list.close()
2160 args += ['--file-list', file_list.name]
2161 try:
2162 input_api.subprocess.check_output(args)
2163 return []
2164 except input_api.subprocess.CalledProcessError as error:
2165 return [output_api.PresubmitError(
2166 'checkperms.py failed:',
2167 long_text=error.output)]
[email protected]fbcafe5a2012-08-08 15:31:222168
2169
Saagar Sanghavifceeaae2020-08-12 16:40:362170def CheckNoAuraWindowPropertyHInHeaders(input_api, output_api):
[email protected]c8278b32012-10-30 20:35:492171 """Makes sure we don't include ui/aura/window_property.h
2172 in header files.
2173 """
2174 pattern = input_api.re.compile(r'^#include\s*"ui/aura/window_property.h"')
2175 errors = []
2176 for f in input_api.AffectedFiles():
2177 if not f.LocalPath().endswith('.h'):
2178 continue
2179 for line_num, line in f.ChangedContents():
2180 if pattern.match(line):
2181 errors.append(' %s:%d' % (f.LocalPath(), line_num))
2182
2183 results = []
2184 if errors:
2185 results.append(output_api.PresubmitError(
2186 'Header files should not include ui/aura/window_property.h', errors))
2187 return results
2188
2189
[email protected]70ca77752012-11-20 03:45:032190def _CheckForVersionControlConflictsInFile(input_api, f):
2191 pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
2192 errors = []
2193 for line_num, line in f.ChangedContents():
Luke Zielinski9bc14ac72019-03-04 19:02:162194 if f.LocalPath().endswith(('.md', '.rst', '.txt')):
dbeam95c35a2f2015-06-02 01:40:232195 # First-level headers in markdown look a lot like version control
2196 # conflict markers. http://daringfireball.net/projects/markdown/basics
2197 continue
[email protected]70ca77752012-11-20 03:45:032198 if pattern.match(line):
2199 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2200 return errors
2201
2202
Saagar Sanghavifceeaae2020-08-12 16:40:362203def CheckForVersionControlConflicts(input_api, output_api):
[email protected]70ca77752012-11-20 03:45:032204 """Usually this is not intentional and will cause a compile failure."""
2205 errors = []
2206 for f in input_api.AffectedFiles():
2207 errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
2208
2209 results = []
2210 if errors:
2211 results.append(output_api.PresubmitError(
2212 'Version control conflict markers found, please resolve.', errors))
2213 return results
2214
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:202215
Saagar Sanghavifceeaae2020-08-12 16:40:362216def CheckGoogleSupportAnswerUrlOnUpload(input_api, output_api):
estadee17314a02017-01-12 16:22:162217 pattern = input_api.re.compile('support\.google\.com\/chrome.*/answer')
2218 errors = []
2219 for f in input_api.AffectedFiles():
2220 for line_num, line in f.ChangedContents():
2221 if pattern.search(line):
2222 errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
2223
2224 results = []
2225 if errors:
2226 results.append(output_api.PresubmitPromptWarning(
Vaclav Brozekd5de76a2018-03-17 07:57:502227 'Found Google support URL addressed by answer number. Please replace '
2228 'with a p= identifier instead. See crbug.com/679462\n', errors))
estadee17314a02017-01-12 16:22:162229 return results
2230
[email protected]70ca77752012-11-20 03:45:032231
Saagar Sanghavifceeaae2020-08-12 16:40:362232def CheckHardcodedGoogleHostsInLowerLayers(input_api, output_api):
[email protected]06e6d0ff2012-12-11 01:36:442233 def FilterFile(affected_file):
2234 """Filter function for use with input_api.AffectedSourceFiles,
2235 below. This filters out everything except non-test files from
2236 top-level directories that generally speaking should not hard-code
2237 service URLs (e.g. src/android_webview/, src/content/ and others).
2238 """
2239 return input_api.FilterSourceFile(
2240 affected_file,
James Cook24a504192020-07-23 00:08:442241 files_to_check=[r'^(android_webview|base|content|net)[\\/].*'],
2242 files_to_skip=(_EXCLUDED_PATHS +
2243 _TEST_CODE_EXCLUDED_PATHS +
2244 input_api.DEFAULT_FILES_TO_SKIP))
[email protected]06e6d0ff2012-12-11 01:36:442245
reillyi38965732015-11-16 18:27:332246 base_pattern = ('"[^"]*(google|googleapis|googlezip|googledrive|appspot)'
2247 '\.(com|net)[^"]*"')
[email protected]de4f7d22013-05-23 14:27:462248 comment_pattern = input_api.re.compile('//.*%s' % base_pattern)
2249 pattern = input_api.re.compile(base_pattern)
[email protected]06e6d0ff2012-12-11 01:36:442250 problems = [] # items are (filename, line_number, line)
2251 for f in input_api.AffectedSourceFiles(FilterFile):
2252 for line_num, line in f.ChangedContents():
[email protected]de4f7d22013-05-23 14:27:462253 if not comment_pattern.search(line) and pattern.search(line):
[email protected]06e6d0ff2012-12-11 01:36:442254 problems.append((f.LocalPath(), line_num, line))
2255
2256 if problems:
[email protected]f7051d52013-04-02 18:31:422257 return [output_api.PresubmitPromptOrNotify(
[email protected]06e6d0ff2012-12-11 01:36:442258 'Most layers below src/chrome/ should not hardcode service URLs.\n'
[email protected]b0149772014-03-27 16:47:582259 'Are you sure this is correct?',
[email protected]06e6d0ff2012-12-11 01:36:442260 [' %s:%d: %s' % (
2261 problem[0], problem[1], problem[2]) for problem in problems])]
[email protected]2fdd1f362013-01-16 03:56:032262 else:
2263 return []
[email protected]06e6d0ff2012-12-11 01:36:442264
2265
Saagar Sanghavifceeaae2020-08-12 16:40:362266def CheckChromeOsSyncedPrefRegistration(input_api, output_api):
James Cook6b6597c2019-11-06 22:05:292267 """Warns if Chrome OS C++ files register syncable prefs as browser prefs."""
2268 def FileFilter(affected_file):
2269 """Includes directories known to be Chrome OS only."""
2270 return input_api.FilterSourceFile(
2271 affected_file,
James Cook24a504192020-07-23 00:08:442272 files_to_check=('^ash/',
2273 '^chromeos/', # Top-level src/chromeos.
2274 '/chromeos/', # Any path component.
2275 '^components/arc',
2276 '^components/exo'),
2277 files_to_skip=(input_api.DEFAULT_FILES_TO_SKIP))
James Cook6b6597c2019-11-06 22:05:292278
2279 prefs = []
2280 priority_prefs = []
2281 for f in input_api.AffectedFiles(file_filter=FileFilter):
2282 for line_num, line in f.ChangedContents():
2283 if input_api.re.search('PrefRegistrySyncable::SYNCABLE_PREF', line):
2284 prefs.append(' %s:%d:' % (f.LocalPath(), line_num))
2285 prefs.append(' %s' % line)
2286 if input_api.re.search(
2287 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF', line):
2288 priority_prefs.append(' %s:%d' % (f.LocalPath(), line_num))
2289 priority_prefs.append(' %s' % line)
2290
2291 results = []
2292 if (prefs):
2293 results.append(output_api.PresubmitPromptWarning(
2294 'Preferences were registered as SYNCABLE_PREF and will be controlled '
2295 'by browser sync settings. If these prefs should be controlled by OS '
2296 'sync settings use SYNCABLE_OS_PREF instead.\n' + '\n'.join(prefs)))
2297 if (priority_prefs):
2298 results.append(output_api.PresubmitPromptWarning(
2299 'Preferences were registered as SYNCABLE_PRIORITY_PREF and will be '
2300 'controlled by browser sync settings. If these prefs should be '
2301 'controlled by OS sync settings use SYNCABLE_OS_PRIORITY_PREF '
2302 'instead.\n' + '\n'.join(prefs)))
2303 return results
2304
2305
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492306# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362307def CheckNoAbbreviationInPngFileName(input_api, output_api):
[email protected]d2530012013-01-25 16:39:272308 """Makes sure there are no abbreviations in the name of PNG files.
binji0dcdf342014-12-12 18:32:312309 The native_client_sdk directory is excluded because it has auto-generated PNG
2310 files for documentation.
[email protected]d2530012013-01-25 16:39:272311 """
[email protected]d2530012013-01-25 16:39:272312 errors = []
James Cook24a504192020-07-23 00:08:442313 files_to_check = [r'.*_[a-z]_.*\.png$|.*_[a-z]\.png$']
2314 files_to_skip = [r'^native_client_sdk[\\/]']
binji0dcdf342014-12-12 18:32:312315 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442316 f, files_to_check=files_to_check, files_to_skip=files_to_skip)
binji0dcdf342014-12-12 18:32:312317 for f in input_api.AffectedFiles(include_deletes=False,
2318 file_filter=file_filter):
2319 errors.append(' %s' % f.LocalPath())
[email protected]d2530012013-01-25 16:39:272320
2321 results = []
2322 if errors:
2323 results.append(output_api.PresubmitError(
2324 'The name of PNG files should not have abbreviations. \n'
2325 'Use _hover.png, _center.png, instead of _h.png, _c.png.\n'
2326 'Contact [email protected] if you have questions.', errors))
2327 return results
2328
2329
Daniel Cheng4dcdb6b2017-04-13 08:30:172330def _ExtractAddRulesFromParsedDeps(parsed_deps):
2331 """Extract the rules that add dependencies from a parsed DEPS file.
2332
2333 Args:
2334 parsed_deps: the locals dictionary from evaluating the DEPS file."""
2335 add_rules = set()
2336 add_rules.update([
2337 rule[1:] for rule in parsed_deps.get('include_rules', [])
2338 if rule.startswith('+') or rule.startswith('!')
2339 ])
Vaclav Brozekd5de76a2018-03-17 07:57:502340 for _, rules in parsed_deps.get('specific_include_rules',
Daniel Cheng4dcdb6b2017-04-13 08:30:172341 {}).iteritems():
2342 add_rules.update([
2343 rule[1:] for rule in rules
2344 if rule.startswith('+') or rule.startswith('!')
2345 ])
2346 return add_rules
2347
2348
2349def _ParseDeps(contents):
2350 """Simple helper for parsing DEPS files."""
2351 # Stubs for handling special syntax in the root DEPS file.
Daniel Cheng4dcdb6b2017-04-13 08:30:172352 class _VarImpl:
2353
2354 def __init__(self, local_scope):
2355 self._local_scope = local_scope
2356
2357 def Lookup(self, var_name):
2358 """Implements the Var syntax."""
2359 try:
2360 return self._local_scope['vars'][var_name]
2361 except KeyError:
2362 raise Exception('Var is not defined: %s' % var_name)
2363
2364 local_scope = {}
2365 global_scope = {
Daniel Cheng4dcdb6b2017-04-13 08:30:172366 'Var': _VarImpl(local_scope).Lookup,
Ben Pastene3e49749c2020-07-06 20:22:592367 'Str': str,
Daniel Cheng4dcdb6b2017-04-13 08:30:172368 }
2369 exec contents in global_scope, local_scope
2370 return local_scope
2371
2372
2373def _CalculateAddedDeps(os_path, old_contents, new_contents):
Saagar Sanghavi0bc3e692020-08-13 19:46:592374 """Helper method for CheckAddedDepsHaveTargetApprovals. Returns
[email protected]14a6131c2014-01-08 01:15:412375 a set of DEPS entries that we should look up.
2376
2377 For a directory (rather than a specific filename) we fake a path to
2378 a specific filename by adding /DEPS. This is chosen as a file that
2379 will seldom or never be subject to per-file include_rules.
2380 """
[email protected]2b438d62013-11-14 17:54:142381 # We ignore deps entries on auto-generated directories.
2382 AUTO_GENERATED_DIRS = ['grit', 'jni']
[email protected]f32e2d1e2013-07-26 21:39:082383
Daniel Cheng4dcdb6b2017-04-13 08:30:172384 old_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(old_contents))
2385 new_deps = _ExtractAddRulesFromParsedDeps(_ParseDeps(new_contents))
2386
2387 added_deps = new_deps.difference(old_deps)
2388
[email protected]2b438d62013-11-14 17:54:142389 results = set()
Daniel Cheng4dcdb6b2017-04-13 08:30:172390 for added_dep in added_deps:
2391 if added_dep.split('/')[0] in AUTO_GENERATED_DIRS:
2392 continue
2393 # Assume that a rule that ends in .h is a rule for a specific file.
2394 if added_dep.endswith('.h'):
2395 results.add(added_dep)
2396 else:
2397 results.add(os_path.join(added_dep, 'DEPS'))
[email protected]f32e2d1e2013-07-26 21:39:082398 return results
2399
2400
Saagar Sanghavifceeaae2020-08-12 16:40:362401def CheckAddedDepsHaveTargetApprovals(input_api, output_api):
[email protected]e871964c2013-05-13 14:14:552402 """When a dependency prefixed with + is added to a DEPS file, we
2403 want to make sure that the change is reviewed by an OWNER of the
2404 target file or directory, to avoid layering violations from being
2405 introduced. This check verifies that this happens.
2406 """
Daniel Cheng4dcdb6b2017-04-13 08:30:172407 virtual_depended_on_files = set()
jochen53efcdd2016-01-29 05:09:242408
2409 file_filter = lambda f: not input_api.re.match(
Kent Tamura32dbbcb2018-11-30 12:28:492410 r"^third_party[\\/]blink[\\/].*", f.LocalPath())
jochen53efcdd2016-01-29 05:09:242411 for f in input_api.AffectedFiles(include_deletes=False,
2412 file_filter=file_filter):
[email protected]e871964c2013-05-13 14:14:552413 filename = input_api.os_path.basename(f.LocalPath())
2414 if filename == 'DEPS':
Daniel Cheng4dcdb6b2017-04-13 08:30:172415 virtual_depended_on_files.update(_CalculateAddedDeps(
2416 input_api.os_path,
2417 '\n'.join(f.OldContents()),
2418 '\n'.join(f.NewContents())))
[email protected]e871964c2013-05-13 14:14:552419
[email protected]e871964c2013-05-13 14:14:552420 if not virtual_depended_on_files:
2421 return []
2422
2423 if input_api.is_committing:
2424 if input_api.tbr:
2425 return [output_api.PresubmitNotifyResult(
2426 '--tbr was specified, skipping OWNERS check for DEPS additions')]
Paweł Hajdan, Jrbe6739ea2016-04-28 15:07:272427 if input_api.dry_run:
2428 return [output_api.PresubmitNotifyResult(
2429 'This is a dry run, skipping OWNERS check for DEPS additions')]
[email protected]e871964c2013-05-13 14:14:552430 if not input_api.change.issue:
2431 return [output_api.PresubmitError(
2432 "DEPS approval by OWNERS check failed: this change has "
Aaron Gable65a99d92017-10-09 19:17:402433 "no change number, so we can't check it for approvals.")]
[email protected]e871964c2013-05-13 14:14:552434 output = output_api.PresubmitError
2435 else:
2436 output = output_api.PresubmitNotifyResult
2437
2438 owners_db = input_api.owners_db
tandriied3b7e12016-05-12 14:38:502439 owner_email, reviewers = (
2440 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
2441 input_api,
2442 owners_db.email_regexp,
2443 approval_needed=input_api.is_committing))
[email protected]e871964c2013-05-13 14:14:552444
2445 owner_email = owner_email or input_api.change.author_email
2446
[email protected]de4f7d22013-05-23 14:27:462447 reviewers_plus_owner = set(reviewers)
[email protected]e71c6082013-05-22 02:28:512448 if owner_email:
[email protected]de4f7d22013-05-23 14:27:462449 reviewers_plus_owner.add(owner_email)
[email protected]e871964c2013-05-13 14:14:552450 missing_files = owners_db.files_not_covered_by(virtual_depended_on_files,
2451 reviewers_plus_owner)
[email protected]14a6131c2014-01-08 01:15:412452
2453 # We strip the /DEPS part that was added by
2454 # _FilesToCheckForIncomingDeps to fake a path to a file in a
2455 # directory.
2456 def StripDeps(path):
2457 start_deps = path.rfind('/DEPS')
2458 if start_deps != -1:
2459 return path[:start_deps]
2460 else:
2461 return path
2462 unapproved_dependencies = ["'+%s'," % StripDeps(path)
[email protected]e871964c2013-05-13 14:14:552463 for path in missing_files]
2464
2465 if unapproved_dependencies:
2466 output_list = [
Paweł Hajdan, Jrec17f882016-07-04 14:16:152467 output('You need LGTM from owners of depends-on paths in DEPS that were '
2468 'modified in this CL:\n %s' %
2469 '\n '.join(sorted(unapproved_dependencies)))]
2470 suggested_owners = owners_db.reviewers_for(missing_files, owner_email)
2471 output_list.append(output(
2472 'Suggested missing target path OWNERS:\n %s' %
2473 '\n '.join(suggested_owners or [])))
[email protected]e871964c2013-05-13 14:14:552474 return output_list
2475
2476 return []
2477
2478
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492479# TODO: add unit tests.
Saagar Sanghavifceeaae2020-08-12 16:40:362480def CheckSpamLogging(input_api, output_api):
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492481 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
James Cook24a504192020-07-23 00:08:442482 files_to_skip = (_EXCLUDED_PATHS +
2483 _TEST_CODE_EXCLUDED_PATHS +
2484 input_api.DEFAULT_FILES_TO_SKIP +
2485 (r"^base[\\/]logging\.h$",
2486 r"^base[\\/]logging\.cc$",
2487 r"^base[\\/]task[\\/]thread_pool[\\/]task_tracker\.cc$",
2488 r"^chrome[\\/]app[\\/]chrome_main_delegate\.cc$",
2489 r"^chrome[\\/]browser[\\/]chrome_browser_main\.cc$",
2490 r"^chrome[\\/]browser[\\/]ui[\\/]startup[\\/]"
2491 r"startup_browser_creator\.cc$",
2492 r"^chrome[\\/]browser[\\/]browser_switcher[\\/]bho[\\/].*",
2493 r"^chrome[\\/]browser[\\/]diagnostics[\\/]" +
2494 r"diagnostics_writer\.cc$",
2495 r"^chrome[\\/]chrome_cleaner[\\/].*",
2496 r"^chrome[\\/]chrome_elf[\\/]dll_hash[\\/]" +
2497 r"dll_hash_main\.cc$",
2498 r"^chrome[\\/]installer[\\/]setup[\\/].*",
2499 r"^chromecast[\\/]",
2500 r"^cloud_print[\\/]",
2501 r"^components[\\/]browser_watcher[\\/]"
2502 r"dump_stability_report_main_win.cc$",
2503 r"^components[\\/]media_control[\\/]renderer[\\/]"
2504 r"media_playback_options\.cc$",
2505 r"^components[\\/]zucchini[\\/].*",
2506 # TODO(peter): Remove exception. https://crbug.com/534537
2507 r"^content[\\/]browser[\\/]notifications[\\/]"
2508 r"notification_event_dispatcher_impl\.cc$",
2509 r"^content[\\/]common[\\/]gpu[\\/]client[\\/]"
2510 r"gl_helper_benchmark\.cc$",
2511 r"^courgette[\\/]courgette_minimal_tool\.cc$",
2512 r"^courgette[\\/]courgette_tool\.cc$",
2513 r"^extensions[\\/]renderer[\\/]logging_native_handler\.cc$",
2514 r"^fuchsia[\\/]engine[\\/]browser[\\/]frame_impl.cc$",
2515 r"^fuchsia[\\/]engine[\\/]context_provider_main.cc$",
2516 r"^headless[\\/]app[\\/]headless_shell\.cc$",
2517 r"^ipc[\\/]ipc_logging\.cc$",
2518 r"^native_client_sdk[\\/]",
2519 r"^remoting[\\/]base[\\/]logging\.h$",
2520 r"^remoting[\\/]host[\\/].*",
2521 r"^sandbox[\\/]linux[\\/].*",
2522 r"^storage[\\/]browser[\\/]file_system[\\/]" +
2523 r"dump_file_system.cc$",
2524 r"^tools[\\/]",
2525 r"^ui[\\/]base[\\/]resource[\\/]data_pack.cc$",
2526 r"^ui[\\/]aura[\\/]bench[\\/]bench_main\.cc$",
2527 r"^ui[\\/]ozone[\\/]platform[\\/]cast[\\/]",
2528 r"^ui[\\/]base[\\/]x[\\/]xwmstartupcheck[\\/]"
2529 r"xwmstartupcheck\.cc$"))
[email protected]85218562013-11-22 07:41:402530 source_file_filter = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:442531 x, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]85218562013-11-22 07:41:402532
thomasanderson625d3932017-03-29 07:16:582533 log_info = set([])
2534 printf = set([])
[email protected]85218562013-11-22 07:41:402535
2536 for f in input_api.AffectedSourceFiles(source_file_filter):
thomasanderson625d3932017-03-29 07:16:582537 for _, line in f.ChangedContents():
2538 if input_api.re.search(r"\bD?LOG\s*\(\s*INFO\s*\)", line):
2539 log_info.add(f.LocalPath())
2540 elif input_api.re.search(r"\bD?LOG_IF\s*\(\s*INFO\s*,", line):
2541 log_info.add(f.LocalPath())
[email protected]18b466b2013-12-02 22:01:372542
thomasanderson625d3932017-03-29 07:16:582543 if input_api.re.search(r"\bprintf\(", line):
2544 printf.add(f.LocalPath())
2545 elif input_api.re.search(r"\bfprintf\((stdout|stderr)", line):
2546 printf.add(f.LocalPath())
[email protected]85218562013-11-22 07:41:402547
2548 if log_info:
2549 return [output_api.PresubmitError(
2550 'These files spam the console log with LOG(INFO):',
2551 items=log_info)]
2552 if printf:
2553 return [output_api.PresubmitError(
2554 'These files spam the console log with printf/fprintf:',
2555 items=printf)]
2556 return []
2557
2558
Saagar Sanghavifceeaae2020-08-12 16:40:362559def CheckForAnonymousVariables(input_api, output_api):
[email protected]49aa76a2013-12-04 06:59:162560 """These types are all expected to hold locks while in scope and
2561 so should never be anonymous (which causes them to be immediately
2562 destroyed)."""
2563 they_who_must_be_named = [
2564 'base::AutoLock',
2565 'base::AutoReset',
2566 'base::AutoUnlock',
2567 'SkAutoAlphaRestore',
2568 'SkAutoBitmapShaderInstall',
2569 'SkAutoBlitterChoose',
2570 'SkAutoBounderCommit',
2571 'SkAutoCallProc',
2572 'SkAutoCanvasRestore',
2573 'SkAutoCommentBlock',
2574 'SkAutoDescriptor',
2575 'SkAutoDisableDirectionCheck',
2576 'SkAutoDisableOvalCheck',
2577 'SkAutoFree',
2578 'SkAutoGlyphCache',
2579 'SkAutoHDC',
2580 'SkAutoLockColors',
2581 'SkAutoLockPixels',
2582 'SkAutoMalloc',
2583 'SkAutoMaskFreeImage',
2584 'SkAutoMutexAcquire',
2585 'SkAutoPathBoundsUpdate',
2586 'SkAutoPDFRelease',
2587 'SkAutoRasterClipValidate',
2588 'SkAutoRef',
2589 'SkAutoTime',
2590 'SkAutoTrace',
2591 'SkAutoUnref',
2592 ]
2593 anonymous = r'(%s)\s*[({]' % '|'.join(they_who_must_be_named)
2594 # bad: base::AutoLock(lock.get());
2595 # not bad: base::AutoLock lock(lock.get());
2596 bad_pattern = input_api.re.compile(anonymous)
2597 # good: new base::AutoLock(lock.get())
2598 good_pattern = input_api.re.compile(r'\bnew\s*' + anonymous)
2599 errors = []
2600
2601 for f in input_api.AffectedFiles():
2602 if not f.LocalPath().endswith(('.cc', '.h', '.inl', '.m', '.mm')):
2603 continue
2604 for linenum, line in f.ChangedContents():
2605 if bad_pattern.search(line) and not good_pattern.search(line):
2606 errors.append('%s:%d' % (f.LocalPath(), linenum))
2607
2608 if errors:
2609 return [output_api.PresubmitError(
2610 'These lines create anonymous variables that need to be named:',
2611 items=errors)]
2612 return []
2613
2614
Saagar Sanghavifceeaae2020-08-12 16:40:362615def CheckUniquePtrOnUpload(input_api, output_api):
Vaclav Brozekb7fadb692018-08-30 06:39:532616 # Returns whether |template_str| is of the form <T, U...> for some types T
2617 # and U. Assumes that |template_str| is already in the form <...>.
2618 def HasMoreThanOneArg(template_str):
2619 # Level of <...> nesting.
2620 nesting = 0
2621 for c in template_str:
2622 if c == '<':
2623 nesting += 1
2624 elif c == '>':
2625 nesting -= 1
2626 elif c == ',' and nesting == 1:
2627 return True
2628 return False
2629
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:492630 file_inclusion_pattern = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
Peter Kasting4844e46e2018-02-23 07:27:102631 sources = lambda affected_file: input_api.FilterSourceFile(
2632 affected_file,
James Cook24a504192020-07-23 00:08:442633 files_to_skip=(_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS +
2634 input_api.DEFAULT_FILES_TO_SKIP),
2635 files_to_check=file_inclusion_pattern)
Vaclav Brozeka54c528b2018-04-06 19:23:552636
2637 # Pattern to capture a single "<...>" block of template arguments. It can
2638 # handle linearly nested blocks, such as "<std::vector<std::set<T>>>", but
2639 # cannot handle branching structures, such as "<pair<set<T>,set<U>>". The
2640 # latter would likely require counting that < and > match, which is not
2641 # expressible in regular languages. Should the need arise, one can introduce
2642 # limited counting (matching up to a total number of nesting depth), which
2643 # should cover all practical cases for already a low nesting limit.
2644 template_arg_pattern = (
2645 r'<[^>]*' # Opening block of <.
2646 r'>([^<]*>)?') # Closing block of >.
2647 # Prefix expressing that whatever follows is not already inside a <...>
2648 # block.
2649 not_inside_template_arg_pattern = r'(^|[^<,\s]\s*)'
Peter Kasting4844e46e2018-02-23 07:27:102650 null_construct_pattern = input_api.re.compile(
Vaclav Brozeka54c528b2018-04-06 19:23:552651 not_inside_template_arg_pattern
2652 + r'\bstd::unique_ptr'
2653 + template_arg_pattern
2654 + r'\(\)')
2655
2656 # Same as template_arg_pattern, but excluding type arrays, e.g., <T[]>.
2657 template_arg_no_array_pattern = (
2658 r'<[^>]*[^]]' # Opening block of <.
2659 r'>([^(<]*[^]]>)?') # Closing block of >.
2660 # Prefix saying that what follows is the start of an expression.
2661 start_of_expr_pattern = r'(=|\breturn|^)\s*'
2662 # Suffix saying that what follows are call parentheses with a non-empty list
2663 # of arguments.
2664 nonempty_arg_list_pattern = r'\(([^)]|$)'
Vaclav Brozekb7fadb692018-08-30 06:39:532665 # Put the template argument into a capture group for deeper examination later.
Vaclav Brozeka54c528b2018-04-06 19:23:552666 return_construct_pattern = input_api.re.compile(
2667 start_of_expr_pattern
2668 + r'std::unique_ptr'
Vaclav Brozekb7fadb692018-08-30 06:39:532669 + '(?P<template_arg>'
Vaclav Brozeka54c528b2018-04-06 19:23:552670 + template_arg_no_array_pattern
Vaclav Brozekb7fadb692018-08-30 06:39:532671 + ')'
Vaclav Brozeka54c528b2018-04-06 19:23:552672 + nonempty_arg_list_pattern)
2673
Vaclav Brozek851d9602018-04-04 16:13:052674 problems_constructor = []
2675 problems_nullptr = []
Peter Kasting4844e46e2018-02-23 07:27:102676 for f in input_api.AffectedSourceFiles(sources):
2677 for line_number, line in f.ChangedContents():
2678 # Disallow:
2679 # return std::unique_ptr<T>(foo);
2680 # bar = std::unique_ptr<T>(foo);
2681 # But allow:
2682 # return std::unique_ptr<T[]>(foo);
2683 # bar = std::unique_ptr<T[]>(foo);
Vaclav Brozekb7fadb692018-08-30 06:39:532684 # And also allow cases when the second template argument is present. Those
2685 # cases cannot be handled by std::make_unique:
2686 # return std::unique_ptr<T, U>(foo);
2687 # bar = std::unique_ptr<T, U>(foo);
Vaclav Brozek851d9602018-04-04 16:13:052688 local_path = f.LocalPath()
Vaclav Brozekb7fadb692018-08-30 06:39:532689 return_construct_result = return_construct_pattern.search(line)
2690 if return_construct_result and not HasMoreThanOneArg(
2691 return_construct_result.group('template_arg')):
Vaclav Brozek851d9602018-04-04 16:13:052692 problems_constructor.append(
2693 '%s:%d\n %s' % (local_path, line_number, line.strip()))
Peter Kasting4844e46e2018-02-23 07:27:102694 # Disallow:
2695 # std::unique_ptr<T>()
2696 if null_construct_pattern.search(line):
Vaclav Brozek851d9602018-04-04 16:13:052697 problems_nullptr.append(
2698 '%s:%d\n %s' % (local_path, line_number, line.strip()))
2699
2700 errors = []
Vaclav Brozekc2fecf42018-04-06 16:40:162701 if problems_nullptr:
Vaclav Brozek851d9602018-04-04 16:13:052702 errors.append(output_api.PresubmitError(
2703 'The following files use std::unique_ptr<T>(). Use nullptr instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162704 problems_nullptr))
2705 if problems_constructor:
Vaclav Brozek851d9602018-04-04 16:13:052706 errors.append(output_api.PresubmitError(
2707 'The following files use explicit std::unique_ptr constructor.'
2708 'Use std::make_unique<T>() instead.',
Vaclav Brozekc2fecf42018-04-06 16:40:162709 problems_constructor))
Peter Kasting4844e46e2018-02-23 07:27:102710 return errors
2711
2712
Saagar Sanghavifceeaae2020-08-12 16:40:362713def CheckUserActionUpdate(input_api, output_api):
[email protected]999261d2014-03-03 20:08:082714 """Checks if any new user action has been added."""
[email protected]2f92dec2014-03-07 19:21:522715 if any('actions.xml' == input_api.os_path.basename(f) for f in
[email protected]999261d2014-03-03 20:08:082716 input_api.LocalPaths()):
[email protected]2f92dec2014-03-07 19:21:522717 # If actions.xml is already included in the changelist, the PRESUBMIT
2718 # for actions.xml will do a more complete presubmit check.
[email protected]999261d2014-03-03 20:08:082719 return []
2720
[email protected]999261d2014-03-03 20:08:082721 file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm'))
2722 action_re = r'[^a-zA-Z]UserMetricsAction\("([^"]*)'
[email protected]2f92dec2014-03-07 19:21:522723 current_actions = None
[email protected]999261d2014-03-03 20:08:082724 for f in input_api.AffectedFiles(file_filter=file_filter):
2725 for line_num, line in f.ChangedContents():
2726 match = input_api.re.search(action_re, line)
2727 if match:
[email protected]2f92dec2014-03-07 19:21:522728 # Loads contents in tools/metrics/actions/actions.xml to memory. It's
2729 # loaded only once.
2730 if not current_actions:
2731 with open('tools/metrics/actions/actions.xml') as actions_f:
2732 current_actions = actions_f.read()
2733 # Search for the matched user action name in |current_actions|.
[email protected]999261d2014-03-03 20:08:082734 for action_name in match.groups():
[email protected]2f92dec2014-03-07 19:21:522735 action = 'name="{0}"'.format(action_name)
2736 if action not in current_actions:
[email protected]999261d2014-03-03 20:08:082737 return [output_api.PresubmitPromptWarning(
2738 'File %s line %d: %s is missing in '
[email protected]2f92dec2014-03-07 19:21:522739 'tools/metrics/actions/actions.xml. Please run '
2740 'tools/metrics/actions/extract_actions.py to update.'
[email protected]999261d2014-03-03 20:08:082741 % (f.LocalPath(), line_num, action_name))]
2742 return []
2743
2744
Daniel Cheng13ca61a882017-08-25 15:11:252745def _ImportJSONCommentEater(input_api):
2746 import sys
2747 sys.path = sys.path + [input_api.os_path.join(
2748 input_api.PresubmitLocalPath(),
2749 'tools', 'json_comment_eater')]
2750 import json_comment_eater
2751 return json_comment_eater
2752
2753
[email protected]99171a92014-06-03 08:44:472754def _GetJSONParseError(input_api, filename, eat_comments=True):
2755 try:
2756 contents = input_api.ReadFile(filename)
2757 if eat_comments:
Daniel Cheng13ca61a882017-08-25 15:11:252758 json_comment_eater = _ImportJSONCommentEater(input_api)
plundblad1f5a4509f2015-07-23 11:31:132759 contents = json_comment_eater.Nom(contents)
[email protected]99171a92014-06-03 08:44:472760
2761 input_api.json.loads(contents)
2762 except ValueError as e:
2763 return e
2764 return None
2765
2766
2767def _GetIDLParseError(input_api, filename):
2768 try:
2769 contents = input_api.ReadFile(filename)
2770 idl_schema = input_api.os_path.join(
2771 input_api.PresubmitLocalPath(),
2772 'tools', 'json_schema_compiler', 'idl_schema.py')
2773 process = input_api.subprocess.Popen(
2774 [input_api.python_executable, idl_schema],
2775 stdin=input_api.subprocess.PIPE,
2776 stdout=input_api.subprocess.PIPE,
2777 stderr=input_api.subprocess.PIPE,
2778 universal_newlines=True)
2779 (_, error) = process.communicate(input=contents)
2780 return error or None
2781 except ValueError as e:
2782 return e
2783
2784
Saagar Sanghavifceeaae2020-08-12 16:40:362785def CheckParseErrors(input_api, output_api):
[email protected]99171a92014-06-03 08:44:472786 """Check that IDL and JSON files do not contain syntax errors."""
2787 actions = {
2788 '.idl': _GetIDLParseError,
2789 '.json': _GetJSONParseError,
2790 }
[email protected]99171a92014-06-03 08:44:472791 # Most JSON files are preprocessed and support comments, but these do not.
2792 json_no_comments_patterns = [
Egor Paskoce145c42018-09-28 19:31:042793 r'^testing[\\/]',
[email protected]99171a92014-06-03 08:44:472794 ]
2795 # Only run IDL checker on files in these directories.
2796 idl_included_patterns = [
Egor Paskoce145c42018-09-28 19:31:042797 r'^chrome[\\/]common[\\/]extensions[\\/]api[\\/]',
2798 r'^extensions[\\/]common[\\/]api[\\/]',
[email protected]99171a92014-06-03 08:44:472799 ]
2800
2801 def get_action(affected_file):
2802 filename = affected_file.LocalPath()
2803 return actions.get(input_api.os_path.splitext(filename)[1])
2804
[email protected]99171a92014-06-03 08:44:472805 def FilterFile(affected_file):
2806 action = get_action(affected_file)
2807 if not action:
2808 return False
2809 path = affected_file.LocalPath()
2810
Erik Staab2dd72b12020-04-16 15:03:402811 if _MatchesFile(input_api,
2812 _KNOWN_TEST_DATA_AND_INVALID_JSON_FILE_PATTERNS,
2813 path):
[email protected]99171a92014-06-03 08:44:472814 return False
2815
2816 if (action == _GetIDLParseError and
Sean Kau46e29bc2017-08-28 16:31:162817 not _MatchesFile(input_api, idl_included_patterns, path)):
[email protected]99171a92014-06-03 08:44:472818 return False
2819 return True
2820
2821 results = []
2822 for affected_file in input_api.AffectedFiles(
2823 file_filter=FilterFile, include_deletes=False):
2824 action = get_action(affected_file)
2825 kwargs = {}
2826 if (action == _GetJSONParseError and
Sean Kau46e29bc2017-08-28 16:31:162827 _MatchesFile(input_api, json_no_comments_patterns,
2828 affected_file.LocalPath())):
[email protected]99171a92014-06-03 08:44:472829 kwargs['eat_comments'] = False
2830 parse_error = action(input_api,
2831 affected_file.AbsoluteLocalPath(),
2832 **kwargs)
2833 if parse_error:
2834 results.append(output_api.PresubmitError('%s could not be parsed: %s' %
2835 (affected_file.LocalPath(), parse_error)))
2836 return results
2837
2838
Saagar Sanghavifceeaae2020-08-12 16:40:362839def CheckJavaStyle(input_api, output_api):
[email protected]760deea2013-12-10 19:33:492840 """Runs checkstyle on changed java files and returns errors if any exist."""
mohan.reddyf21db962014-10-16 12:26:472841 import sys
[email protected]760deea2013-12-10 19:33:492842 original_sys_path = sys.path
2843 try:
2844 sys.path = sys.path + [input_api.os_path.join(
2845 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkstyle')]
2846 import checkstyle
2847 finally:
2848 # Restore sys.path to what it was before.
2849 sys.path = original_sys_path
2850
2851 return checkstyle.RunCheckstyle(
davileen72d76532015-01-20 22:30:092852 input_api, output_api, 'tools/android/checkstyle/chromium-style-5.0.xml',
James Cook24a504192020-07-23 00:08:442853 files_to_skip=_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP)
[email protected]760deea2013-12-10 19:33:492854
2855
Saagar Sanghavifceeaae2020-08-12 16:40:362856def CheckPythonDevilInit(input_api, output_api):
Nate Fischerdfd9812e2019-07-18 22:03:002857 """Checks to make sure devil is initialized correctly in python scripts."""
2858 script_common_initialize_pattern = input_api.re.compile(
2859 r'script_common\.InitializeEnvironment\(')
2860 devil_env_config_initialize = input_api.re.compile(
2861 r'devil_env\.config\.Initialize\(')
2862
2863 errors = []
2864
2865 sources = lambda affected_file: input_api.FilterSourceFile(
2866 affected_file,
James Cook24a504192020-07-23 00:08:442867 files_to_skip=(_EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP +
2868 (r'^build[\\/]android[\\/]devil_chromium\.py',
2869 r'^third_party[\\/].*',)),
2870 files_to_check=[r'.*\.py$'])
Nate Fischerdfd9812e2019-07-18 22:03:002871
2872 for f in input_api.AffectedSourceFiles(sources):
2873 for line_num, line in f.ChangedContents():
2874 if (script_common_initialize_pattern.search(line) or
2875 devil_env_config_initialize.search(line)):
2876 errors.append("%s:%d" % (f.LocalPath(), line_num))
2877
2878 results = []
2879
2880 if errors:
2881 results.append(output_api.PresubmitError(
2882 'Devil initialization should always be done using '
2883 'devil_chromium.Initialize() in the chromium project, to use better '
2884 'defaults for dependencies (ex. up-to-date version of adb).',
2885 errors))
2886
2887 return results
2888
2889
Sean Kau46e29bc2017-08-28 16:31:162890def _MatchesFile(input_api, patterns, path):
2891 for pattern in patterns:
2892 if input_api.re.search(pattern, path):
2893 return True
2894 return False
2895
2896
Daniel Cheng7052cdf2017-11-21 19:23:292897def _GetOwnersFilesToCheckForIpcOwners(input_api):
2898 """Gets a list of OWNERS files to check for correct security owners.
dchenge07de812016-06-20 19:27:172899
Daniel Cheng7052cdf2017-11-21 19:23:292900 Returns:
2901 A dictionary mapping an OWNER file to the list of OWNERS rules it must
2902 contain to cover IPC-related files with noparent reviewer rules.
2903 """
2904 # Whether or not a file affects IPC is (mostly) determined by a simple list
2905 # of filename patterns.
dchenge07de812016-06-20 19:27:172906 file_patterns = [
palmerb19a0932017-01-24 04:00:312907 # Legacy IPC:
dchenge07de812016-06-20 19:27:172908 '*_messages.cc',
2909 '*_messages*.h',
2910 '*_param_traits*.*',
palmerb19a0932017-01-24 04:00:312911 # Mojo IPC:
dchenge07de812016-06-20 19:27:172912 '*.mojom',
Daniel Cheng1f386932018-01-29 19:56:472913 '*_mojom_traits*.*',
dchenge07de812016-06-20 19:27:172914 '*_struct_traits*.*',
2915 '*_type_converter*.*',
palmerb19a0932017-01-24 04:00:312916 '*.typemap',
2917 # Android native IPC:
2918 '*.aidl',
2919 # Blink uses a different file naming convention:
2920 '*EnumTraits*.*',
Daniel Chenge0bf3f62018-01-30 01:56:472921 "*MojomTraits*.*",
dchenge07de812016-06-20 19:27:172922 '*StructTraits*.*',
2923 '*TypeConverter*.*',
2924 ]
2925
scottmg7a6ed5ba2016-11-04 18:22:042926 # These third_party directories do not contain IPCs, but contain files
2927 # matching the above patterns, which trigger false positives.
2928 exclude_paths = [
2929 'third_party/crashpad/*',
Raphael Kubo da Costa4a224cf42019-11-19 18:44:162930 'third_party/blink/renderer/platform/bindings/*',
Andres Medinae684cf42018-08-27 18:48:232931 'third_party/protobuf/benchmarks/python/*',
Nico Weberee3dc9b2017-08-31 17:09:292932 'third_party/win_build_output/*',
Dan Harringtonb60e1aa2019-11-20 08:48:542933 'third_party/feed_library/*',
Scott Violet9f82d362019-11-06 21:42:162934 # These files are just used to communicate between class loaders running
2935 # in the same process.
2936 'weblayer/browser/java/org/chromium/weblayer_private/interfaces/*',
Mugdha Lakhani6230b962020-01-13 13:00:572937 'weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/*',
2938
scottmg7a6ed5ba2016-11-04 18:22:042939 ]
2940
dchenge07de812016-06-20 19:27:172941 # Dictionary mapping an OWNERS file path to Patterns.
2942 # Patterns is a dictionary mapping glob patterns (suitable for use in per-file
2943 # rules ) to a PatternEntry.
2944 # PatternEntry is a dictionary with two keys:
2945 # - 'files': the files that are matched by this pattern
2946 # - 'rules': the per-file rules needed for this pattern
2947 # For example, if we expect OWNERS file to contain rules for *.mojom and
2948 # *_struct_traits*.*, Patterns might look like this:
2949 # {
2950 # '*.mojom': {
2951 # 'files': ...,
2952 # 'rules': [
2953 # 'per-file *.mojom=set noparent',
2954 # 'per-file *.mojom=file://ipc/SECURITY_OWNERS',
2955 # ],
2956 # },
2957 # '*_struct_traits*.*': {
2958 # 'files': ...,
2959 # 'rules': [
2960 # 'per-file *_struct_traits*.*=set noparent',
2961 # 'per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS',
2962 # ],
2963 # },
2964 # }
2965 to_check = {}
2966
Daniel Cheng13ca61a882017-08-25 15:11:252967 def AddPatternToCheck(input_file, pattern):
2968 owners_file = input_api.os_path.join(
2969 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
2970 if owners_file not in to_check:
2971 to_check[owners_file] = {}
2972 if pattern not in to_check[owners_file]:
2973 to_check[owners_file][pattern] = {
2974 'files': [],
2975 'rules': [
2976 'per-file %s=set noparent' % pattern,
2977 'per-file %s=file://ipc/SECURITY_OWNERS' % pattern,
2978 ]
2979 }
Vaclav Brozekd5de76a2018-03-17 07:57:502980 to_check[owners_file][pattern]['files'].append(input_file)
Daniel Cheng13ca61a882017-08-25 15:11:252981
dchenge07de812016-06-20 19:27:172982 # Iterate through the affected files to see what we actually need to check
2983 # for. We should only nag patch authors about per-file rules if a file in that
2984 # directory would match that pattern. If a directory only contains *.mojom
2985 # files and no *_messages*.h files, we should only nag about rules for
2986 # *.mojom files.
Daniel Cheng13ca61a882017-08-25 15:11:252987 for f in input_api.AffectedFiles(include_deletes=False):
Daniel Cheng76f49cc2020-04-21 01:48:262988 # Manifest files don't have a strong naming convention. Instead, try to find
2989 # affected .cc and .h files which look like they contain a manifest
2990 # definition.
2991 manifest_pattern = input_api.re.compile('manifests?\.(cc|h)$')
2992 test_manifest_pattern = input_api.re.compile('test_manifests?\.(cc|h)')
2993 if (manifest_pattern.search(f.LocalPath()) and not
2994 test_manifest_pattern.search(f.LocalPath())):
2995 # We expect all actual service manifest files to contain at least one
2996 # qualified reference to service_manager::Manifest.
2997 if 'service_manager::Manifest' in '\n'.join(f.NewContents()):
Daniel Cheng13ca61a882017-08-25 15:11:252998 AddPatternToCheck(f, input_api.os_path.basename(f.LocalPath()))
dchenge07de812016-06-20 19:27:172999 for pattern in file_patterns:
3000 if input_api.fnmatch.fnmatch(
3001 input_api.os_path.basename(f.LocalPath()), pattern):
scottmg7a6ed5ba2016-11-04 18:22:043002 skip = False
3003 for exclude in exclude_paths:
3004 if input_api.fnmatch.fnmatch(f.LocalPath(), exclude):
3005 skip = True
3006 break
3007 if skip:
3008 continue
Daniel Cheng13ca61a882017-08-25 15:11:253009 AddPatternToCheck(f, pattern)
dchenge07de812016-06-20 19:27:173010 break
3011
Daniel Cheng7052cdf2017-11-21 19:23:293012 return to_check
3013
3014
Wez17c66962020-04-29 15:26:033015def _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check):
3016 """Adds OWNERS files to check for correct Fuchsia security owners."""
3017
3018 file_patterns = [
3019 # Component specifications.
3020 '*.cml', # Component Framework v2.
3021 '*.cmx', # Component Framework v1.
3022
3023 # Fuchsia IDL protocol specifications.
3024 '*.fidl',
3025 ]
3026
3027 def AddPatternToCheck(input_file, pattern):
3028 owners_file = input_api.os_path.join(
3029 input_api.os_path.dirname(input_file.LocalPath()), 'OWNERS')
3030 if owners_file not in to_check:
3031 to_check[owners_file] = {}
3032 if pattern not in to_check[owners_file]:
3033 to_check[owners_file][pattern] = {
3034 'files': [],
3035 'rules': [
3036 'per-file %s=set noparent' % pattern,
3037 'per-file %s=file://fuchsia/SECURITY_OWNERS' % pattern,
3038 ]
3039 }
3040 to_check[owners_file][pattern]['files'].append(input_file)
3041
3042 # Iterate through the affected files to see what we actually need to check
3043 # for. We should only nag patch authors about per-file rules if a file in that
3044 # directory would match that pattern.
3045 for f in input_api.AffectedFiles(include_deletes=False):
3046 for pattern in file_patterns:
3047 if input_api.fnmatch.fnmatch(
3048 input_api.os_path.basename(f.LocalPath()), pattern):
3049 AddPatternToCheck(f, pattern)
3050 break
3051
3052 return to_check
3053
3054
Saagar Sanghavifceeaae2020-08-12 16:40:363055def CheckSecurityOwners(input_api, output_api):
Daniel Cheng7052cdf2017-11-21 19:23:293056 """Checks that affected files involving IPC have an IPC OWNERS rule."""
3057 to_check = _GetOwnersFilesToCheckForIpcOwners(input_api)
Wez17c66962020-04-29 15:26:033058 _AddOwnersFilesToCheckForFuchsiaSecurityOwners(input_api, to_check)
Daniel Cheng7052cdf2017-11-21 19:23:293059
3060 if to_check:
3061 # If there are any OWNERS files to check, there are IPC-related changes in
3062 # this CL. Auto-CC the review list.
3063 output_api.AppendCC('[email protected]')
3064
3065 # Go through the OWNERS files to check, filtering out rules that are already
3066 # present in that OWNERS file.
dchenge07de812016-06-20 19:27:173067 for owners_file, patterns in to_check.iteritems():
3068 try:
3069 with file(owners_file) as f:
3070 lines = set(f.read().splitlines())
3071 for entry in patterns.itervalues():
3072 entry['rules'] = [rule for rule in entry['rules'] if rule not in lines
3073 ]
3074 except IOError:
3075 # No OWNERS file, so all the rules are definitely missing.
3076 continue
3077
3078 # All the remaining lines weren't found in OWNERS files, so emit an error.
3079 errors = []
3080 for owners_file, patterns in to_check.iteritems():
3081 missing_lines = []
3082 files = []
Vaclav Brozekd5de76a2018-03-17 07:57:503083 for _, entry in patterns.iteritems():
dchenge07de812016-06-20 19:27:173084 missing_lines.extend(entry['rules'])
3085 files.extend([' %s' % f.LocalPath() for f in entry['files']])
3086 if missing_lines:
3087 errors.append(
Vaclav Brozek1893a972018-04-25 05:48:053088 'Because of the presence of files:\n%s\n\n'
3089 '%s needs the following %d lines added:\n\n%s' %
3090 ('\n'.join(files), owners_file, len(missing_lines),
3091 '\n'.join(missing_lines)))
dchenge07de812016-06-20 19:27:173092
3093 results = []
3094 if errors:
vabrf5ce3bf92016-07-11 14:52:413095 if input_api.is_committing:
3096 output = output_api.PresubmitError
3097 else:
3098 output = output_api.PresubmitPromptWarning
3099 results.append(output(
Daniel Cheng52111692017-06-14 08:00:593100 'Found OWNERS files that need to be updated for IPC security ' +
3101 'review coverage.\nPlease update the OWNERS files below:',
dchenge07de812016-06-20 19:27:173102 long_text='\n\n'.join(errors)))
3103
3104 return results
3105
3106
Robert Sesek2c905332020-05-06 23:17:133107def _GetFilesUsingSecurityCriticalFunctions(input_api):
3108 """Checks affected files for changes to security-critical calls. This
3109 function checks the full change diff, to catch both additions/changes
3110 and removals.
3111
3112 Returns a dict keyed by file name, and the value is a set of detected
3113 functions.
3114 """
3115 # Map of function pretty name (displayed in an error) to the pattern to
3116 # match it with.
3117 _PATTERNS_TO_CHECK = {
Alex Goughbc964dd2020-06-15 17:52:373118 'content::GetServiceSandboxType<>()':
3119 'GetServiceSandboxType\\<'
Robert Sesek2c905332020-05-06 23:17:133120 }
3121 _PATTERNS_TO_CHECK = {
3122 k: input_api.re.compile(v)
3123 for k, v in _PATTERNS_TO_CHECK.items()
3124 }
3125
3126 # Scan all affected files for changes touching _FUNCTIONS_TO_CHECK.
3127 files_to_functions = {}
3128 for f in input_api.AffectedFiles():
3129 diff = f.GenerateScmDiff()
3130 for line in diff.split('\n'):
3131 # Not using just RightHandSideLines() because removing a
3132 # call to a security-critical function can be just as important
3133 # as adding or changing the arguments.
3134 if line.startswith('-') or (line.startswith('+') and
3135 not line.startswith('++')):
3136 for name, pattern in _PATTERNS_TO_CHECK.items():
3137 if pattern.search(line):
3138 path = f.LocalPath()
3139 if not path in files_to_functions:
3140 files_to_functions[path] = set()
3141 files_to_functions[path].add(name)
3142 return files_to_functions
3143
3144
Saagar Sanghavifceeaae2020-08-12 16:40:363145def CheckSecurityChanges(input_api, output_api):
Robert Sesek2c905332020-05-06 23:17:133146 """Checks that changes involving security-critical functions are reviewed
3147 by the security team.
3148 """
3149 files_to_functions = _GetFilesUsingSecurityCriticalFunctions(input_api)
3150 if len(files_to_functions):
3151 owners_db = input_api.owners_db
3152 owner_email, reviewers = (
3153 input_api.canned_checks.GetCodereviewOwnerAndReviewers(
3154 input_api,
3155 owners_db.email_regexp,
3156 approval_needed=input_api.is_committing))
3157
3158 # Load the OWNERS file for security changes.
3159 owners_file = 'ipc/SECURITY_OWNERS'
3160 security_owners = owners_db.owners_rooted_at_file(owners_file)
3161
3162 has_security_owner = any([owner in reviewers for owner in security_owners])
3163 if not has_security_owner:
3164 msg = 'The following files change calls to security-sensive functions\n' \
3165 'that need to be reviewed by {}.\n'.format(owners_file)
3166 for path, names in files_to_functions.items():
3167 msg += ' {}\n'.format(path)
3168 for name in names:
3169 msg += ' {}\n'.format(name)
3170 msg += '\n'
3171
3172 if input_api.is_committing:
3173 output = output_api.PresubmitError
3174 else:
3175 output = output_api.PresubmitNotifyResult
3176 return [output(msg)]
3177
3178 return []
3179
3180
Saagar Sanghavifceeaae2020-08-12 16:40:363181def CheckSetNoParent(input_api, output_api):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263182 """Checks that set noparent is only used together with an OWNERS file in
3183 //build/OWNERS.setnoparent (see also
3184 //docs/code_reviews.md#owners-files-details)
3185 """
3186 errors = []
3187
3188 allowed_owners_files_file = 'build/OWNERS.setnoparent'
3189 allowed_owners_files = set()
3190 with open(allowed_owners_files_file, 'r') as f:
3191 for line in f:
3192 line = line.strip()
3193 if not line or line.startswith('#'):
3194 continue
3195 allowed_owners_files.add(line)
3196
3197 per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
3198
3199 for f in input_api.AffectedFiles(include_deletes=False):
3200 if not f.LocalPath().endswith('OWNERS'):
3201 continue
3202
3203 found_owners_files = set()
3204 found_set_noparent_lines = dict()
3205
3206 # Parse the OWNERS file.
3207 for lineno, line in enumerate(f.NewContents(), 1):
3208 line = line.strip()
3209 if line.startswith('set noparent'):
3210 found_set_noparent_lines[''] = lineno
3211 if line.startswith('file://'):
3212 if line in allowed_owners_files:
3213 found_owners_files.add('')
3214 if line.startswith('per-file'):
3215 match = per_file_pattern.match(line)
3216 if match:
3217 glob = match.group(1).strip()
3218 directive = match.group(2).strip()
3219 if directive == 'set noparent':
3220 found_set_noparent_lines[glob] = lineno
3221 if directive.startswith('file://'):
3222 if directive in allowed_owners_files:
3223 found_owners_files.add(glob)
3224
3225 # Check that every set noparent line has a corresponding file:// line
3226 # listed in build/OWNERS.setnoparent.
3227 for set_noparent_line in found_set_noparent_lines:
3228 if set_noparent_line in found_owners_files:
3229 continue
3230 errors.append(' %s:%d' % (f.LocalPath(),
3231 found_set_noparent_lines[set_noparent_line]))
3232
3233 results = []
3234 if errors:
3235 if input_api.is_committing:
3236 output = output_api.PresubmitError
3237 else:
3238 output = output_api.PresubmitPromptWarning
3239 results.append(output(
3240 'Found the following "set noparent" restrictions in OWNERS files that '
3241 'do not include owners from build/OWNERS.setnoparent:',
3242 long_text='\n\n'.join(errors)))
3243 return results
3244
3245
Saagar Sanghavifceeaae2020-08-12 16:40:363246def CheckUselessForwardDeclarations(input_api, output_api):
jbriance2c51e821a2016-12-12 08:24:313247 """Checks that added or removed lines in non third party affected
3248 header files do not lead to new useless class or struct forward
3249 declaration.
jbriance9e12f162016-11-25 07:57:503250 """
3251 results = []
3252 class_pattern = input_api.re.compile(r'^class\s+(\w+);$',
3253 input_api.re.MULTILINE)
3254 struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$',
3255 input_api.re.MULTILINE)
3256 for f in input_api.AffectedFiles(include_deletes=False):
jbriance2c51e821a2016-12-12 08:24:313257 if (f.LocalPath().startswith('third_party') and
Kent Tamurae9b3a9ec2017-08-31 02:20:193258 not f.LocalPath().startswith('third_party/blink') and
Kent Tamura32dbbcb2018-11-30 12:28:493259 not f.LocalPath().startswith('third_party\\blink')):
jbriance2c51e821a2016-12-12 08:24:313260 continue
3261
jbriance9e12f162016-11-25 07:57:503262 if not f.LocalPath().endswith('.h'):
3263 continue
3264
3265 contents = input_api.ReadFile(f)
3266 fwd_decls = input_api.re.findall(class_pattern, contents)
3267 fwd_decls.extend(input_api.re.findall(struct_pattern, contents))
3268
3269 useless_fwd_decls = []
3270 for decl in fwd_decls:
3271 count = sum(1 for _ in input_api.re.finditer(
3272 r'\b%s\b' % input_api.re.escape(decl), contents))
3273 if count == 1:
3274 useless_fwd_decls.append(decl)
3275
3276 if not useless_fwd_decls:
3277 continue
3278
3279 for line in f.GenerateScmDiff().splitlines():
3280 if (line.startswith('-') and not line.startswith('--') or
3281 line.startswith('+') and not line.startswith('++')):
3282 for decl in useless_fwd_decls:
3283 if input_api.re.search(r'\b%s\b' % decl, line[1:]):
3284 results.append(output_api.PresubmitPromptWarning(
ricea6416dea2017-05-19 12:39:243285 '%s: %s forward declaration is no longer needed' %
jbriance9e12f162016-11-25 07:57:503286 (f.LocalPath(), decl)))
3287 useless_fwd_decls.remove(decl)
3288
3289 return results
3290
Jinsong Fan91ebbbd2019-04-16 14:57:173291def _CheckAndroidDebuggableBuild(input_api, output_api):
3292 """Checks that code uses BuildInfo.isDebugAndroid() instead of
3293 Build.TYPE.equals('') or ''.equals(Build.TYPE) to check if
3294 this is a debuggable build of Android.
3295 """
3296 build_type_check_pattern = input_api.re.compile(
3297 r'\bBuild\.TYPE\.equals\(|\.equals\(\s*\bBuild\.TYPE\)')
3298
3299 errors = []
3300
3301 sources = lambda affected_file: input_api.FilterSourceFile(
3302 affected_file,
James Cook24a504192020-07-23 00:08:443303 files_to_skip=(_EXCLUDED_PATHS +
3304 _TEST_CODE_EXCLUDED_PATHS +
3305 input_api.DEFAULT_FILES_TO_SKIP +
3306 (r"^android_webview[\\/]support_library[\\/]"
3307 "boundary_interfaces[\\/]",
3308 r"^chrome[\\/]android[\\/]webapk[\\/].*",
3309 r'^third_party[\\/].*',
3310 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
3311 r"webview[\\/]chromium[\\/]License.*",)),
3312 files_to_check=[r'.*\.java$'])
Jinsong Fan91ebbbd2019-04-16 14:57:173313
3314 for f in input_api.AffectedSourceFiles(sources):
3315 for line_num, line in f.ChangedContents():
3316 if build_type_check_pattern.search(line):
3317 errors.append("%s:%d" % (f.LocalPath(), line_num))
3318
3319 results = []
3320
3321 if errors:
3322 results.append(output_api.PresubmitPromptWarning(
3323 'Build.TYPE.equals or .equals(Build.TYPE) usage is detected.'
3324 ' Please use BuildInfo.isDebugAndroid() instead.',
3325 errors))
3326
3327 return results
jbriance9e12f162016-11-25 07:57:503328
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493329# TODO: add unit tests
dskiba88634f4e2015-08-14 23:03:293330def _CheckAndroidToastUsage(input_api, output_api):
3331 """Checks that code uses org.chromium.ui.widget.Toast instead of
3332 android.widget.Toast (Chromium Toast doesn't force hardware
3333 acceleration on low-end devices, saving memory).
3334 """
3335 toast_import_pattern = input_api.re.compile(
3336 r'^import android\.widget\.Toast;$')
3337
3338 errors = []
3339
3340 sources = lambda affected_file: input_api.FilterSourceFile(
3341 affected_file,
James Cook24a504192020-07-23 00:08:443342 files_to_skip=(_EXCLUDED_PATHS +
3343 _TEST_CODE_EXCLUDED_PATHS +
3344 input_api.DEFAULT_FILES_TO_SKIP +
3345 (r'^chromecast[\\/].*',
3346 r'^remoting[\\/].*')),
3347 files_to_check=[r'.*\.java$'])
dskiba88634f4e2015-08-14 23:03:293348
3349 for f in input_api.AffectedSourceFiles(sources):
3350 for line_num, line in f.ChangedContents():
3351 if toast_import_pattern.search(line):
3352 errors.append("%s:%d" % (f.LocalPath(), line_num))
3353
3354 results = []
3355
3356 if errors:
3357 results.append(output_api.PresubmitError(
3358 'android.widget.Toast usage is detected. Android toasts use hardware'
3359 ' acceleration, and can be\ncostly on low-end devices. Please use'
3360 ' org.chromium.ui.widget.Toast instead.\n'
3361 'Contact [email protected] if you have any questions.',
3362 errors))
3363
3364 return results
3365
3366
dgnaa68d5e2015-06-10 10:08:223367def _CheckAndroidCrLogUsage(input_api, output_api):
3368 """Checks that new logs using org.chromium.base.Log:
3369 - Are using 'TAG' as variable name for the tags (warn)
dgn38736db2015-09-18 19:20:513370 - Are using a tag that is shorter than 20 characters (error)
dgnaa68d5e2015-06-10 10:08:223371 """
pkotwicza1dd0b002016-05-16 14:41:043372
torne89540622017-03-24 19:41:303373 # Do not check format of logs in the given files
pkotwicza1dd0b002016-05-16 14:41:043374 cr_log_check_excluded_paths = [
torne89540622017-03-24 19:41:303375 # //chrome/android/webapk cannot depend on //base
Egor Paskoce145c42018-09-28 19:31:043376 r"^chrome[\\/]android[\\/]webapk[\\/].*",
torne89540622017-03-24 19:41:303377 # WebView license viewer code cannot depend on //base; used in stub APK.
Egor Paskoce145c42018-09-28 19:31:043378 r"^android_webview[\\/]glue[\\/]java[\\/]src[\\/]com[\\/]android[\\/]"
3379 r"webview[\\/]chromium[\\/]License.*",
Egor Paskoa5c05b02018-09-28 16:04:093380 # The customtabs_benchmark is a small app that does not depend on Chromium
3381 # java pieces.
Egor Paskoce145c42018-09-28 19:31:043382 r"tools[\\/]android[\\/]customtabs_benchmark[\\/].*",
pkotwicza1dd0b002016-05-16 14:41:043383 ]
3384
dgnaa68d5e2015-06-10 10:08:223385 cr_log_import_pattern = input_api.re.compile(
dgn87d9fb62015-06-12 09:15:123386 r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE)
3387 class_in_base_pattern = input_api.re.compile(
3388 r'^package org\.chromium\.base;$', input_api.re.MULTILINE)
3389 has_some_log_import_pattern = input_api.re.compile(
3390 r'^import .*\.Log;$', input_api.re.MULTILINE)
dgnaa68d5e2015-06-10 10:08:223391 # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
Tomasz Śniatowski3ae2f102020-03-23 15:35:553392 log_call_pattern = input_api.re.compile(r'\bLog\.\w\((?P<tag>\"?\w+)')
dgnaa68d5e2015-06-10 10:08:223393 log_decl_pattern = input_api.re.compile(
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463394 r'static final String TAG = "(?P<name>(.*))"')
Tomasz Śniatowski3ae2f102020-03-23 15:35:553395 rough_log_decl_pattern = input_api.re.compile(r'\bString TAG\s*=')
dgnaa68d5e2015-06-10 10:08:223396
Torne (Richard Coles)3bd7ad02019-10-22 21:20:463397 REF_MSG = ('See docs/android_logging.md for more info.')
James Cook24a504192020-07-23 00:08:443398 sources = lambda x: input_api.FilterSourceFile(x,
3399 files_to_check=[r'.*\.java$'],
3400 files_to_skip=cr_log_check_excluded_paths)
dgn87d9fb62015-06-12 09:15:123401
dgnaa68d5e2015-06-10 10:08:223402 tag_decl_errors = []
3403 tag_length_errors = []
dgn87d9fb62015-06-12 09:15:123404 tag_errors = []
dgn38736db2015-09-18 19:20:513405 tag_with_dot_errors = []
dgn87d9fb62015-06-12 09:15:123406 util_log_errors = []
dgnaa68d5e2015-06-10 10:08:223407
3408 for f in input_api.AffectedSourceFiles(sources):
3409 file_content = input_api.ReadFile(f)
3410 has_modified_logs = False
dgnaa68d5e2015-06-10 10:08:223411 # Per line checks
dgn87d9fb62015-06-12 09:15:123412 if (cr_log_import_pattern.search(file_content) or
3413 (class_in_base_pattern.search(file_content) and
3414 not has_some_log_import_pattern.search(file_content))):
3415 # Checks to run for files using cr log
dgnaa68d5e2015-06-10 10:08:223416 for line_num, line in f.ChangedContents():
Tomasz Śniatowski3ae2f102020-03-23 15:35:553417 if rough_log_decl_pattern.search(line):
3418 has_modified_logs = True
dgnaa68d5e2015-06-10 10:08:223419
3420 # Check if the new line is doing some logging
dgn87d9fb62015-06-12 09:15:123421 match = log_call_pattern.search(line)
dgnaa68d5e2015-06-10 10:08:223422 if match:
3423 has_modified_logs = True
3424
3425 # Make sure it uses "TAG"
3426 if not match.group('tag') == 'TAG':
3427 tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgn87d9fb62015-06-12 09:15:123428 else:
3429 # Report non cr Log function calls in changed lines
3430 for line_num, line in f.ChangedContents():
3431 if log_call_pattern.search(line):
3432 util_log_errors.append("%s:%d" % (f.LocalPath(), line_num))
dgnaa68d5e2015-06-10 10:08:223433
3434 # Per file checks
3435 if has_modified_logs:
3436 # Make sure the tag is using the "cr" prefix and is not too long
3437 match = log_decl_pattern.search(file_content)
dgn38736db2015-09-18 19:20:513438 tag_name = match.group('name') if match else None
3439 if not tag_name:
dgnaa68d5e2015-06-10 10:08:223440 tag_decl_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513441 elif len(tag_name) > 20:
dgnaa68d5e2015-06-10 10:08:223442 tag_length_errors.append(f.LocalPath())
dgn38736db2015-09-18 19:20:513443 elif '.' in tag_name:
3444 tag_with_dot_errors.append(f.LocalPath())
dgnaa68d5e2015-06-10 10:08:223445
3446 results = []
3447 if tag_decl_errors:
3448 results.append(output_api.PresubmitPromptWarning(
3449 'Please define your tags using the suggested format: .\n'
dgn38736db2015-09-18 19:20:513450 '"private static final String TAG = "<package tag>".\n'
3451 'They will be prepended with "cr_" automatically.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223452 tag_decl_errors))
3453
3454 if tag_length_errors:
3455 results.append(output_api.PresubmitError(
3456 'The tag length is restricted by the system to be at most '
dgn38736db2015-09-18 19:20:513457 '20 characters.\n' + REF_MSG,
dgnaa68d5e2015-06-10 10:08:223458 tag_length_errors))
3459
3460 if tag_errors:
3461 results.append(output_api.PresubmitPromptWarning(
3462 'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
3463 tag_errors))
3464
dgn87d9fb62015-06-12 09:15:123465 if util_log_errors:
dgn4401aa52015-04-29 16:26:173466 results.append(output_api.PresubmitPromptWarning(
dgn87d9fb62015-06-12 09:15:123467 'Please use org.chromium.base.Log for new logs.\n' + REF_MSG,
3468 util_log_errors))
3469
dgn38736db2015-09-18 19:20:513470 if tag_with_dot_errors:
3471 results.append(output_api.PresubmitPromptWarning(
3472 'Dot in log tags cause them to be elided in crash reports.\n' + REF_MSG,
3473 tag_with_dot_errors))
3474
dgn4401aa52015-04-29 16:26:173475 return results
3476
3477
Yoland Yanb92fa522017-08-28 17:37:063478def _CheckAndroidTestJUnitFrameworkImport(input_api, output_api):
3479 """Checks that junit.framework.* is no longer used."""
3480 deprecated_junit_framework_pattern = input_api.re.compile(
3481 r'^import junit\.framework\..*;',
3482 input_api.re.MULTILINE)
3483 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443484 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063485 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133486 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063487 for line_num, line in f.ChangedContents():
3488 if deprecated_junit_framework_pattern.search(line):
3489 errors.append("%s:%d" % (f.LocalPath(), line_num))
3490
3491 results = []
3492 if errors:
3493 results.append(output_api.PresubmitError(
3494 'APIs from junit.framework.* are deprecated, please use JUnit4 framework'
3495 '(org.junit.*) from //third_party/junit. Contact [email protected]'
3496 ' if you have any question.', errors))
3497 return results
3498
3499
3500def _CheckAndroidTestJUnitInheritance(input_api, output_api):
3501 """Checks that if new Java test classes have inheritance.
3502 Either the new test class is JUnit3 test or it is a JUnit4 test class
3503 with a base class, either case is undesirable.
3504 """
3505 class_declaration_pattern = input_api.re.compile(r'^public class \w*Test ')
3506
3507 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443508 x, files_to_check=[r'.*Test\.java$'], files_to_skip=None)
Yoland Yanb92fa522017-08-28 17:37:063509 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133510 for f in input_api.AffectedFiles(file_filter=sources):
Yoland Yanb92fa522017-08-28 17:37:063511 if not f.OldContents():
3512 class_declaration_start_flag = False
3513 for line_num, line in f.ChangedContents():
3514 if class_declaration_pattern.search(line):
3515 class_declaration_start_flag = True
3516 if class_declaration_start_flag and ' extends ' in line:
3517 errors.append('%s:%d' % (f.LocalPath(), line_num))
3518 if '{' in line:
3519 class_declaration_start_flag = False
3520
3521 results = []
3522 if errors:
3523 results.append(output_api.PresubmitPromptWarning(
3524 'The newly created files include Test classes that inherits from base'
3525 ' class. Please do not use inheritance in JUnit4 tests or add new'
3526 ' JUnit3 tests. Contact [email protected] if you have any'
3527 ' questions.', errors))
3528 return results
3529
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203530
yolandyan45001472016-12-21 21:12:423531def _CheckAndroidTestAnnotationUsage(input_api, output_api):
3532 """Checks that android.test.suitebuilder.annotation.* is no longer used."""
3533 deprecated_annotation_import_pattern = input_api.re.compile(
3534 r'^import android\.test\.suitebuilder\.annotation\..*;',
3535 input_api.re.MULTILINE)
3536 sources = lambda x: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443537 x, files_to_check=[r'.*\.java$'], files_to_skip=None)
yolandyan45001472016-12-21 21:12:423538 errors = []
Edward Lemur7bbfdf12020-01-15 02:06:133539 for f in input_api.AffectedFiles(file_filter=sources):
yolandyan45001472016-12-21 21:12:423540 for line_num, line in f.ChangedContents():
3541 if deprecated_annotation_import_pattern.search(line):
3542 errors.append("%s:%d" % (f.LocalPath(), line_num))
3543
3544 results = []
3545 if errors:
3546 results.append(output_api.PresubmitError(
3547 'Annotations in android.test.suitebuilder.annotation have been'
3548 ' deprecated since API level 24. Please use android.support.test.filters'
3549 ' from //third_party/android_support_test_runner:runner_java instead.'
3550 ' Contact [email protected] if you have any questions.', errors))
3551 return results
3552
3553
agrieve7b6479d82015-10-07 14:24:223554def _CheckAndroidNewMdpiAssetLocation(input_api, output_api):
3555 """Checks if MDPI assets are placed in a correct directory."""
3556 file_filter = lambda f: (f.LocalPath().endswith('.png') and
3557 ('/res/drawable/' in f.LocalPath() or
3558 '/res/drawable-ldrtl/' in f.LocalPath()))
3559 errors = []
3560 for f in input_api.AffectedFiles(include_deletes=False,
3561 file_filter=file_filter):
3562 errors.append(' %s' % f.LocalPath())
3563
3564 results = []
3565 if errors:
3566 results.append(output_api.PresubmitError(
3567 'MDPI assets should be placed in /res/drawable-mdpi/ or '
3568 '/res/drawable-ldrtl-mdpi/\ninstead of /res/drawable/ and'
3569 '/res/drawable-ldrtl/.\n'
3570 'Contact [email protected] if you have questions.', errors))
3571 return results
3572
3573
Nate Fischer535972b2017-09-16 01:06:183574def _CheckAndroidWebkitImports(input_api, output_api):
3575 """Checks that code uses org.chromium.base.Callback instead of
Bo Liubfde1c02019-09-24 23:08:353576 android.webview.ValueCallback except in the WebView glue layer
3577 and WebLayer.
Nate Fischer535972b2017-09-16 01:06:183578 """
3579 valuecallback_import_pattern = input_api.re.compile(
3580 r'^import android\.webkit\.ValueCallback;$')
3581
3582 errors = []
3583
3584 sources = lambda affected_file: input_api.FilterSourceFile(
3585 affected_file,
James Cook24a504192020-07-23 00:08:443586 files_to_skip=(_EXCLUDED_PATHS +
3587 _TEST_CODE_EXCLUDED_PATHS +
3588 input_api.DEFAULT_FILES_TO_SKIP +
3589 (r'^android_webview[\\/]glue[\\/].*',
3590 r'^weblayer[\\/].*',)),
3591 files_to_check=[r'.*\.java$'])
Nate Fischer535972b2017-09-16 01:06:183592
3593 for f in input_api.AffectedSourceFiles(sources):
3594 for line_num, line in f.ChangedContents():
3595 if valuecallback_import_pattern.search(line):
3596 errors.append("%s:%d" % (f.LocalPath(), line_num))
3597
3598 results = []
3599
3600 if errors:
3601 results.append(output_api.PresubmitError(
3602 'android.webkit.ValueCallback usage is detected outside of the glue'
3603 ' layer. To stay compatible with the support library, android.webkit.*'
3604 ' classes should only be used inside the glue layer and'
3605 ' org.chromium.base.Callback should be used instead.',
3606 errors))
3607
3608 return results
3609
3610
Becky Zhou7c69b50992018-12-10 19:37:573611def _CheckAndroidXmlStyle(input_api, output_api, is_check_on_upload):
3612 """Checks Android XML styles """
3613 import sys
3614 original_sys_path = sys.path
3615 try:
3616 sys.path = sys.path + [input_api.os_path.join(
3617 input_api.PresubmitLocalPath(), 'tools', 'android', 'checkxmlstyle')]
3618 import checkxmlstyle
3619 finally:
3620 # Restore sys.path to what it was before.
3621 sys.path = original_sys_path
3622
3623 if is_check_on_upload:
3624 return checkxmlstyle.CheckStyleOnUpload(input_api, output_api)
3625 else:
3626 return checkxmlstyle.CheckStyleOnCommit(input_api, output_api)
3627
3628
agrievef32bcc72016-04-04 14:57:403629class PydepsChecker(object):
3630 def __init__(self, input_api, pydeps_files):
3631 self._file_cache = {}
3632 self._input_api = input_api
3633 self._pydeps_files = pydeps_files
3634
3635 def _LoadFile(self, path):
3636 """Returns the list of paths within a .pydeps file relative to //."""
3637 if path not in self._file_cache:
3638 with open(path) as f:
3639 self._file_cache[path] = f.read()
3640 return self._file_cache[path]
3641
3642 def _ComputeNormalizedPydepsEntries(self, pydeps_path):
3643 """Returns an interable of paths within the .pydep, relativized to //."""
3644 os_path = self._input_api.os_path
3645 pydeps_dir = os_path.dirname(pydeps_path)
3646 entries = (l.rstrip() for l in self._LoadFile(pydeps_path).splitlines()
3647 if not l.startswith('*'))
3648 return (os_path.normpath(os_path.join(pydeps_dir, e)) for e in entries)
3649
3650 def _CreateFilesToPydepsMap(self):
3651 """Returns a map of local_path -> list_of_pydeps."""
3652 ret = {}
3653 for pydep_local_path in self._pydeps_files:
3654 for path in self._ComputeNormalizedPydepsEntries(pydep_local_path):
3655 ret.setdefault(path, []).append(pydep_local_path)
3656 return ret
3657
3658 def ComputeAffectedPydeps(self):
3659 """Returns an iterable of .pydeps files that might need regenerating."""
3660 affected_pydeps = set()
3661 file_to_pydeps_map = None
3662 for f in self._input_api.AffectedFiles(include_deletes=True):
3663 local_path = f.LocalPath()
Andrew Grieve892bb3f2019-03-20 17:33:463664 # Changes to DEPS can lead to .pydeps changes if any .py files are in
3665 # subrepositories. We can't figure out which files change, so re-check
3666 # all files.
3667 # Changes to print_python_deps.py affect all .pydeps.
Andrew Grieveb773bad2020-06-05 18:00:383668 if local_path in ('DEPS', 'PRESUBMIT.py') or local_path.endswith(
3669 'print_python_deps.py'):
agrievef32bcc72016-04-04 14:57:403670 return self._pydeps_files
3671 elif local_path.endswith('.pydeps'):
3672 if local_path in self._pydeps_files:
3673 affected_pydeps.add(local_path)
3674 elif local_path.endswith('.py'):
3675 if file_to_pydeps_map is None:
3676 file_to_pydeps_map = self._CreateFilesToPydepsMap()
3677 affected_pydeps.update(file_to_pydeps_map.get(local_path, ()))
3678 return affected_pydeps
3679
3680 def DetermineIfStale(self, pydeps_path):
3681 """Runs print_python_deps.py to see if the files is stale."""
phajdan.jr0d9878552016-11-04 10:49:413682 import difflib
John Budorick47ca3fe2018-02-10 00:53:103683 import os
3684
agrievef32bcc72016-04-04 14:57:403685 old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
Mohamed Heikale217fc852020-07-06 19:44:033686 if old_pydeps_data:
3687 cmd = old_pydeps_data[1][1:].strip()
3688 old_contents = old_pydeps_data[2:]
3689 else:
3690 # A default cmd that should work in most cases (as long as pydeps filename
3691 # matches the script name) so that PRESUBMIT.py does not crash if pydeps
3692 # file is empty/new.
3693 cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
3694 pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
3695 old_contents = []
John Budorick47ca3fe2018-02-10 00:53:103696 env = dict(os.environ)
3697 env['PYTHONDONTWRITEBYTECODE'] = '1'
agrievef32bcc72016-04-04 14:57:403698 new_pydeps_data = self._input_api.subprocess.check_output(
John Budorick47ca3fe2018-02-10 00:53:103699 cmd + ' --output ""', shell=True, env=env)
phajdan.jr0d9878552016-11-04 10:49:413700 new_contents = new_pydeps_data.splitlines()[2:]
Mohamed Heikale217fc852020-07-06 19:44:033701 if old_contents != new_contents:
phajdan.jr0d9878552016-11-04 10:49:413702 return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
agrievef32bcc72016-04-04 14:57:403703
3704
Tibor Goldschwendt360793f72019-06-25 18:23:493705def _ParseGclientArgs():
3706 args = {}
3707 with open('build/config/gclient_args.gni', 'r') as f:
3708 for line in f:
3709 line = line.strip()
3710 if not line or line.startswith('#'):
3711 continue
3712 attribute, value = line.split('=')
3713 args[attribute.strip()] = value.strip()
3714 return args
3715
3716
Saagar Sanghavifceeaae2020-08-12 16:40:363717def CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
agrievef32bcc72016-04-04 14:57:403718 """Checks if a .pydeps file needs to be regenerated."""
John Chencde89192018-01-27 21:18:403719 # This check is for Python dependency lists (.pydeps files), and involves
3720 # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
3721 # doesn't work on Windows and Mac, so skip it on other platforms.
agrieve9bc4200b2016-05-04 16:33:283722 if input_api.platform != 'linux2':
agrievebb9c5b472016-04-22 15:13:003723 return []
Tibor Goldschwendt360793f72019-06-25 18:23:493724 is_android = _ParseGclientArgs().get('checkout_android', 'false') == 'true'
Mohamed Heikal7cd4d8312020-06-16 16:49:403725 pydeps_to_check = _ALL_PYDEPS_FILES if is_android else _GENERIC_PYDEPS_FILES
agrievef32bcc72016-04-04 14:57:403726 results = []
3727 # First, check for new / deleted .pydeps.
3728 for f in input_api.AffectedFiles(include_deletes=True):
Zhiling Huang45cabf32018-03-10 00:50:033729 # Check whether we are running the presubmit check for a file in src.
3730 # f.LocalPath is relative to repo (src, or internal repo).
3731 # os_path.exists is relative to src repo.
3732 # Therefore if os_path.exists is true, it means f.LocalPath is relative
3733 # to src and we can conclude that the pydeps is in src.
3734 if input_api.os_path.exists(f.LocalPath()):
3735 if f.LocalPath().endswith('.pydeps'):
3736 if f.Action() == 'D' and f.LocalPath() in _ALL_PYDEPS_FILES:
3737 results.append(output_api.PresubmitError(
3738 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3739 'remove %s' % f.LocalPath()))
3740 elif f.Action() != 'D' and f.LocalPath() not in _ALL_PYDEPS_FILES:
3741 results.append(output_api.PresubmitError(
3742 'Please update _ALL_PYDEPS_FILES within //PRESUBMIT.py to '
3743 'include %s' % f.LocalPath()))
agrievef32bcc72016-04-04 14:57:403744
3745 if results:
3746 return results
3747
Mohamed Heikal7cd4d8312020-06-16 16:49:403748 checker = checker_for_tests or PydepsChecker(input_api, _ALL_PYDEPS_FILES)
3749 affected_pydeps = set(checker.ComputeAffectedPydeps())
3750 affected_android_pydeps = affected_pydeps.intersection(
3751 set(_ANDROID_SPECIFIC_PYDEPS_FILES))
3752 if affected_android_pydeps and not is_android:
3753 results.append(output_api.PresubmitPromptOrNotify(
3754 'You have changed python files that may affect pydeps for android\n'
3755 'specific scripts. However, the relevant presumbit check cannot be\n'
3756 'run because you are not using an Android checkout. To validate that\n'
3757 'the .pydeps are correct, re-run presubmit in an Android checkout, or\n'
3758 'use the android-internal-presubmit optional trybot.\n'
3759 'Possibly stale pydeps files:\n{}'.format(
3760 '\n'.join(affected_android_pydeps))))
agrievef32bcc72016-04-04 14:57:403761
Mohamed Heikal7cd4d8312020-06-16 16:49:403762 affected_pydeps_to_check = affected_pydeps.intersection(set(pydeps_to_check))
3763 for pydep_path in affected_pydeps_to_check:
agrievef32bcc72016-04-04 14:57:403764 try:
phajdan.jr0d9878552016-11-04 10:49:413765 result = checker.DetermineIfStale(pydep_path)
3766 if result:
3767 cmd, diff = result
agrievef32bcc72016-04-04 14:57:403768 results.append(output_api.PresubmitError(
phajdan.jr0d9878552016-11-04 10:49:413769 'File is stale: %s\nDiff (apply to fix):\n%s\n'
3770 'To regenerate, run:\n\n %s' %
3771 (pydep_path, diff, cmd)))
agrievef32bcc72016-04-04 14:57:403772 except input_api.subprocess.CalledProcessError as error:
3773 return [output_api.PresubmitError('Error running: %s' % error.cmd,
3774 long_text=error.output)]
3775
3776 return results
3777
3778
Saagar Sanghavifceeaae2020-08-12 16:40:363779def CheckSingletonInHeaders(input_api, output_api):
glidere61efad2015-02-18 17:39:433780 """Checks to make sure no header files have |Singleton<|."""
3781 def FileFilter(affected_file):
3782 # It's ok for base/memory/singleton.h to have |Singleton<|.
James Cook24a504192020-07-23 00:08:443783 files_to_skip = (_EXCLUDED_PATHS +
3784 input_api.DEFAULT_FILES_TO_SKIP +
3785 (r"^base[\\/]memory[\\/]singleton\.h$",
3786 r"^net[\\/]quic[\\/]platform[\\/]impl[\\/]"
3787 r"quic_singleton_impl\.h$"))
3788 return input_api.FilterSourceFile(affected_file,
3789 files_to_skip=files_to_skip)
glidere61efad2015-02-18 17:39:433790
sergeyu34d21222015-09-16 00:11:443791 pattern = input_api.re.compile(r'(?<!class\sbase::)Singleton\s*<')
glidere61efad2015-02-18 17:39:433792 files = []
3793 for f in input_api.AffectedSourceFiles(FileFilter):
3794 if (f.LocalPath().endswith('.h') or f.LocalPath().endswith('.hxx') or
3795 f.LocalPath().endswith('.hpp') or f.LocalPath().endswith('.inl')):
3796 contents = input_api.ReadFile(f)
3797 for line in contents.splitlines(False):
oysteinec430ad42015-10-22 20:55:243798 if (not line.lstrip().startswith('//') and # Strip C++ comment.
glidere61efad2015-02-18 17:39:433799 pattern.search(line)):
3800 files.append(f)
3801 break
3802
3803 if files:
yolandyandaabc6d2016-04-18 18:29:393804 return [output_api.PresubmitError(
sergeyu34d21222015-09-16 00:11:443805 'Found base::Singleton<T> in the following header files.\n' +
glidere61efad2015-02-18 17:39:433806 'Please move them to an appropriate source file so that the ' +
3807 'template gets instantiated in a single compilation unit.',
3808 files) ]
3809 return []
3810
3811
[email protected]fd20b902014-05-09 02:14:533812_DEPRECATED_CSS = [
3813 # Values
3814 ( "-webkit-box", "flex" ),
3815 ( "-webkit-inline-box", "inline-flex" ),
3816 ( "-webkit-flex", "flex" ),
3817 ( "-webkit-inline-flex", "inline-flex" ),
3818 ( "-webkit-min-content", "min-content" ),
3819 ( "-webkit-max-content", "max-content" ),
3820
3821 # Properties
3822 ( "-webkit-background-clip", "background-clip" ),
3823 ( "-webkit-background-origin", "background-origin" ),
3824 ( "-webkit-background-size", "background-size" ),
3825 ( "-webkit-box-shadow", "box-shadow" ),
dbeam6936c67f2017-01-19 01:51:443826 ( "-webkit-user-select", "user-select" ),
[email protected]fd20b902014-05-09 02:14:533827
3828 # Functions
3829 ( "-webkit-gradient", "gradient" ),
3830 ( "-webkit-repeating-gradient", "repeating-gradient" ),
3831 ( "-webkit-linear-gradient", "linear-gradient" ),
3832 ( "-webkit-repeating-linear-gradient", "repeating-linear-gradient" ),
3833 ( "-webkit-radial-gradient", "radial-gradient" ),
3834 ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ),
3835]
3836
Wei-Yin Chen (陳威尹)f799d442018-07-31 02:20:203837
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493838# TODO: add unit tests
Saagar Sanghavifceeaae2020-08-12 16:40:363839def CheckNoDeprecatedCss(input_api, output_api):
[email protected]fd20b902014-05-09 02:14:533840 """ Make sure that we don't use deprecated CSS
[email protected]9a48e3f82014-05-22 00:06:253841 properties, functions or values. Our external
mdjonesae0286c32015-06-10 18:10:343842 documentation and iOS CSS for dom distiller
3843 (reader mode) are ignored by the hooks as it
[email protected]9a48e3f82014-05-22 00:06:253844 needs to be consumed by WebKit. """
[email protected]fd20b902014-05-09 02:14:533845 results = []
Wei-Yin Chen (陳威尹)dca729a2018-07-31 21:35:493846 file_inclusion_pattern = [r".+\.css$"]
James Cook24a504192020-07-23 00:08:443847 files_to_skip = (_EXCLUDED_PATHS +
3848 _TEST_CODE_EXCLUDED_PATHS +
3849 input_api.DEFAULT_FILES_TO_SKIP +
3850 (r"^chrome/common/extensions/docs",
3851 r"^chrome/docs",
3852 r"^components/dom_distiller/core/css/distilledpage_ios.css",
3853 r"^components/neterror/resources/neterror.css",
3854 r"^native_client_sdk"))
[email protected]9a48e3f82014-05-22 00:06:253855 file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:443856 f, files_to_check=file_inclusion_pattern, files_to_skip=files_to_skip)
[email protected]fd20b902014-05-09 02:14:533857 for fpath in input_api.AffectedFiles(file_filter=file_filter):
3858 for line_num, line in fpath.ChangedContents():
3859 for (deprecated_value, value) in _DEPRECATED_CSS:
dbeam070cfe62014-10-22 06:44:023860 if deprecated_value in line:
[email protected]fd20b902014-05-09 02:14:533861 results.append(output_api.PresubmitError(
3862 "%s:%d: Use of deprecated CSS %s, use %s instead" %
3863 (fpath.LocalPath(), line_num, deprecated_value, value)))
3864 return results
3865
mohan.reddyf21db962014-10-16 12:26:473866
Saagar Sanghavifceeaae2020-08-12 16:40:363867def CheckForRelativeIncludes(input_api, output_api):
rlanday6802cf632017-05-30 17:48:363868 bad_files = {}
3869 for f in input_api.AffectedFiles(include_deletes=False):
3870 if (f.LocalPath().startswith('third_party') and
Kent Tamura32dbbcb2018-11-30 12:28:493871 not f.LocalPath().startswith('third_party/blink') and
3872 not f.LocalPath().startswith('third_party\\blink')):
rlanday6802cf632017-05-30 17:48:363873 continue
3874
Daniel Bratell65b033262019-04-23 08:17:063875 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
rlanday6802cf632017-05-30 17:48:363876 continue
3877
Vaclav Brozekd5de76a2018-03-17 07:57:503878 relative_includes = [line for _, line in f.ChangedContents()
rlanday6802cf632017-05-30 17:48:363879 if "#include" in line and "../" in line]
3880 if not relative_includes:
3881 continue
3882 bad_files[f.LocalPath()] = relative_includes
3883
3884 if not bad_files:
3885 return []
3886
3887 error_descriptions = []
3888 for file_path, bad_lines in bad_files.iteritems():
3889 error_description = file_path
3890 for line in bad_lines:
3891 error_description += '\n ' + line
3892 error_descriptions.append(error_description)
3893
3894 results = []
3895 results.append(output_api.PresubmitError(
3896 'You added one or more relative #include paths (including "../").\n'
3897 'These shouldn\'t be used because they can be used to include headers\n'
3898 'from code that\'s not correctly specified as a dependency in the\n'
3899 'relevant BUILD.gn file(s).',
3900 error_descriptions))
3901
3902 return results
3903
Takeshi Yoshinoe387aa32017-08-02 13:16:133904
Saagar Sanghavifceeaae2020-08-12 16:40:363905def CheckForCcIncludes(input_api, output_api):
Daniel Bratell65b033262019-04-23 08:17:063906 """Check that nobody tries to include a cc file. It's a relatively
3907 common error which results in duplicate symbols in object
3908 files. This may not always break the build until someone later gets
3909 very confusing linking errors."""
3910 results = []
3911 for f in input_api.AffectedFiles(include_deletes=False):
3912 # We let third_party code do whatever it wants
3913 if (f.LocalPath().startswith('third_party') and
3914 not f.LocalPath().startswith('third_party/blink') and
3915 not f.LocalPath().startswith('third_party\\blink')):
3916 continue
3917
3918 if not _IsCPlusPlusFile(input_api, f.LocalPath()):
3919 continue
3920
3921 for _, line in f.ChangedContents():
3922 if line.startswith('#include "'):
3923 included_file = line.split('"')[1]
3924 if _IsCPlusPlusFile(input_api, included_file):
3925 # The most common naming for external files with C++ code,
3926 # apart from standard headers, is to call them foo.inc, but
3927 # Chromium sometimes uses foo-inc.cc so allow that as well.
3928 if not included_file.endswith(('.h', '-inc.cc')):
3929 results.append(output_api.PresubmitError(
3930 'Only header files or .inc files should be included in other\n'
3931 'C++ files. Compiling the contents of a cc file more than once\n'
3932 'will cause duplicate information in the build which may later\n'
3933 'result in strange link_errors.\n' +
3934 f.LocalPath() + ':\n ' +
3935 line))
3936
3937 return results
3938
3939
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203940def _CheckWatchlistDefinitionsEntrySyntax(key, value, ast):
3941 if not isinstance(key, ast.Str):
3942 return 'Key at line %d must be a string literal' % key.lineno
3943 if not isinstance(value, ast.Dict):
3944 return 'Value at line %d must be a dict' % value.lineno
3945 if len(value.keys) != 1:
3946 return 'Dict at line %d must have single entry' % value.lineno
3947 if not isinstance(value.keys[0], ast.Str) or value.keys[0].s != 'filepath':
3948 return (
3949 'Entry at line %d must have a string literal \'filepath\' as key' %
3950 value.lineno)
3951 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133952
Takeshi Yoshinoe387aa32017-08-02 13:16:133953
Sergey Ulanov4af16052018-11-08 02:41:463954def _CheckWatchlistsEntrySyntax(key, value, ast, email_regex):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203955 if not isinstance(key, ast.Str):
3956 return 'Key at line %d must be a string literal' % key.lineno
3957 if not isinstance(value, ast.List):
3958 return 'Value at line %d must be a list' % value.lineno
Sergey Ulanov4af16052018-11-08 02:41:463959 for element in value.elts:
3960 if not isinstance(element, ast.Str):
3961 return 'Watchlist elements on line %d is not a string' % key.lineno
3962 if not email_regex.match(element.s):
3963 return ('Watchlist element on line %d doesn\'t look like a valid ' +
3964 'email: %s') % (key.lineno, element.s)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203965 return None
Takeshi Yoshinoe387aa32017-08-02 13:16:133966
Takeshi Yoshinoe387aa32017-08-02 13:16:133967
Sergey Ulanov4af16052018-11-08 02:41:463968def _CheckWATCHLISTSEntries(wd_dict, w_dict, input_api):
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203969 mismatch_template = (
3970 'Mismatch between WATCHLIST_DEFINITIONS entry (%s) and WATCHLISTS '
3971 'entry (%s)')
Takeshi Yoshinoe387aa32017-08-02 13:16:133972
Sergey Ulanov4af16052018-11-08 02:41:463973 email_regex = input_api.re.compile(
3974 r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$")
3975
3976 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203977 i = 0
3978 last_key = ''
3979 while True:
3980 if i >= len(wd_dict.keys):
3981 if i >= len(w_dict.keys):
3982 return None
3983 return mismatch_template % ('missing', 'line %d' % w_dict.keys[i].lineno)
3984 elif i >= len(w_dict.keys):
3985 return (
3986 mismatch_template % ('line %d' % wd_dict.keys[i].lineno, 'missing'))
Takeshi Yoshinoe387aa32017-08-02 13:16:133987
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203988 wd_key = wd_dict.keys[i]
3989 w_key = w_dict.keys[i]
Takeshi Yoshinoe387aa32017-08-02 13:16:133990
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203991 result = _CheckWatchlistDefinitionsEntrySyntax(
3992 wd_key, wd_dict.values[i], ast)
3993 if result is not None:
3994 return 'Bad entry in WATCHLIST_DEFINITIONS dict: %s' % result
Takeshi Yoshinoe387aa32017-08-02 13:16:133995
Sergey Ulanov4af16052018-11-08 02:41:463996 result = _CheckWatchlistsEntrySyntax(
3997 w_key, w_dict.values[i], ast, email_regex)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:203998 if result is not None:
3999 return 'Bad entry in WATCHLISTS dict: %s' % result
4000
4001 if wd_key.s != w_key.s:
4002 return mismatch_template % (
4003 '%s at line %d' % (wd_key.s, wd_key.lineno),
4004 '%s at line %d' % (w_key.s, w_key.lineno))
4005
4006 if wd_key.s < last_key:
4007 return (
4008 'WATCHLISTS dict is not sorted lexicographically at line %d and %d' %
4009 (wd_key.lineno, w_key.lineno))
4010 last_key = wd_key.s
4011
4012 i = i + 1
4013
4014
Sergey Ulanov4af16052018-11-08 02:41:464015def _CheckWATCHLISTSSyntax(expression, input_api):
4016 ast = input_api.ast
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204017 if not isinstance(expression, ast.Expression):
4018 return 'WATCHLISTS file must contain a valid expression'
4019 dictionary = expression.body
4020 if not isinstance(dictionary, ast.Dict) or len(dictionary.keys) != 2:
4021 return 'WATCHLISTS file must have single dict with exactly two entries'
4022
4023 first_key = dictionary.keys[0]
4024 first_value = dictionary.values[0]
4025 second_key = dictionary.keys[1]
4026 second_value = dictionary.values[1]
4027
4028 if (not isinstance(first_key, ast.Str) or
4029 first_key.s != 'WATCHLIST_DEFINITIONS' or
4030 not isinstance(first_value, ast.Dict)):
4031 return (
4032 'The first entry of the dict in WATCHLISTS file must be '
4033 'WATCHLIST_DEFINITIONS dict')
4034
4035 if (not isinstance(second_key, ast.Str) or
4036 second_key.s != 'WATCHLISTS' or
4037 not isinstance(second_value, ast.Dict)):
4038 return (
4039 'The second entry of the dict in WATCHLISTS file must be '
4040 'WATCHLISTS dict')
4041
Sergey Ulanov4af16052018-11-08 02:41:464042 return _CheckWATCHLISTSEntries(first_value, second_value, input_api)
Takeshi Yoshinoe387aa32017-08-02 13:16:134043
4044
Saagar Sanghavifceeaae2020-08-12 16:40:364045def CheckWATCHLISTS(input_api, output_api):
Takeshi Yoshinoe387aa32017-08-02 13:16:134046 for f in input_api.AffectedFiles(include_deletes=False):
4047 if f.LocalPath() == 'WATCHLISTS':
4048 contents = input_api.ReadFile(f, 'r')
4049
4050 try:
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204051 # First, make sure that it can be evaluated.
Takeshi Yoshinoe387aa32017-08-02 13:16:134052 input_api.ast.literal_eval(contents)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204053 # Get an AST tree for it and scan the tree for detailed style checking.
4054 expression = input_api.ast.parse(
4055 contents, filename='WATCHLISTS', mode='eval')
4056 except ValueError as e:
4057 return [output_api.PresubmitError(
4058 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4059 except SyntaxError as e:
4060 return [output_api.PresubmitError(
4061 'Cannot parse WATCHLISTS file', long_text=repr(e))]
4062 except TypeError as e:
4063 return [output_api.PresubmitError(
4064 'Cannot parse WATCHLISTS file', long_text=repr(e))]
Takeshi Yoshinoe387aa32017-08-02 13:16:134065
Sergey Ulanov4af16052018-11-08 02:41:464066 result = _CheckWATCHLISTSSyntax(expression, input_api)
Takeshi Yoshino3a8f9cb52017-08-10 11:32:204067 if result is not None:
4068 return [output_api.PresubmitError(result)]
4069 break
Takeshi Yoshinoe387aa32017-08-02 13:16:134070
4071 return []
4072
4073
Saagar Sanghavifceeaae2020-08-12 16:40:364074def CheckNewHeaderWithoutGnChangeOnUpload(input_api, output_api):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194075 """Checks that newly added header files have corresponding GN changes.
4076 Note that this is only a heuristic. To be precise, run script:
4077 build/check_gn_headers.py.
4078 """
4079
4080 def headers(f):
4081 return input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444082 f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS, ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194083
4084 new_headers = []
4085 for f in input_api.AffectedSourceFiles(headers):
4086 if f.Action() != 'A':
4087 continue
4088 new_headers.append(f.LocalPath())
4089
4090 def gn_files(f):
James Cook24a504192020-07-23 00:08:444091 return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn', ))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:194092
4093 all_gn_changed_contents = ''
4094 for f in input_api.AffectedSourceFiles(gn_files):
4095 for _, line in f.ChangedContents():
4096 all_gn_changed_contents += line
4097
4098 problems = []
4099 for header in new_headers:
4100 basename = input_api.os_path.basename(header)
4101 if basename not in all_gn_changed_contents:
4102 problems.append(header)
4103
4104 if problems:
4105 return [output_api.PresubmitPromptWarning(
4106 'Missing GN changes for new header files', items=sorted(problems),
4107 long_text='Please double check whether newly added header files need '
4108 'corresponding changes in gn or gni files.\nThis checking is only a '
4109 'heuristic. Run build/check_gn_headers.py to be precise.\n'
4110 'Read https://crbug.com/661774 for more info.')]
4111 return []
4112
4113
Saagar Sanghavifceeaae2020-08-12 16:40:364114def CheckCorrectProductNameInMessages(input_api, output_api):
Michael Giuffridad3bc8672018-10-25 22:48:024115 """Check that Chromium-branded strings don't include "Chrome" or vice versa.
4116
4117 This assumes we won't intentionally reference one product from the other
4118 product.
4119 """
4120 all_problems = []
4121 test_cases = [{
4122 "filename_postfix": "google_chrome_strings.grd",
4123 "correct_name": "Chrome",
4124 "incorrect_name": "Chromium",
4125 }, {
4126 "filename_postfix": "chromium_strings.grd",
4127 "correct_name": "Chromium",
4128 "incorrect_name": "Chrome",
4129 }]
4130
4131 for test_case in test_cases:
4132 problems = []
4133 filename_filter = lambda x: x.LocalPath().endswith(
4134 test_case["filename_postfix"])
4135
4136 # Check each new line. Can yield false positives in multiline comments, but
4137 # easier than trying to parse the XML because messages can have nested
4138 # children, and associating message elements with affected lines is hard.
4139 for f in input_api.AffectedSourceFiles(filename_filter):
4140 for line_num, line in f.ChangedContents():
4141 if "<message" in line or "<!--" in line or "-->" in line:
4142 continue
4143 if test_case["incorrect_name"] in line:
4144 problems.append(
4145 "Incorrect product name in %s:%d" % (f.LocalPath(), line_num))
4146
4147 if problems:
4148 message = (
4149 "Strings in %s-branded string files should reference \"%s\", not \"%s\""
4150 % (test_case["correct_name"], test_case["correct_name"],
4151 test_case["incorrect_name"]))
4152 all_problems.append(
4153 output_api.PresubmitPromptWarning(message, items=problems))
4154
4155 return all_problems
4156
4157
Saagar Sanghavifceeaae2020-08-12 16:40:364158def CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
Dirk Pranke3c18a382019-03-15 01:07:514159 # TODO(crbug.com/941824): We need to make sure the entries in
4160 # //buildtools/DEPS are kept in sync with the entries in //DEPS
4161 # so that users of //buildtools in other projects get the same tooling
4162 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
4163 # support to gclient, we can eliminate the duplication and delete
4164 # this presubmit check.
4165
4166 # Update this regexp if new revisions are added to the files.
4167 rev_regexp = input_api.re.compile(
Xiaohui Chen3fdc6742020-02-29 02:13:264168 "'((clang_format|libcxx|libcxxabi|libunwind)_revision|gn_version)':")
Dirk Pranke3c18a382019-03-15 01:07:514169
4170 # If a user is changing one revision, they need to change the same
4171 # line in both files. This means that any given change should contain
4172 # exactly the same list of changed lines that match the regexps. The
4173 # replace(' ', '') call allows us to ignore whitespace changes to the
4174 # lines. The 'long_text' parameter to the error will contain the
4175 # list of changed lines in both files, which should make it easy enough
4176 # to spot the error without going overboard in this implementation.
4177 revs_changes = {
4178 'DEPS': {},
4179 'buildtools/DEPS': {},
4180 }
4181 long_text = ''
4182
4183 for f in input_api.AffectedFiles(
4184 file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
4185 for line_num, line in f.ChangedContents():
4186 if rev_regexp.search(line):
4187 revs_changes[f.LocalPath()][line.replace(' ', '')] = line
4188 long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
4189
4190 if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
4191 return [output_api.PresubmitError(
4192 'Change buildtools revisions in sync in both //DEPS and '
4193 '//buildtools/DEPS.', long_text=long_text + '\n')]
4194 else:
4195 return []
4196
4197
Saagar Sanghavifceeaae2020-08-12 16:40:364198def CheckForTooLargeFiles(input_api, output_api):
Daniel Bratell93eb6c62019-04-29 20:13:364199 """Avoid large files, especially binary files, in the repository since
4200 git doesn't scale well for those. They will be in everyone's repo
4201 clones forever, forever making Chromium slower to clone and work
4202 with."""
4203
4204 # Uploading files to cloud storage is not trivial so we don't want
4205 # to set the limit too low, but the upper limit for "normal" large
4206 # files seems to be 1-2 MB, with a handful around 5-8 MB, so
4207 # anything over 20 MB is exceptional.
4208 TOO_LARGE_FILE_SIZE_LIMIT = 20 * 1024 * 1024 # 10 MB
4209
4210 too_large_files = []
4211 for f in input_api.AffectedFiles():
4212 # Check both added and modified files (but not deleted files).
4213 if f.Action() in ('A', 'M'):
Dirk Pranked6d45c32019-04-30 22:37:384214 size = input_api.os_path.getsize(f.AbsoluteLocalPath())
Daniel Bratell93eb6c62019-04-29 20:13:364215 if size > TOO_LARGE_FILE_SIZE_LIMIT:
4216 too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
4217
4218 if too_large_files:
4219 message = (
4220 'Do not commit large files to git since git scales badly for those.\n' +
4221 'Instead put the large files in cloud storage and use DEPS to\n' +
4222 'fetch them.\n' + '\n'.join(too_large_files)
4223 )
4224 return [output_api.PresubmitError(
4225 'Too large files found in commit', long_text=message + '\n')]
4226 else:
4227 return []
4228
Max Morozb47503b2019-08-08 21:03:274229
Saagar Sanghavifceeaae2020-08-12 16:40:364230def CheckFuzzTargetsOnUpload(input_api, output_api):
Max Morozb47503b2019-08-08 21:03:274231 """Checks specific for fuzz target sources."""
4232 EXPORTED_SYMBOLS = [
4233 'LLVMFuzzerInitialize',
4234 'LLVMFuzzerCustomMutator',
4235 'LLVMFuzzerCustomCrossOver',
4236 'LLVMFuzzerMutate',
4237 ]
4238
4239 REQUIRED_HEADER = '#include "testing/libfuzzer/libfuzzer_exports.h"'
4240
4241 def FilterFile(affected_file):
4242 """Ignore libFuzzer source code."""
James Cook24a504192020-07-23 00:08:444243 files_to_check = r'.*fuzz.*\.(h|hpp|hcc|cc|cpp|cxx)$'
4244 files_to_skip = r"^third_party[\\/]libFuzzer"
Max Morozb47503b2019-08-08 21:03:274245
4246 return input_api.FilterSourceFile(
4247 affected_file,
James Cook24a504192020-07-23 00:08:444248 files_to_check=[files_to_check],
4249 files_to_skip=[files_to_skip])
Max Morozb47503b2019-08-08 21:03:274250
4251 files_with_missing_header = []
4252 for f in input_api.AffectedSourceFiles(FilterFile):
4253 contents = input_api.ReadFile(f, 'r')
4254 if REQUIRED_HEADER in contents:
4255 continue
4256
4257 if any(symbol in contents for symbol in EXPORTED_SYMBOLS):
4258 files_with_missing_header.append(f.LocalPath())
4259
4260 if not files_with_missing_header:
4261 return []
4262
4263 long_text = (
4264 'If you define any of the libFuzzer optional functions (%s), it is '
4265 'recommended to add \'%s\' directive. Otherwise, the fuzz target may '
4266 'work incorrectly on Mac (crbug.com/687076).\nNote that '
4267 'LLVMFuzzerInitialize should not be used, unless your fuzz target needs '
4268 'to access command line arguments passed to the fuzzer. Instead, prefer '
4269 'static initialization and shared resources as documented in '
4270 'https://chromium.googlesource.com/chromium/src/+/master/testing/'
4271 'libfuzzer/efficient_fuzzing.md#simplifying-initialization_cleanup.\n' % (
4272 ', '.join(EXPORTED_SYMBOLS), REQUIRED_HEADER)
4273 )
4274
4275 return [output_api.PresubmitPromptWarning(
4276 message="Missing '%s' in:" % REQUIRED_HEADER,
4277 items=files_with_missing_header,
4278 long_text=long_text)]
4279
4280
Mohamed Heikald048240a2019-11-12 16:57:374281def _CheckNewImagesWarning(input_api, output_api):
4282 """
4283 Warns authors who add images into the repo to make sure their images are
4284 optimized before committing.
4285 """
4286 images_added = False
4287 image_paths = []
4288 errors = []
4289 filter_lambda = lambda x: input_api.FilterSourceFile(
4290 x,
James Cook24a504192020-07-23 00:08:444291 files_to_skip=(('(?i).*test', r'.*\/junit\/')
4292 + input_api.DEFAULT_FILES_TO_SKIP),
4293 files_to_check=[r'.*\/(drawable|mipmap)' ]
Mohamed Heikald048240a2019-11-12 16:57:374294 )
4295 for f in input_api.AffectedFiles(
4296 include_deletes=False, file_filter=filter_lambda):
4297 local_path = f.LocalPath().lower()
4298 if any(local_path.endswith(extension) for extension in _IMAGE_EXTENSIONS):
4299 images_added = True
4300 image_paths.append(f)
4301 if images_added:
4302 errors.append(output_api.PresubmitPromptWarning(
4303 'It looks like you are trying to commit some images. If these are '
4304 'non-test-only images, please make sure to read and apply the tips in '
4305 'https://chromium.googlesource.com/chromium/src/+/HEAD/docs/speed/'
4306 'binary_size/optimization_advice.md#optimizing-images\nThis check is '
4307 'FYI only and will not block your CL on the CQ.', image_paths))
4308 return errors
4309
4310
Saagar Sanghavifceeaae2020-08-12 16:40:364311def ChecksAndroidSpecificOnUpload(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574312 """Groups upload checks that target android code."""
dgnaa68d5e2015-06-10 10:08:224313 results = []
dgnaa68d5e2015-06-10 10:08:224314 results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
Jinsong Fan91ebbbd2019-04-16 14:57:174315 results.extend(_CheckAndroidDebuggableBuild(input_api, output_api))
agrieve7b6479d82015-10-07 14:24:224316 results.extend(_CheckAndroidNewMdpiAssetLocation(input_api, output_api))
dskiba88634f4e2015-08-14 23:03:294317 results.extend(_CheckAndroidToastUsage(input_api, output_api))
Yoland Yanb92fa522017-08-28 17:37:064318 results.extend(_CheckAndroidTestJUnitInheritance(input_api, output_api))
4319 results.extend(_CheckAndroidTestJUnitFrameworkImport(input_api, output_api))
yolandyan45001472016-12-21 21:12:424320 results.extend(_CheckAndroidTestAnnotationUsage(input_api, output_api))
Nate Fischer535972b2017-09-16 01:06:184321 results.extend(_CheckAndroidWebkitImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574322 results.extend(_CheckAndroidXmlStyle(input_api, output_api, True))
Mohamed Heikald048240a2019-11-12 16:57:374323 results.extend(_CheckNewImagesWarning(input_api, output_api))
Michael Thiessen44457642020-02-06 00:24:154324 results.extend(_CheckAndroidNoBannedImports(input_api, output_api))
Becky Zhou7c69b50992018-12-10 19:37:574325 return results
4326
Saagar Sanghavifceeaae2020-08-12 16:40:364327def ChecksAndroidSpecificOnCommit(input_api, output_api):
Becky Zhou7c69b50992018-12-10 19:37:574328 """Groups commit checks that target android code."""
4329 results = []
4330 results.extend(_CheckAndroidXmlStyle(input_api, output_api, False))
dgnaa68d5e2015-06-10 10:08:224331 return results
4332
Chris Hall59f8d0c72020-05-01 07:31:194333# TODO(chrishall): could we additionally match on any path owned by
4334# ui/accessibility/OWNERS ?
4335_ACCESSIBILITY_PATHS = (
4336 r"^chrome[\\/]browser.*[\\/]accessibility[\\/]",
4337 r"^chrome[\\/]browser[\\/]extensions[\\/]api[\\/]automation.*[\\/]",
4338 r"^chrome[\\/]renderer[\\/]extensions[\\/]accessibility_.*",
4339 r"^chrome[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4340 r"^content[\\/]browser[\\/]accessibility[\\/]",
4341 r"^content[\\/]renderer[\\/]accessibility[\\/]",
4342 r"^content[\\/]tests[\\/]data[\\/]accessibility[\\/]",
4343 r"^extensions[\\/]renderer[\\/]api[\\/]automation[\\/]",
4344 r"^ui[\\/]accessibility[\\/]",
4345 r"^ui[\\/]views[\\/]accessibility[\\/]",
4346)
4347
Saagar Sanghavifceeaae2020-08-12 16:40:364348def CheckAccessibilityRelnotesField(input_api, output_api):
Chris Hall59f8d0c72020-05-01 07:31:194349 """Checks that commits to accessibility code contain an AX-Relnotes field in
4350 their commit message."""
4351 def FileFilter(affected_file):
4352 paths = _ACCESSIBILITY_PATHS
James Cook24a504192020-07-23 00:08:444353 return input_api.FilterSourceFile(affected_file, files_to_check=paths)
Chris Hall59f8d0c72020-05-01 07:31:194354
4355 # Only consider changes affecting accessibility paths.
4356 if not any(input_api.AffectedFiles(file_filter=FileFilter)):
4357 return []
4358
Akihiro Ota08108e542020-05-20 15:30:534359 # AX-Relnotes can appear in either the description or the footer.
4360 # When searching the description, require 'AX-Relnotes:' to appear at the
4361 # beginning of a line.
4362 ax_regex = input_api.re.compile('ax-relnotes[:=]')
4363 description_has_relnotes = any(ax_regex.match(line)
4364 for line in input_api.change.DescriptionText().lower().splitlines())
4365
4366 footer_relnotes = input_api.change.GitFootersFromDescription().get(
4367 'AX-Relnotes', [])
4368 if description_has_relnotes or footer_relnotes:
Chris Hall59f8d0c72020-05-01 07:31:194369 return []
4370
4371 # TODO(chrishall): link to Relnotes documentation in message.
4372 message = ("Missing 'AX-Relnotes:' field required for accessibility changes"
4373 "\n please add 'AX-Relnotes: [release notes].' to describe any "
4374 "user-facing changes"
4375 "\n otherwise add 'AX-Relnotes: n/a.' if this change has no "
4376 "user-facing effects"
4377 "\n if this is confusing or annoying then please contact members "
4378 "of ui/accessibility/OWNERS.")
4379
4380 return [output_api.PresubmitNotifyResult(message)]
dgnaa68d5e2015-06-10 10:08:224381
Saagar Sanghavifceeaae2020-08-12 16:40:364382def ChecksCommon(input_api, output_api):
[email protected]22c9bd72011-03-27 16:47:394383 """Checks common to both upload and commit."""
4384 results = []
4385 results.extend(input_api.canned_checks.PanProjectChecks(
[email protected]3de922f2013-12-20 13:27:384386 input_api, output_api,
qyearsleyfa2cfcf82016-12-15 18:03:544387 excluded_paths=_EXCLUDED_PATHS))
Eric Boren6fd2b932018-01-25 15:05:084388
4389 author = input_api.change.author_email
4390 if author and author not in _KNOWN_ROBOTS:
4391 results.extend(
4392 input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api))
4393
[email protected]9f919cc2013-07-31 03:04:044394 results.extend(
4395 input_api.canned_checks.CheckChangeHasNoTabs(
4396 input_api,
4397 output_api,
4398 source_file_filter=lambda x: x.LocalPath().endswith('.grd')))
Sergiy Byelozyorov366b6482017-11-06 18:20:434399 results.extend(input_api.RunTests(
4400 input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
[email protected]2299dcf2012-11-15 19:56:244401
Edward Lesmesce51df52020-08-04 22:10:174402 dirmd_bin = input_api.os_path.join(
4403 input_api.PresubmitLocalPath(), 'third_party', 'depot_tools', 'dirmd')
4404 results.extend(input_api.RunTests(
4405 input_api.canned_checks.CheckDirMetadataFormat(
4406 input_api, output_api, dirmd_bin)))
4407 results.extend(
4408 input_api.canned_checks.CheckOwnersDirMetadataExclusive(
4409 input_api, output_api))
4410
Vaclav Brozekcdc7defb2018-03-20 09:54:354411 for f in input_api.AffectedFiles():
4412 path, name = input_api.os_path.split(f.LocalPath())
4413 if name == 'PRESUBMIT.py':
4414 full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path)
Caleb Rouleaua6117be2018-05-11 20:10:004415 test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py')
4416 if f.Action() != 'D' and input_api.os_path.exists(test_file):
Dirk Pranke38557312018-04-18 00:53:074417 # The PRESUBMIT.py file (and the directory containing it) might
4418 # have been affected by being moved or removed, so only try to
4419 # run the tests if they still exist.
4420 results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
4421 input_api, output_api, full_path,
James Cook24a504192020-07-23 00:08:444422 files_to_check=[r'^PRESUBMIT_test\.py$']))
[email protected]22c9bd72011-03-27 16:47:394423 return results
[email protected]1f7b4172010-01-28 01:17:344424
[email protected]b337cb5b2011-01-23 21:24:054425
Saagar Sanghavifceeaae2020-08-12 16:40:364426def CheckPatchFiles(input_api, output_api):
[email protected]b8079ae4a2012-12-05 19:56:494427 problems = [f.LocalPath() for f in input_api.AffectedFiles()
4428 if f.LocalPath().endswith(('.orig', '.rej'))]
4429 if problems:
4430 return [output_api.PresubmitError(
4431 "Don't commit .rej and .orig files.", problems)]
[email protected]2fdd1f362013-01-16 03:56:034432 else:
4433 return []
[email protected]b8079ae4a2012-12-05 19:56:494434
4435
Saagar Sanghavifceeaae2020-08-12 16:40:364436def CheckBuildConfigMacrosWithoutInclude(input_api, output_api):
Kent Tamura79ef8f82017-07-18 00:00:214437 # Excludes OS_CHROMEOS, which is not defined in build_config.h.
4438 macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bdefined\(((OS_(?!CHROMEOS)|'
4439 'COMPILER_|ARCH_CPU_|WCHAR_T_IS_)[^)]*)')
Kent Tamura5a8755d2017-06-29 23:37:074440 include_re = input_api.re.compile(
4441 r'^#include\s+"build/build_config.h"', input_api.re.MULTILINE)
4442 extension_re = input_api.re.compile(r'\.[a-z]+$')
4443 errors = []
4444 for f in input_api.AffectedFiles():
4445 if not f.LocalPath().endswith(('.h', '.c', '.cc', '.cpp', '.m', '.mm')):
4446 continue
4447 found_line_number = None
4448 found_macro = None
4449 for line_num, line in f.ChangedContents():
4450 match = macro_re.search(line)
4451 if match:
4452 found_line_number = line_num
4453 found_macro = match.group(2)
4454 break
4455 if not found_line_number:
4456 continue
4457
4458 found_include = False
4459 for line in f.NewContents():
4460 if include_re.search(line):
4461 found_include = True
4462 break
4463 if found_include:
4464 continue
4465
4466 if not f.LocalPath().endswith('.h'):
4467 primary_header_path = extension_re.sub('.h', f.AbsoluteLocalPath())
4468 try:
4469 content = input_api.ReadFile(primary_header_path, 'r')
4470 if include_re.search(content):
4471 continue
4472 except IOError:
4473 pass
4474 errors.append('%s:%d %s macro is used without including build/'
4475 'build_config.h.'
4476 % (f.LocalPath(), found_line_number, found_macro))
4477 if errors:
4478 return [output_api.PresubmitPromptWarning('\n'.join(errors))]
4479 return []
4480
4481
[email protected]b00342e7f2013-03-26 16:21:544482def _DidYouMeanOSMacro(bad_macro):
4483 try:
4484 return {'A': 'OS_ANDROID',
4485 'B': 'OS_BSD',
4486 'C': 'OS_CHROMEOS',
4487 'F': 'OS_FREEBSD',
Avi Drissman34594e902020-07-25 05:35:444488 'I': 'OS_IOS',
[email protected]b00342e7f2013-03-26 16:21:544489 'L': 'OS_LINUX',
Avi Drissman34594e902020-07-25 05:35:444490 'M': 'OS_MAC',
[email protected]b00342e7f2013-03-26 16:21:544491 'N': 'OS_NACL',
4492 'O': 'OS_OPENBSD',
4493 'P': 'OS_POSIX',
4494 'S': 'OS_SOLARIS',
4495 'W': 'OS_WIN'}[bad_macro[3].upper()]
4496 except KeyError:
4497 return ''
4498
4499
4500def _CheckForInvalidOSMacrosInFile(input_api, f):
4501 """Check for sensible looking, totally invalid OS macros."""
4502 preprocessor_statement = input_api.re.compile(r'^\s*#')
4503 os_macro = input_api.re.compile(r'defined\((OS_[^)]+)\)')
4504 results = []
4505 for lnum, line in f.ChangedContents():
4506 if preprocessor_statement.search(line):
4507 for match in os_macro.finditer(line):
4508 if not match.group(1) in _VALID_OS_MACROS:
4509 good = _DidYouMeanOSMacro(match.group(1))
4510 did_you_mean = ' (did you mean %s?)' % good if good else ''
4511 results.append(' %s:%d %s%s' % (f.LocalPath(),
4512 lnum,
4513 match.group(1),
4514 did_you_mean))
4515 return results
4516
4517
Saagar Sanghavifceeaae2020-08-12 16:40:364518def CheckForInvalidOSMacros(input_api, output_api):
[email protected]b00342e7f2013-03-26 16:21:544519 """Check all affected files for invalid OS macros."""
4520 bad_macros = []
tzik3f295992018-12-04 20:32:234521 for f in input_api.AffectedSourceFiles(None):
ellyjones47654342016-05-06 15:50:474522 if not f.LocalPath().endswith(('.py', '.js', '.html', '.css', '.md')):
[email protected]b00342e7f2013-03-26 16:21:544523 bad_macros.extend(_CheckForInvalidOSMacrosInFile(input_api, f))
4524
4525 if not bad_macros:
4526 return []
4527
4528 return [output_api.PresubmitError(
4529 'Possibly invalid OS macro[s] found. Please fix your code\n'
4530 'or add your macro to src/PRESUBMIT.py.', bad_macros)]
4531
lliabraa35bab3932014-10-01 12:16:444532
4533def _CheckForInvalidIfDefinedMacrosInFile(input_api, f):
4534 """Check all affected files for invalid "if defined" macros."""
4535 ALWAYS_DEFINED_MACROS = (
4536 "TARGET_CPU_PPC",
4537 "TARGET_CPU_PPC64",
4538 "TARGET_CPU_68K",
4539 "TARGET_CPU_X86",
4540 "TARGET_CPU_ARM",
4541 "TARGET_CPU_MIPS",
4542 "TARGET_CPU_SPARC",
4543 "TARGET_CPU_ALPHA",
4544 "TARGET_IPHONE_SIMULATOR",
4545 "TARGET_OS_EMBEDDED",
4546 "TARGET_OS_IPHONE",
4547 "TARGET_OS_MAC",
4548 "TARGET_OS_UNIX",
4549 "TARGET_OS_WIN32",
4550 )
4551 ifdef_macro = input_api.re.compile(r'^\s*#.*(?:ifdef\s|defined\()([^\s\)]+)')
4552 results = []
4553 for lnum, line in f.ChangedContents():
4554 for match in ifdef_macro.finditer(line):
4555 if match.group(1) in ALWAYS_DEFINED_MACROS:
4556 always_defined = ' %s is always defined. ' % match.group(1)
4557 did_you_mean = 'Did you mean \'#if %s\'?' % match.group(1)
4558 results.append(' %s:%d %s\n\t%s' % (f.LocalPath(),
4559 lnum,
4560 always_defined,
4561 did_you_mean))
4562 return results
4563
4564
Saagar Sanghavifceeaae2020-08-12 16:40:364565def CheckForInvalidIfDefinedMacros(input_api, output_api):
lliabraa35bab3932014-10-01 12:16:444566 """Check all affected files for invalid "if defined" macros."""
4567 bad_macros = []
Mirko Bonadei28112c02019-05-17 20:25:054568 skipped_paths = ['third_party/sqlite/', 'third_party/abseil-cpp/']
lliabraa35bab3932014-10-01 12:16:444569 for f in input_api.AffectedFiles():
Mirko Bonadei28112c02019-05-17 20:25:054570 if any([f.LocalPath().startswith(path) for path in skipped_paths]):
sdefresne4e1eccb32017-05-24 08:45:214571 continue
lliabraa35bab3932014-10-01 12:16:444572 if f.LocalPath().endswith(('.h', '.c', '.cc', '.m', '.mm')):
4573 bad_macros.extend(_CheckForInvalidIfDefinedMacrosInFile(input_api, f))
4574
4575 if not bad_macros:
4576 return []
4577
4578 return [output_api.PresubmitError(
4579 'Found ifdef check on always-defined macro[s]. Please fix your code\n'
4580 'or check the list of ALWAYS_DEFINED_MACROS in src/PRESUBMIT.py.',
4581 bad_macros)]
4582
4583
Saagar Sanghavifceeaae2020-08-12 16:40:364584def CheckForIPCRules(input_api, output_api):
mlamouria82272622014-09-16 18:45:044585 """Check for same IPC rules described in
4586 http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc
4587 """
4588 base_pattern = r'IPC_ENUM_TRAITS\('
4589 inclusion_pattern = input_api.re.compile(r'(%s)' % base_pattern)
4590 comment_pattern = input_api.re.compile(r'//.*(%s)' % base_pattern)
4591
4592 problems = []
4593 for f in input_api.AffectedSourceFiles(None):
4594 local_path = f.LocalPath()
4595 if not local_path.endswith('.h'):
4596 continue
4597 for line_number, line in f.ChangedContents():
4598 if inclusion_pattern.search(line) and not comment_pattern.search(line):
4599 problems.append(
4600 '%s:%d\n %s' % (local_path, line_number, line.strip()))
4601
4602 if problems:
4603 return [output_api.PresubmitPromptWarning(
4604 _IPC_ENUM_TRAITS_DEPRECATED, problems)]
4605 else:
4606 return []
4607
[email protected]b00342e7f2013-03-26 16:21:544608
Saagar Sanghavifceeaae2020-08-12 16:40:364609def CheckForLongPathnames(input_api, output_api):
Stephen Martinis97a394142018-06-07 23:06:054610 """Check to make sure no files being submitted have long paths.
4611 This causes issues on Windows.
4612 """
4613 problems = []
Stephen Martinisc4b246b2019-10-31 23:04:194614 for f in input_api.AffectedTestableFiles():
Stephen Martinis97a394142018-06-07 23:06:054615 local_path = f.LocalPath()
4616 # Windows has a path limit of 260 characters. Limit path length to 200 so
4617 # that we have some extra for the prefix on dev machines and the bots.
4618 if len(local_path) > 200:
4619 problems.append(local_path)
4620
4621 if problems:
4622 return [output_api.PresubmitError(_LONG_PATH_ERROR, problems)]
4623 else:
4624 return []
4625
4626
Saagar Sanghavifceeaae2020-08-12 16:40:364627def CheckForIncludeGuards(input_api, output_api):
Daniel Bratell8ba52722018-03-02 16:06:144628 """Check that header files have proper guards against multiple inclusion.
4629 If a file should not have such guards (and it probably should) then it
4630 should include the string "no-include-guard-because-multiply-included".
4631 """
Daniel Bratell6a75baef62018-06-04 10:04:454632 def is_chromium_header_file(f):
4633 # We only check header files under the control of the Chromium
4634 # project. That is, those outside third_party apart from
4635 # third_party/blink.
Kinuko Yasuda0cdb3da2019-07-31 21:50:324636 # We also exclude *_message_generator.h headers as they use
4637 # include guards in a special, non-typical way.
Daniel Bratell6a75baef62018-06-04 10:04:454638 file_with_path = input_api.os_path.normpath(f.LocalPath())
4639 return (file_with_path.endswith('.h') and
Kinuko Yasuda0cdb3da2019-07-31 21:50:324640 not file_with_path.endswith('_message_generator.h') and
Daniel Bratell6a75baef62018-06-04 10:04:454641 (not file_with_path.startswith('third_party') or
4642 file_with_path.startswith(
4643 input_api.os_path.join('third_party', 'blink'))))
Daniel Bratell8ba52722018-03-02 16:06:144644
4645 def replace_special_with_underscore(string):
Olivier Robinbba137492018-07-30 11:31:344646 return input_api.re.sub(r'[+\\/.-]', '_', string)
Daniel Bratell8ba52722018-03-02 16:06:144647
4648 errors = []
4649
Daniel Bratell6a75baef62018-06-04 10:04:454650 for f in input_api.AffectedSourceFiles(is_chromium_header_file):
Daniel Bratell8ba52722018-03-02 16:06:144651 guard_name = None
4652 guard_line_number = None
4653 seen_guard_end = False
4654
4655 file_with_path = input_api.os_path.normpath(f.LocalPath())
4656 base_file_name = input_api.os_path.splitext(
4657 input_api.os_path.basename(file_with_path))[0]
4658 upper_base_file_name = base_file_name.upper()
4659
4660 expected_guard = replace_special_with_underscore(
4661 file_with_path.upper() + '_')
Daniel Bratell8ba52722018-03-02 16:06:144662
4663 # For "path/elem/file_name.h" we should really only accept
Daniel Bratell39b5b062018-05-16 18:09:574664 # PATH_ELEM_FILE_NAME_H_ per coding style. Unfortunately there
4665 # are too many (1000+) files with slight deviations from the
4666 # coding style. The most important part is that the include guard
4667 # is there, and that it's unique, not the name so this check is
4668 # forgiving for existing files.
Daniel Bratell8ba52722018-03-02 16:06:144669 #
4670 # As code becomes more uniform, this could be made stricter.
4671
4672 guard_name_pattern_list = [
4673 # Anything with the right suffix (maybe with an extra _).
4674 r'\w+_H__?',
4675
Daniel Bratell39b5b062018-05-16 18:09:574676 # To cover include guards with old Blink style.
Daniel Bratell8ba52722018-03-02 16:06:144677 r'\w+_h',
4678
4679 # Anything including the uppercase name of the file.
4680 r'\w*' + input_api.re.escape(replace_special_with_underscore(
4681 upper_base_file_name)) + r'\w*',
4682 ]
4683 guard_name_pattern = '|'.join(guard_name_pattern_list)
4684 guard_pattern = input_api.re.compile(
4685 r'#ifndef\s+(' + guard_name_pattern + ')')
4686
4687 for line_number, line in enumerate(f.NewContents()):
4688 if 'no-include-guard-because-multiply-included' in line:
4689 guard_name = 'DUMMY' # To not trigger check outside the loop.
4690 break
4691
4692 if guard_name is None:
4693 match = guard_pattern.match(line)
4694 if match:
4695 guard_name = match.group(1)
4696 guard_line_number = line_number
4697
Daniel Bratell39b5b062018-05-16 18:09:574698 # We allow existing files to use include guards whose names
Daniel Bratell6a75baef62018-06-04 10:04:454699 # don't match the chromium style guide, but new files should
4700 # get it right.
4701 if not f.OldContents():
Daniel Bratell39b5b062018-05-16 18:09:574702 if guard_name != expected_guard:
Daniel Bratell8ba52722018-03-02 16:06:144703 errors.append(output_api.PresubmitPromptWarning(
4704 'Header using the wrong include guard name %s' % guard_name,
4705 ['%s:%d' % (f.LocalPath(), line_number + 1)],
Istiaque Ahmed9ad6cd22019-10-04 00:26:574706 'Expected: %r\nFound: %r' % (expected_guard, guard_name)))
Daniel Bratell8ba52722018-03-02 16:06:144707 else:
4708 # The line after #ifndef should have a #define of the same name.
4709 if line_number == guard_line_number + 1:
4710 expected_line = '#define %s' % guard_name
4711 if line != expected_line:
4712 errors.append(output_api.PresubmitPromptWarning(
4713 'Missing "%s" for include guard' % expected_line,
4714 ['%s:%d' % (f.LocalPath(), line_number + 1)],
4715 'Expected: %r\nGot: %r' % (expected_line, line)))
4716
4717 if not seen_guard_end and line == '#endif // %s' % guard_name:
4718 seen_guard_end = True
4719 elif seen_guard_end:
4720 if line.strip() != '':
4721 errors.append(output_api.PresubmitPromptWarning(
4722 'Include guard %s not covering the whole file' % (
4723 guard_name), [f.LocalPath()]))
4724 break # Nothing else to check and enough to warn once.
4725
4726 if guard_name is None:
4727 errors.append(output_api.PresubmitPromptWarning(
4728 'Missing include guard %s' % expected_guard,
4729 [f.LocalPath()],
4730 'Missing include guard in %s\n'
4731 'Recommended name: %s\n'
4732 'This check can be disabled by having the string\n'
4733 'no-include-guard-because-multiply-included in the header.' %
4734 (f.LocalPath(), expected_guard)))
4735
4736 return errors
4737
4738
Saagar Sanghavifceeaae2020-08-12 16:40:364739def CheckForWindowsLineEndings(input_api, output_api):
mostynbb639aca52015-01-07 20:31:234740 """Check source code and known ascii text files for Windows style line
4741 endings.
4742 """
earthdok1b5e0ee2015-03-10 15:19:104743 known_text_files = r'.*\.(txt|html|htm|mhtml|py|gyp|gypi|gn|isolate)$'
mostynbb639aca52015-01-07 20:31:234744
4745 file_inclusion_pattern = (
4746 known_text_files,
4747 r'.+%s' % _IMPLEMENTATION_EXTENSIONS
4748 )
4749
mostynbb639aca52015-01-07 20:31:234750 problems = []
Andrew Grieve933d12e2017-10-30 20:22:534751 source_file_filter = lambda f: input_api.FilterSourceFile(
James Cook24a504192020-07-23 00:08:444752 f, files_to_check=file_inclusion_pattern, files_to_skip=None)
Andrew Grieve933d12e2017-10-30 20:22:534753 for f in input_api.AffectedSourceFiles(source_file_filter):
Vaclav Brozekd5de76a2018-03-17 07:57:504754 include_file = False
4755 for _, line in f.ChangedContents():
mostynbb639aca52015-01-07 20:31:234756 if line.endswith('\r\n'):
Vaclav Brozekd5de76a2018-03-17 07:57:504757 include_file = True
4758 if include_file:
4759 problems.append(f.LocalPath())
mostynbb639aca52015-01-07 20:31:234760
4761 if problems:
4762 return [output_api.PresubmitPromptWarning('Are you sure that you want '
4763 'these files to contain Windows style line endings?\n' +
4764 '\n'.join(problems))]
4765
4766 return []
4767
4768
Saagar Sanghavifceeaae2020-08-12 16:40:364769def CheckSyslogUseWarningOnUpload(input_api, output_api, src_file_filter=None):
pastarmovj89f7ee12016-09-20 14:58:134770 """Checks that all source files use SYSLOG properly."""
4771 syslog_files = []
Saagar Sanghavifceeaae2020-08-12 16:40:364772 for f in input_api.AffectedSourceFiles(src_file_filter):
pastarmovj032ba5bc2017-01-12 10:41:564773 for line_number, line in f.ChangedContents():
4774 if 'SYSLOG' in line:
4775 syslog_files.append(f.LocalPath() + ':' + str(line_number))
4776
pastarmovj89f7ee12016-09-20 14:58:134777 if syslog_files:
4778 return [output_api.PresubmitPromptWarning(
4779 'Please make sure there are no privacy sensitive bits of data in SYSLOG'
4780 ' calls.\nFiles to check:\n', items=syslog_files)]
4781 return []
4782
4783
[email protected]1f7b4172010-01-28 01:17:344784def CheckChangeOnUpload(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364785 if input_api.version < [2, 0, 0]:
4786 return [output_api.PresubmitError("Your depot_tools is out of date. "
4787 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4788 "but your version is %d.%d.%d" % tuple(input_api.version))]
[email protected]1f7b4172010-01-28 01:17:344789 results = []
scottmg39b29952014-12-08 18:31:284790 results.extend(
jam93a6ee792017-02-08 23:59:224791 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544792 return results
[email protected]ca8d1982009-02-19 16:33:124793
4794
[email protected]1bfb8322014-04-23 01:02:414795def GetTryServerMasterForBot(bot):
4796 """Returns the Try Server master for the given bot.
4797
[email protected]0bb112362014-07-26 04:38:324798 It tries to guess the master from the bot name, but may still fail
4799 and return None. There is no longer a default master.
4800 """
4801 # Potentially ambiguous bot names are listed explicitly.
4802 master_map = {
tandriie5587792016-07-14 00:34:504803 'chromium_presubmit': 'master.tryserver.chromium.linux',
4804 'tools_build_presubmit': 'master.tryserver.chromium.linux',
[email protected]1bfb8322014-04-23 01:02:414805 }
[email protected]0bb112362014-07-26 04:38:324806 master = master_map.get(bot)
4807 if not master:
wnwen4fbaab82016-05-25 12:54:364808 if 'android' in bot:
tandriie5587792016-07-14 00:34:504809 master = 'master.tryserver.chromium.android'
wnwen4fbaab82016-05-25 12:54:364810 elif 'linux' in bot or 'presubmit' in bot:
tandriie5587792016-07-14 00:34:504811 master = 'master.tryserver.chromium.linux'
[email protected]0bb112362014-07-26 04:38:324812 elif 'win' in bot:
tandriie5587792016-07-14 00:34:504813 master = 'master.tryserver.chromium.win'
[email protected]0bb112362014-07-26 04:38:324814 elif 'mac' in bot or 'ios' in bot:
tandriie5587792016-07-14 00:34:504815 master = 'master.tryserver.chromium.mac'
[email protected]0bb112362014-07-26 04:38:324816 return master
[email protected]1bfb8322014-04-23 01:02:414817
4818
[email protected]ca8d1982009-02-19 16:33:124819def CheckChangeOnCommit(input_api, output_api):
Saagar Sanghavifceeaae2020-08-12 16:40:364820 if input_api.version < [2, 0, 0]:
4821 return [output_api.PresubmitError("Your depot_tools is out of date. "
4822 "This PRESUBMIT.py requires at least presubmit_support version 2.0.0, "
4823 "but your version is %d.%d.%d" % tuple(input_api.version))]
4824
[email protected]fe5f57c52009-06-05 14:25:544825 results = []
[email protected]fe5f57c52009-06-05 14:25:544826 # Make sure the tree is 'open'.
[email protected]806e98e2010-03-19 17:49:274827 results.extend(input_api.canned_checks.CheckTreeIsOpen(
[email protected]7f238152009-08-12 19:00:344828 input_api,
4829 output_api,
[email protected]2fdd1f362013-01-16 03:56:034830 json_url='http://chromium-status.appspot.com/current?format=json'))
[email protected]806e98e2010-03-19 17:49:274831
jam93a6ee792017-02-08 23:59:224832 results.extend(
4833 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
[email protected]3e4eb112011-01-18 03:29:544834 results.extend(input_api.canned_checks.CheckChangeHasBugField(
4835 input_api, output_api))
Dan Beam39f28cb2019-10-04 01:01:384836 results.extend(input_api.canned_checks.CheckChangeHasNoUnwantedTags(
4837 input_api, output_api))
[email protected]c4b47562011-12-05 23:39:414838 results.extend(input_api.canned_checks.CheckChangeHasDescription(
4839 input_api, output_api))
[email protected]fe5f57c52009-06-05 14:25:544840 return results
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144841
4842
Saagar Sanghavifceeaae2020-08-12 16:40:364843def CheckStrings(input_api, output_api):
Rainhard Findlingfc31844c52020-05-15 09:58:264844 """Check string ICU syntax validity and if translation screenshots exist."""
Edward Lesmesf7c5c6d2020-05-14 23:30:024845 # Skip translation screenshots check if a SkipTranslationScreenshotsCheck
4846 # footer is set to true.
4847 git_footers = input_api.change.GitFootersFromDescription()
Rainhard Findlingfc31844c52020-05-15 09:58:264848 skip_screenshot_check_footer = [
Edward Lesmesf7c5c6d2020-05-14 23:30:024849 footer.lower()
4850 for footer in git_footers.get(u'Skip-Translation-Screenshots-Check', [])]
Rainhard Findlingfc31844c52020-05-15 09:58:264851 run_screenshot_check = u'true' not in skip_screenshot_check_footer
Edward Lesmesf7c5c6d2020-05-14 23:30:024852
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144853 import os
Rainhard Findlingfc31844c52020-05-15 09:58:264854 import re
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144855 import sys
4856 from io import StringIO
4857
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144858 new_or_added_paths = set(f.LocalPath()
4859 for f in input_api.AffectedFiles()
4860 if (f.Action() == 'A' or f.Action() == 'M'))
4861 removed_paths = set(f.LocalPath()
4862 for f in input_api.AffectedFiles(include_deletes=True)
4863 if f.Action() == 'D')
4864
Andrew Grieve0e8790c2020-09-03 17:27:324865 affected_grds = [
4866 f for f in input_api.AffectedFiles()
4867 if f.LocalPath().endswith(('.grd', '.grdp'))
4868 ]
4869 affected_grds = [f for f in affected_grds if not 'testdata' in f.LocalPath()]
meacer8c0d3832019-12-26 21:46:164870 if not affected_grds:
4871 return []
4872
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144873 affected_png_paths = [f.AbsoluteLocalPath()
4874 for f in input_api.AffectedFiles()
4875 if (f.LocalPath().endswith('.png'))]
4876
4877 # Check for screenshots. Developers can upload screenshots using
4878 # tools/translation/upload_screenshots.py which finds and uploads
4879 # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
4880 # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
4881 # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
4882 #
4883 # The logic here is as follows:
4884 #
4885 # - If the CL has a .png file under the screenshots directory for a grd
4886 # file, warn the developer. Actual images should never be checked into the
4887 # Chrome repo.
4888 #
4889 # - If the CL contains modified or new messages in grd files and doesn't
4890 # contain the corresponding .sha1 files, warn the developer to add images
4891 # and upload them via tools/translation/upload_screenshots.py.
4892 #
4893 # - If the CL contains modified or new messages in grd files and the
4894 # corresponding .sha1 files, everything looks good.
4895 #
4896 # - If the CL contains removed messages in grd files but the corresponding
4897 # .sha1 files aren't removed, warn the developer to remove them.
4898 unnecessary_screenshots = []
4899 missing_sha1 = []
4900 unnecessary_sha1_files = []
4901
Rainhard Findlingfc31844c52020-05-15 09:58:264902 # This checks verifies that the ICU syntax of messages this CL touched is
4903 # valid, and reports any found syntax errors.
4904 # Without this presubmit check, ICU syntax errors in Chromium strings can land
4905 # without developers being aware of them. Later on, such ICU syntax errors
4906 # break message extraction for translation, hence would block Chromium
4907 # translations until they are fixed.
4908 icu_syntax_errors = []
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144909
4910 def _CheckScreenshotAdded(screenshots_dir, message_id):
4911 sha1_path = input_api.os_path.join(
4912 screenshots_dir, message_id + '.png.sha1')
4913 if sha1_path not in new_or_added_paths:
4914 missing_sha1.append(sha1_path)
4915
4916
4917 def _CheckScreenshotRemoved(screenshots_dir, message_id):
4918 sha1_path = input_api.os_path.join(
4919 screenshots_dir, message_id + '.png.sha1')
meacere7be7532019-10-02 17:41:034920 if input_api.os_path.exists(sha1_path) and sha1_path not in removed_paths:
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144921 unnecessary_sha1_files.append(sha1_path)
4922
Rainhard Findlingfc31844c52020-05-15 09:58:264923
4924 def _ValidateIcuSyntax(text, level, signatures):
4925 """Validates ICU syntax of a text string.
4926
4927 Check if text looks similar to ICU and checks for ICU syntax correctness
4928 in this case. Reports various issues with ICU syntax and values of
4929 variants. Supports checking of nested messages. Accumulate information of
4930 each ICU messages found in the text for further checking.
4931
4932 Args:
4933 text: a string to check.
4934 level: a number of current nesting level.
4935 signatures: an accumulator, a list of tuple of (level, variable,
4936 kind, variants).
4937
4938 Returns:
4939 None if a string is not ICU or no issue detected.
4940 A tuple of (message, start index, end index) if an issue detected.
4941 """
4942 valid_types = {
4943 'plural': (frozenset(
4944 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4945 frozenset(['=1', 'other'])),
4946 'selectordinal': (frozenset(
4947 ['=0', '=1', 'zero', 'one', 'two', 'few', 'many', 'other']),
4948 frozenset(['one', 'other'])),
4949 'select': (frozenset(), frozenset(['other'])),
4950 }
4951
4952 # Check if the message looks like an attempt to use ICU
4953 # plural. If yes - check if its syntax strictly matches ICU format.
4954 like = re.match(r'^[^{]*\{[^{]*\b(plural|selectordinal|select)\b', text)
4955 if not like:
4956 signatures.append((level, None, None, None))
4957 return
4958
4959 # Check for valid prefix and suffix
4960 m = re.match(
4961 r'^([^{]*\{)([a-zA-Z0-9_]+),\s*'
4962 r'(plural|selectordinal|select),\s*'
4963 r'(?:offset:\d+)?\s*(.*)', text, re.DOTALL)
4964 if not m:
4965 return (('This message looks like an ICU plural, '
4966 'but does not follow ICU syntax.'), like.start(), like.end())
4967 starting, variable, kind, variant_pairs = m.groups()
4968 variants, depth, last_pos = _ParseIcuVariants(variant_pairs, m.start(4))
4969 if depth:
4970 return ('Invalid ICU format. Unbalanced opening bracket', last_pos,
4971 len(text))
4972 first = text[0]
4973 ending = text[last_pos:]
4974 if not starting:
4975 return ('Invalid ICU format. No initial opening bracket', last_pos - 1,
4976 last_pos)
4977 if not ending or '}' not in ending:
4978 return ('Invalid ICU format. No final closing bracket', last_pos - 1,
4979 last_pos)
4980 elif first != '{':
4981 return (
4982 ('Invalid ICU format. Extra characters at the start of a complex '
4983 'message (go/icu-message-migration): "%s"') %
4984 starting, 0, len(starting))
4985 elif ending != '}':
4986 return (('Invalid ICU format. Extra characters at the end of a complex '
4987 'message (go/icu-message-migration): "%s"')
4988 % ending, last_pos - 1, len(text) - 1)
4989 if kind not in valid_types:
4990 return (('Unknown ICU message type %s. '
4991 'Valid types are: plural, select, selectordinal') % kind, 0, 0)
4992 known, required = valid_types[kind]
4993 defined_variants = set()
4994 for variant, variant_range, value, value_range in variants:
4995 start, end = variant_range
4996 if variant in defined_variants:
4997 return ('Variant "%s" is defined more than once' % variant,
4998 start, end)
4999 elif known and variant not in known:
5000 return ('Variant "%s" is not valid for %s message' % (variant, kind),
5001 start, end)
5002 defined_variants.add(variant)
5003 # Check for nested structure
5004 res = _ValidateIcuSyntax(value[1:-1], level + 1, signatures)
5005 if res:
5006 return (res[0], res[1] + value_range[0] + 1,
5007 res[2] + value_range[0] + 1)
5008 missing = required - defined_variants
5009 if missing:
5010 return ('Required variants missing: %s' % ', '.join(missing), 0,
5011 len(text))
5012 signatures.append((level, variable, kind, defined_variants))
5013
5014
5015 def _ParseIcuVariants(text, offset=0):
5016 """Parse variants part of ICU complex message.
5017
5018 Builds a tuple of variant names and values, as well as
5019 their offsets in the input string.
5020
5021 Args:
5022 text: a string to parse
5023 offset: additional offset to add to positions in the text to get correct
5024 position in the complete ICU string.
5025
5026 Returns:
5027 List of tuples, each tuple consist of four fields: variant name,
5028 variant name span (tuple of two integers), variant value, value
5029 span (tuple of two integers).
5030 """
5031 depth, start, end = 0, -1, -1
5032 variants = []
5033 key = None
5034 for idx, char in enumerate(text):
5035 if char == '{':
5036 if not depth:
5037 start = idx
5038 chunk = text[end + 1:start]
5039 key = chunk.strip()
5040 pos = offset + end + 1 + chunk.find(key)
5041 span = (pos, pos + len(key))
5042 depth += 1
5043 elif char == '}':
5044 if not depth:
5045 return variants, depth, offset + idx
5046 depth -= 1
5047 if not depth:
5048 end = idx
5049 variants.append((key, span, text[start:end + 1], (offset + start,
5050 offset + end + 1)))
5051 return variants, depth, offset + end + 1
5052
meacer8c0d3832019-12-26 21:46:165053 try:
5054 old_sys_path = sys.path
5055 sys.path = sys.path + [input_api.os_path.join(
5056 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5057 from helper import grd_helper
5058 finally:
5059 sys.path = old_sys_path
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145060
5061 for f in affected_grds:
5062 file_path = f.LocalPath()
5063 old_id_to_msg_map = {}
5064 new_id_to_msg_map = {}
Mustafa Emre Acerd697ac92020-02-06 19:03:385065 # Note that this code doesn't check if the file has been deleted. This is
5066 # OK because it only uses the old and new file contents and doesn't load
5067 # the file via its path.
5068 # It's also possible that a file's content refers to a renamed or deleted
5069 # file via a <part> tag, such as <part file="now-deleted-file.grdp">. This
5070 # is OK as well, because grd_helper ignores <part> tags when loading .grd or
5071 # .grdp files.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145072 if file_path.endswith('.grdp'):
5073 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585074 old_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395075 unicode('\n'.join(f.OldContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145076 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585077 new_id_to_msg_map = grd_helper.GetGrdpMessagesFromString(
Mustafa Emre Acerc8a012d2018-07-31 00:00:395078 unicode('\n'.join(f.NewContents())))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145079 else:
meacerff8a9b62019-12-10 19:43:585080 file_dir = input_api.os_path.dirname(file_path) or '.'
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145081 if f.OldContents():
meacerff8a9b62019-12-10 19:43:585082 old_id_to_msg_map = grd_helper.GetGrdMessages(
5083 StringIO(unicode('\n'.join(f.OldContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145084 if f.NewContents():
meacerff8a9b62019-12-10 19:43:585085 new_id_to_msg_map = grd_helper.GetGrdMessages(
5086 StringIO(unicode('\n'.join(f.NewContents()))), file_dir)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145087
Rainhard Findlingd8d04372020-08-13 13:30:095088 grd_name, ext = input_api.os_path.splitext(
5089 input_api.os_path.basename(file_path))
5090 screenshots_dir = input_api.os_path.join(
5091 input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
5092
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145093 # Compute added, removed and modified message IDs.
5094 old_ids = set(old_id_to_msg_map)
5095 new_ids = set(new_id_to_msg_map)
5096 added_ids = new_ids - old_ids
5097 removed_ids = old_ids - new_ids
5098 modified_ids = set([])
5099 for key in old_ids.intersection(new_ids):
Rainhard Findling1a3e71e2020-09-21 07:33:355100 if (old_id_to_msg_map[key].ContentsAsXml('', True)
Rainhard Findlingd8d04372020-08-13 13:30:095101 != new_id_to_msg_map[key].ContentsAsXml('', True)):
5102 # The message content itself changed. Require an updated screenshot.
5103 modified_ids.add(key)
Rainhard Findling1a3e71e2020-09-21 07:33:355104 elif old_id_to_msg_map[key].attrs['meaning'] != \
5105 new_id_to_msg_map[key].attrs['meaning']:
5106 # The message meaning changed. Ensure there is a screenshot for it.
5107 sha1_path = input_api.os_path.join(screenshots_dir, key + '.png.sha1')
5108 if sha1_path not in new_or_added_paths and not \
5109 input_api.os_path.exists(sha1_path):
5110 # There is neither a previous screenshot nor is a new one added now.
5111 # Require a screenshot.
5112 modified_ids.add(key)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145113
Rainhard Findlingfc31844c52020-05-15 09:58:265114 if run_screenshot_check:
5115 # Check the screenshot directory for .png files. Warn if there is any.
5116 for png_path in affected_png_paths:
5117 if png_path.startswith(screenshots_dir):
5118 unnecessary_screenshots.append(png_path)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145119
Rainhard Findlingfc31844c52020-05-15 09:58:265120 for added_id in added_ids:
5121 _CheckScreenshotAdded(screenshots_dir, added_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145122
Rainhard Findlingfc31844c52020-05-15 09:58:265123 for modified_id in modified_ids:
5124 _CheckScreenshotAdded(screenshots_dir, modified_id)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145125
Rainhard Findlingfc31844c52020-05-15 09:58:265126 for removed_id in removed_ids:
5127 _CheckScreenshotRemoved(screenshots_dir, removed_id)
5128
5129 # Check new and changed strings for ICU syntax errors.
5130 for key in added_ids.union(modified_ids):
5131 msg = new_id_to_msg_map[key].ContentsAsXml('', True)
5132 err = _ValidateIcuSyntax(msg, 0, [])
5133 if err is not None:
5134 icu_syntax_errors.append(str(key) + ': ' + str(err[0]))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145135
5136 results = []
Rainhard Findlingfc31844c52020-05-15 09:58:265137 if run_screenshot_check:
5138 if unnecessary_screenshots:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005139 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265140 'Do not include actual screenshots in the changelist. Run '
5141 'tools/translate/upload_screenshots.py to upload them instead:',
5142 sorted(unnecessary_screenshots)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145143
Rainhard Findlingfc31844c52020-05-15 09:58:265144 if missing_sha1:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005145 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265146 'You are adding or modifying UI strings.\n'
5147 'To ensure the best translations, take screenshots of the relevant UI '
5148 '(https://g.co/chrome/translation) and add these files to your '
5149 'changelist:', sorted(missing_sha1)))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145150
Rainhard Findlingfc31844c52020-05-15 09:58:265151 if unnecessary_sha1_files:
Mustafa Emre Acerc6ed2682020-07-07 07:24:005152 results.append(output_api.PresubmitError(
Rainhard Findlingfc31844c52020-05-15 09:58:265153 'You removed strings associated with these files. Remove:',
5154 sorted(unnecessary_sha1_files)))
5155 else:
5156 results.append(output_api.PresubmitPromptOrNotify('Skipping translation '
5157 'screenshots check.'))
5158
5159 if icu_syntax_errors:
Rainhard Findling0e8d74c12020-06-26 13:48:075160 results.append(output_api.PresubmitPromptWarning(
Rainhard Findlingfc31844c52020-05-15 09:58:265161 'ICU syntax errors were found in the following strings (problems or '
5162 'feedback? Contact [email protected]):', items=icu_syntax_errors))
Mustafa Emre Acer29bf6ac92018-07-30 21:42:145163
5164 return results
Mustafa Emre Acer51f2f742020-03-09 19:41:125165
5166
Saagar Sanghavifceeaae2020-08-12 16:40:365167def CheckTranslationExpectations(input_api, output_api,
Mustafa Emre Acer51f2f742020-03-09 19:41:125168 repo_root=None,
5169 translation_expectations_path=None,
5170 grd_files=None):
5171 import sys
5172 affected_grds = [f for f in input_api.AffectedFiles()
5173 if (f.LocalPath().endswith('.grd') or
5174 f.LocalPath().endswith('.grdp'))]
5175 if not affected_grds:
5176 return []
5177
5178 try:
5179 old_sys_path = sys.path
5180 sys.path = sys.path + [
5181 input_api.os_path.join(
5182 input_api.PresubmitLocalPath(), 'tools', 'translation')]
5183 from helper import git_helper
5184 from helper import translation_helper
5185 finally:
5186 sys.path = old_sys_path
5187
5188 # Check that translation expectations can be parsed and we can get a list of
5189 # translatable grd files. |repo_root| and |translation_expectations_path| are
5190 # only passed by tests.
5191 if not repo_root:
5192 repo_root = input_api.PresubmitLocalPath()
5193 if not translation_expectations_path:
5194 translation_expectations_path = input_api.os_path.join(
5195 repo_root, 'tools', 'gritsettings',
5196 'translation_expectations.pyl')
5197 if not grd_files:
5198 grd_files = git_helper.list_grds_in_repository(repo_root)
5199
5200 try:
5201 translation_helper.get_translatable_grds(repo_root, grd_files,
5202 translation_expectations_path)
5203 except Exception as e:
5204 return [output_api.PresubmitNotifyResult(
5205 'Failed to get a list of translatable grd files. This happens when:\n'
5206 ' - One of the modified grd or grdp files cannot be parsed or\n'
5207 ' - %s is not updated.\n'
5208 'Stack:\n%s' % (translation_expectations_path, str(e)))]
5209 return []
Ken Rockotc31f4832020-05-29 18:58:515210
5211
Saagar Sanghavifceeaae2020-08-12 16:40:365212def CheckStableMojomChanges(input_api, output_api):
Ken Rockotc31f4832020-05-29 18:58:515213 """Changes to [Stable] mojom types must preserve backward-compatibility."""
Ken Rockotad7901f942020-06-04 20:17:095214 changed_mojoms = input_api.AffectedFiles(
5215 include_deletes=True,
5216 file_filter=lambda f: f.LocalPath().endswith(('.mojom')))
Ken Rockotc31f4832020-05-29 18:58:515217 delta = []
5218 for mojom in changed_mojoms:
5219 old_contents = ''.join(mojom.OldContents()) or None
5220 new_contents = ''.join(mojom.NewContents()) or None
5221 delta.append({
5222 'filename': mojom.LocalPath(),
5223 'old': '\n'.join(mojom.OldContents()) or None,
5224 'new': '\n'.join(mojom.NewContents()) or None,
5225 })
5226
5227 process = input_api.subprocess.Popen(
5228 [input_api.python_executable,
5229 input_api.os_path.join(input_api.PresubmitLocalPath(), 'mojo',
5230 'public', 'tools', 'mojom',
5231 'check_stable_mojom_compatibility.py'),
5232 '--src-root', input_api.PresubmitLocalPath()],
5233 stdin=input_api.subprocess.PIPE,
5234 stdout=input_api.subprocess.PIPE,
5235 stderr=input_api.subprocess.PIPE,
5236 universal_newlines=True)
5237 (x, error) = process.communicate(input=input_api.json.dumps(delta))
5238 if process.returncode:
5239 return [output_api.PresubmitError(
5240 'One or more [Stable] mojom definitions appears to have been changed '
5241 'in a way that is not backward-compatible.',
5242 long_text=error)]
5243 return []